@docmentis/udoc-viewer 0.1.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/README.md +180 -0
- package/dist/UDocClient.d.ts +197 -0
- package/dist/UDocClient.d.ts.map +1 -0
- package/dist/UDocClient.js +170 -0
- package/dist/UDocClient.js.map +1 -0
- package/dist/UDocViewer.d.ts +196 -0
- package/dist/UDocViewer.d.ts.map +1 -0
- package/dist/UDocViewer.js +427 -0
- package/dist/UDocViewer.js.map +1 -0
- package/dist/WorkerClient.d.ts +36 -0
- package/dist/WorkerClient.d.ts.map +1 -0
- package/dist/WorkerClient.js +121 -0
- package/dist/WorkerClient.js.map +1 -0
- package/dist/annotation/AnnotationLayer.d.ts +166 -0
- package/dist/annotation/AnnotationLayer.d.ts.map +1 -0
- package/dist/annotation/AnnotationLayer.js +1090 -0
- package/dist/annotation/AnnotationLayer.js.map +1 -0
- package/dist/annotation/index.d.ts +6 -0
- package/dist/annotation/index.d.ts.map +1 -0
- package/dist/annotation/index.js +6 -0
- package/dist/annotation/index.js.map +1 -0
- package/dist/components/FloatingBar.d.ts +102 -0
- package/dist/components/FloatingBar.d.ts.map +1 -0
- package/dist/components/FloatingBar.js +513 -0
- package/dist/components/FloatingBar.js.map +1 -0
- package/dist/components/Header.d.ts +46 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.js +93 -0
- package/dist/components/Header.js.map +1 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +4 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/panels/CommentsPanel.d.ts +33 -0
- package/dist/components/panels/CommentsPanel.d.ts.map +1 -0
- package/dist/components/panels/CommentsPanel.js +176 -0
- package/dist/components/panels/CommentsPanel.js.map +1 -0
- package/dist/components/panels/OutlinePanel.d.ts +30 -0
- package/dist/components/panels/OutlinePanel.d.ts.map +1 -0
- package/dist/components/panels/OutlinePanel.js +144 -0
- package/dist/components/panels/OutlinePanel.js.map +1 -0
- package/dist/components/panels/ThumbnailsPanel.d.ts +51 -0
- package/dist/components/panels/ThumbnailsPanel.d.ts.map +1 -0
- package/dist/components/panels/ThumbnailsPanel.js +160 -0
- package/dist/components/panels/ThumbnailsPanel.js.map +1 -0
- package/dist/components/panels/index.d.ts +7 -0
- package/dist/components/panels/index.d.ts.map +1 -0
- package/dist/components/panels/index.js +4 -0
- package/dist/components/panels/index.js.map +1 -0
- package/dist/constants.d.ts +25 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +46 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/NavigationController.d.ts +54 -0
- package/dist/core/NavigationController.d.ts.map +1 -0
- package/dist/core/NavigationController.js +145 -0
- package/dist/core/NavigationController.js.map +1 -0
- package/dist/core/PerfTimer.d.ts +12 -0
- package/dist/core/PerfTimer.d.ts.map +1 -0
- package/dist/core/PerfTimer.js +32 -0
- package/dist/core/PerfTimer.js.map +1 -0
- package/dist/core/ViewerState.d.ts +108 -0
- package/dist/core/ViewerState.d.ts.map +1 -0
- package/dist/core/ViewerState.js +179 -0
- package/dist/core/ViewerState.js.map +1 -0
- package/dist/core/constants.d.ts +24 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +42 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +11 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/types.d.ts +573 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -0
- package/dist/icons/icons.d.ts +41 -0
- package/dist/icons/icons.d.ts.map +1 -0
- package/dist/icons/icons.js +51 -0
- package/dist/icons/icons.js.map +1 -0
- package/dist/icons/index.d.ts +3 -0
- package/dist/icons/index.d.ts.map +1 -0
- package/dist/icons/index.js +2 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/BandManager.d.ts +87 -0
- package/dist/layout/BandManager.d.ts.map +1 -0
- package/dist/layout/BandManager.js +185 -0
- package/dist/layout/BandManager.js.map +1 -0
- package/dist/layout/LayoutCalculator.d.ts +42 -0
- package/dist/layout/LayoutCalculator.d.ts.map +1 -0
- package/dist/layout/LayoutCalculator.js +180 -0
- package/dist/layout/LayoutCalculator.js.map +1 -0
- package/dist/layout/LayoutState.d.ts +46 -0
- package/dist/layout/LayoutState.d.ts.map +1 -0
- package/dist/layout/LayoutState.js +109 -0
- package/dist/layout/LayoutState.js.map +1 -0
- package/dist/layout/TransitionCoordinator.d.ts +11 -0
- package/dist/layout/TransitionCoordinator.d.ts.map +1 -0
- package/dist/layout/TransitionCoordinator.js +22 -0
- package/dist/layout/TransitionCoordinator.js.map +1 -0
- package/dist/layout/index.d.ts +7 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +4 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/rendering/BandManager.d.ts +87 -0
- package/dist/rendering/BandManager.d.ts.map +1 -0
- package/dist/rendering/BandManager.js +185 -0
- package/dist/rendering/BandManager.js.map +1 -0
- package/dist/rendering/PageCache.d.ts +75 -0
- package/dist/rendering/PageCache.d.ts.map +1 -0
- package/dist/rendering/PageCache.js +122 -0
- package/dist/rendering/PageCache.js.map +1 -0
- package/dist/rendering/RenderQueue.d.ts +75 -0
- package/dist/rendering/RenderQueue.d.ts.map +1 -0
- package/dist/rendering/RenderQueue.js +105 -0
- package/dist/rendering/RenderQueue.js.map +1 -0
- package/dist/rendering/ThumbnailQueue.d.ts +57 -0
- package/dist/rendering/ThumbnailQueue.d.ts.map +1 -0
- package/dist/rendering/ThumbnailQueue.js +85 -0
- package/dist/rendering/ThumbnailQueue.js.map +1 -0
- package/dist/rendering/index.d.ts +13 -0
- package/dist/rendering/index.d.ts.map +1 -0
- package/dist/rendering/index.js +10 -0
- package/dist/rendering/index.js.map +1 -0
- package/dist/rendering/types.d.ts +72 -0
- package/dist/rendering/types.d.ts.map +1 -0
- package/dist/rendering/types.js +5 -0
- package/dist/rendering/types.js.map +1 -0
- package/dist/styles/index.d.ts +6 -0
- package/dist/styles/index.d.ts.map +1 -0
- package/dist/styles/index.js +1221 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/Component.d.ts +127 -0
- package/dist/ui/Component.d.ts.map +1 -0
- package/dist/ui/Component.js +201 -0
- package/dist/ui/Component.js.map +1 -0
- package/dist/ui/annotation/AnnotationLayer.d.ts +90 -0
- package/dist/ui/annotation/AnnotationLayer.d.ts.map +1 -0
- package/dist/ui/annotation/AnnotationLayer.js +322 -0
- package/dist/ui/annotation/AnnotationLayer.js.map +1 -0
- package/dist/ui/annotation/LinkRenderer.d.ts +32 -0
- package/dist/ui/annotation/LinkRenderer.d.ts.map +1 -0
- package/dist/ui/annotation/LinkRenderer.js +74 -0
- package/dist/ui/annotation/LinkRenderer.js.map +1 -0
- package/dist/ui/annotation/MarkupRenderer.d.ts +40 -0
- package/dist/ui/annotation/MarkupRenderer.d.ts.map +1 -0
- package/dist/ui/annotation/MarkupRenderer.js +154 -0
- package/dist/ui/annotation/MarkupRenderer.js.map +1 -0
- package/dist/ui/annotation/ShapeRenderer.d.ts +46 -0
- package/dist/ui/annotation/ShapeRenderer.d.ts.map +1 -0
- package/dist/ui/annotation/ShapeRenderer.js +376 -0
- package/dist/ui/annotation/ShapeRenderer.js.map +1 -0
- package/dist/ui/annotation/TextRenderer.d.ts +36 -0
- package/dist/ui/annotation/TextRenderer.d.ts.map +1 -0
- package/dist/ui/annotation/TextRenderer.js +199 -0
- package/dist/ui/annotation/TextRenderer.js.map +1 -0
- package/dist/ui/annotation/index.d.ts +17 -0
- package/dist/ui/annotation/index.d.ts.map +1 -0
- package/dist/ui/annotation/index.js +13 -0
- package/dist/ui/annotation/index.js.map +1 -0
- package/dist/ui/annotation/utils.d.ts +40 -0
- package/dist/ui/annotation/utils.d.ts.map +1 -0
- package/dist/ui/annotation/utils.js +62 -0
- package/dist/ui/annotation/utils.js.map +1 -0
- package/dist/ui/components/CommentsContent.d.ts +35 -0
- package/dist/ui/components/CommentsContent.d.ts.map +1 -0
- package/dist/ui/components/CommentsContent.js +203 -0
- package/dist/ui/components/CommentsContent.js.map +1 -0
- package/dist/ui/components/FloatingBar.d.ts +55 -0
- package/dist/ui/components/FloatingBar.d.ts.map +1 -0
- package/dist/ui/components/FloatingBar.js +585 -0
- package/dist/ui/components/FloatingBar.js.map +1 -0
- package/dist/ui/components/Header.d.ts +29 -0
- package/dist/ui/components/Header.d.ts.map +1 -0
- package/dist/ui/components/Header.js +127 -0
- package/dist/ui/components/Header.js.map +1 -0
- package/dist/ui/components/LeftPanel.d.ts +54 -0
- package/dist/ui/components/LeftPanel.d.ts.map +1 -0
- package/dist/ui/components/LeftPanel.js +202 -0
- package/dist/ui/components/LeftPanel.js.map +1 -0
- package/dist/ui/components/OutlineContent.d.ts +34 -0
- package/dist/ui/components/OutlineContent.d.ts.map +1 -0
- package/dist/ui/components/OutlineContent.js +147 -0
- package/dist/ui/components/OutlineContent.js.map +1 -0
- package/dist/ui/components/RightPanel.d.ts +52 -0
- package/dist/ui/components/RightPanel.d.ts.map +1 -0
- package/dist/ui/components/RightPanel.js +142 -0
- package/dist/ui/components/RightPanel.js.map +1 -0
- package/dist/ui/components/Viewport.d.ts +70 -0
- package/dist/ui/components/Viewport.d.ts.map +1 -0
- package/dist/ui/components/Viewport.js +173 -0
- package/dist/ui/components/Viewport.js.map +1 -0
- package/dist/ui/components/index.d.ts +11 -0
- package/dist/ui/components/index.d.ts.map +1 -0
- package/dist/ui/components/index.js +10 -0
- package/dist/ui/components/index.js.map +1 -0
- package/dist/ui/framework/component.d.ts +68 -0
- package/dist/ui/framework/component.d.ts.map +1 -0
- package/dist/ui/framework/component.js +87 -0
- package/dist/ui/framework/component.js.map +1 -0
- package/dist/ui/framework/dom.d.ts +19 -0
- package/dist/ui/framework/dom.d.ts.map +1 -0
- package/dist/ui/framework/dom.js +29 -0
- package/dist/ui/framework/dom.js.map +1 -0
- package/dist/ui/framework/events.d.ts +18 -0
- package/dist/ui/framework/events.d.ts.map +1 -0
- package/dist/ui/framework/events.js +23 -0
- package/dist/ui/framework/events.js.map +1 -0
- package/dist/ui/framework/index.d.ts +15 -0
- package/dist/ui/framework/index.d.ts.map +1 -0
- package/dist/ui/framework/index.js +15 -0
- package/dist/ui/framework/index.js.map +1 -0
- package/dist/ui/framework/selectors.d.ts +51 -0
- package/dist/ui/framework/selectors.d.ts.map +1 -0
- package/dist/ui/framework/selectors.js +30 -0
- package/dist/ui/framework/selectors.js.map +1 -0
- package/dist/ui/framework/store.d.ts +37 -0
- package/dist/ui/framework/store.d.ts.map +1 -0
- package/dist/ui/framework/store.js +54 -0
- package/dist/ui/framework/store.js.map +1 -0
- package/dist/ui/icons/icons.d.ts +43 -0
- package/dist/ui/icons/icons.d.ts.map +1 -0
- package/dist/ui/icons/icons.js +46 -0
- package/dist/ui/icons/icons.js.map +1 -0
- package/dist/ui/icons/index.d.ts +11 -0
- package/dist/ui/icons/index.d.ts.map +1 -0
- package/dist/ui/icons/index.js +18 -0
- package/dist/ui/icons/index.js.map +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +9 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/styles/base.css.d.ts +5 -0
- package/dist/ui/styles/base.css.d.ts.map +1 -0
- package/dist/ui/styles/base.css.js +49 -0
- package/dist/ui/styles/base.css.js.map +1 -0
- package/dist/ui/styles/floating-bar.css.d.ts +5 -0
- package/dist/ui/styles/floating-bar.css.d.ts.map +1 -0
- package/dist/ui/styles/floating-bar.css.js +417 -0
- package/dist/ui/styles/floating-bar.css.js.map +1 -0
- package/dist/ui/styles/header.css.d.ts +5 -0
- package/dist/ui/styles/header.css.d.ts.map +1 -0
- package/dist/ui/styles/header.css.js +49 -0
- package/dist/ui/styles/header.css.js.map +1 -0
- package/dist/ui/styles/index.d.ts +21 -0
- package/dist/ui/styles/index.d.ts.map +1 -0
- package/dist/ui/styles/index.js +48 -0
- package/dist/ui/styles/index.js.map +1 -0
- package/dist/ui/styles/panels.css.d.ts +5 -0
- package/dist/ui/styles/panels.css.d.ts.map +1 -0
- package/dist/ui/styles/panels.css.js +446 -0
- package/dist/ui/styles/panels.css.js.map +1 -0
- package/dist/ui/styles/responsive.css.d.ts +5 -0
- package/dist/ui/styles/responsive.css.d.ts.map +1 -0
- package/dist/ui/styles/responsive.css.js +201 -0
- package/dist/ui/styles/responsive.css.js.map +1 -0
- package/dist/ui/styles/variables.css.d.ts +6 -0
- package/dist/ui/styles/variables.css.d.ts.map +1 -0
- package/dist/ui/styles/variables.css.js +75 -0
- package/dist/ui/styles/variables.css.js.map +1 -0
- package/dist/ui/styles/viewport.css.d.ts +5 -0
- package/dist/ui/styles/viewport.css.d.ts.map +1 -0
- package/dist/ui/styles/viewport.css.js +87 -0
- package/dist/ui/styles/viewport.css.js.map +1 -0
- package/dist/ui/viewer/actions.d.ts +103 -0
- package/dist/ui/viewer/actions.d.ts.map +1 -0
- package/dist/ui/viewer/actions.js +2 -0
- package/dist/ui/viewer/actions.js.map +1 -0
- package/dist/ui/viewer/annotation/LinkRenderer.d.ts +9 -0
- package/dist/ui/viewer/annotation/LinkRenderer.d.ts.map +1 -0
- package/dist/ui/viewer/annotation/LinkRenderer.js +17 -0
- package/dist/ui/viewer/annotation/LinkRenderer.js.map +1 -0
- package/dist/ui/viewer/annotation/MarkupRenderer.d.ts +21 -0
- package/dist/ui/viewer/annotation/MarkupRenderer.d.ts.map +1 -0
- package/dist/ui/viewer/annotation/MarkupRenderer.js +138 -0
- package/dist/ui/viewer/annotation/MarkupRenderer.js.map +1 -0
- package/dist/ui/viewer/annotation/ShapeRenderer.d.ts +33 -0
- package/dist/ui/viewer/annotation/ShapeRenderer.d.ts.map +1 -0
- package/dist/ui/viewer/annotation/ShapeRenderer.js +378 -0
- package/dist/ui/viewer/annotation/ShapeRenderer.js.map +1 -0
- package/dist/ui/viewer/annotation/TextRenderer.d.ts +23 -0
- package/dist/ui/viewer/annotation/TextRenderer.d.ts.map +1 -0
- package/dist/ui/viewer/annotation/TextRenderer.js +196 -0
- package/dist/ui/viewer/annotation/TextRenderer.js.map +1 -0
- package/dist/ui/viewer/annotation/index.d.ts +8 -0
- package/dist/ui/viewer/annotation/index.d.ts.map +1 -0
- package/dist/ui/viewer/annotation/index.js +8 -0
- package/dist/ui/viewer/annotation/index.js.map +1 -0
- package/dist/ui/viewer/annotation/render.d.ts +24 -0
- package/dist/ui/viewer/annotation/render.d.ts.map +1 -0
- package/dist/ui/viewer/annotation/render.js +184 -0
- package/dist/ui/viewer/annotation/render.js.map +1 -0
- package/dist/ui/viewer/annotation/types.d.ts +239 -0
- package/dist/ui/viewer/annotation/types.d.ts.map +1 -0
- package/dist/ui/viewer/annotation/types.js +7 -0
- package/dist/ui/viewer/annotation/types.js.map +1 -0
- package/dist/ui/viewer/annotation/utils.d.ts +37 -0
- package/dist/ui/viewer/annotation/utils.d.ts.map +1 -0
- package/dist/ui/viewer/annotation/utils.js +82 -0
- package/dist/ui/viewer/annotation/utils.js.map +1 -0
- package/dist/ui/viewer/components/AnnotationPanel.d.ts +19 -0
- package/dist/ui/viewer/components/AnnotationPanel.d.ts.map +1 -0
- package/dist/ui/viewer/components/AnnotationPanel.js +284 -0
- package/dist/ui/viewer/components/AnnotationPanel.js.map +1 -0
- package/dist/ui/viewer/components/FloatingToolbar.d.ts +9 -0
- package/dist/ui/viewer/components/FloatingToolbar.d.ts.map +1 -0
- package/dist/ui/viewer/components/FloatingToolbar.js +305 -0
- package/dist/ui/viewer/components/FloatingToolbar.js.map +1 -0
- package/dist/ui/viewer/components/LeftPanel.d.ts +10 -0
- package/dist/ui/viewer/components/LeftPanel.d.ts.map +1 -0
- package/dist/ui/viewer/components/LeftPanel.js +165 -0
- package/dist/ui/viewer/components/LeftPanel.js.map +1 -0
- package/dist/ui/viewer/components/OutlinePanel.d.ts +10 -0
- package/dist/ui/viewer/components/OutlinePanel.d.ts.map +1 -0
- package/dist/ui/viewer/components/OutlinePanel.js +169 -0
- package/dist/ui/viewer/components/OutlinePanel.js.map +1 -0
- package/dist/ui/viewer/components/RightPanel.d.ts +9 -0
- package/dist/ui/viewer/components/RightPanel.d.ts.map +1 -0
- package/dist/ui/viewer/components/RightPanel.js +102 -0
- package/dist/ui/viewer/components/RightPanel.js.map +1 -0
- package/dist/ui/viewer/components/Spread.d.ts +41 -0
- package/dist/ui/viewer/components/Spread.d.ts.map +1 -0
- package/dist/ui/viewer/components/Spread.js +278 -0
- package/dist/ui/viewer/components/Spread.js.map +1 -0
- package/dist/ui/viewer/components/ThumbnailPanel.d.ts +11 -0
- package/dist/ui/viewer/components/ThumbnailPanel.d.ts.map +1 -0
- package/dist/ui/viewer/components/ThumbnailPanel.js +206 -0
- package/dist/ui/viewer/components/ThumbnailPanel.js.map +1 -0
- package/dist/ui/viewer/components/Toolbar.d.ts +9 -0
- package/dist/ui/viewer/components/Toolbar.d.ts.map +1 -0
- package/dist/ui/viewer/components/Toolbar.js +93 -0
- package/dist/ui/viewer/components/Toolbar.js.map +1 -0
- package/dist/ui/viewer/components/ViewModeMenu.d.ts +9 -0
- package/dist/ui/viewer/components/ViewModeMenu.d.ts.map +1 -0
- package/dist/ui/viewer/components/ViewModeMenu.js +169 -0
- package/dist/ui/viewer/components/ViewModeMenu.js.map +1 -0
- package/dist/ui/viewer/components/Viewport.d.ts +10 -0
- package/dist/ui/viewer/components/Viewport.d.ts.map +1 -0
- package/dist/ui/viewer/components/Viewport.js +793 -0
- package/dist/ui/viewer/components/Viewport.js.map +1 -0
- package/dist/ui/viewer/effects.d.ts +9 -0
- package/dist/ui/viewer/effects.d.ts.map +1 -0
- package/dist/ui/viewer/effects.js +179 -0
- package/dist/ui/viewer/effects.js.map +1 -0
- package/dist/ui/viewer/icons.d.ts +32 -0
- package/dist/ui/viewer/icons.d.ts.map +1 -0
- package/dist/ui/viewer/icons.js +44 -0
- package/dist/ui/viewer/icons.js.map +1 -0
- package/dist/ui/viewer/index.d.ts +6 -0
- package/dist/ui/viewer/index.d.ts.map +1 -0
- package/dist/ui/viewer/index.js +6 -0
- package/dist/ui/viewer/index.js.map +1 -0
- package/dist/ui/viewer/layout/index.d.ts +3 -0
- package/dist/ui/viewer/layout/index.d.ts.map +1 -0
- package/dist/ui/viewer/layout/index.js +3 -0
- package/dist/ui/viewer/layout/index.js.map +1 -0
- package/dist/ui/viewer/layout/pixelAlign.d.ts +7 -0
- package/dist/ui/viewer/layout/pixelAlign.d.ts.map +1 -0
- package/dist/ui/viewer/layout/pixelAlign.js +22 -0
- package/dist/ui/viewer/layout/pixelAlign.js.map +1 -0
- package/dist/ui/viewer/layout/spreadLayout.d.ts +93 -0
- package/dist/ui/viewer/layout/spreadLayout.d.ts.map +1 -0
- package/dist/ui/viewer/layout/spreadLayout.js +303 -0
- package/dist/ui/viewer/layout/spreadLayout.js.map +1 -0
- package/dist/ui/viewer/navigation.d.ts +80 -0
- package/dist/ui/viewer/navigation.d.ts.map +1 -0
- package/dist/ui/viewer/navigation.js +59 -0
- package/dist/ui/viewer/navigation.js.map +1 -0
- package/dist/ui/viewer/reducer.d.ts +4 -0
- package/dist/ui/viewer/reducer.d.ts.map +1 -0
- package/dist/ui/viewer/reducer.js +229 -0
- package/dist/ui/viewer/reducer.js.map +1 -0
- package/dist/ui/viewer/rendering/RenderManager.d.ts +76 -0
- package/dist/ui/viewer/rendering/RenderManager.d.ts.map +1 -0
- package/dist/ui/viewer/rendering/RenderManager.js +236 -0
- package/dist/ui/viewer/rendering/RenderManager.js.map +1 -0
- package/dist/ui/viewer/shell.d.ts +29 -0
- package/dist/ui/viewer/shell.d.ts.map +1 -0
- package/dist/ui/viewer/shell.js +70 -0
- package/dist/ui/viewer/shell.js.map +1 -0
- package/dist/ui/viewer/state.d.ts +72 -0
- package/dist/ui/viewer/state.d.ts.map +1 -0
- package/dist/ui/viewer/state.js +47 -0
- package/dist/ui/viewer/state.js.map +1 -0
- package/dist/view/LayoutCalculator.d.ts +42 -0
- package/dist/view/LayoutCalculator.d.ts.map +1 -0
- package/dist/view/LayoutCalculator.js +180 -0
- package/dist/view/LayoutCalculator.js.map +1 -0
- package/dist/view/TransitionCoordinator.d.ts +11 -0
- package/dist/view/TransitionCoordinator.d.ts.map +1 -0
- package/dist/view/TransitionCoordinator.js +22 -0
- package/dist/view/TransitionCoordinator.js.map +1 -0
- package/dist/view/ViewState.d.ts +46 -0
- package/dist/view/ViewState.d.ts.map +1 -0
- package/dist/view/ViewState.js +109 -0
- package/dist/view/ViewState.js.map +1 -0
- package/dist/view/index.d.ts +7 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view/index.js +4 -0
- package/dist/view/index.js.map +1 -0
- package/dist/wasm/udoc.d.ts +202 -0
- package/dist/wasm/udoc.js +929 -0
- package/dist/wasm/udoc_bg.wasm +0 -0
- package/dist/wasm/udoc_bg.wasm.d.ts +28 -0
- package/dist/worker/WorkerClient.d.ts +103 -0
- package/dist/worker/WorkerClient.d.ts.map +1 -0
- package/dist/worker/WorkerClient.js +182 -0
- package/dist/worker/WorkerClient.js.map +1 -0
- package/dist/worker/index.d.ts +4 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +2 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/types.d.ts +81 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +6 -0
- package/dist/worker/types.js.map +1 -0
- package/dist/worker/worker.d.ts +191 -0
- package/dist/worker/worker.d.ts.map +1 -0
- package/dist/worker/worker.js +127 -0
- package/dist/worker/worker.js.map +1 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +205 -0
- package/dist/worker.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,1090 @@
|
|
|
1
|
+
// PDF uses 72 points per inch, CSS uses 96 pixels per inch
|
|
2
|
+
const POINTS_TO_CSS_PIXELS = 96 / 72;
|
|
3
|
+
/**
|
|
4
|
+
* Manages annotation rendering and interaction for a document viewer.
|
|
5
|
+
*
|
|
6
|
+
* Annotations are rendered directly inside page slot elements for accurate positioning.
|
|
7
|
+
*/
|
|
8
|
+
export class AnnotationLayer {
|
|
9
|
+
/** Annotations indexed by page index */
|
|
10
|
+
pageAnnotations = new Map();
|
|
11
|
+
/** Overlay elements indexed by page index */
|
|
12
|
+
overlays = new Map();
|
|
13
|
+
/** Callback for internal link navigation */
|
|
14
|
+
onNavigate;
|
|
15
|
+
/** Callback for external link activation */
|
|
16
|
+
onOpenUri;
|
|
17
|
+
/** Current zoom level */
|
|
18
|
+
zoom = 1;
|
|
19
|
+
/** Currently active popup element */
|
|
20
|
+
activePopup = null;
|
|
21
|
+
/** Bound handler for clicking outside popup */
|
|
22
|
+
boundHandleDocumentClick = null;
|
|
23
|
+
/** Bound handler for escape key */
|
|
24
|
+
boundHandleEscapeKey = null;
|
|
25
|
+
/**
|
|
26
|
+
* Set the callback for internal link navigation.
|
|
27
|
+
*/
|
|
28
|
+
setNavigateCallback(callback) {
|
|
29
|
+
this.onNavigate = callback;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Set the callback for external URI links.
|
|
33
|
+
*/
|
|
34
|
+
setOpenUriCallback(callback) {
|
|
35
|
+
this.onOpenUri = callback;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Set annotations for a specific page.
|
|
39
|
+
*/
|
|
40
|
+
setPageAnnotations(pageIndex, annotations) {
|
|
41
|
+
this.pageAnnotations.set(pageIndex, annotations);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get annotations for a specific page.
|
|
45
|
+
*/
|
|
46
|
+
getPageAnnotations(pageIndex) {
|
|
47
|
+
return this.pageAnnotations.get(pageIndex) ?? [];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get all annotations with metadata, grouped by page.
|
|
51
|
+
* Returns only annotations that have metadata (comments).
|
|
52
|
+
*/
|
|
53
|
+
getAllAnnotationsWithMetadata() {
|
|
54
|
+
const result = new Map();
|
|
55
|
+
for (const [pageIndex, annotations] of this.pageAnnotations) {
|
|
56
|
+
const withMetadata = annotations.filter(a => a.metadata);
|
|
57
|
+
if (withMetadata.length > 0) {
|
|
58
|
+
result.set(pageIndex, withMetadata);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Clear all annotations and overlays.
|
|
65
|
+
*/
|
|
66
|
+
clear() {
|
|
67
|
+
this.hidePopup();
|
|
68
|
+
this.pageAnnotations.clear();
|
|
69
|
+
for (const overlay of this.overlays.values()) {
|
|
70
|
+
overlay.remove();
|
|
71
|
+
}
|
|
72
|
+
this.overlays.clear();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Set the current zoom level.
|
|
76
|
+
*/
|
|
77
|
+
setZoom(zoom) {
|
|
78
|
+
this.zoom = zoom;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Show a popup for an annotation.
|
|
82
|
+
* @param anchorElement The element to anchor the popup to
|
|
83
|
+
* @param metadata The annotation metadata to display
|
|
84
|
+
* @param color The annotation color for styling
|
|
85
|
+
*/
|
|
86
|
+
showPopup(anchorElement, metadata, color) {
|
|
87
|
+
// Hide any existing popup first
|
|
88
|
+
this.hidePopup();
|
|
89
|
+
// Create popup container
|
|
90
|
+
const popup = document.createElement('div');
|
|
91
|
+
popup.className = 'udoc-annotation-popup';
|
|
92
|
+
popup.style.cssText = `
|
|
93
|
+
position: absolute;
|
|
94
|
+
background: white;
|
|
95
|
+
border: 1px solid ${color};
|
|
96
|
+
border-radius: 4px;
|
|
97
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
|
98
|
+
max-width: 300px;
|
|
99
|
+
min-width: 150px;
|
|
100
|
+
font-size: 13px;
|
|
101
|
+
line-height: 1.4;
|
|
102
|
+
color: #333;
|
|
103
|
+
z-index: 1000;
|
|
104
|
+
pointer-events: auto;
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
`;
|
|
107
|
+
// Create header section - show author if exists, otherwise fallback to subject
|
|
108
|
+
const headerText = metadata.author || metadata.subject;
|
|
109
|
+
if (headerText) {
|
|
110
|
+
const header = document.createElement('div');
|
|
111
|
+
header.style.cssText = `
|
|
112
|
+
background: ${color};
|
|
113
|
+
padding: 6px 10px;
|
|
114
|
+
color: white;
|
|
115
|
+
font-weight: 500;
|
|
116
|
+
font-size: 12px;
|
|
117
|
+
text-shadow: 0 1px 1px rgba(0,0,0,0.2);
|
|
118
|
+
`;
|
|
119
|
+
header.textContent = headerText;
|
|
120
|
+
popup.appendChild(header);
|
|
121
|
+
}
|
|
122
|
+
// Create body section (contents) if exists
|
|
123
|
+
if (metadata.contents) {
|
|
124
|
+
const body = document.createElement('div');
|
|
125
|
+
body.style.cssText = `
|
|
126
|
+
padding: 8px 10px;
|
|
127
|
+
word-wrap: break-word;
|
|
128
|
+
white-space: pre-wrap;
|
|
129
|
+
`;
|
|
130
|
+
body.textContent = metadata.contents;
|
|
131
|
+
popup.appendChild(body);
|
|
132
|
+
}
|
|
133
|
+
// Position the popup relative to the anchor element
|
|
134
|
+
const anchorRect = anchorElement.getBoundingClientRect();
|
|
135
|
+
const overlay = anchorElement.closest('.udoc-annotation-overlay');
|
|
136
|
+
if (!overlay)
|
|
137
|
+
return;
|
|
138
|
+
const overlayRect = overlay.getBoundingClientRect();
|
|
139
|
+
// Position popup below and to the right of the icon
|
|
140
|
+
const popupX = anchorRect.left - overlayRect.left + anchorRect.width + 4;
|
|
141
|
+
const popupY = anchorRect.top - overlayRect.top;
|
|
142
|
+
popup.style.left = `${popupX}px`;
|
|
143
|
+
popup.style.top = `${popupY}px`;
|
|
144
|
+
overlay.appendChild(popup);
|
|
145
|
+
this.activePopup = popup;
|
|
146
|
+
// Adjust position if popup goes off-screen
|
|
147
|
+
requestAnimationFrame(() => {
|
|
148
|
+
const popupRect = popup.getBoundingClientRect();
|
|
149
|
+
const viewportWidth = window.innerWidth;
|
|
150
|
+
const viewportHeight = window.innerHeight;
|
|
151
|
+
// If popup extends beyond right edge, position to the left of the icon
|
|
152
|
+
if (popupRect.right > viewportWidth - 10) {
|
|
153
|
+
const newX = anchorRect.left - overlayRect.left - popupRect.width - 4;
|
|
154
|
+
popup.style.left = `${Math.max(0, newX)}px`;
|
|
155
|
+
}
|
|
156
|
+
// If popup extends beyond bottom edge, adjust upward
|
|
157
|
+
if (popupRect.bottom > viewportHeight - 10) {
|
|
158
|
+
const newY = popupY - (popupRect.bottom - viewportHeight) - 10;
|
|
159
|
+
popup.style.top = `${Math.max(0, newY)}px`;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
// Set up event handlers for closing
|
|
163
|
+
this.boundHandleDocumentClick = (e) => {
|
|
164
|
+
if (!popup.contains(e.target) && !anchorElement.contains(e.target)) {
|
|
165
|
+
this.hidePopup();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
this.boundHandleEscapeKey = (e) => {
|
|
169
|
+
if (e.key === 'Escape') {
|
|
170
|
+
this.hidePopup();
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
// Delay adding click listener to avoid immediate close
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
document.addEventListener('click', this.boundHandleDocumentClick);
|
|
176
|
+
}, 0);
|
|
177
|
+
document.addEventListener('keydown', this.boundHandleEscapeKey);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Hide the currently active popup.
|
|
181
|
+
*/
|
|
182
|
+
hidePopup() {
|
|
183
|
+
if (this.activePopup) {
|
|
184
|
+
this.activePopup.remove();
|
|
185
|
+
this.activePopup = null;
|
|
186
|
+
}
|
|
187
|
+
if (this.boundHandleDocumentClick) {
|
|
188
|
+
document.removeEventListener('click', this.boundHandleDocumentClick);
|
|
189
|
+
this.boundHandleDocumentClick = null;
|
|
190
|
+
}
|
|
191
|
+
if (this.boundHandleEscapeKey) {
|
|
192
|
+
document.removeEventListener('keydown', this.boundHandleEscapeKey);
|
|
193
|
+
this.boundHandleEscapeKey = null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Create or get an annotation overlay for a slot element.
|
|
198
|
+
* The overlay is positioned absolutely within the slot.
|
|
199
|
+
*
|
|
200
|
+
* @param slotEl The slot element to attach the overlay to
|
|
201
|
+
* @param pageIndex The page index for this slot
|
|
202
|
+
* @returns The overlay element
|
|
203
|
+
*/
|
|
204
|
+
getOrCreateOverlay(slotEl, pageIndex) {
|
|
205
|
+
let overlay = this.overlays.get(pageIndex);
|
|
206
|
+
if (overlay && overlay.parentElement === slotEl) {
|
|
207
|
+
return overlay;
|
|
208
|
+
}
|
|
209
|
+
// Create new overlay
|
|
210
|
+
overlay = document.createElement('div');
|
|
211
|
+
overlay.className = 'udoc-annotation-overlay';
|
|
212
|
+
overlay.style.cssText = `
|
|
213
|
+
position: absolute;
|
|
214
|
+
top: 0;
|
|
215
|
+
left: 0;
|
|
216
|
+
width: 100%;
|
|
217
|
+
height: 100%;
|
|
218
|
+
pointer-events: none;
|
|
219
|
+
`;
|
|
220
|
+
slotEl.appendChild(overlay);
|
|
221
|
+
this.overlays.set(pageIndex, overlay);
|
|
222
|
+
return overlay;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Render annotations for a specific page into its slot overlay.
|
|
226
|
+
*
|
|
227
|
+
* @param slotEl The slot element containing the page
|
|
228
|
+
* @param pageIndex The page index
|
|
229
|
+
*/
|
|
230
|
+
renderPageAnnotations(slotEl, pageIndex) {
|
|
231
|
+
const annotations = this.pageAnnotations.get(pageIndex);
|
|
232
|
+
if (!annotations || annotations.length === 0) {
|
|
233
|
+
// Remove overlay if no annotations
|
|
234
|
+
const existing = this.overlays.get(pageIndex);
|
|
235
|
+
if (existing) {
|
|
236
|
+
existing.remove();
|
|
237
|
+
this.overlays.delete(pageIndex);
|
|
238
|
+
}
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const overlay = this.getOrCreateOverlay(slotEl, pageIndex);
|
|
242
|
+
overlay.innerHTML = '';
|
|
243
|
+
for (const annotation of annotations) {
|
|
244
|
+
if (!annotation.bounds)
|
|
245
|
+
continue;
|
|
246
|
+
// Replies are now nested under parent annotations, so all annotations here are top-level
|
|
247
|
+
switch (annotation.type) {
|
|
248
|
+
case 'link':
|
|
249
|
+
this.renderLinkAnnotation(overlay, annotation);
|
|
250
|
+
break;
|
|
251
|
+
case 'highlight':
|
|
252
|
+
this.renderHighlightAnnotation(overlay, annotation);
|
|
253
|
+
break;
|
|
254
|
+
case 'underline':
|
|
255
|
+
this.renderUnderlineAnnotation(overlay, annotation);
|
|
256
|
+
break;
|
|
257
|
+
case 'strikeOut':
|
|
258
|
+
this.renderStrikeOutAnnotation(overlay, annotation);
|
|
259
|
+
break;
|
|
260
|
+
case 'squiggly':
|
|
261
|
+
this.renderSquigglyAnnotation(overlay, annotation);
|
|
262
|
+
break;
|
|
263
|
+
// Phase 2: Text Annotations
|
|
264
|
+
case 'text':
|
|
265
|
+
this.renderTextAnnotation(overlay, annotation);
|
|
266
|
+
break;
|
|
267
|
+
case 'freeText':
|
|
268
|
+
this.renderFreeTextAnnotation(overlay, annotation);
|
|
269
|
+
break;
|
|
270
|
+
case 'stamp':
|
|
271
|
+
this.renderStampAnnotation(overlay, annotation);
|
|
272
|
+
break;
|
|
273
|
+
// Phase 3: Drawing Shape Annotations
|
|
274
|
+
case 'line':
|
|
275
|
+
this.renderLineAnnotation(overlay, annotation);
|
|
276
|
+
break;
|
|
277
|
+
case 'square':
|
|
278
|
+
this.renderSquareAnnotation(overlay, annotation);
|
|
279
|
+
break;
|
|
280
|
+
case 'circle':
|
|
281
|
+
this.renderCircleAnnotation(overlay, annotation);
|
|
282
|
+
break;
|
|
283
|
+
case 'polygon':
|
|
284
|
+
this.renderPolygonAnnotation(overlay, annotation);
|
|
285
|
+
break;
|
|
286
|
+
case 'polyLine':
|
|
287
|
+
this.renderPolyLineAnnotation(overlay, annotation);
|
|
288
|
+
break;
|
|
289
|
+
case 'ink':
|
|
290
|
+
this.renderInkAnnotation(overlay, annotation);
|
|
291
|
+
break;
|
|
292
|
+
// Additional Annotation Types
|
|
293
|
+
case 'caret':
|
|
294
|
+
this.renderCaretAnnotation(overlay, annotation);
|
|
295
|
+
break;
|
|
296
|
+
case 'redact':
|
|
297
|
+
this.renderRedactAnnotation(overlay, annotation);
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Render a link annotation as a clickable box.
|
|
304
|
+
*/
|
|
305
|
+
renderLinkAnnotation(overlay, annotation) {
|
|
306
|
+
const screenX = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
307
|
+
const screenY = annotation.bounds.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
308
|
+
const screenWidth = annotation.bounds.width * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
309
|
+
const screenHeight = annotation.bounds.height * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
310
|
+
const box = document.createElement('div');
|
|
311
|
+
box.className = 'udoc-annotation-box udoc-annotation-link';
|
|
312
|
+
box.style.cssText = `
|
|
313
|
+
position: absolute;
|
|
314
|
+
left: ${screenX}px;
|
|
315
|
+
top: ${screenY}px;
|
|
316
|
+
width: ${screenWidth}px;
|
|
317
|
+
height: ${screenHeight}px;
|
|
318
|
+
pointer-events: auto;
|
|
319
|
+
cursor: pointer;
|
|
320
|
+
`;
|
|
321
|
+
box.addEventListener('click', (e) => {
|
|
322
|
+
e.preventDefault();
|
|
323
|
+
e.stopPropagation();
|
|
324
|
+
if (annotation.action) {
|
|
325
|
+
this.handleLinkAction(annotation.action);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
overlay.appendChild(box);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Render a highlight annotation as a colored overlay.
|
|
332
|
+
*/
|
|
333
|
+
renderHighlightAnnotation(overlay, annotation) {
|
|
334
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
335
|
+
const color = this.colorToRgb(annotation.color, 'rgb(255, 255, 0)'); // Default yellow
|
|
336
|
+
const opacity = annotation.opacity ?? 0.4;
|
|
337
|
+
for (const quad of annotation.quads) {
|
|
338
|
+
const scaledPoints = this.scaleQuadPoints(quad.points);
|
|
339
|
+
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
340
|
+
polygon.setAttribute('points', scaledPoints.map((p) => `${p.x},${p.y}`).join(' '));
|
|
341
|
+
polygon.setAttribute('fill', color);
|
|
342
|
+
polygon.setAttribute('fill-opacity', String(opacity));
|
|
343
|
+
polygon.setAttribute('style', 'mix-blend-mode: multiply;');
|
|
344
|
+
svg.appendChild(polygon);
|
|
345
|
+
}
|
|
346
|
+
overlay.appendChild(svg);
|
|
347
|
+
// Add clickable overlay when metadata exists
|
|
348
|
+
this.addTextMarkupClickHandler(overlay, annotation, color);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Add a clickable overlay for text markup annotations when metadata exists.
|
|
352
|
+
*/
|
|
353
|
+
addTextMarkupClickHandler(overlay, annotation, color) {
|
|
354
|
+
if (!annotation.metadata)
|
|
355
|
+
return;
|
|
356
|
+
const screenX = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
357
|
+
const screenY = annotation.bounds.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
358
|
+
const screenWidth = annotation.bounds.width * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
359
|
+
const screenHeight = annotation.bounds.height * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
360
|
+
const clickArea = document.createElement('div');
|
|
361
|
+
clickArea.className = 'udoc-annotation-click-area';
|
|
362
|
+
clickArea.style.cssText = `
|
|
363
|
+
position: absolute;
|
|
364
|
+
left: ${screenX}px;
|
|
365
|
+
top: ${screenY}px;
|
|
366
|
+
width: ${screenWidth}px;
|
|
367
|
+
height: ${screenHeight}px;
|
|
368
|
+
pointer-events: auto;
|
|
369
|
+
cursor: pointer;
|
|
370
|
+
`;
|
|
371
|
+
clickArea.addEventListener('click', (e) => {
|
|
372
|
+
e.stopPropagation();
|
|
373
|
+
this.showPopup(clickArea, annotation.metadata, color);
|
|
374
|
+
});
|
|
375
|
+
overlay.appendChild(clickArea);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Render an underline annotation as lines along the bottom of text.
|
|
379
|
+
*/
|
|
380
|
+
renderUnderlineAnnotation(overlay, annotation) {
|
|
381
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
382
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 128, 0)'); // Default green
|
|
383
|
+
const strokeWidth = Math.max(1, 1 * this.zoom);
|
|
384
|
+
for (const quad of annotation.quads) {
|
|
385
|
+
const scaledPoints = this.scaleQuadPoints(quad.points);
|
|
386
|
+
// Draw line along bottom edge (from bottom-left to bottom-right)
|
|
387
|
+
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
388
|
+
line.setAttribute('x1', String(scaledPoints[0].x));
|
|
389
|
+
line.setAttribute('y1', String(scaledPoints[0].y));
|
|
390
|
+
line.setAttribute('x2', String(scaledPoints[1].x));
|
|
391
|
+
line.setAttribute('y2', String(scaledPoints[1].y));
|
|
392
|
+
line.setAttribute('stroke', color);
|
|
393
|
+
line.setAttribute('stroke-width', String(strokeWidth));
|
|
394
|
+
svg.appendChild(line);
|
|
395
|
+
}
|
|
396
|
+
overlay.appendChild(svg);
|
|
397
|
+
// Add clickable overlay when metadata exists
|
|
398
|
+
this.addTextMarkupClickHandler(overlay, annotation, color);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Render a strikeout annotation as lines through the middle of text.
|
|
402
|
+
*/
|
|
403
|
+
renderStrikeOutAnnotation(overlay, annotation) {
|
|
404
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
405
|
+
const color = this.colorToRgb(annotation.color, 'rgb(255, 0, 0)'); // Default red
|
|
406
|
+
const strokeWidth = Math.max(1, 1 * this.zoom);
|
|
407
|
+
for (const quad of annotation.quads) {
|
|
408
|
+
const scaledPoints = this.scaleQuadPoints(quad.points);
|
|
409
|
+
// Calculate middle Y between top and bottom
|
|
410
|
+
const midLeftY = (scaledPoints[0].y + scaledPoints[3].y) / 2;
|
|
411
|
+
const midRightY = (scaledPoints[1].y + scaledPoints[2].y) / 2;
|
|
412
|
+
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
413
|
+
line.setAttribute('x1', String(scaledPoints[0].x));
|
|
414
|
+
line.setAttribute('y1', String(midLeftY));
|
|
415
|
+
line.setAttribute('x2', String(scaledPoints[1].x));
|
|
416
|
+
line.setAttribute('y2', String(midRightY));
|
|
417
|
+
line.setAttribute('stroke', color);
|
|
418
|
+
line.setAttribute('stroke-width', String(strokeWidth));
|
|
419
|
+
svg.appendChild(line);
|
|
420
|
+
}
|
|
421
|
+
overlay.appendChild(svg);
|
|
422
|
+
// Add clickable overlay when metadata exists
|
|
423
|
+
this.addTextMarkupClickHandler(overlay, annotation, color);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Render a squiggly annotation as wavy lines under text.
|
|
427
|
+
*/
|
|
428
|
+
renderSquigglyAnnotation(overlay, annotation) {
|
|
429
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
430
|
+
const color = this.colorToRgb(annotation.color, 'rgb(255, 0, 0)'); // Default red
|
|
431
|
+
const strokeWidth = Math.max(1, 1 * this.zoom);
|
|
432
|
+
const wavelength = 4 * this.zoom;
|
|
433
|
+
const amplitude = 2 * this.zoom;
|
|
434
|
+
for (const quad of annotation.quads) {
|
|
435
|
+
const scaledPoints = this.scaleQuadPoints(quad.points);
|
|
436
|
+
const startX = scaledPoints[0].x;
|
|
437
|
+
const endX = scaledPoints[1].x;
|
|
438
|
+
const startY = scaledPoints[0].y;
|
|
439
|
+
const endY = scaledPoints[1].y;
|
|
440
|
+
// Generate wavy path
|
|
441
|
+
let path = `M ${startX} ${startY}`;
|
|
442
|
+
const totalLength = Math.sqrt((endX - startX) ** 2 + (endY - startY) ** 2);
|
|
443
|
+
const steps = Math.ceil(totalLength / wavelength);
|
|
444
|
+
for (let i = 0; i < steps; i++) {
|
|
445
|
+
const t1 = (i + 0.5) / steps;
|
|
446
|
+
const t2 = (i + 1) / steps;
|
|
447
|
+
const midX = startX + (endX - startX) * t1;
|
|
448
|
+
const midY = startY + (endY - startY) * t1;
|
|
449
|
+
const nextX = startX + (endX - startX) * t2;
|
|
450
|
+
const nextY = startY + (endY - startY) * t2;
|
|
451
|
+
// Alternate up and down
|
|
452
|
+
const direction = i % 2 === 0 ? -1 : 1;
|
|
453
|
+
path += ` Q ${midX} ${midY + amplitude * direction}, ${nextX} ${nextY}`;
|
|
454
|
+
}
|
|
455
|
+
const pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
456
|
+
pathEl.setAttribute('d', path);
|
|
457
|
+
pathEl.setAttribute('stroke', color);
|
|
458
|
+
pathEl.setAttribute('stroke-width', String(strokeWidth));
|
|
459
|
+
pathEl.setAttribute('fill', 'none');
|
|
460
|
+
svg.appendChild(pathEl);
|
|
461
|
+
}
|
|
462
|
+
overlay.appendChild(svg);
|
|
463
|
+
// Add clickable overlay when metadata exists
|
|
464
|
+
this.addTextMarkupClickHandler(overlay, annotation, color);
|
|
465
|
+
}
|
|
466
|
+
// =========================================================================
|
|
467
|
+
// Phase 2: Text Annotation Renderers
|
|
468
|
+
// =========================================================================
|
|
469
|
+
/**
|
|
470
|
+
* Render a text (sticky note) annotation as an icon.
|
|
471
|
+
*/
|
|
472
|
+
renderTextAnnotation(overlay, annotation) {
|
|
473
|
+
const screenX = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
474
|
+
const iconSize = 20 * this.zoom;
|
|
475
|
+
const color = this.colorToRgb(annotation.color, 'rgb(255, 208, 0)'); // Default yellow
|
|
476
|
+
// Position at bottom-left of bounds (PDF anchors sticky notes at lower-left corner)
|
|
477
|
+
// After Y-flip, lower-left becomes bottom-left in screen coords
|
|
478
|
+
const screenY = (annotation.bounds.y + annotation.bounds.height) * POINTS_TO_CSS_PIXELS * this.zoom -
|
|
479
|
+
iconSize;
|
|
480
|
+
// Create icon container
|
|
481
|
+
const icon = document.createElement('div');
|
|
482
|
+
icon.className = 'udoc-annotation-text-icon';
|
|
483
|
+
icon.style.cssText = `
|
|
484
|
+
position: absolute;
|
|
485
|
+
left: ${screenX}px;
|
|
486
|
+
top: ${screenY}px;
|
|
487
|
+
width: ${iconSize}px;
|
|
488
|
+
height: ${iconSize}px;
|
|
489
|
+
pointer-events: auto;
|
|
490
|
+
cursor: pointer;
|
|
491
|
+
`;
|
|
492
|
+
// Create SVG icon based on type
|
|
493
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
494
|
+
svg.setAttribute('viewBox', '0 0 24 24');
|
|
495
|
+
svg.setAttribute('width', String(iconSize));
|
|
496
|
+
svg.setAttribute('height', String(iconSize));
|
|
497
|
+
// Use a note/comment icon path
|
|
498
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
499
|
+
path.setAttribute('d', 'M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z');
|
|
500
|
+
path.setAttribute('fill', color);
|
|
501
|
+
path.setAttribute('stroke', 'rgba(0,0,0,0.3)');
|
|
502
|
+
path.setAttribute('stroke-width', '1');
|
|
503
|
+
svg.appendChild(path);
|
|
504
|
+
icon.appendChild(svg);
|
|
505
|
+
// Add click handler to show popup with metadata
|
|
506
|
+
if (annotation.metadata) {
|
|
507
|
+
icon.addEventListener('click', (e) => {
|
|
508
|
+
e.stopPropagation();
|
|
509
|
+
this.showPopup(icon, annotation.metadata, color);
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
overlay.appendChild(icon);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Render a free text (typewriter/text box) annotation.
|
|
516
|
+
*/
|
|
517
|
+
renderFreeTextAnnotation(overlay, annotation) {
|
|
518
|
+
const screenX = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
519
|
+
const screenY = annotation.bounds.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
520
|
+
const screenWidth = annotation.bounds.width * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
521
|
+
const screenHeight = annotation.bounds.height * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
522
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 0, 0)'); // Default black
|
|
523
|
+
const borderColor = this.colorToRgb(annotation.borderColor, 'transparent');
|
|
524
|
+
// Create text box
|
|
525
|
+
const textBox = document.createElement('div');
|
|
526
|
+
textBox.className = 'udoc-annotation-freetext';
|
|
527
|
+
textBox.style.cssText = `
|
|
528
|
+
position: absolute;
|
|
529
|
+
left: ${screenX}px;
|
|
530
|
+
top: ${screenY}px;
|
|
531
|
+
width: ${screenWidth}px;
|
|
532
|
+
height: ${screenHeight}px;
|
|
533
|
+
color: ${color};
|
|
534
|
+
border: 1px solid ${borderColor};
|
|
535
|
+
font-size: ${12 * this.zoom}px;
|
|
536
|
+
font-family: Helvetica, Arial, sans-serif;
|
|
537
|
+
text-align: ${annotation.justification};
|
|
538
|
+
overflow: hidden;
|
|
539
|
+
word-wrap: break-word;
|
|
540
|
+
pointer-events: none;
|
|
541
|
+
padding: ${2 * this.zoom}px;
|
|
542
|
+
box-sizing: border-box;
|
|
543
|
+
`;
|
|
544
|
+
if (annotation.contents) {
|
|
545
|
+
textBox.textContent = annotation.contents;
|
|
546
|
+
}
|
|
547
|
+
// Render callout line if present
|
|
548
|
+
if (annotation.calloutLine && annotation.calloutLine.length >= 2) {
|
|
549
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
550
|
+
const lineColor = this.colorToRgb(annotation.borderColor, 'rgb(0, 0, 0)');
|
|
551
|
+
const strokeWidth = Math.max(1, 1 * this.zoom);
|
|
552
|
+
const pathData = annotation.calloutLine
|
|
553
|
+
.map((point, i) => {
|
|
554
|
+
const x = point.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
555
|
+
const y = point.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
556
|
+
return `${i === 0 ? 'M' : 'L'} ${x} ${y}`;
|
|
557
|
+
})
|
|
558
|
+
.join(' ');
|
|
559
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
560
|
+
path.setAttribute('d', pathData);
|
|
561
|
+
path.setAttribute('stroke', lineColor);
|
|
562
|
+
path.setAttribute('stroke-width', String(strokeWidth));
|
|
563
|
+
path.setAttribute('fill', 'none');
|
|
564
|
+
svg.appendChild(path);
|
|
565
|
+
overlay.appendChild(svg);
|
|
566
|
+
}
|
|
567
|
+
overlay.appendChild(textBox);
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Render a stamp annotation as a bordered text label.
|
|
571
|
+
*/
|
|
572
|
+
renderStampAnnotation(overlay, annotation) {
|
|
573
|
+
const screenX = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
574
|
+
const screenY = annotation.bounds.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
575
|
+
const screenWidth = annotation.bounds.width * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
576
|
+
const screenHeight = annotation.bounds.height * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
577
|
+
const color = this.colorToRgb(annotation.color, 'rgb(255, 0, 0)'); // Default red
|
|
578
|
+
// If stamp has custom appearance, we just show the bounds
|
|
579
|
+
// (actual appearance would be rendered via the page content)
|
|
580
|
+
// For standard stamps, show the name
|
|
581
|
+
const stamp = document.createElement('div');
|
|
582
|
+
stamp.className = 'udoc-annotation-stamp';
|
|
583
|
+
stamp.style.cssText = `
|
|
584
|
+
position: absolute;
|
|
585
|
+
left: ${screenX}px;
|
|
586
|
+
top: ${screenY}px;
|
|
587
|
+
width: ${screenWidth}px;
|
|
588
|
+
height: ${screenHeight}px;
|
|
589
|
+
display: flex;
|
|
590
|
+
align-items: center;
|
|
591
|
+
justify-content: center;
|
|
592
|
+
pointer-events: none;
|
|
593
|
+
`;
|
|
594
|
+
// Only show text for standard stamps without custom appearance
|
|
595
|
+
if (!annotation.hasCustomAppearance && annotation.name) {
|
|
596
|
+
const label = document.createElement('span');
|
|
597
|
+
label.style.cssText = `
|
|
598
|
+
color: ${color};
|
|
599
|
+
font-size: ${Math.min(screenHeight * 0.4, 16 * this.zoom)}px;
|
|
600
|
+
font-weight: bold;
|
|
601
|
+
font-family: Helvetica, Arial, sans-serif;
|
|
602
|
+
text-transform: uppercase;
|
|
603
|
+
border: 2px solid ${color};
|
|
604
|
+
padding: ${2 * this.zoom}px ${4 * this.zoom}px;
|
|
605
|
+
transform: rotate(-15deg);
|
|
606
|
+
white-space: nowrap;
|
|
607
|
+
`;
|
|
608
|
+
label.textContent = annotation.name;
|
|
609
|
+
stamp.appendChild(label);
|
|
610
|
+
}
|
|
611
|
+
overlay.appendChild(stamp);
|
|
612
|
+
}
|
|
613
|
+
// =========================================================================
|
|
614
|
+
// Phase 3: Drawing Shape Annotation Renderers
|
|
615
|
+
// =========================================================================
|
|
616
|
+
/**
|
|
617
|
+
* Render a line annotation with optional line endings.
|
|
618
|
+
*/
|
|
619
|
+
renderLineAnnotation(overlay, annotation) {
|
|
620
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
621
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 0, 0)');
|
|
622
|
+
const interiorColor = this.colorToRgb(annotation.interiorColor, color);
|
|
623
|
+
const strokeWidth = (annotation.borderWidth ?? 1) * this.zoom;
|
|
624
|
+
const opacity = annotation.opacity ?? 1;
|
|
625
|
+
// Scale coordinates
|
|
626
|
+
const startX = annotation.start.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
627
|
+
const startY = annotation.start.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
628
|
+
const endX = annotation.end.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
629
|
+
const endY = annotation.end.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
630
|
+
// Create group for line and endings
|
|
631
|
+
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
632
|
+
g.setAttribute('opacity', String(opacity));
|
|
633
|
+
// Draw main line
|
|
634
|
+
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
635
|
+
line.setAttribute('x1', String(startX));
|
|
636
|
+
line.setAttribute('y1', String(startY));
|
|
637
|
+
line.setAttribute('x2', String(endX));
|
|
638
|
+
line.setAttribute('y2', String(endY));
|
|
639
|
+
line.setAttribute('stroke', color);
|
|
640
|
+
line.setAttribute('stroke-width', String(strokeWidth));
|
|
641
|
+
g.appendChild(line);
|
|
642
|
+
// Draw line endings
|
|
643
|
+
const angle = Math.atan2(endY - startY, endX - startX);
|
|
644
|
+
this.drawLineEnding(g, startX, startY, annotation.startEnding, angle + Math.PI, strokeWidth, color, interiorColor);
|
|
645
|
+
this.drawLineEnding(g, endX, endY, annotation.endEnding, angle, strokeWidth, color, interiorColor);
|
|
646
|
+
svg.appendChild(g);
|
|
647
|
+
overlay.appendChild(svg);
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Draw a line ending at a point.
|
|
651
|
+
*/
|
|
652
|
+
drawLineEnding(g, x, y, ending, angle, strokeWidth, color, interiorColor) {
|
|
653
|
+
if (ending === 'None')
|
|
654
|
+
return;
|
|
655
|
+
const size = strokeWidth * 4;
|
|
656
|
+
switch (ending) {
|
|
657
|
+
case 'OpenArrow': {
|
|
658
|
+
const p1x = x - size * Math.cos(angle - Math.PI / 6);
|
|
659
|
+
const p1y = y - size * Math.sin(angle - Math.PI / 6);
|
|
660
|
+
const p2x = x - size * Math.cos(angle + Math.PI / 6);
|
|
661
|
+
const p2y = y - size * Math.sin(angle + Math.PI / 6);
|
|
662
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
663
|
+
path.setAttribute('d', `M ${p1x} ${p1y} L ${x} ${y} L ${p2x} ${p2y}`);
|
|
664
|
+
path.setAttribute('stroke', color);
|
|
665
|
+
path.setAttribute('stroke-width', String(strokeWidth));
|
|
666
|
+
path.setAttribute('fill', 'none');
|
|
667
|
+
g.appendChild(path);
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
case 'ClosedArrow': {
|
|
671
|
+
const p1x = x - size * Math.cos(angle - Math.PI / 6);
|
|
672
|
+
const p1y = y - size * Math.sin(angle - Math.PI / 6);
|
|
673
|
+
const p2x = x - size * Math.cos(angle + Math.PI / 6);
|
|
674
|
+
const p2y = y - size * Math.sin(angle + Math.PI / 6);
|
|
675
|
+
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
676
|
+
polygon.setAttribute('points', `${x},${y} ${p1x},${p1y} ${p2x},${p2y}`);
|
|
677
|
+
polygon.setAttribute('fill', interiorColor);
|
|
678
|
+
polygon.setAttribute('stroke', color);
|
|
679
|
+
polygon.setAttribute('stroke-width', String(strokeWidth * 0.5));
|
|
680
|
+
g.appendChild(polygon);
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
683
|
+
case 'Circle': {
|
|
684
|
+
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
|
|
685
|
+
circle.setAttribute('cx', String(x));
|
|
686
|
+
circle.setAttribute('cy', String(y));
|
|
687
|
+
circle.setAttribute('r', String(size / 2));
|
|
688
|
+
circle.setAttribute('fill', interiorColor);
|
|
689
|
+
circle.setAttribute('stroke', color);
|
|
690
|
+
circle.setAttribute('stroke-width', String(strokeWidth * 0.5));
|
|
691
|
+
g.appendChild(circle);
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
case 'Square': {
|
|
695
|
+
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
696
|
+
rect.setAttribute('x', String(x - size / 2));
|
|
697
|
+
rect.setAttribute('y', String(y - size / 2));
|
|
698
|
+
rect.setAttribute('width', String(size));
|
|
699
|
+
rect.setAttribute('height', String(size));
|
|
700
|
+
rect.setAttribute('fill', interiorColor);
|
|
701
|
+
rect.setAttribute('stroke', color);
|
|
702
|
+
rect.setAttribute('stroke-width', String(strokeWidth * 0.5));
|
|
703
|
+
g.appendChild(rect);
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
case 'Diamond': {
|
|
707
|
+
const dx = size / 2;
|
|
708
|
+
const points = `${x},${y - dx} ${x + dx},${y} ${x},${y + dx} ${x - dx},${y}`;
|
|
709
|
+
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
710
|
+
polygon.setAttribute('points', points);
|
|
711
|
+
polygon.setAttribute('fill', interiorColor);
|
|
712
|
+
polygon.setAttribute('stroke', color);
|
|
713
|
+
polygon.setAttribute('stroke-width', String(strokeWidth * 0.5));
|
|
714
|
+
g.appendChild(polygon);
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
case 'Butt': {
|
|
718
|
+
// Perpendicular line
|
|
719
|
+
const perpAngle = angle + Math.PI / 2;
|
|
720
|
+
const p1x = x + (size / 2) * Math.cos(perpAngle);
|
|
721
|
+
const p1y = y + (size / 2) * Math.sin(perpAngle);
|
|
722
|
+
const p2x = x - (size / 2) * Math.cos(perpAngle);
|
|
723
|
+
const p2y = y - (size / 2) * Math.sin(perpAngle);
|
|
724
|
+
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
725
|
+
line.setAttribute('x1', String(p1x));
|
|
726
|
+
line.setAttribute('y1', String(p1y));
|
|
727
|
+
line.setAttribute('x2', String(p2x));
|
|
728
|
+
line.setAttribute('y2', String(p2y));
|
|
729
|
+
line.setAttribute('stroke', color);
|
|
730
|
+
line.setAttribute('stroke-width', String(strokeWidth));
|
|
731
|
+
g.appendChild(line);
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
case 'ROpenArrow': {
|
|
735
|
+
// Reversed open arrow (pointing away from line)
|
|
736
|
+
const p1x = x + size * Math.cos(angle - Math.PI / 6);
|
|
737
|
+
const p1y = y + size * Math.sin(angle - Math.PI / 6);
|
|
738
|
+
const p2x = x + size * Math.cos(angle + Math.PI / 6);
|
|
739
|
+
const p2y = y + size * Math.sin(angle + Math.PI / 6);
|
|
740
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
741
|
+
path.setAttribute('d', `M ${p1x} ${p1y} L ${x} ${y} L ${p2x} ${p2y}`);
|
|
742
|
+
path.setAttribute('stroke', color);
|
|
743
|
+
path.setAttribute('stroke-width', String(strokeWidth));
|
|
744
|
+
path.setAttribute('fill', 'none');
|
|
745
|
+
g.appendChild(path);
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
748
|
+
case 'RClosedArrow': {
|
|
749
|
+
// Reversed closed arrow
|
|
750
|
+
const p1x = x + size * Math.cos(angle - Math.PI / 6);
|
|
751
|
+
const p1y = y + size * Math.sin(angle - Math.PI / 6);
|
|
752
|
+
const p2x = x + size * Math.cos(angle + Math.PI / 6);
|
|
753
|
+
const p2y = y + size * Math.sin(angle + Math.PI / 6);
|
|
754
|
+
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
755
|
+
polygon.setAttribute('points', `${x},${y} ${p1x},${p1y} ${p2x},${p2y}`);
|
|
756
|
+
polygon.setAttribute('fill', interiorColor);
|
|
757
|
+
polygon.setAttribute('stroke', color);
|
|
758
|
+
polygon.setAttribute('stroke-width', String(strokeWidth * 0.5));
|
|
759
|
+
g.appendChild(polygon);
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
case 'Slash': {
|
|
763
|
+
// Slash line
|
|
764
|
+
const slashAngle = angle + Math.PI / 4;
|
|
765
|
+
const p1x = x + (size / 2) * Math.cos(slashAngle);
|
|
766
|
+
const p1y = y + (size / 2) * Math.sin(slashAngle);
|
|
767
|
+
const p2x = x - (size / 2) * Math.cos(slashAngle);
|
|
768
|
+
const p2y = y - (size / 2) * Math.sin(slashAngle);
|
|
769
|
+
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
770
|
+
line.setAttribute('x1', String(p1x));
|
|
771
|
+
line.setAttribute('y1', String(p1y));
|
|
772
|
+
line.setAttribute('x2', String(p2x));
|
|
773
|
+
line.setAttribute('y2', String(p2y));
|
|
774
|
+
line.setAttribute('stroke', color);
|
|
775
|
+
line.setAttribute('stroke-width', String(strokeWidth));
|
|
776
|
+
g.appendChild(line);
|
|
777
|
+
break;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Render a square/rectangle annotation.
|
|
783
|
+
*/
|
|
784
|
+
renderSquareAnnotation(overlay, annotation) {
|
|
785
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
786
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 0, 0)');
|
|
787
|
+
const interiorColor = annotation.interiorColor
|
|
788
|
+
? this.colorToRgb(annotation.interiorColor, 'none')
|
|
789
|
+
: 'none';
|
|
790
|
+
const strokeWidth = (annotation.borderWidth ?? 1) * this.zoom;
|
|
791
|
+
const opacity = annotation.opacity ?? 1;
|
|
792
|
+
const x = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
793
|
+
const y = annotation.bounds.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
794
|
+
const width = annotation.bounds.width * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
795
|
+
const height = annotation.bounds.height * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
796
|
+
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
797
|
+
rect.setAttribute('x', String(x + strokeWidth / 2));
|
|
798
|
+
rect.setAttribute('y', String(y + strokeWidth / 2));
|
|
799
|
+
rect.setAttribute('width', String(Math.max(0, width - strokeWidth)));
|
|
800
|
+
rect.setAttribute('height', String(Math.max(0, height - strokeWidth)));
|
|
801
|
+
rect.setAttribute('fill', interiorColor);
|
|
802
|
+
rect.setAttribute('stroke', color);
|
|
803
|
+
rect.setAttribute('stroke-width', String(strokeWidth));
|
|
804
|
+
rect.setAttribute('opacity', String(opacity));
|
|
805
|
+
// Apply dash pattern for dashed style
|
|
806
|
+
if (annotation.borderStyle === 'dashed') {
|
|
807
|
+
rect.setAttribute('stroke-dasharray', `${strokeWidth * 3} ${strokeWidth * 2}`);
|
|
808
|
+
}
|
|
809
|
+
svg.appendChild(rect);
|
|
810
|
+
overlay.appendChild(svg);
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Render a circle/ellipse annotation.
|
|
814
|
+
*/
|
|
815
|
+
renderCircleAnnotation(overlay, annotation) {
|
|
816
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
817
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 0, 0)');
|
|
818
|
+
const interiorColor = annotation.interiorColor
|
|
819
|
+
? this.colorToRgb(annotation.interiorColor, 'none')
|
|
820
|
+
: 'none';
|
|
821
|
+
const strokeWidth = (annotation.borderWidth ?? 1) * this.zoom;
|
|
822
|
+
const opacity = annotation.opacity ?? 1;
|
|
823
|
+
const x = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
824
|
+
const y = annotation.bounds.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
825
|
+
const width = annotation.bounds.width * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
826
|
+
const height = annotation.bounds.height * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
827
|
+
const cx = x + width / 2;
|
|
828
|
+
const cy = y + height / 2;
|
|
829
|
+
const rx = (width - strokeWidth) / 2;
|
|
830
|
+
const ry = (height - strokeWidth) / 2;
|
|
831
|
+
const ellipse = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse');
|
|
832
|
+
ellipse.setAttribute('cx', String(cx));
|
|
833
|
+
ellipse.setAttribute('cy', String(cy));
|
|
834
|
+
ellipse.setAttribute('rx', String(Math.max(0, rx)));
|
|
835
|
+
ellipse.setAttribute('ry', String(Math.max(0, ry)));
|
|
836
|
+
ellipse.setAttribute('fill', interiorColor);
|
|
837
|
+
ellipse.setAttribute('stroke', color);
|
|
838
|
+
ellipse.setAttribute('stroke-width', String(strokeWidth));
|
|
839
|
+
ellipse.setAttribute('opacity', String(opacity));
|
|
840
|
+
// Apply dash pattern for dashed style
|
|
841
|
+
if (annotation.borderStyle === 'dashed') {
|
|
842
|
+
ellipse.setAttribute('stroke-dasharray', `${strokeWidth * 3} ${strokeWidth * 2}`);
|
|
843
|
+
}
|
|
844
|
+
svg.appendChild(ellipse);
|
|
845
|
+
overlay.appendChild(svg);
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Render a polygon annotation (closed shape).
|
|
849
|
+
*/
|
|
850
|
+
renderPolygonAnnotation(overlay, annotation) {
|
|
851
|
+
if (!annotation.vertices || annotation.vertices.length < 3)
|
|
852
|
+
return;
|
|
853
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
854
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 0, 0)');
|
|
855
|
+
const interiorColor = annotation.interiorColor
|
|
856
|
+
? this.colorToRgb(annotation.interiorColor, 'none')
|
|
857
|
+
: 'none';
|
|
858
|
+
const strokeWidth = (annotation.borderWidth ?? 1) * this.zoom;
|
|
859
|
+
const opacity = annotation.opacity ?? 1;
|
|
860
|
+
const scaledPoints = annotation.vertices.map((p) => ({
|
|
861
|
+
x: p.x * POINTS_TO_CSS_PIXELS * this.zoom,
|
|
862
|
+
y: p.y * POINTS_TO_CSS_PIXELS * this.zoom,
|
|
863
|
+
}));
|
|
864
|
+
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
865
|
+
polygon.setAttribute('points', scaledPoints.map((p) => `${p.x},${p.y}`).join(' '));
|
|
866
|
+
polygon.setAttribute('fill', interiorColor);
|
|
867
|
+
polygon.setAttribute('stroke', color);
|
|
868
|
+
polygon.setAttribute('stroke-width', String(strokeWidth));
|
|
869
|
+
polygon.setAttribute('opacity', String(opacity));
|
|
870
|
+
svg.appendChild(polygon);
|
|
871
|
+
overlay.appendChild(svg);
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Render a polyline annotation (open path).
|
|
875
|
+
*/
|
|
876
|
+
renderPolyLineAnnotation(overlay, annotation) {
|
|
877
|
+
if (!annotation.vertices || annotation.vertices.length < 2)
|
|
878
|
+
return;
|
|
879
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
880
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 0, 0)');
|
|
881
|
+
const strokeWidth = (annotation.borderWidth ?? 1) * this.zoom;
|
|
882
|
+
const opacity = annotation.opacity ?? 1;
|
|
883
|
+
const scaledPoints = annotation.vertices.map((p) => ({
|
|
884
|
+
x: p.x * POINTS_TO_CSS_PIXELS * this.zoom,
|
|
885
|
+
y: p.y * POINTS_TO_CSS_PIXELS * this.zoom,
|
|
886
|
+
}));
|
|
887
|
+
const polyline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
|
|
888
|
+
polyline.setAttribute('points', scaledPoints.map((p) => `${p.x},${p.y}`).join(' '));
|
|
889
|
+
polyline.setAttribute('fill', 'none');
|
|
890
|
+
polyline.setAttribute('stroke', color);
|
|
891
|
+
polyline.setAttribute('stroke-width', String(strokeWidth));
|
|
892
|
+
polyline.setAttribute('opacity', String(opacity));
|
|
893
|
+
svg.appendChild(polyline);
|
|
894
|
+
overlay.appendChild(svg);
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Render an ink (freehand) annotation.
|
|
898
|
+
*/
|
|
899
|
+
renderInkAnnotation(overlay, annotation) {
|
|
900
|
+
if (!annotation.inkList || annotation.inkList.length === 0)
|
|
901
|
+
return;
|
|
902
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
903
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 0, 0)');
|
|
904
|
+
const strokeWidth = (annotation.borderWidth ?? 1) * this.zoom;
|
|
905
|
+
const opacity = annotation.opacity ?? 1;
|
|
906
|
+
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
907
|
+
g.setAttribute('opacity', String(opacity));
|
|
908
|
+
for (const stroke of annotation.inkList) {
|
|
909
|
+
if (stroke.length < 2)
|
|
910
|
+
continue;
|
|
911
|
+
const pathData = stroke
|
|
912
|
+
.map((p, i) => {
|
|
913
|
+
const x = p.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
914
|
+
const y = p.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
915
|
+
return `${i === 0 ? 'M' : 'L'} ${x} ${y}`;
|
|
916
|
+
})
|
|
917
|
+
.join(' ');
|
|
918
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
919
|
+
path.setAttribute('d', pathData);
|
|
920
|
+
path.setAttribute('fill', 'none');
|
|
921
|
+
path.setAttribute('stroke', color);
|
|
922
|
+
path.setAttribute('stroke-width', String(strokeWidth));
|
|
923
|
+
path.setAttribute('stroke-linecap', 'round');
|
|
924
|
+
path.setAttribute('stroke-linejoin', 'round');
|
|
925
|
+
g.appendChild(path);
|
|
926
|
+
}
|
|
927
|
+
svg.appendChild(g);
|
|
928
|
+
overlay.appendChild(svg);
|
|
929
|
+
}
|
|
930
|
+
// =========================================================================
|
|
931
|
+
// Additional Annotation Renderers: Caret and Redact
|
|
932
|
+
// =========================================================================
|
|
933
|
+
/**
|
|
934
|
+
* Render a caret (text insertion point) annotation.
|
|
935
|
+
*/
|
|
936
|
+
renderCaretAnnotation(overlay, annotation) {
|
|
937
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
938
|
+
const color = this.colorToRgb(annotation.color, 'rgb(0, 128, 255)'); // Default blue
|
|
939
|
+
const opacity = annotation.opacity ?? 1;
|
|
940
|
+
const x = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
941
|
+
const y = annotation.bounds.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
942
|
+
const width = annotation.bounds.width * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
943
|
+
const height = annotation.bounds.height * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
944
|
+
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
945
|
+
g.setAttribute('opacity', String(opacity));
|
|
946
|
+
// Draw caret symbol (^) or paragraph marker
|
|
947
|
+
if (annotation.symbol === 'P') {
|
|
948
|
+
// Paragraph symbol (¶)
|
|
949
|
+
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
|
950
|
+
text.setAttribute('x', String(x + width / 2));
|
|
951
|
+
text.setAttribute('y', String(y + height * 0.8));
|
|
952
|
+
text.setAttribute('fill', color);
|
|
953
|
+
text.setAttribute('font-size', String(Math.min(height, 16 * this.zoom)));
|
|
954
|
+
text.setAttribute('text-anchor', 'middle');
|
|
955
|
+
text.textContent = '¶';
|
|
956
|
+
g.appendChild(text);
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
// Default caret (^) - draw as an inverted V
|
|
960
|
+
const caretHeight = Math.min(height, 12 * this.zoom);
|
|
961
|
+
const caretWidth = caretHeight * 0.8;
|
|
962
|
+
const centerX = x + width / 2;
|
|
963
|
+
const bottomY = y + height;
|
|
964
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
965
|
+
path.setAttribute('d', `M ${centerX - caretWidth / 2} ${bottomY} L ${centerX} ${bottomY - caretHeight} L ${centerX + caretWidth / 2} ${bottomY}`);
|
|
966
|
+
path.setAttribute('stroke', color);
|
|
967
|
+
path.setAttribute('stroke-width', String(2 * this.zoom));
|
|
968
|
+
path.setAttribute('fill', 'none');
|
|
969
|
+
path.setAttribute('stroke-linecap', 'round');
|
|
970
|
+
path.setAttribute('stroke-linejoin', 'round');
|
|
971
|
+
g.appendChild(path);
|
|
972
|
+
}
|
|
973
|
+
svg.appendChild(g);
|
|
974
|
+
overlay.appendChild(svg);
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Render a redact annotation (marks content for removal).
|
|
978
|
+
*/
|
|
979
|
+
renderRedactAnnotation(overlay, annotation) {
|
|
980
|
+
const svg = this.createSvgOverlay(annotation.bounds);
|
|
981
|
+
const borderColor = this.colorToRgb(annotation.color, 'rgb(255, 0, 0)'); // Default red border
|
|
982
|
+
const fillColor = this.colorToRgb(annotation.interiorColor, 'rgb(0, 0, 0)'); // Default black fill
|
|
983
|
+
const opacity = annotation.opacity ?? 1;
|
|
984
|
+
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
985
|
+
g.setAttribute('opacity', String(opacity));
|
|
986
|
+
// If we have quads, draw each quad region
|
|
987
|
+
if (annotation.quads && annotation.quads.length > 0) {
|
|
988
|
+
for (const quad of annotation.quads) {
|
|
989
|
+
const scaledPoints = this.scaleQuadPoints(quad.points);
|
|
990
|
+
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
991
|
+
polygon.setAttribute('points', scaledPoints.map((p) => `${p.x},${p.y}`).join(' '));
|
|
992
|
+
polygon.setAttribute('fill', fillColor);
|
|
993
|
+
polygon.setAttribute('fill-opacity', '0.3');
|
|
994
|
+
polygon.setAttribute('stroke', borderColor);
|
|
995
|
+
polygon.setAttribute('stroke-width', String(2 * this.zoom));
|
|
996
|
+
polygon.setAttribute('stroke-dasharray', `${4 * this.zoom} ${2 * this.zoom}`);
|
|
997
|
+
g.appendChild(polygon);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
// Draw the entire bounds as a redaction area
|
|
1002
|
+
const x = annotation.bounds.x * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
1003
|
+
const y = annotation.bounds.y * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
1004
|
+
const width = annotation.bounds.width * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
1005
|
+
const height = annotation.bounds.height * POINTS_TO_CSS_PIXELS * this.zoom;
|
|
1006
|
+
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
1007
|
+
rect.setAttribute('x', String(x));
|
|
1008
|
+
rect.setAttribute('y', String(y));
|
|
1009
|
+
rect.setAttribute('width', String(width));
|
|
1010
|
+
rect.setAttribute('height', String(height));
|
|
1011
|
+
rect.setAttribute('fill', fillColor);
|
|
1012
|
+
rect.setAttribute('fill-opacity', '0.3');
|
|
1013
|
+
rect.setAttribute('stroke', borderColor);
|
|
1014
|
+
rect.setAttribute('stroke-width', String(2 * this.zoom));
|
|
1015
|
+
rect.setAttribute('stroke-dasharray', `${4 * this.zoom} ${2 * this.zoom}`);
|
|
1016
|
+
g.appendChild(rect);
|
|
1017
|
+
// Add overlay text if present
|
|
1018
|
+
if (annotation.overlayText) {
|
|
1019
|
+
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
|
1020
|
+
text.setAttribute('x', String(x + width / 2));
|
|
1021
|
+
text.setAttribute('y', String(y + height / 2));
|
|
1022
|
+
text.setAttribute('fill', borderColor);
|
|
1023
|
+
text.setAttribute('font-size', String(Math.min(height * 0.6, 14 * this.zoom)));
|
|
1024
|
+
text.setAttribute('text-anchor', 'middle');
|
|
1025
|
+
text.setAttribute('dominant-baseline', 'middle');
|
|
1026
|
+
text.textContent = annotation.overlayText;
|
|
1027
|
+
g.appendChild(text);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
svg.appendChild(g);
|
|
1031
|
+
overlay.appendChild(svg);
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Create an SVG element sized to cover the annotation overlay.
|
|
1035
|
+
*/
|
|
1036
|
+
createSvgOverlay(_bounds) {
|
|
1037
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
1038
|
+
svg.style.cssText = `
|
|
1039
|
+
position: absolute;
|
|
1040
|
+
top: 0;
|
|
1041
|
+
left: 0;
|
|
1042
|
+
width: 100%;
|
|
1043
|
+
height: 100%;
|
|
1044
|
+
pointer-events: none;
|
|
1045
|
+
overflow: visible;
|
|
1046
|
+
`;
|
|
1047
|
+
return svg;
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Scale quad points from PDF coordinates to screen pixels.
|
|
1051
|
+
*/
|
|
1052
|
+
scaleQuadPoints(points) {
|
|
1053
|
+
return points.map((p) => ({
|
|
1054
|
+
x: p.x * POINTS_TO_CSS_PIXELS * this.zoom,
|
|
1055
|
+
y: p.y * POINTS_TO_CSS_PIXELS * this.zoom,
|
|
1056
|
+
}));
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Convert annotation color to CSS rgb() string.
|
|
1060
|
+
*/
|
|
1061
|
+
colorToRgb(color, defaultColor) {
|
|
1062
|
+
if (!color)
|
|
1063
|
+
return defaultColor;
|
|
1064
|
+
const r = Math.round(color.r * 255);
|
|
1065
|
+
const g = Math.round(color.g * 255);
|
|
1066
|
+
const b = Math.round(color.b * 255);
|
|
1067
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
1068
|
+
}
|
|
1069
|
+
handleLinkAction(action) {
|
|
1070
|
+
if (action.actionType === 'goTo') {
|
|
1071
|
+
if (this.onNavigate) {
|
|
1072
|
+
this.onNavigate(action.destination);
|
|
1073
|
+
return true;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
else if (action.actionType === 'uri') {
|
|
1077
|
+
if (this.onOpenUri) {
|
|
1078
|
+
this.onOpenUri(action.uri);
|
|
1079
|
+
return true;
|
|
1080
|
+
}
|
|
1081
|
+
else {
|
|
1082
|
+
// Default behavior: open in new tab
|
|
1083
|
+
window.open(action.uri, '_blank', 'noopener,noreferrer');
|
|
1084
|
+
return true;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
return false;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
//# sourceMappingURL=AnnotationLayer.js.map
|