@kritzel/engine 0.4.31
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/LICENSE.md +50 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
- package/dist/cjs/engine.constants-CakmdKMW.js +28206 -0
- package/dist/cjs/index-BbbWU2aN.js +1742 -0
- package/dist/cjs/index.cjs.js +4232 -0
- package/dist/cjs/kritzel-awareness-cursors_5.cjs.entry.js +28004 -0
- package/dist/cjs/loader.cjs.js +13 -0
- package/dist/cjs/stencil.cjs.js +25 -0
- package/dist/collection/classes/core/core.class.js +1389 -0
- package/dist/collection/classes/core/reviver.class.js +124 -0
- package/dist/collection/classes/core/store.class.js +337 -0
- package/dist/collection/classes/core/viewport.class.js +794 -0
- package/dist/collection/classes/core/workspace.class.js +112 -0
- package/dist/collection/classes/handlers/base.handler.js +20 -0
- package/dist/collection/classes/handlers/context-menu.handler.js +170 -0
- package/dist/collection/classes/handlers/hover.handler.js +35 -0
- package/dist/collection/classes/handlers/key.handler.js +162 -0
- package/dist/collection/classes/handlers/line-handle.handler.js +475 -0
- package/dist/collection/classes/handlers/move.handler.js +295 -0
- package/dist/collection/classes/handlers/resize.handler.js +327 -0
- package/dist/collection/classes/handlers/rotation.handler.js +174 -0
- package/dist/collection/classes/handlers/selection.handler.js +526 -0
- package/dist/collection/classes/managers/anchor.manager.js +1476 -0
- package/dist/collection/classes/managers/browser-permission.manager.js +64 -0
- package/dist/collection/classes/managers/clipboard.manager.js +346 -0
- package/dist/collection/classes/managers/clipboard.types.js +1 -0
- package/dist/collection/classes/managers/cursor.manager.js +139 -0
- package/dist/collection/classes/managers/license.manager.js +341 -0
- package/dist/collection/classes/managers/localization.manager.js +227 -0
- package/dist/collection/classes/managers/theme.manager.js +206 -0
- package/dist/collection/classes/objects/base-object.class.js +462 -0
- package/dist/collection/classes/objects/dynamic-object.class.js +437 -0
- package/dist/collection/classes/objects/group.class.js +590 -0
- package/dist/collection/classes/objects/image.class.js +500 -0
- package/dist/collection/classes/objects/line.class.js +789 -0
- package/dist/collection/classes/objects/path.class.js +578 -0
- package/dist/collection/classes/objects/selection-box.class.js +32 -0
- package/dist/collection/classes/objects/selection-group.class.js +752 -0
- package/dist/collection/classes/objects/shape.class.js +628 -0
- package/dist/collection/classes/objects/text.class.js +461 -0
- package/dist/collection/classes/providers/assets/asset-resolver.class.js +536 -0
- package/dist/collection/classes/providers/assets/http-asset-provider.class.js +111 -0
- package/dist/collection/classes/providers/assets/indexeddb-asset-provider.class.js +241 -0
- package/dist/collection/classes/providers/assets/presigned-asset-provider.class.js +86 -0
- package/dist/collection/classes/providers/paste-intent/event-paste-intent.provider.js +48 -0
- package/dist/collection/classes/providers/paste-intent/ios-paste-intent.provider.js +16 -0
- package/dist/collection/classes/providers/paste-intent/navigator-paste-intent.provider.js +86 -0
- package/dist/collection/classes/providers/sync/broadcast-sync-provider.class.js +100 -0
- package/dist/collection/classes/providers/sync/hocuspocus-sync-provider.class.js +333 -0
- package/dist/collection/classes/providers/sync/in-memory-sync-provider.class.js +69 -0
- package/dist/collection/classes/providers/sync/indexeddb-sync-provider.class.js +39 -0
- package/dist/collection/classes/providers/sync/websocket-sync-provider.class.js +110 -0
- package/dist/collection/classes/registries/dynamic-object-renderer.registry.js +52 -0
- package/dist/collection/classes/registries/font-registry.class.js +161 -0
- package/dist/collection/classes/registries/icon-registry.class.js +118 -0
- package/dist/collection/classes/registries/paste-intent-provider.registry.js +26 -0
- package/dist/collection/classes/registries/tool.registry.js +69 -0
- package/dist/collection/classes/structures/app-state-map.structure.js +461 -0
- package/dist/collection/classes/structures/object-map.structure.js +1103 -0
- package/dist/collection/classes/structures/quadtree.structure.js +251 -0
- package/dist/collection/classes/tools/base-tool.class.js +88 -0
- package/dist/collection/classes/tools/brush-tool.class.js +236 -0
- package/dist/collection/classes/tools/eraser-tool.class.js +133 -0
- package/dist/collection/classes/tools/image-tool.class.js +152 -0
- package/dist/collection/classes/tools/line-tool.class.js +249 -0
- package/dist/collection/classes/tools/selection-tool.class.js +611 -0
- package/dist/collection/classes/tools/shape-tool.class.js +251 -0
- package/dist/collection/classes/tools/text-tool.class.js +179 -0
- package/dist/collection/collection-manifest.json +17 -0
- package/dist/collection/components/kritzel-awareness-cursors/kritzel-awareness-cursors.css +115 -0
- package/dist/collection/components/kritzel-awareness-cursors/kritzel-awareness-cursors.js +380 -0
- package/dist/collection/components/kritzel-cursor-trail/kritzel-cursor-trail.css +10 -0
- package/dist/collection/components/kritzel-cursor-trail/kritzel-cursor-trail.js +153 -0
- package/dist/collection/components/kritzel-engine/kritzel-engine.css +81 -0
- package/dist/collection/components/kritzel-engine/kritzel-engine.js +6345 -0
- package/dist/collection/components/kritzel-icon/kritzel-icon.css +18 -0
- package/dist/collection/components/kritzel-icon/kritzel-icon.js +93 -0
- package/dist/collection/components/kritzel-watermark/kritzel-watermark.css +29 -0
- package/dist/collection/components/kritzel-watermark/kritzel-watermark.js +83 -0
- package/dist/collection/configs/default-asset-storage.config.js +9 -0
- package/dist/collection/configs/default-brush-tool.config.js +9 -0
- package/dist/collection/configs/default-engine-config.js +73 -0
- package/dist/collection/configs/default-line-tool.config.js +12 -0
- package/dist/collection/configs/default-shape-tool.config.js +15 -0
- package/dist/collection/configs/default-sync.config.js +6 -0
- package/dist/collection/configs/default-text-tool.config.js +12 -0
- package/dist/collection/constants/color-palette.constants.js +40 -0
- package/dist/collection/constants/core.constants.js +1 -0
- package/dist/collection/constants/engine.constants.js +4 -0
- package/dist/collection/constants/license.constants.js +25 -0
- package/dist/collection/constants/schema.constants.js +4 -0
- package/dist/collection/constants/storage.constants.js +1 -0
- package/dist/collection/constants/stroke-size.constants.js +2 -0
- package/dist/collection/constants/text-tool-fonts.constants.js +18 -0
- package/dist/collection/constants/version.js +6 -0
- package/dist/collection/enums/alignment.enum.js +9 -0
- package/dist/collection/enums/event-button.enum.js +6 -0
- package/dist/collection/enums/handle-type.enum.js +7 -0
- package/dist/collection/enums/shape-type.enum.js +6 -0
- package/dist/collection/events/active-workspace-change.event.js +1 -0
- package/dist/collection/events/editor-is-ready.event.js +1 -0
- package/dist/collection/events/login.event.js +1 -0
- package/dist/collection/helpers/alignment.helper.js +73 -0
- package/dist/collection/helpers/class.helper.js +5 -0
- package/dist/collection/helpers/color.helper.js +106 -0
- package/dist/collection/helpers/cursor.helper.js +57 -0
- package/dist/collection/helpers/devices.helper.js +28 -0
- package/dist/collection/helpers/event.helper.js +58 -0
- package/dist/collection/helpers/geometry.helper.js +149 -0
- package/dist/collection/helpers/html.helper.js +116 -0
- package/dist/collection/helpers/image-file.helper.js +6 -0
- package/dist/collection/helpers/keyboard.helper.js +55 -0
- package/dist/collection/helpers/localization.helper.js +25 -0
- package/dist/collection/helpers/math.helper.js +8 -0
- package/dist/collection/helpers/migration.helper.js +45 -0
- package/dist/collection/helpers/object.helper.js +29 -0
- package/dist/collection/helpers/svg-export.helper.js +655 -0
- package/dist/collection/helpers/theme.helper.js +77 -0
- package/dist/collection/helpers/tool-config.helper.js +63 -0
- package/dist/collection/helpers/wheel.helper.js +113 -0
- package/dist/collection/index.js +107 -0
- package/dist/collection/interfaces/anchor.interface.js +1 -0
- package/dist/collection/interfaces/arrow-head.interface.js +1 -0
- package/dist/collection/interfaces/asset-provider.interface.js +1 -0
- package/dist/collection/interfaces/asset-storage-config.interface.js +1 -0
- package/dist/collection/interfaces/asset.interface.js +1 -0
- package/dist/collection/interfaces/bounding-box.interface.js +1 -0
- package/dist/collection/interfaces/clonable.interface.js +1 -0
- package/dist/collection/interfaces/context-menu-item.interface.js +1 -0
- package/dist/collection/interfaces/context-menu-state.interface.js +1 -0
- package/dist/collection/interfaces/debug-info.interface.js +1 -0
- package/dist/collection/interfaces/dialog.interface.js +1 -0
- package/dist/collection/interfaces/document-metadata.interface.js +1 -0
- package/dist/collection/interfaces/dynamic-object-renderer.interface.js +1 -0
- package/dist/collection/interfaces/engine-state.interface.js +1 -0
- package/dist/collection/interfaces/font.interface.js +1 -0
- package/dist/collection/interfaces/localization.interface.js +1 -0
- package/dist/collection/interfaces/login-config.interface.js +1 -0
- package/dist/collection/interfaces/master-detail.interface.js +1 -0
- package/dist/collection/interfaces/menu-item.interface.js +1 -0
- package/dist/collection/interfaces/migration.interface.js +1 -0
- package/dist/collection/interfaces/notification.interface.js +1 -0
- package/dist/collection/interfaces/object-change-event.interface.js +1 -0
- package/dist/collection/interfaces/object-export.interface.js +1 -0
- package/dist/collection/interfaces/object.interface.js +1 -0
- package/dist/collection/interfaces/paste-intent-provider.interface.js +1 -0
- package/dist/collection/interfaces/point.interface.js +1 -0
- package/dist/collection/interfaces/polygon.interface.js +1 -0
- package/dist/collection/interfaces/remote-cursor.interface.js +1 -0
- package/dist/collection/interfaces/selection-state.interface.js +1 -0
- package/dist/collection/interfaces/serializable.interface.js +1 -0
- package/dist/collection/interfaces/settings.interface.js +1 -0
- package/dist/collection/interfaces/share.interface.js +1 -0
- package/dist/collection/interfaces/shortcut.interface.js +1 -0
- package/dist/collection/interfaces/sync-config.interface.js +21 -0
- package/dist/collection/interfaces/sync-provider.interface.js +1 -0
- package/dist/collection/interfaces/theme.interface.js +1 -0
- package/dist/collection/interfaces/tool-config.interface.js +1 -0
- package/dist/collection/interfaces/tool-type.interface.js +1 -0
- package/dist/collection/interfaces/tool.interface.js +1 -0
- package/dist/collection/interfaces/toolbar-item.interface.js +1 -0
- package/dist/collection/interfaces/undo-state.interface.js +1 -0
- package/dist/collection/interfaces/user.interface.js +1 -0
- package/dist/collection/interfaces/viewport-state.interface.js +1 -0
- package/dist/collection/locales/de-locale.js +119 -0
- package/dist/collection/locales/en-locale.js +120 -0
- package/dist/collection/locales/fr-locale.js +119 -0
- package/dist/collection/migrations/app-state.migrations.js +47 -0
- package/dist/collection/migrations/workspace.migrations.js +67 -0
- package/dist/collection/themes/dark-theme.js +340 -0
- package/dist/collection/themes/light-theme.js +346 -0
- package/dist/collection/types/deep-readonly.type.js +1 -0
- package/dist/collection/types/state.types.js +1 -0
- package/dist/components/index.d.ts +47 -0
- package/dist/components/index.js +4143 -0
- package/dist/components/kritzel-awareness-cursors.d.ts +11 -0
- package/dist/components/kritzel-awareness-cursors.js +6 -0
- package/dist/components/kritzel-cursor-trail.d.ts +11 -0
- package/dist/components/kritzel-cursor-trail.js +6 -0
- package/dist/components/kritzel-engine.d.ts +11 -0
- package/dist/components/kritzel-engine.js +52641 -0
- package/dist/components/kritzel-icon.d.ts +11 -0
- package/dist/components/kritzel-icon.js +6 -0
- package/dist/components/kritzel-watermark.d.ts +11 -0
- package/dist/components/kritzel-watermark.js +6 -0
- package/dist/components/p-B2Htv9ou.js +49 -0
- package/dist/components/p-BvRGQvVI.js +3456 -0
- package/dist/components/p-CfSx6HU_.js +1469 -0
- package/dist/components/p-YP8wAcF4.js +122 -0
- package/dist/components/p-fx6msYHJ.js +167 -0
- package/dist/esm/app-globals-DQuL1Twl.js +3 -0
- package/dist/esm/engine.constants-Bl5-pbq-.js +28143 -0
- package/dist/esm/index-BU9Mv7y0.js +1715 -0
- package/dist/esm/index.js +4134 -0
- package/dist/esm/kritzel-awareness-cursors_5.entry.js +27978 -0
- package/dist/esm/loader.js +11 -0
- package/dist/esm/stencil.js +21 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/stencil/index.esm.js +4134 -0
- package/dist/stencil/p-BU9Mv7y0.js +1702 -0
- package/dist/stencil/p-Bl5-pbq-.js +28143 -0
- package/dist/stencil/p-DQuL1Twl.js +3 -0
- package/dist/stencil/p-f0a8b7af.entry.js +27978 -0
- package/dist/stencil/stencil.esm.js +21 -0
- package/dist/types/classes/core/core.class.d.ts +532 -0
- package/dist/types/classes/core/reviver.class.d.ts +32 -0
- package/dist/types/classes/core/store.class.d.ts +198 -0
- package/dist/types/classes/core/viewport.class.d.ts +256 -0
- package/dist/types/classes/core/workspace.class.d.ts +95 -0
- package/dist/types/classes/handlers/base.handler.d.ts +18 -0
- package/dist/types/classes/handlers/context-menu.handler.d.ts +67 -0
- package/dist/types/classes/handlers/hover.handler.d.ts +23 -0
- package/dist/types/classes/handlers/key.handler.d.ts +44 -0
- package/dist/types/classes/handlers/line-handle.handler.d.ts +115 -0
- package/dist/types/classes/handlers/move.handler.d.ts +94 -0
- package/dist/types/classes/handlers/resize.handler.d.ts +95 -0
- package/dist/types/classes/handlers/rotation.handler.d.ts +50 -0
- package/dist/types/classes/handlers/selection.handler.d.ts +153 -0
- package/dist/types/classes/managers/anchor.manager.d.ts +513 -0
- package/dist/types/classes/managers/browser-permission.manager.d.ts +41 -0
- package/dist/types/classes/managers/clipboard.manager.d.ts +71 -0
- package/dist/types/classes/managers/clipboard.types.d.ts +23 -0
- package/dist/types/classes/managers/cursor.manager.d.ts +66 -0
- package/dist/types/classes/managers/license.manager.d.ts +147 -0
- package/dist/types/classes/managers/localization.manager.d.ts +145 -0
- package/dist/types/classes/managers/theme.manager.d.ts +112 -0
- package/dist/types/classes/objects/base-object.class.d.ts +266 -0
- package/dist/types/classes/objects/dynamic-object.class.d.ts +148 -0
- package/dist/types/classes/objects/group.class.d.ts +231 -0
- package/dist/types/classes/objects/image.class.d.ts +246 -0
- package/dist/types/classes/objects/line.class.d.ts +285 -0
- package/dist/types/classes/objects/path.class.d.ts +220 -0
- package/dist/types/classes/objects/selection-box.class.d.ts +19 -0
- package/dist/types/classes/objects/selection-group.class.d.ts +267 -0
- package/dist/types/classes/objects/shape.class.d.ts +322 -0
- package/dist/types/classes/objects/text.class.d.ts +197 -0
- package/dist/types/classes/providers/assets/asset-resolver.class.d.ts +141 -0
- package/dist/types/classes/providers/assets/http-asset-provider.class.d.ts +79 -0
- package/dist/types/classes/providers/assets/indexeddb-asset-provider.class.d.ts +69 -0
- package/dist/types/classes/providers/assets/presigned-asset-provider.class.d.ts +69 -0
- package/dist/types/classes/providers/paste-intent/event-paste-intent.provider.d.ts +8 -0
- package/dist/types/classes/providers/paste-intent/ios-paste-intent.provider.d.ts +6 -0
- package/dist/types/classes/providers/paste-intent/navigator-paste-intent.provider.d.ts +9 -0
- package/dist/types/classes/providers/sync/broadcast-sync-provider.class.d.ts +23 -0
- package/dist/types/classes/providers/sync/hocuspocus-sync-provider.class.d.ts +163 -0
- package/dist/types/classes/providers/sync/in-memory-sync-provider.class.d.ts +39 -0
- package/dist/types/classes/providers/sync/indexeddb-sync-provider.class.d.ts +25 -0
- package/dist/types/classes/providers/sync/websocket-sync-provider.class.d.ts +63 -0
- package/dist/types/classes/registries/dynamic-object-renderer.registry.d.ts +32 -0
- package/dist/types/classes/registries/font-registry.class.d.ts +19 -0
- package/dist/types/classes/registries/icon-registry.class.d.ts +39 -0
- package/dist/types/classes/registries/paste-intent-provider.registry.d.ts +10 -0
- package/dist/types/classes/registries/tool.registry.d.ts +53 -0
- package/dist/types/classes/structures/app-state-map.structure.d.ts +171 -0
- package/dist/types/classes/structures/object-map.structure.d.ts +403 -0
- package/dist/types/classes/structures/quadtree.structure.d.ts +128 -0
- package/dist/types/classes/tools/base-tool.class.d.ts +72 -0
- package/dist/types/classes/tools/brush-tool.class.d.ts +68 -0
- package/dist/types/classes/tools/eraser-tool.class.d.ts +38 -0
- package/dist/types/classes/tools/image-tool.class.d.ts +74 -0
- package/dist/types/classes/tools/line-tool.class.d.ts +63 -0
- package/dist/types/classes/tools/selection-tool.class.d.ts +188 -0
- package/dist/types/classes/tools/shape-tool.class.d.ts +90 -0
- package/dist/types/classes/tools/text-tool.class.d.ts +66 -0
- package/dist/types/components/kritzel-awareness-cursors/kritzel-awareness-cursors.d.ts +29 -0
- package/dist/types/components/kritzel-cursor-trail/kritzel-cursor-trail.d.ts +19 -0
- package/dist/types/components/kritzel-engine/kritzel-engine.d.ts +695 -0
- package/dist/types/components/kritzel-icon/kritzel-icon.d.ts +6 -0
- package/dist/types/components/kritzel-watermark/kritzel-watermark.d.ts +20 -0
- package/dist/types/components.d.ts +981 -0
- package/dist/types/configs/default-asset-storage.config.d.ts +8 -0
- package/dist/types/configs/default-brush-tool.config.d.ts +2 -0
- package/dist/types/configs/default-engine-config.d.ts +2 -0
- package/dist/types/configs/default-line-tool.config.d.ts +2 -0
- package/dist/types/configs/default-shape-tool.config.d.ts +2 -0
- package/dist/types/configs/default-sync.config.d.ts +5 -0
- package/dist/types/configs/default-text-tool.config.d.ts +2 -0
- package/dist/types/constants/color-palette.constants.d.ts +31 -0
- package/dist/types/constants/core.constants.d.ts +0 -0
- package/dist/types/constants/engine.constants.d.ts +4 -0
- package/dist/types/constants/license.constants.d.ts +25 -0
- package/dist/types/constants/schema.constants.d.ts +4 -0
- package/dist/types/constants/storage.constants.d.ts +1 -0
- package/dist/types/constants/stroke-size.constants.d.ts +2 -0
- package/dist/types/constants/text-tool-fonts.constants.d.ts +3 -0
- package/dist/types/constants/version.d.ts +6 -0
- package/dist/types/enums/alignment.enum.d.ts +8 -0
- package/dist/types/enums/event-button.enum.d.ts +5 -0
- package/dist/types/enums/handle-type.enum.d.ts +6 -0
- package/dist/types/enums/shape-type.enum.d.ts +5 -0
- package/dist/types/events/active-workspace-change.event.d.ts +7 -0
- package/dist/types/events/editor-is-ready.event.d.ts +18 -0
- package/dist/types/events/login.event.d.ts +3 -0
- package/dist/types/helpers/alignment.helper.d.ts +21 -0
- package/dist/types/helpers/class.helper.d.ts +3 -0
- package/dist/types/helpers/color.helper.d.ts +34 -0
- package/dist/types/helpers/cursor.helper.d.ts +22 -0
- package/dist/types/helpers/devices.helper.d.ts +8 -0
- package/dist/types/helpers/event.helper.d.ts +6 -0
- package/dist/types/helpers/geometry.helper.d.ts +38 -0
- package/dist/types/helpers/html.helper.d.ts +8 -0
- package/dist/types/helpers/image-file.helper.d.ts +3 -0
- package/dist/types/helpers/keyboard.helper.d.ts +6 -0
- package/dist/types/helpers/localization.helper.d.ts +18 -0
- package/dist/types/helpers/math.helper.d.ts +4 -0
- package/dist/types/helpers/migration.helper.d.ts +30 -0
- package/dist/types/helpers/object.helper.d.ts +9 -0
- package/dist/types/helpers/svg-export.helper.d.ts +231 -0
- package/dist/types/helpers/theme.helper.d.ts +42 -0
- package/dist/types/helpers/tool-config.helper.d.ts +4 -0
- package/dist/types/helpers/wheel.helper.d.ts +9 -0
- package/dist/types/index.d.ts +109 -0
- package/dist/types/interfaces/anchor.interface.d.ts +147 -0
- package/dist/types/interfaces/arrow-head.interface.d.ts +27 -0
- package/dist/types/interfaces/asset-provider.interface.d.ts +88 -0
- package/dist/types/interfaces/asset-storage-config.interface.d.ts +40 -0
- package/dist/types/interfaces/asset.interface.d.ts +43 -0
- package/dist/types/interfaces/bounding-box.interface.d.ts +8 -0
- package/dist/types/interfaces/clonable.interface.d.ts +3 -0
- package/dist/types/interfaces/context-menu-item.interface.d.ts +25 -0
- package/dist/types/interfaces/context-menu-state.interface.d.ts +16 -0
- package/dist/types/interfaces/debug-info.interface.d.ts +7 -0
- package/dist/types/interfaces/dialog.interface.d.ts +4 -0
- package/dist/types/interfaces/document-metadata.interface.d.ts +6 -0
- package/dist/types/interfaces/dynamic-object-renderer.interface.d.ts +40 -0
- package/dist/types/interfaces/engine-state.interface.d.ts +82 -0
- package/dist/types/interfaces/font.interface.d.ts +15 -0
- package/dist/types/interfaces/localization.interface.d.ts +143 -0
- package/dist/types/interfaces/login-config.interface.d.ts +24 -0
- package/dist/types/interfaces/master-detail.interface.d.ts +14 -0
- package/dist/types/interfaces/menu-item.interface.d.ts +27 -0
- package/dist/types/interfaces/migration.interface.d.ts +16 -0
- package/dist/types/interfaces/notification.interface.d.ts +10 -0
- package/dist/types/interfaces/object-change-event.interface.d.ts +31 -0
- package/dist/types/interfaces/object-export.interface.d.ts +20 -0
- package/dist/types/interfaces/object.interface.d.ts +53 -0
- package/dist/types/interfaces/paste-intent-provider.interface.d.ts +10 -0
- package/dist/types/interfaces/point.interface.d.ts +4 -0
- package/dist/types/interfaces/polygon.interface.d.ts +7 -0
- package/dist/types/interfaces/remote-cursor.interface.d.ts +18 -0
- package/dist/types/interfaces/selection-state.interface.d.ts +7 -0
- package/dist/types/interfaces/serializable.interface.d.ts +5 -0
- package/dist/types/interfaces/settings.interface.d.ts +25 -0
- package/dist/types/interfaces/share.interface.d.ts +9 -0
- package/dist/types/interfaces/shortcut.interface.d.ts +10 -0
- package/dist/types/interfaces/sync-config.interface.d.ts +41 -0
- package/dist/types/interfaces/sync-provider.interface.d.ts +66 -0
- package/dist/types/interfaces/theme.interface.d.ts +553 -0
- package/dist/types/interfaces/tool-config.interface.d.ts +24 -0
- package/dist/types/interfaces/tool-type.interface.d.ts +1 -0
- package/dist/types/interfaces/tool.interface.d.ts +8 -0
- package/dist/types/interfaces/toolbar-item.interface.d.ts +66 -0
- package/dist/types/interfaces/undo-state.interface.d.ts +6 -0
- package/dist/types/interfaces/user.interface.d.ts +22 -0
- package/dist/types/interfaces/viewport-state.interface.d.ts +7 -0
- package/dist/types/locales/de-locale.d.ts +5 -0
- package/dist/types/locales/en-locale.d.ts +6 -0
- package/dist/types/locales/fr-locale.d.ts +5 -0
- package/dist/types/migrations/app-state.migrations.d.ts +11 -0
- package/dist/types/migrations/workspace.migrations.d.ts +11 -0
- package/dist/types/stencil-public-runtime.d.ts +1873 -0
- package/dist/types/themes/dark-theme.d.ts +5 -0
- package/dist/types/themes/light-theme.d.ts +5 -0
- package/dist/types/types/deep-readonly.type.d.ts +7 -0
- package/dist/types/types/state.types.d.ts +3 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +101 -0
- package/readme.md +11 -0
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
import { KritzelEventHelper } from "../../helpers/event.helper";
|
|
2
|
+
import { KritzelSelectionBox } from "../objects/selection-box.class";
|
|
3
|
+
import { KritzelSelectionGroup } from "../objects/selection-group.class";
|
|
4
|
+
import { KritzelGroup } from "../objects/group.class";
|
|
5
|
+
import { KritzelBaseHandler } from "./base.handler";
|
|
6
|
+
/**
|
|
7
|
+
* Handles object selection interactions on the canvas.
|
|
8
|
+
* Supports both click-to-select and drag-to-select (marquee) selection modes
|
|
9
|
+
* for mouse, touch, and pen input types. Also handles additive selection
|
|
10
|
+
* via shift/ctrl modifiers.
|
|
11
|
+
*/
|
|
12
|
+
export class KritzelSelectionHandler extends KritzelBaseHandler {
|
|
13
|
+
startX = 0;
|
|
14
|
+
startY = 0;
|
|
15
|
+
touchStartX = 0;
|
|
16
|
+
touchStartY = 0;
|
|
17
|
+
touchStartTimeout = null;
|
|
18
|
+
/**
|
|
19
|
+
* Tracks previously selected objects for efficient deselection.
|
|
20
|
+
* Uses a Set for O(1) lookup when determining which objects need to be deselected.
|
|
21
|
+
*/
|
|
22
|
+
_previouslySelectedObjects = new Set();
|
|
23
|
+
/**
|
|
24
|
+
* Indicates whether the current selection action is a single click (no drag).
|
|
25
|
+
* @returns `true` if a selection box exists with zero width and height
|
|
26
|
+
*/
|
|
27
|
+
get isSelectionClick() {
|
|
28
|
+
const selectionBox = this._core.store.selectionBox;
|
|
29
|
+
return selectionBox && selectionBox.width === 0 && selectionBox.height === 0;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Indicates whether the current selection action is a drag selection (marquee).
|
|
33
|
+
* @returns `true` if a selection box exists with non-zero width or height
|
|
34
|
+
*/
|
|
35
|
+
get isSelectionDrag() {
|
|
36
|
+
const selectionBox = this._core.store.selectionBox;
|
|
37
|
+
return selectionBox && (selectionBox.width > 0 || selectionBox.height > 0);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a new selection handler instance.
|
|
41
|
+
* @param core - The KritzelCore instance providing access to store, engine, and other core services
|
|
42
|
+
*/
|
|
43
|
+
constructor(core) {
|
|
44
|
+
super(core);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Handles the pointer down event to initiate selection.
|
|
48
|
+
* For mouse input, starts selection on left-click when no selection group exists or in additive mode.
|
|
49
|
+
* For touch/pen input, initiates selection after a brief delay (80ms) to distinguish from other gestures.
|
|
50
|
+
* @param event - The pointer event containing input type, coordinates, and modifier keys
|
|
51
|
+
*/
|
|
52
|
+
handlePointerDown(event) {
|
|
53
|
+
if (this._core.store.state.isResizeHandleSelected || this._core.store.state.isRotationHandleSelected) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const isAdditive = event.shiftKey || event.ctrlKey;
|
|
57
|
+
if (event.pointerType === 'mouse') {
|
|
58
|
+
if (KritzelEventHelper.isLeftClick(event) && (!this._core.store.selectionGroup || isAdditive)) {
|
|
59
|
+
this.startMouseSelection(event, isAdditive);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
63
|
+
this.touchStartTimeout = setTimeout(() => {
|
|
64
|
+
if (this._core.store.state.pointers.size === 1 && !this._core.store.state.isScaling && (!this._core.store.selectionGroup || isAdditive)) {
|
|
65
|
+
this.startTouchSelection(event, isAdditive);
|
|
66
|
+
this.updateTouchSelection();
|
|
67
|
+
}
|
|
68
|
+
}, 80);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Handles the pointer move event to update the selection box during drag selection.
|
|
73
|
+
* For mouse input, updates selection when actively selecting.
|
|
74
|
+
* For touch/pen input, updates selection and cancels long-touch timeout if movement exceeds threshold.
|
|
75
|
+
* @param event - The pointer event containing current pointer position and input type
|
|
76
|
+
*/
|
|
77
|
+
handlePointerMove(event) {
|
|
78
|
+
if (event.pointerType === 'mouse') {
|
|
79
|
+
if (this._core.store.state.isSelecting) {
|
|
80
|
+
this.updateMouseSelection(event);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
84
|
+
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
85
|
+
const x = Math.round(activePointers[0].clientX - this._core.store.offsetX);
|
|
86
|
+
const y = Math.round(activePointers[0].clientY - this._core.store.offsetY);
|
|
87
|
+
const moveDeltaX = Math.abs(x - this.touchStartX);
|
|
88
|
+
const moveDeltaY = Math.abs(y - this.touchStartY);
|
|
89
|
+
const moveThreshold = 5;
|
|
90
|
+
if ((moveDeltaX > moveThreshold || moveDeltaY > moveThreshold) && this._core.store.state.isSelecting) {
|
|
91
|
+
this.updateTouchSelection();
|
|
92
|
+
const timeout = this._core.store.state.longTouchTimeout;
|
|
93
|
+
if (timeout) {
|
|
94
|
+
globalThis.clearTimeout?.(timeout);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Handles the pointer up event to complete the selection action.
|
|
101
|
+
* Determines whether the action was a click or drag selection and processes accordingly.
|
|
102
|
+
* Triggers object edit mode when a single object is selected without movement.
|
|
103
|
+
* Emits objects change event after selection completes.
|
|
104
|
+
* @param event - The pointer event containing input type, coordinates, and modifier keys
|
|
105
|
+
*/
|
|
106
|
+
handlePointerUp(event) {
|
|
107
|
+
if (event.pointerType === 'mouse') {
|
|
108
|
+
if (KritzelEventHelper.isLeftClick(event)) {
|
|
109
|
+
const hasObjectsMoved = this._core.store.state.hasObjectsChanged;
|
|
110
|
+
const selectionGroup = this._core.store.selectionGroup;
|
|
111
|
+
const isAdditive = event.shiftKey || event.ctrlKey;
|
|
112
|
+
if (selectionGroup?.objects.length === 1 && hasObjectsMoved === false && !isAdditive) {
|
|
113
|
+
selectionGroup.objects[0].edit(event);
|
|
114
|
+
}
|
|
115
|
+
this._core.store.state.hasObjectsChanged = false;
|
|
116
|
+
if (this._core.store.state.isSelecting) {
|
|
117
|
+
if (this.isSelectionClick) {
|
|
118
|
+
this.handleSelectionClick(event);
|
|
119
|
+
}
|
|
120
|
+
if (this.isSelectionDrag) {
|
|
121
|
+
const isAdditive = event.shiftKey || event.ctrlKey;
|
|
122
|
+
this.updateMouseSelection(event);
|
|
123
|
+
this.addSelectedObjectsToSelectionGroup(isAdditive);
|
|
124
|
+
this.removeSelectionBox();
|
|
125
|
+
}
|
|
126
|
+
this._core.engine.emitObjectsChange();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (event.pointerType === 'touch' || event.pointerType === 'pen') {
|
|
131
|
+
clearTimeout(this.touchStartTimeout);
|
|
132
|
+
const hasObjectsMoved = this._core.store.state.hasObjectsChanged;
|
|
133
|
+
const selectionGroup = this._core.store.selectionGroup;
|
|
134
|
+
const isAdditive = event.shiftKey || event.ctrlKey;
|
|
135
|
+
if (selectionGroup?.objects.length === 1 && hasObjectsMoved === false && !isAdditive) {
|
|
136
|
+
selectionGroup.objects[0].edit(event);
|
|
137
|
+
}
|
|
138
|
+
this._core.store.state.hasObjectsChanged = false;
|
|
139
|
+
if (this._core.store.state.isSelecting) {
|
|
140
|
+
if (this.isSelectionClick) {
|
|
141
|
+
this.handleSelectionClick(event);
|
|
142
|
+
}
|
|
143
|
+
if (this.isSelectionDrag) {
|
|
144
|
+
const isAdditive = event.shiftKey || event.ctrlKey;
|
|
145
|
+
this.updateTouchSelection();
|
|
146
|
+
this.addSelectedObjectsToSelectionGroup(isAdditive);
|
|
147
|
+
this.removeSelectionBox();
|
|
148
|
+
}
|
|
149
|
+
this._core.engine.emitObjectsChange();
|
|
150
|
+
this._core.store.state.skipContextMenu = false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Removes the selection box from the canvas and resets selection state.
|
|
156
|
+
* Clears the selecting flag and removes the selection box object from the store.
|
|
157
|
+
*/
|
|
158
|
+
removeSelectionBox() {
|
|
159
|
+
this._core.store.state.isSelecting = false;
|
|
160
|
+
this._core.store.objects.remove(o => o instanceof KritzelSelectionBox);
|
|
161
|
+
this._core.store.setSelectionBox(null);
|
|
162
|
+
this._core.store.objects.clearLocalSelectionBox();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Initiates a mouse-based selection by creating a selection box at the click position.
|
|
166
|
+
* Calculates canvas coordinates accounting for offset, translation, and scale.
|
|
167
|
+
* In non-additive mode, clears any existing selection group.
|
|
168
|
+
* @param event - The mouse event containing click coordinates
|
|
169
|
+
* @param isAdditive - When `true`, preserves existing selection group for adding objects
|
|
170
|
+
*/
|
|
171
|
+
startMouseSelection(event, isAdditive = false) {
|
|
172
|
+
let clientX, clientY;
|
|
173
|
+
clientX = event.clientX - this._core.store.offsetX;
|
|
174
|
+
clientY = event.clientY - this._core.store.offsetY;
|
|
175
|
+
const selectionBox = KritzelSelectionBox.create(this._core);
|
|
176
|
+
this.startX = (clientX - this._core.store.state.translateX) / this._core.store.state.scale;
|
|
177
|
+
this.startY = (clientY - this._core.store.state.translateY) / this._core.store.state.scale;
|
|
178
|
+
selectionBox.translateX = this.startX;
|
|
179
|
+
selectionBox.translateY = this.startY;
|
|
180
|
+
this._core.store.state.isSelecting = true;
|
|
181
|
+
this._core.removeSelectionBox();
|
|
182
|
+
if (!isAdditive) {
|
|
183
|
+
this._core.removeSelectionGroup();
|
|
184
|
+
}
|
|
185
|
+
this._core.store.objects.insert(selectionBox);
|
|
186
|
+
this._core.store.setSelectionBox(selectionBox);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Initiates a touch/pen-based selection by creating a selection box at the touch position.
|
|
190
|
+
* Uses the first active pointer from the pointers map to determine coordinates.
|
|
191
|
+
* In non-additive mode, clears any existing selection group.
|
|
192
|
+
* @param _event - The pointer event (unused, coordinates from active pointers)
|
|
193
|
+
* @param isAdditive - When `true`, preserves existing selection group for adding objects
|
|
194
|
+
*/
|
|
195
|
+
startTouchSelection(_event, isAdditive = false) {
|
|
196
|
+
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
197
|
+
const firstTouch = activePointers[0];
|
|
198
|
+
if (!firstTouch) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
let clientX, clientY;
|
|
202
|
+
clientX = Math.round(firstTouch.clientX - this._core.store.offsetX);
|
|
203
|
+
clientY = Math.round(firstTouch.clientY - this._core.store.offsetY);
|
|
204
|
+
this.touchStartX = clientX;
|
|
205
|
+
this.touchStartY = clientY;
|
|
206
|
+
const selectionBox = KritzelSelectionBox.create(this._core);
|
|
207
|
+
this.startX = (clientX - this._core.store.state.translateX) / this._core.store.state.scale;
|
|
208
|
+
this.startY = (clientY - this._core.store.state.translateY) / this._core.store.state.scale;
|
|
209
|
+
selectionBox.translateX = this.startX;
|
|
210
|
+
selectionBox.translateY = this.startY;
|
|
211
|
+
this._core.store.state.isSelecting = true;
|
|
212
|
+
this._core.removeSelectionBox();
|
|
213
|
+
if (!isAdditive) {
|
|
214
|
+
this._core.removeSelectionGroup();
|
|
215
|
+
}
|
|
216
|
+
this._core.store.objects.insert(selectionBox);
|
|
217
|
+
this._core.store.setSelectionBox(selectionBox);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Updates the selection box dimensions during mouse drag.
|
|
221
|
+
* Calculates the new width, height, and position based on current mouse position
|
|
222
|
+
* relative to the start position. Supports selection in any direction.
|
|
223
|
+
* @param event - The mouse event containing current cursor position
|
|
224
|
+
*/
|
|
225
|
+
updateMouseSelection(event) {
|
|
226
|
+
let clientX, clientY;
|
|
227
|
+
clientX = event.clientX - this._core.store.offsetX;
|
|
228
|
+
clientY = event.clientY - this._core.store.offsetY;
|
|
229
|
+
const selectionBox = this._core.store.selectionBox;
|
|
230
|
+
if (selectionBox) {
|
|
231
|
+
const currentX = (clientX - this._core.store.state.translateX) / selectionBox.scale;
|
|
232
|
+
const currentY = (clientY - this._core.store.state.translateY) / selectionBox.scale;
|
|
233
|
+
const width = Math.abs(currentX - this.startX) * selectionBox.scale;
|
|
234
|
+
const height = Math.abs(currentY - this.startY) * selectionBox.scale;
|
|
235
|
+
selectionBox.width = width;
|
|
236
|
+
selectionBox.height = height;
|
|
237
|
+
selectionBox.translateX = Math.min(currentX, this.startX);
|
|
238
|
+
selectionBox.translateY = Math.min(currentY, this.startY);
|
|
239
|
+
this._core.store.objects.setLocalSelectionBox({
|
|
240
|
+
x: selectionBox.translateX,
|
|
241
|
+
y: selectionBox.translateY,
|
|
242
|
+
width: width / selectionBox.scale,
|
|
243
|
+
height: height / selectionBox.scale,
|
|
244
|
+
});
|
|
245
|
+
if (width > 0 || height > 0) {
|
|
246
|
+
this.updateSelectedObjects();
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
this.clearSelectionPreview();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Updates the selection box dimensions during touch/pen drag.
|
|
255
|
+
* Uses the first active pointer to calculate new dimensions.
|
|
256
|
+
* Supports selection in any direction by using absolute width/height
|
|
257
|
+
* and positioning at the minimum coordinates.
|
|
258
|
+
*/
|
|
259
|
+
updateTouchSelection() {
|
|
260
|
+
const activePointers = Array.from(this._core.store.state.pointers.values());
|
|
261
|
+
const firstTouch = activePointers[0];
|
|
262
|
+
if (!firstTouch) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
let clientX, clientY;
|
|
266
|
+
clientX = Math.round(firstTouch.clientX - this._core.store.offsetX);
|
|
267
|
+
clientY = Math.round(firstTouch.clientY - this._core.store.offsetY);
|
|
268
|
+
const selectionBox = this._core.store.selectionBox;
|
|
269
|
+
if (selectionBox) {
|
|
270
|
+
const currentX = (clientX - this._core.store.state.translateX) / selectionBox.scale;
|
|
271
|
+
const currentY = (clientY - this._core.store.state.translateY) / selectionBox.scale;
|
|
272
|
+
const width = Math.abs(currentX - this.startX) * selectionBox.scale;
|
|
273
|
+
const height = Math.abs(currentY - this.startY) * selectionBox.scale;
|
|
274
|
+
selectionBox.width = width;
|
|
275
|
+
selectionBox.height = height;
|
|
276
|
+
selectionBox.translateX = Math.min(currentX, this.startX);
|
|
277
|
+
selectionBox.translateY = Math.min(currentY, this.startY);
|
|
278
|
+
this._core.store.objects.setLocalSelectionBox({
|
|
279
|
+
x: selectionBox.translateX,
|
|
280
|
+
y: selectionBox.translateY,
|
|
281
|
+
width: width / selectionBox.scale,
|
|
282
|
+
height: height / selectionBox.scale,
|
|
283
|
+
});
|
|
284
|
+
if (width > 0 || height > 0) {
|
|
285
|
+
this.updateSelectedObjects();
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
this.clearSelectionPreview();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Updates the selection state of objects intersecting with the selection box.
|
|
294
|
+
* Uses quadtree spatial indexing for efficient O(log n + k) candidate lookup.
|
|
295
|
+
* Performs polygon-based hit testing for accurate rotated selection support.
|
|
296
|
+
* Efficiently deselects only previously selected objects that no longer intersect.
|
|
297
|
+
*/
|
|
298
|
+
updateSelectedObjects() {
|
|
299
|
+
const selectionBox = this._core.store.selectionBox;
|
|
300
|
+
if (!selectionBox)
|
|
301
|
+
return;
|
|
302
|
+
// Compute rotatedPolygon once per update (not per object)
|
|
303
|
+
const selectionPolygon = selectionBox.rotatedPolygon;
|
|
304
|
+
// Calculate bounding box from the polygon we already have to avoid recomputing it
|
|
305
|
+
// calling selectionBox.rotatedBoundingBox would trigger another rotatedPolygon computation
|
|
306
|
+
const xValues = [selectionPolygon.topLeft.x, selectionPolygon.topRight.x, selectionPolygon.bottomRight.x, selectionPolygon.bottomLeft.x];
|
|
307
|
+
const yValues = [selectionPolygon.topLeft.y, selectionPolygon.topRight.y, selectionPolygon.bottomRight.y, selectionPolygon.bottomLeft.y];
|
|
308
|
+
const minX = Math.min(...xValues);
|
|
309
|
+
const maxX = Math.max(...xValues);
|
|
310
|
+
const minY = Math.min(...yValues);
|
|
311
|
+
const maxY = Math.max(...yValues);
|
|
312
|
+
// Use quadtree spatial query to get only nearby candidates - O(log n + k) instead of O(n)
|
|
313
|
+
const selectionBounds = {
|
|
314
|
+
x: minX,
|
|
315
|
+
y: minY,
|
|
316
|
+
z: selectionBox.scale,
|
|
317
|
+
width: maxX - minX,
|
|
318
|
+
height: maxY - minY,
|
|
319
|
+
};
|
|
320
|
+
const candidates = this._core.store.objects.query(selectionBounds);
|
|
321
|
+
// Track newly selected objects for efficient comparison
|
|
322
|
+
const newlySelectedObjects = new Set();
|
|
323
|
+
// Only test candidates that overlap the bounding box
|
|
324
|
+
for (const object of candidates) {
|
|
325
|
+
if (object instanceof KritzelSelectionBox || object instanceof KritzelSelectionGroup)
|
|
326
|
+
continue;
|
|
327
|
+
const isHit = object.hitTestPolygon(selectionPolygon);
|
|
328
|
+
object.isSelected = isHit;
|
|
329
|
+
if (isHit) {
|
|
330
|
+
newlySelectedObjects.add(object);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
// Deselect only objects that were previously selected but aren't anymore
|
|
334
|
+
// This is O(k) where k is the number of previously selected objects, not O(n)
|
|
335
|
+
for (const prevObj of this._previouslySelectedObjects) {
|
|
336
|
+
if (!newlySelectedObjects.has(prevObj)) {
|
|
337
|
+
prevObj.isSelected = false;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
this._previouslySelectedObjects = newlySelectedObjects;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Handles a single-click selection action.
|
|
344
|
+
* Finds the topmost object at the click position and adds it to the selection group.
|
|
345
|
+
* Supports additive selection mode via shift/ctrl modifier keys.
|
|
346
|
+
* @param event - The pointer event containing click coordinates and modifier keys
|
|
347
|
+
*/
|
|
348
|
+
handleSelectionClick(event) {
|
|
349
|
+
const selectedObject = this.getTopmostHitObject(event);
|
|
350
|
+
const isAdditive = event.shiftKey || event.ctrlKey;
|
|
351
|
+
this.clearSelectionPreview();
|
|
352
|
+
if (selectedObject) {
|
|
353
|
+
this.addObjectToSelectionGroup(selectedObject, isAdditive);
|
|
354
|
+
}
|
|
355
|
+
this.removeSelectionBox();
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Finds the topmost (highest z-order) object at the pointer position.
|
|
359
|
+
* Iterates through overlapping objects from top to bottom and performs hit testing.
|
|
360
|
+
* Excludes selection-related objects (selection box and selection group).
|
|
361
|
+
* @param event - The pointer event used to query overlapping DOM elements
|
|
362
|
+
* @returns The topmost object that passes hit testing, or `null` if none found
|
|
363
|
+
*/
|
|
364
|
+
getTopmostHitObject(event) {
|
|
365
|
+
const pointerX = this._core.store.state.pointerX;
|
|
366
|
+
const pointerY = this._core.store.state.pointerY;
|
|
367
|
+
const overlappingObjects = this._core.getObjectsFromPointerEvent(event, '.object');
|
|
368
|
+
for (const object of overlappingObjects) {
|
|
369
|
+
if (object instanceof KritzelSelectionBox || object instanceof KritzelSelectionGroup)
|
|
370
|
+
continue;
|
|
371
|
+
if (object.hitTest(pointerX, pointerY)) {
|
|
372
|
+
return object;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Clears the visual selection preview by deselecting all previously selected objects.
|
|
379
|
+
* Operates in O(k) time where k is the number of previously selected objects,
|
|
380
|
+
* rather than O(n) by iterating only tracked objects.
|
|
381
|
+
*/
|
|
382
|
+
clearSelectionPreview() {
|
|
383
|
+
// Only clear previously tracked selected objects - O(k) instead of O(n)
|
|
384
|
+
const selectedGroupIds = new Set(this._core.store.selectionGroup?.objectIds ?? []);
|
|
385
|
+
for (const obj of this._previouslySelectedObjects) {
|
|
386
|
+
if (!selectedGroupIds.has(obj.id)) {
|
|
387
|
+
obj.isSelected = false;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
this._previouslySelectedObjects.clear();
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Adds a single object to the selection group.
|
|
394
|
+
* Resolves child objects to their parent groups before adding.
|
|
395
|
+
* In additive mode (shift), toggles object presence in existing group.
|
|
396
|
+
* In non-additive mode, creates a new selection group with the object.
|
|
397
|
+
* @param object - The object to add to selection (may be a child of a group)
|
|
398
|
+
* @param shiftKey - When `true`, adds to/removes from existing selection group
|
|
399
|
+
*/
|
|
400
|
+
addObjectToSelectionGroup(object, shiftKey = false) {
|
|
401
|
+
if (!object) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
// Resolve child objects to their parent groups
|
|
405
|
+
const parentGroup = KritzelGroup.findParentGroup(this._core, object.id);
|
|
406
|
+
const objectToSelect = parentGroup || object;
|
|
407
|
+
// When the click resolves to a parent group, clear the child's own flag so
|
|
408
|
+
// it does not linger as selected and re-select the group on the next interaction.
|
|
409
|
+
if (parentGroup) {
|
|
410
|
+
object.isSelected = false;
|
|
411
|
+
}
|
|
412
|
+
const existingGroup = this._core.store.selectionGroup;
|
|
413
|
+
if (shiftKey && existingGroup) {
|
|
414
|
+
existingGroup.addOrRemove(objectToSelect);
|
|
415
|
+
this.removeDescendantsOfSelectedGroups(existingGroup);
|
|
416
|
+
if (existingGroup.objects.length === 0) {
|
|
417
|
+
this._core.removeSelectionGroup();
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
this._core.rerender();
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
const selectionGroup = KritzelSelectionGroup.create(this._core);
|
|
425
|
+
selectionGroup.addOrRemove(objectToSelect);
|
|
426
|
+
selectionGroup.isSelected = true;
|
|
427
|
+
this._core.addSelectionGroup(selectionGroup);
|
|
428
|
+
this._core.rerender();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Adds all currently selected objects to a selection group.
|
|
433
|
+
* Builds a parent group lookup map for efficient O(n) resolution of child objects.
|
|
434
|
+
* Deduplicates objects by ID to prevent duplicate entries from group resolution.
|
|
435
|
+
* In additive mode, adds to existing group; otherwise creates a new selection group.
|
|
436
|
+
* Captures unchanged snapshots and refreshes dimensions once at the end for O(n) performance.
|
|
437
|
+
* @param shiftKey - When `true`, adds objects to existing selection group
|
|
438
|
+
*/
|
|
439
|
+
addSelectedObjectsToSelectionGroup(shiftKey = false) {
|
|
440
|
+
const selectedObjects = this._core.store.selectedObjects;
|
|
441
|
+
if (selectedObjects.length === 0) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
// Build parent group lookup map ONCE - O(g * c) instead of O(n * g * c)
|
|
445
|
+
const allGroups = this._core.store.objects.filter(obj => obj.__class__ === 'KritzelGroup');
|
|
446
|
+
const childToParentMap = new Map();
|
|
447
|
+
for (const group of allGroups) {
|
|
448
|
+
for (const childId of group.childIds) {
|
|
449
|
+
childToParentMap.set(childId, group);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
// Resolve child objects to their parent groups in a single pass - O(n)
|
|
453
|
+
const resolvedObjects = new Map();
|
|
454
|
+
for (const obj of selectedObjects) {
|
|
455
|
+
const parentGroup = childToParentMap.get(obj.id);
|
|
456
|
+
if (parentGroup) {
|
|
457
|
+
// The child was selected (e.g. via marquee preview) but selection is
|
|
458
|
+
// represented by its parent group. Clear the child's flag so it does
|
|
459
|
+
// not linger as selected and re-select the group on the next interaction.
|
|
460
|
+
obj.isSelected = false;
|
|
461
|
+
resolvedObjects.set(parentGroup.id, parentGroup);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
resolvedObjects.set(obj.id, obj);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
const unrolledObjects = Array.from(resolvedObjects.values());
|
|
468
|
+
const filteredObjects = this.filterDescendantsOfSelectedGroups(unrolledObjects);
|
|
469
|
+
const existingGroup = this._core.store.selectionGroup;
|
|
470
|
+
if (shiftKey && existingGroup) {
|
|
471
|
+
existingGroup.addObjects(filteredObjects);
|
|
472
|
+
this.removeDescendantsOfSelectedGroups(existingGroup);
|
|
473
|
+
this._previouslySelectedObjects.clear();
|
|
474
|
+
this._core.rerender();
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
// Create selection group and set all IDs at once (no per-item refresh)
|
|
478
|
+
const selectionGroup = KritzelSelectionGroup.create(this._core);
|
|
479
|
+
selectionGroup.objectIds = filteredObjects.map(o => o.id);
|
|
480
|
+
filteredObjects.forEach(obj => {
|
|
481
|
+
obj.isSelected = true;
|
|
482
|
+
});
|
|
483
|
+
// Only refresh dimensions and capture snapshots ONCE at the end - O(n) instead of O(n²)
|
|
484
|
+
if (selectionGroup.length === 1) {
|
|
485
|
+
selectionGroup.rotation = selectionGroup.objects[0].rotation;
|
|
486
|
+
}
|
|
487
|
+
selectionGroup.captureUnchangedSnapshots();
|
|
488
|
+
selectionGroup.refreshObjectDimensions();
|
|
489
|
+
selectionGroup.isSelected = true;
|
|
490
|
+
this._core.addSelectionGroup(selectionGroup);
|
|
491
|
+
this._previouslySelectedObjects.clear();
|
|
492
|
+
this._core.rerender();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Removes objects that are descendants of any KritzelGroup also present in the list.
|
|
497
|
+
* Prevents an ancestor group and one of its descendants from coexisting in a selection,
|
|
498
|
+
* which would otherwise cause the descendant to be transformed twice (once via the
|
|
499
|
+
* ancestor group, and once directly).
|
|
500
|
+
* @param objects - The candidate objects for the selection.
|
|
501
|
+
* @returns A new array with descendants of selected groups removed.
|
|
502
|
+
*/
|
|
503
|
+
filterDescendantsOfSelectedGroups(objects) {
|
|
504
|
+
const descendantIds = new Set();
|
|
505
|
+
for (const obj of objects) {
|
|
506
|
+
if (obj instanceof KritzelGroup) {
|
|
507
|
+
KritzelGroup.collectDescendantIds(obj, descendantIds);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (descendantIds.size === 0) {
|
|
511
|
+
return objects;
|
|
512
|
+
}
|
|
513
|
+
return objects.filter(o => !descendantIds.has(o.id));
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Mutates an existing selection group to remove any descendants of groups
|
|
517
|
+
* already present in it. See {@link filterDescendantsOfSelectedGroups}.
|
|
518
|
+
* @param selectionGroup - The selection group to clean up in place.
|
|
519
|
+
*/
|
|
520
|
+
removeDescendantsOfSelectedGroups(selectionGroup) {
|
|
521
|
+
const filtered = this.filterDescendantsOfSelectedGroups(selectionGroup.objects);
|
|
522
|
+
if (filtered.length !== selectionGroup.objects.length) {
|
|
523
|
+
selectionGroup.objectIds = filtered.map(o => o.id);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|