@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.
Files changed (434) hide show
  1. package/README.md +180 -0
  2. package/dist/UDocClient.d.ts +197 -0
  3. package/dist/UDocClient.d.ts.map +1 -0
  4. package/dist/UDocClient.js +170 -0
  5. package/dist/UDocClient.js.map +1 -0
  6. package/dist/UDocViewer.d.ts +196 -0
  7. package/dist/UDocViewer.d.ts.map +1 -0
  8. package/dist/UDocViewer.js +427 -0
  9. package/dist/UDocViewer.js.map +1 -0
  10. package/dist/WorkerClient.d.ts +36 -0
  11. package/dist/WorkerClient.d.ts.map +1 -0
  12. package/dist/WorkerClient.js +121 -0
  13. package/dist/WorkerClient.js.map +1 -0
  14. package/dist/annotation/AnnotationLayer.d.ts +166 -0
  15. package/dist/annotation/AnnotationLayer.d.ts.map +1 -0
  16. package/dist/annotation/AnnotationLayer.js +1090 -0
  17. package/dist/annotation/AnnotationLayer.js.map +1 -0
  18. package/dist/annotation/index.d.ts +6 -0
  19. package/dist/annotation/index.d.ts.map +1 -0
  20. package/dist/annotation/index.js +6 -0
  21. package/dist/annotation/index.js.map +1 -0
  22. package/dist/components/FloatingBar.d.ts +102 -0
  23. package/dist/components/FloatingBar.d.ts.map +1 -0
  24. package/dist/components/FloatingBar.js +513 -0
  25. package/dist/components/FloatingBar.js.map +1 -0
  26. package/dist/components/Header.d.ts +46 -0
  27. package/dist/components/Header.d.ts.map +1 -0
  28. package/dist/components/Header.js +93 -0
  29. package/dist/components/Header.js.map +1 -0
  30. package/dist/components/index.d.ts +6 -0
  31. package/dist/components/index.d.ts.map +1 -0
  32. package/dist/components/index.js +4 -0
  33. package/dist/components/index.js.map +1 -0
  34. package/dist/components/panels/CommentsPanel.d.ts +33 -0
  35. package/dist/components/panels/CommentsPanel.d.ts.map +1 -0
  36. package/dist/components/panels/CommentsPanel.js +176 -0
  37. package/dist/components/panels/CommentsPanel.js.map +1 -0
  38. package/dist/components/panels/OutlinePanel.d.ts +30 -0
  39. package/dist/components/panels/OutlinePanel.d.ts.map +1 -0
  40. package/dist/components/panels/OutlinePanel.js +144 -0
  41. package/dist/components/panels/OutlinePanel.js.map +1 -0
  42. package/dist/components/panels/ThumbnailsPanel.d.ts +51 -0
  43. package/dist/components/panels/ThumbnailsPanel.d.ts.map +1 -0
  44. package/dist/components/panels/ThumbnailsPanel.js +160 -0
  45. package/dist/components/panels/ThumbnailsPanel.js.map +1 -0
  46. package/dist/components/panels/index.d.ts +7 -0
  47. package/dist/components/panels/index.d.ts.map +1 -0
  48. package/dist/components/panels/index.js +4 -0
  49. package/dist/components/panels/index.js.map +1 -0
  50. package/dist/constants.d.ts +25 -0
  51. package/dist/constants.d.ts.map +1 -0
  52. package/dist/constants.js +46 -0
  53. package/dist/constants.js.map +1 -0
  54. package/dist/core/NavigationController.d.ts +54 -0
  55. package/dist/core/NavigationController.d.ts.map +1 -0
  56. package/dist/core/NavigationController.js +145 -0
  57. package/dist/core/NavigationController.js.map +1 -0
  58. package/dist/core/PerfTimer.d.ts +12 -0
  59. package/dist/core/PerfTimer.d.ts.map +1 -0
  60. package/dist/core/PerfTimer.js +32 -0
  61. package/dist/core/PerfTimer.js.map +1 -0
  62. package/dist/core/ViewerState.d.ts +108 -0
  63. package/dist/core/ViewerState.d.ts.map +1 -0
  64. package/dist/core/ViewerState.js +179 -0
  65. package/dist/core/ViewerState.js.map +1 -0
  66. package/dist/core/constants.d.ts +24 -0
  67. package/dist/core/constants.d.ts.map +1 -0
  68. package/dist/core/constants.js +42 -0
  69. package/dist/core/constants.js.map +1 -0
  70. package/dist/core/index.d.ts +8 -0
  71. package/dist/core/index.d.ts.map +1 -0
  72. package/dist/core/index.js +11 -0
  73. package/dist/core/index.js.map +1 -0
  74. package/dist/core/types.d.ts +573 -0
  75. package/dist/core/types.d.ts.map +1 -0
  76. package/dist/core/types.js +5 -0
  77. package/dist/core/types.js.map +1 -0
  78. package/dist/icons/icons.d.ts +41 -0
  79. package/dist/icons/icons.d.ts.map +1 -0
  80. package/dist/icons/icons.js +51 -0
  81. package/dist/icons/icons.js.map +1 -0
  82. package/dist/icons/index.d.ts +3 -0
  83. package/dist/icons/index.d.ts.map +1 -0
  84. package/dist/icons/index.js +2 -0
  85. package/dist/icons/index.js.map +1 -0
  86. package/dist/index.d.ts +7 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.js +6 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/layout/BandManager.d.ts +87 -0
  91. package/dist/layout/BandManager.d.ts.map +1 -0
  92. package/dist/layout/BandManager.js +185 -0
  93. package/dist/layout/BandManager.js.map +1 -0
  94. package/dist/layout/LayoutCalculator.d.ts +42 -0
  95. package/dist/layout/LayoutCalculator.d.ts.map +1 -0
  96. package/dist/layout/LayoutCalculator.js +180 -0
  97. package/dist/layout/LayoutCalculator.js.map +1 -0
  98. package/dist/layout/LayoutState.d.ts +46 -0
  99. package/dist/layout/LayoutState.d.ts.map +1 -0
  100. package/dist/layout/LayoutState.js +109 -0
  101. package/dist/layout/LayoutState.js.map +1 -0
  102. package/dist/layout/TransitionCoordinator.d.ts +11 -0
  103. package/dist/layout/TransitionCoordinator.d.ts.map +1 -0
  104. package/dist/layout/TransitionCoordinator.js +22 -0
  105. package/dist/layout/TransitionCoordinator.js.map +1 -0
  106. package/dist/layout/index.d.ts +7 -0
  107. package/dist/layout/index.d.ts.map +1 -0
  108. package/dist/layout/index.js +4 -0
  109. package/dist/layout/index.js.map +1 -0
  110. package/dist/rendering/BandManager.d.ts +87 -0
  111. package/dist/rendering/BandManager.d.ts.map +1 -0
  112. package/dist/rendering/BandManager.js +185 -0
  113. package/dist/rendering/BandManager.js.map +1 -0
  114. package/dist/rendering/PageCache.d.ts +75 -0
  115. package/dist/rendering/PageCache.d.ts.map +1 -0
  116. package/dist/rendering/PageCache.js +122 -0
  117. package/dist/rendering/PageCache.js.map +1 -0
  118. package/dist/rendering/RenderQueue.d.ts +75 -0
  119. package/dist/rendering/RenderQueue.d.ts.map +1 -0
  120. package/dist/rendering/RenderQueue.js +105 -0
  121. package/dist/rendering/RenderQueue.js.map +1 -0
  122. package/dist/rendering/ThumbnailQueue.d.ts +57 -0
  123. package/dist/rendering/ThumbnailQueue.d.ts.map +1 -0
  124. package/dist/rendering/ThumbnailQueue.js +85 -0
  125. package/dist/rendering/ThumbnailQueue.js.map +1 -0
  126. package/dist/rendering/index.d.ts +13 -0
  127. package/dist/rendering/index.d.ts.map +1 -0
  128. package/dist/rendering/index.js +10 -0
  129. package/dist/rendering/index.js.map +1 -0
  130. package/dist/rendering/types.d.ts +72 -0
  131. package/dist/rendering/types.d.ts.map +1 -0
  132. package/dist/rendering/types.js +5 -0
  133. package/dist/rendering/types.js.map +1 -0
  134. package/dist/styles/index.d.ts +6 -0
  135. package/dist/styles/index.d.ts.map +1 -0
  136. package/dist/styles/index.js +1221 -0
  137. package/dist/styles/index.js.map +1 -0
  138. package/dist/types.d.ts +6 -0
  139. package/dist/types.d.ts.map +1 -0
  140. package/dist/types.js +6 -0
  141. package/dist/types.js.map +1 -0
  142. package/dist/ui/Component.d.ts +127 -0
  143. package/dist/ui/Component.d.ts.map +1 -0
  144. package/dist/ui/Component.js +201 -0
  145. package/dist/ui/Component.js.map +1 -0
  146. package/dist/ui/annotation/AnnotationLayer.d.ts +90 -0
  147. package/dist/ui/annotation/AnnotationLayer.d.ts.map +1 -0
  148. package/dist/ui/annotation/AnnotationLayer.js +322 -0
  149. package/dist/ui/annotation/AnnotationLayer.js.map +1 -0
  150. package/dist/ui/annotation/LinkRenderer.d.ts +32 -0
  151. package/dist/ui/annotation/LinkRenderer.d.ts.map +1 -0
  152. package/dist/ui/annotation/LinkRenderer.js +74 -0
  153. package/dist/ui/annotation/LinkRenderer.js.map +1 -0
  154. package/dist/ui/annotation/MarkupRenderer.d.ts +40 -0
  155. package/dist/ui/annotation/MarkupRenderer.d.ts.map +1 -0
  156. package/dist/ui/annotation/MarkupRenderer.js +154 -0
  157. package/dist/ui/annotation/MarkupRenderer.js.map +1 -0
  158. package/dist/ui/annotation/ShapeRenderer.d.ts +46 -0
  159. package/dist/ui/annotation/ShapeRenderer.d.ts.map +1 -0
  160. package/dist/ui/annotation/ShapeRenderer.js +376 -0
  161. package/dist/ui/annotation/ShapeRenderer.js.map +1 -0
  162. package/dist/ui/annotation/TextRenderer.d.ts +36 -0
  163. package/dist/ui/annotation/TextRenderer.d.ts.map +1 -0
  164. package/dist/ui/annotation/TextRenderer.js +199 -0
  165. package/dist/ui/annotation/TextRenderer.js.map +1 -0
  166. package/dist/ui/annotation/index.d.ts +17 -0
  167. package/dist/ui/annotation/index.d.ts.map +1 -0
  168. package/dist/ui/annotation/index.js +13 -0
  169. package/dist/ui/annotation/index.js.map +1 -0
  170. package/dist/ui/annotation/utils.d.ts +40 -0
  171. package/dist/ui/annotation/utils.d.ts.map +1 -0
  172. package/dist/ui/annotation/utils.js +62 -0
  173. package/dist/ui/annotation/utils.js.map +1 -0
  174. package/dist/ui/components/CommentsContent.d.ts +35 -0
  175. package/dist/ui/components/CommentsContent.d.ts.map +1 -0
  176. package/dist/ui/components/CommentsContent.js +203 -0
  177. package/dist/ui/components/CommentsContent.js.map +1 -0
  178. package/dist/ui/components/FloatingBar.d.ts +55 -0
  179. package/dist/ui/components/FloatingBar.d.ts.map +1 -0
  180. package/dist/ui/components/FloatingBar.js +585 -0
  181. package/dist/ui/components/FloatingBar.js.map +1 -0
  182. package/dist/ui/components/Header.d.ts +29 -0
  183. package/dist/ui/components/Header.d.ts.map +1 -0
  184. package/dist/ui/components/Header.js +127 -0
  185. package/dist/ui/components/Header.js.map +1 -0
  186. package/dist/ui/components/LeftPanel.d.ts +54 -0
  187. package/dist/ui/components/LeftPanel.d.ts.map +1 -0
  188. package/dist/ui/components/LeftPanel.js +202 -0
  189. package/dist/ui/components/LeftPanel.js.map +1 -0
  190. package/dist/ui/components/OutlineContent.d.ts +34 -0
  191. package/dist/ui/components/OutlineContent.d.ts.map +1 -0
  192. package/dist/ui/components/OutlineContent.js +147 -0
  193. package/dist/ui/components/OutlineContent.js.map +1 -0
  194. package/dist/ui/components/RightPanel.d.ts +52 -0
  195. package/dist/ui/components/RightPanel.d.ts.map +1 -0
  196. package/dist/ui/components/RightPanel.js +142 -0
  197. package/dist/ui/components/RightPanel.js.map +1 -0
  198. package/dist/ui/components/Viewport.d.ts +70 -0
  199. package/dist/ui/components/Viewport.d.ts.map +1 -0
  200. package/dist/ui/components/Viewport.js +173 -0
  201. package/dist/ui/components/Viewport.js.map +1 -0
  202. package/dist/ui/components/index.d.ts +11 -0
  203. package/dist/ui/components/index.d.ts.map +1 -0
  204. package/dist/ui/components/index.js +10 -0
  205. package/dist/ui/components/index.js.map +1 -0
  206. package/dist/ui/framework/component.d.ts +68 -0
  207. package/dist/ui/framework/component.d.ts.map +1 -0
  208. package/dist/ui/framework/component.js +87 -0
  209. package/dist/ui/framework/component.js.map +1 -0
  210. package/dist/ui/framework/dom.d.ts +19 -0
  211. package/dist/ui/framework/dom.d.ts.map +1 -0
  212. package/dist/ui/framework/dom.js +29 -0
  213. package/dist/ui/framework/dom.js.map +1 -0
  214. package/dist/ui/framework/events.d.ts +18 -0
  215. package/dist/ui/framework/events.d.ts.map +1 -0
  216. package/dist/ui/framework/events.js +23 -0
  217. package/dist/ui/framework/events.js.map +1 -0
  218. package/dist/ui/framework/index.d.ts +15 -0
  219. package/dist/ui/framework/index.d.ts.map +1 -0
  220. package/dist/ui/framework/index.js +15 -0
  221. package/dist/ui/framework/index.js.map +1 -0
  222. package/dist/ui/framework/selectors.d.ts +51 -0
  223. package/dist/ui/framework/selectors.d.ts.map +1 -0
  224. package/dist/ui/framework/selectors.js +30 -0
  225. package/dist/ui/framework/selectors.js.map +1 -0
  226. package/dist/ui/framework/store.d.ts +37 -0
  227. package/dist/ui/framework/store.d.ts.map +1 -0
  228. package/dist/ui/framework/store.js +54 -0
  229. package/dist/ui/framework/store.js.map +1 -0
  230. package/dist/ui/icons/icons.d.ts +43 -0
  231. package/dist/ui/icons/icons.d.ts.map +1 -0
  232. package/dist/ui/icons/icons.js +46 -0
  233. package/dist/ui/icons/icons.js.map +1 -0
  234. package/dist/ui/icons/index.d.ts +11 -0
  235. package/dist/ui/icons/index.d.ts.map +1 -0
  236. package/dist/ui/icons/index.js +18 -0
  237. package/dist/ui/icons/index.js.map +1 -0
  238. package/dist/ui/index.d.ts +7 -0
  239. package/dist/ui/index.d.ts.map +1 -0
  240. package/dist/ui/index.js +9 -0
  241. package/dist/ui/index.js.map +1 -0
  242. package/dist/ui/styles/base.css.d.ts +5 -0
  243. package/dist/ui/styles/base.css.d.ts.map +1 -0
  244. package/dist/ui/styles/base.css.js +49 -0
  245. package/dist/ui/styles/base.css.js.map +1 -0
  246. package/dist/ui/styles/floating-bar.css.d.ts +5 -0
  247. package/dist/ui/styles/floating-bar.css.d.ts.map +1 -0
  248. package/dist/ui/styles/floating-bar.css.js +417 -0
  249. package/dist/ui/styles/floating-bar.css.js.map +1 -0
  250. package/dist/ui/styles/header.css.d.ts +5 -0
  251. package/dist/ui/styles/header.css.d.ts.map +1 -0
  252. package/dist/ui/styles/header.css.js +49 -0
  253. package/dist/ui/styles/header.css.js.map +1 -0
  254. package/dist/ui/styles/index.d.ts +21 -0
  255. package/dist/ui/styles/index.d.ts.map +1 -0
  256. package/dist/ui/styles/index.js +48 -0
  257. package/dist/ui/styles/index.js.map +1 -0
  258. package/dist/ui/styles/panels.css.d.ts +5 -0
  259. package/dist/ui/styles/panels.css.d.ts.map +1 -0
  260. package/dist/ui/styles/panels.css.js +446 -0
  261. package/dist/ui/styles/panels.css.js.map +1 -0
  262. package/dist/ui/styles/responsive.css.d.ts +5 -0
  263. package/dist/ui/styles/responsive.css.d.ts.map +1 -0
  264. package/dist/ui/styles/responsive.css.js +201 -0
  265. package/dist/ui/styles/responsive.css.js.map +1 -0
  266. package/dist/ui/styles/variables.css.d.ts +6 -0
  267. package/dist/ui/styles/variables.css.d.ts.map +1 -0
  268. package/dist/ui/styles/variables.css.js +75 -0
  269. package/dist/ui/styles/variables.css.js.map +1 -0
  270. package/dist/ui/styles/viewport.css.d.ts +5 -0
  271. package/dist/ui/styles/viewport.css.d.ts.map +1 -0
  272. package/dist/ui/styles/viewport.css.js +87 -0
  273. package/dist/ui/styles/viewport.css.js.map +1 -0
  274. package/dist/ui/viewer/actions.d.ts +103 -0
  275. package/dist/ui/viewer/actions.d.ts.map +1 -0
  276. package/dist/ui/viewer/actions.js +2 -0
  277. package/dist/ui/viewer/actions.js.map +1 -0
  278. package/dist/ui/viewer/annotation/LinkRenderer.d.ts +9 -0
  279. package/dist/ui/viewer/annotation/LinkRenderer.d.ts.map +1 -0
  280. package/dist/ui/viewer/annotation/LinkRenderer.js +17 -0
  281. package/dist/ui/viewer/annotation/LinkRenderer.js.map +1 -0
  282. package/dist/ui/viewer/annotation/MarkupRenderer.d.ts +21 -0
  283. package/dist/ui/viewer/annotation/MarkupRenderer.d.ts.map +1 -0
  284. package/dist/ui/viewer/annotation/MarkupRenderer.js +138 -0
  285. package/dist/ui/viewer/annotation/MarkupRenderer.js.map +1 -0
  286. package/dist/ui/viewer/annotation/ShapeRenderer.d.ts +33 -0
  287. package/dist/ui/viewer/annotation/ShapeRenderer.d.ts.map +1 -0
  288. package/dist/ui/viewer/annotation/ShapeRenderer.js +378 -0
  289. package/dist/ui/viewer/annotation/ShapeRenderer.js.map +1 -0
  290. package/dist/ui/viewer/annotation/TextRenderer.d.ts +23 -0
  291. package/dist/ui/viewer/annotation/TextRenderer.d.ts.map +1 -0
  292. package/dist/ui/viewer/annotation/TextRenderer.js +196 -0
  293. package/dist/ui/viewer/annotation/TextRenderer.js.map +1 -0
  294. package/dist/ui/viewer/annotation/index.d.ts +8 -0
  295. package/dist/ui/viewer/annotation/index.d.ts.map +1 -0
  296. package/dist/ui/viewer/annotation/index.js +8 -0
  297. package/dist/ui/viewer/annotation/index.js.map +1 -0
  298. package/dist/ui/viewer/annotation/render.d.ts +24 -0
  299. package/dist/ui/viewer/annotation/render.d.ts.map +1 -0
  300. package/dist/ui/viewer/annotation/render.js +184 -0
  301. package/dist/ui/viewer/annotation/render.js.map +1 -0
  302. package/dist/ui/viewer/annotation/types.d.ts +239 -0
  303. package/dist/ui/viewer/annotation/types.d.ts.map +1 -0
  304. package/dist/ui/viewer/annotation/types.js +7 -0
  305. package/dist/ui/viewer/annotation/types.js.map +1 -0
  306. package/dist/ui/viewer/annotation/utils.d.ts +37 -0
  307. package/dist/ui/viewer/annotation/utils.d.ts.map +1 -0
  308. package/dist/ui/viewer/annotation/utils.js +82 -0
  309. package/dist/ui/viewer/annotation/utils.js.map +1 -0
  310. package/dist/ui/viewer/components/AnnotationPanel.d.ts +19 -0
  311. package/dist/ui/viewer/components/AnnotationPanel.d.ts.map +1 -0
  312. package/dist/ui/viewer/components/AnnotationPanel.js +284 -0
  313. package/dist/ui/viewer/components/AnnotationPanel.js.map +1 -0
  314. package/dist/ui/viewer/components/FloatingToolbar.d.ts +9 -0
  315. package/dist/ui/viewer/components/FloatingToolbar.d.ts.map +1 -0
  316. package/dist/ui/viewer/components/FloatingToolbar.js +305 -0
  317. package/dist/ui/viewer/components/FloatingToolbar.js.map +1 -0
  318. package/dist/ui/viewer/components/LeftPanel.d.ts +10 -0
  319. package/dist/ui/viewer/components/LeftPanel.d.ts.map +1 -0
  320. package/dist/ui/viewer/components/LeftPanel.js +165 -0
  321. package/dist/ui/viewer/components/LeftPanel.js.map +1 -0
  322. package/dist/ui/viewer/components/OutlinePanel.d.ts +10 -0
  323. package/dist/ui/viewer/components/OutlinePanel.d.ts.map +1 -0
  324. package/dist/ui/viewer/components/OutlinePanel.js +169 -0
  325. package/dist/ui/viewer/components/OutlinePanel.js.map +1 -0
  326. package/dist/ui/viewer/components/RightPanel.d.ts +9 -0
  327. package/dist/ui/viewer/components/RightPanel.d.ts.map +1 -0
  328. package/dist/ui/viewer/components/RightPanel.js +102 -0
  329. package/dist/ui/viewer/components/RightPanel.js.map +1 -0
  330. package/dist/ui/viewer/components/Spread.d.ts +41 -0
  331. package/dist/ui/viewer/components/Spread.d.ts.map +1 -0
  332. package/dist/ui/viewer/components/Spread.js +278 -0
  333. package/dist/ui/viewer/components/Spread.js.map +1 -0
  334. package/dist/ui/viewer/components/ThumbnailPanel.d.ts +11 -0
  335. package/dist/ui/viewer/components/ThumbnailPanel.d.ts.map +1 -0
  336. package/dist/ui/viewer/components/ThumbnailPanel.js +206 -0
  337. package/dist/ui/viewer/components/ThumbnailPanel.js.map +1 -0
  338. package/dist/ui/viewer/components/Toolbar.d.ts +9 -0
  339. package/dist/ui/viewer/components/Toolbar.d.ts.map +1 -0
  340. package/dist/ui/viewer/components/Toolbar.js +93 -0
  341. package/dist/ui/viewer/components/Toolbar.js.map +1 -0
  342. package/dist/ui/viewer/components/ViewModeMenu.d.ts +9 -0
  343. package/dist/ui/viewer/components/ViewModeMenu.d.ts.map +1 -0
  344. package/dist/ui/viewer/components/ViewModeMenu.js +169 -0
  345. package/dist/ui/viewer/components/ViewModeMenu.js.map +1 -0
  346. package/dist/ui/viewer/components/Viewport.d.ts +10 -0
  347. package/dist/ui/viewer/components/Viewport.d.ts.map +1 -0
  348. package/dist/ui/viewer/components/Viewport.js +793 -0
  349. package/dist/ui/viewer/components/Viewport.js.map +1 -0
  350. package/dist/ui/viewer/effects.d.ts +9 -0
  351. package/dist/ui/viewer/effects.d.ts.map +1 -0
  352. package/dist/ui/viewer/effects.js +179 -0
  353. package/dist/ui/viewer/effects.js.map +1 -0
  354. package/dist/ui/viewer/icons.d.ts +32 -0
  355. package/dist/ui/viewer/icons.d.ts.map +1 -0
  356. package/dist/ui/viewer/icons.js +44 -0
  357. package/dist/ui/viewer/icons.js.map +1 -0
  358. package/dist/ui/viewer/index.d.ts +6 -0
  359. package/dist/ui/viewer/index.d.ts.map +1 -0
  360. package/dist/ui/viewer/index.js +6 -0
  361. package/dist/ui/viewer/index.js.map +1 -0
  362. package/dist/ui/viewer/layout/index.d.ts +3 -0
  363. package/dist/ui/viewer/layout/index.d.ts.map +1 -0
  364. package/dist/ui/viewer/layout/index.js +3 -0
  365. package/dist/ui/viewer/layout/index.js.map +1 -0
  366. package/dist/ui/viewer/layout/pixelAlign.d.ts +7 -0
  367. package/dist/ui/viewer/layout/pixelAlign.d.ts.map +1 -0
  368. package/dist/ui/viewer/layout/pixelAlign.js +22 -0
  369. package/dist/ui/viewer/layout/pixelAlign.js.map +1 -0
  370. package/dist/ui/viewer/layout/spreadLayout.d.ts +93 -0
  371. package/dist/ui/viewer/layout/spreadLayout.d.ts.map +1 -0
  372. package/dist/ui/viewer/layout/spreadLayout.js +303 -0
  373. package/dist/ui/viewer/layout/spreadLayout.js.map +1 -0
  374. package/dist/ui/viewer/navigation.d.ts +80 -0
  375. package/dist/ui/viewer/navigation.d.ts.map +1 -0
  376. package/dist/ui/viewer/navigation.js +59 -0
  377. package/dist/ui/viewer/navigation.js.map +1 -0
  378. package/dist/ui/viewer/reducer.d.ts +4 -0
  379. package/dist/ui/viewer/reducer.d.ts.map +1 -0
  380. package/dist/ui/viewer/reducer.js +229 -0
  381. package/dist/ui/viewer/reducer.js.map +1 -0
  382. package/dist/ui/viewer/rendering/RenderManager.d.ts +76 -0
  383. package/dist/ui/viewer/rendering/RenderManager.d.ts.map +1 -0
  384. package/dist/ui/viewer/rendering/RenderManager.js +236 -0
  385. package/dist/ui/viewer/rendering/RenderManager.js.map +1 -0
  386. package/dist/ui/viewer/shell.d.ts +29 -0
  387. package/dist/ui/viewer/shell.d.ts.map +1 -0
  388. package/dist/ui/viewer/shell.js +70 -0
  389. package/dist/ui/viewer/shell.js.map +1 -0
  390. package/dist/ui/viewer/state.d.ts +72 -0
  391. package/dist/ui/viewer/state.d.ts.map +1 -0
  392. package/dist/ui/viewer/state.js +47 -0
  393. package/dist/ui/viewer/state.js.map +1 -0
  394. package/dist/view/LayoutCalculator.d.ts +42 -0
  395. package/dist/view/LayoutCalculator.d.ts.map +1 -0
  396. package/dist/view/LayoutCalculator.js +180 -0
  397. package/dist/view/LayoutCalculator.js.map +1 -0
  398. package/dist/view/TransitionCoordinator.d.ts +11 -0
  399. package/dist/view/TransitionCoordinator.d.ts.map +1 -0
  400. package/dist/view/TransitionCoordinator.js +22 -0
  401. package/dist/view/TransitionCoordinator.js.map +1 -0
  402. package/dist/view/ViewState.d.ts +46 -0
  403. package/dist/view/ViewState.d.ts.map +1 -0
  404. package/dist/view/ViewState.js +109 -0
  405. package/dist/view/ViewState.js.map +1 -0
  406. package/dist/view/index.d.ts +7 -0
  407. package/dist/view/index.d.ts.map +1 -0
  408. package/dist/view/index.js +4 -0
  409. package/dist/view/index.js.map +1 -0
  410. package/dist/wasm/udoc.d.ts +202 -0
  411. package/dist/wasm/udoc.js +929 -0
  412. package/dist/wasm/udoc_bg.wasm +0 -0
  413. package/dist/wasm/udoc_bg.wasm.d.ts +28 -0
  414. package/dist/worker/WorkerClient.d.ts +103 -0
  415. package/dist/worker/WorkerClient.d.ts.map +1 -0
  416. package/dist/worker/WorkerClient.js +182 -0
  417. package/dist/worker/WorkerClient.js.map +1 -0
  418. package/dist/worker/index.d.ts +4 -0
  419. package/dist/worker/index.d.ts.map +1 -0
  420. package/dist/worker/index.js +2 -0
  421. package/dist/worker/index.js.map +1 -0
  422. package/dist/worker/types.d.ts +81 -0
  423. package/dist/worker/types.d.ts.map +1 -0
  424. package/dist/worker/types.js +6 -0
  425. package/dist/worker/types.js.map +1 -0
  426. package/dist/worker/worker.d.ts +191 -0
  427. package/dist/worker/worker.d.ts.map +1 -0
  428. package/dist/worker/worker.js +127 -0
  429. package/dist/worker/worker.js.map +1 -0
  430. package/dist/worker.d.ts +2 -0
  431. package/dist/worker.d.ts.map +1 -0
  432. package/dist/worker.js +205 -0
  433. package/dist/worker.js.map +1 -0
  434. 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