velo-plot 2.0.0 → 3.0.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 (265) hide show
  1. package/README.md +15 -8
  2. package/dist/{ChartCore-BhQ4j7f5.js → ChartCore-BpzRvN4Y.js} +998 -855
  3. package/dist/ChartCore-BpzRvN4Y.js.map +1 -0
  4. package/dist/a11y-Bw6urYpr.js +105 -0
  5. package/dist/a11y-Bw6urYpr.js.map +1 -0
  6. package/dist/angular/hooks-entry.d.ts +1 -0
  7. package/dist/angular/hooks.d.ts +26 -0
  8. package/dist/angular/index.d.ts +8 -0
  9. package/dist/angular/velo-plot.component.d.ts +46 -0
  10. package/dist/angular-hooks.d.ts +1 -0
  11. package/dist/angular-hooks.js +9 -0
  12. package/dist/angular-hooks.js.map +1 -0
  13. package/dist/angular.d.ts +1 -0
  14. package/dist/angular.js +166 -0
  15. package/dist/angular.js.map +1 -0
  16. package/dist/assets/indicator.worker-bv0zC4EX.js.map +1 -1
  17. package/dist/astro/StackedPlot.astro +19 -0
  18. package/dist/astro/VeloPlot.astro +23 -0
  19. package/dist/{axisFormat-SPX-CD5s.js → axisFormat-CzumxpCL.js} +3 -3
  20. package/dist/axisFormat-CzumxpCL.js.map +1 -0
  21. package/dist/bindings/shared/a11y.d.ts +26 -0
  22. package/dist/bindings/shared/chartLifecycle.d.ts +16 -0
  23. package/dist/bindings/shared/chartSyncBridge.d.ts +8 -0
  24. package/dist/bindings/shared/dimensions.d.ts +1 -0
  25. package/dist/bindings/shared/index.d.ts +9 -0
  26. package/dist/bindings/shared/indicatorBridge.d.ts +11 -0
  27. package/dist/bindings/shared/optionsSync.d.ts +7 -0
  28. package/dist/bindings/shared/seriesDiff.d.ts +8 -0
  29. package/dist/bindings/shared/stackedSync.d.ts +9 -0
  30. package/dist/bindings/shared/types.d.ts +46 -0
  31. package/dist/bindings/test-utils/index.d.ts +35 -0
  32. package/dist/bindings/test-utils/mockLifecycle.d.ts +120 -0
  33. package/dist/bindings/test-utils/vitestSveltePlugin.d.ts +3 -0
  34. package/dist/chartSyncBridge-DbWrwtyP.js +57 -0
  35. package/dist/chartSyncBridge-DbWrwtyP.js.map +1 -0
  36. package/dist/core/Chart.d.ts +1 -1
  37. package/dist/core/InteractionManager.d.ts +7 -1
  38. package/dist/core/OverlayRenderer.d.ts +5 -0
  39. package/dist/core/annotations/types.d.ts +1 -1
  40. package/dist/core/chart/ChartAxisManager.d.ts +2 -0
  41. package/dist/core/chart/ChartCore.d.ts +17 -2
  42. package/dist/core/chart/ChartPluginBridge.d.ts +1 -0
  43. package/dist/core/chart/ChartRenderLoop.d.ts +2 -0
  44. package/dist/core/chart/ChartStateManager.d.ts +2 -0
  45. package/dist/core/chart/types.d.ts +6 -1
  46. package/dist/core/clipboard/index.d.ts +1 -1
  47. package/dist/core/debug/index.d.ts +1 -1
  48. package/dist/core/keybindings/index.d.ts +1 -1
  49. package/dist/core/loading/index.d.ts +1 -1
  50. package/dist/core/locale/index.d.ts +1 -1
  51. package/dist/core/stacked/paneResize.d.ts +3 -0
  52. package/dist/core/stacked/types.d.ts +10 -0
  53. package/dist/core/sync/index.d.ts +0 -1
  54. package/dist/core/theme-editor/index.d.ts +1 -1
  55. package/dist/createStackedChart-Dm-YqUT7.js +756 -0
  56. package/dist/createStackedChart-Dm-YqUT7.js.map +1 -0
  57. package/dist/examples/PluginDemonstration.d.ts +1 -1
  58. package/dist/gpuRenderer-BpaMYz-k.js.map +1 -1
  59. package/dist/hooks-CYPCxoZx.js +69 -0
  60. package/dist/hooks-CYPCxoZx.js.map +1 -0
  61. package/dist/{index-D7dTq6VB.js → index-0InEyj0q.js} +130 -134
  62. package/dist/index-0InEyj0q.js.map +1 -0
  63. package/dist/index-BMiZoKmm.js.map +1 -1
  64. package/dist/{index-DoYxf1cV.js → index-CWxIHdwX.js} +38 -98
  65. package/dist/index-CWxIHdwX.js.map +1 -0
  66. package/dist/{index-CUGS98p4.js → index-CaXWSOTk.js} +3 -6
  67. package/dist/index-CaXWSOTk.js.map +1 -0
  68. package/dist/index-Dag88bW4.js.map +1 -1
  69. package/dist/index-qhscKTDy.js.map +1 -1
  70. package/dist/{index-CWipqOLP.js → index-qunX30Xu.js} +2 -2
  71. package/dist/index-qunX30Xu.js.map +1 -0
  72. package/dist/index-x4stH3jD.js.map +1 -1
  73. package/dist/{index.core-fpZ1dYN0.js → index.core-BmZe2jRQ.js} +30 -29
  74. package/dist/index.core-BmZe2jRQ.js.map +1 -0
  75. package/dist/index.core.d.ts +1 -1
  76. package/dist/index.d.ts +3 -3
  77. package/dist/indicators--eJGmVox.js.map +1 -1
  78. package/dist/{mockDatafeed-Cdg5hKEo.js → mockDatafeed-DHIDPcpX.js} +150 -146
  79. package/dist/mockDatafeed-DHIDPcpX.js.map +1 -0
  80. package/dist/optionsSync-QUiN4Inw.js +119 -0
  81. package/dist/optionsSync-QUiN4Inw.js.map +1 -0
  82. package/dist/plugins/3d/index.d.ts +2 -2
  83. package/dist/plugins/3d.d.ts +2 -2
  84. package/dist/plugins/3d.js.map +1 -1
  85. package/dist/plugins/analysis/contours.d.ts +31 -0
  86. package/dist/plugins/analysis/index.d.ts +1 -1
  87. package/dist/plugins/analysis/indicators.d.ts +1 -1
  88. package/dist/plugins/analysis.d.ts +2 -2
  89. package/dist/plugins/analysis.js +495 -408
  90. package/dist/plugins/analysis.js.map +1 -1
  91. package/dist/plugins/annotations/index.d.ts +1 -1
  92. package/dist/plugins/annotations.d.ts +2 -2
  93. package/dist/plugins/annotations.js.map +1 -1
  94. package/dist/plugins/anomaly-detection.js +1 -1
  95. package/dist/plugins/anomaly-detection.js.map +1 -1
  96. package/dist/plugins/broken-axis.d.ts +2 -2
  97. package/dist/plugins/broken-axis.js +170 -181
  98. package/dist/plugins/broken-axis.js.map +1 -1
  99. package/dist/plugins/builtins/crosshair/CrosshairPlugin.d.ts +1 -1
  100. package/dist/plugins/builtins/index.d.ts +1 -1
  101. package/dist/plugins/caching.d.ts +2 -2
  102. package/dist/plugins/clipboard/index.d.ts +2 -2
  103. package/dist/plugins/clipboard.d.ts +2 -2
  104. package/dist/plugins/clipboard.js.map +1 -1
  105. package/dist/plugins/context-menu/index.d.ts +1 -1
  106. package/dist/plugins/context-menu.d.ts +2 -2
  107. package/dist/plugins/context-menu.js +1 -1
  108. package/dist/plugins/context-menu.js.map +1 -1
  109. package/dist/plugins/data-export/index.d.ts +1 -1
  110. package/dist/plugins/data-export.d.ts +2 -2
  111. package/dist/plugins/data-export.js +2 -2
  112. package/dist/plugins/data-export.js.map +1 -1
  113. package/dist/plugins/data-transform.d.ts +2 -2
  114. package/dist/plugins/data-transform.js +19 -19
  115. package/dist/plugins/data-transform.js.map +1 -1
  116. package/dist/plugins/debug/index.d.ts +2 -2
  117. package/dist/plugins/debug.d.ts +2 -2
  118. package/dist/plugins/debug.js +2 -2
  119. package/dist/plugins/debug.js.map +1 -1
  120. package/dist/plugins/forecasting/algorithms.d.ts +7 -2
  121. package/dist/plugins/forecasting/index.d.ts +1 -1
  122. package/dist/plugins/forecasting/types.d.ts +13 -3
  123. package/dist/plugins/forecasting.js +355 -175
  124. package/dist/plugins/forecasting.js.map +1 -1
  125. package/dist/plugins/gpu/index.d.ts +2 -2
  126. package/dist/plugins/gpu.d.ts +2 -2
  127. package/dist/plugins/gpu.js.map +1 -1
  128. package/dist/plugins/i18n/index.d.ts +2 -2
  129. package/dist/plugins/i18n.d.ts +2 -2
  130. package/dist/plugins/i18n.js.map +1 -1
  131. package/dist/plugins/index.d.ts +1 -1
  132. package/dist/plugins/keyboard.d.ts +2 -2
  133. package/dist/plugins/keyboard.js +65 -5
  134. package/dist/plugins/keyboard.js.map +1 -1
  135. package/dist/plugins/latex/symbols.d.ts +50 -0
  136. package/dist/plugins/latex/types.d.ts +13 -1
  137. package/dist/plugins/latex.js +351 -331
  138. package/dist/plugins/latex.js.map +1 -1
  139. package/dist/plugins/lazy-load.d.ts +2 -2
  140. package/dist/plugins/loading/index.d.ts +1 -1
  141. package/dist/plugins/loading.d.ts +2 -2
  142. package/dist/plugins/ml-integration/native-algorithms.d.ts +24 -4
  143. package/dist/plugins/ml-integration/types.d.ts +19 -0
  144. package/dist/plugins/ml-integration.d.ts +2 -2
  145. package/dist/plugins/ml-integration.js +190 -139
  146. package/dist/plugins/ml-integration.js.map +1 -1
  147. package/dist/plugins/offscreen.d.ts +2 -2
  148. package/dist/plugins/pattern-recognition/types.d.ts +28 -1
  149. package/dist/plugins/pattern-recognition.d.ts +2 -2
  150. package/dist/plugins/pattern-recognition.js +417 -344
  151. package/dist/plugins/pattern-recognition.js.map +1 -1
  152. package/dist/plugins/radar.d.ts +2 -2
  153. package/dist/plugins/regression.d.ts +2 -2
  154. package/dist/plugins/regression.js +1 -1
  155. package/dist/plugins/regression.js.map +1 -1
  156. package/dist/plugins/roi.js +9 -9
  157. package/dist/plugins/roi.js.map +1 -1
  158. package/dist/plugins/snapshot/index.d.ts +1 -1
  159. package/dist/plugins/snapshot/types.d.ts +1 -1
  160. package/dist/plugins/snapshot.d.ts +2 -2
  161. package/dist/plugins/snapshot.js +36 -36
  162. package/dist/plugins/snapshot.js.map +1 -1
  163. package/dist/plugins/streaming/index.d.ts +2 -2
  164. package/dist/plugins/streaming.d.ts +2 -2
  165. package/dist/plugins/sync/index.d.ts +3 -2
  166. package/dist/plugins/sync.d.ts +2 -2
  167. package/dist/plugins/sync.js +1 -1
  168. package/dist/plugins/sync.js.map +1 -1
  169. package/dist/plugins/theme-editor/index.d.ts +1 -1
  170. package/dist/plugins/theme-editor.d.ts +2 -2
  171. package/dist/plugins/tools/index.d.ts +1 -1
  172. package/dist/plugins/tools/tooltip/index.d.ts +1 -1
  173. package/dist/plugins/tools.d.ts +2 -2
  174. package/dist/plugins/tools.js +1 -1
  175. package/dist/plugins/types.d.ts +1 -1
  176. package/dist/plugins/video-recorder.d.ts +2 -2
  177. package/dist/plugins/virtualization.d.ts +2 -2
  178. package/dist/plugins/virtualization.js +1 -1
  179. package/dist/pool-DZ8shSqv.js +109 -0
  180. package/dist/pool-DZ8shSqv.js.map +1 -0
  181. package/dist/react/StackedPlot.d.ts +31 -0
  182. package/dist/react/VeloPlot.d.ts +29 -0
  183. package/dist/react/index.d.ts +25 -3
  184. package/dist/react/useChartSync.d.ts +8 -0
  185. package/dist/react/useIndicator.d.ts +12 -0
  186. package/dist/react/useVeloPlot.d.ts +19 -0
  187. package/dist/react.js +328 -24
  188. package/dist/react.js.map +1 -1
  189. package/dist/scientific/index.d.ts +48 -0
  190. package/dist/scientific.d.ts +1 -0
  191. package/dist/scientific.js +91 -0
  192. package/dist/scientific.js.map +1 -0
  193. package/dist/solid/VeloPlot.d.ts +16 -0
  194. package/dist/solid/index.d.ts +13 -0
  195. package/dist/solid/useChartSync.d.ts +6 -0
  196. package/dist/solid/useIndicator.d.ts +11 -0
  197. package/dist/solid/useStackedPlot.d.ts +14 -0
  198. package/dist/solid/useVeloPlot.d.ts +18 -0
  199. package/dist/solid.d.ts +1 -0
  200. package/dist/solid.js +172 -0
  201. package/dist/solid.js.map +1 -0
  202. package/dist/stackedSync-tnrunZMt.js +100 -0
  203. package/dist/stackedSync-tnrunZMt.js.map +1 -0
  204. package/dist/svelte/StackedPlot.svelte +29 -0
  205. package/dist/svelte/StackedPlot.test.ts +114 -0
  206. package/dist/svelte/VeloPlot.svelte +44 -0
  207. package/dist/svelte/VeloPlot.test.ts +105 -0
  208. package/dist/svelte/index.d.ts +11 -0
  209. package/dist/svelte/index.test.ts +20 -0
  210. package/dist/svelte/index.ts +15 -0
  211. package/dist/svelte/useChartSync.d.ts +8 -0
  212. package/dist/svelte/useChartSync.test.ts +49 -0
  213. package/dist/svelte/useChartSync.ts +29 -0
  214. package/dist/svelte/useIndicator.d.ts +13 -0
  215. package/dist/svelte/useIndicator.test.ts +67 -0
  216. package/dist/svelte/useIndicator.ts +43 -0
  217. package/dist/svelte/useStackedPlot.d.ts +16 -0
  218. package/dist/svelte/useStackedPlot.test.ts +76 -0
  219. package/dist/svelte/useStackedPlot.ts +54 -0
  220. package/dist/svelte/useVeloPlot.d.ts +21 -0
  221. package/dist/svelte/useVeloPlot.test.ts +100 -0
  222. package/dist/svelte/useVeloPlot.ts +81 -0
  223. package/dist/svelte.d.ts +1 -0
  224. package/dist/svelte.js +143 -0
  225. package/dist/svelte.js.map +1 -0
  226. package/dist/symbols-DT0eLlpW.js +568 -0
  227. package/dist/symbols-DT0eLlpW.js.map +1 -0
  228. package/dist/testing/index.d.ts +1 -1
  229. package/dist/theme/index.d.ts +2 -1
  230. package/dist/trading.js +7 -7
  231. package/dist/types.d.ts +1 -1
  232. package/dist/{utils-BK5UUXxj.js → utils-Dx0h0bgQ.js} +9 -9
  233. package/dist/{utils-BK5UUXxj.js.map → utils-Dx0h0bgQ.js.map} +1 -1
  234. package/dist/velo-plot.full.js +444 -433
  235. package/dist/velo-plot.full.js.map +1 -1
  236. package/dist/velo-plot.js +15 -15
  237. package/dist/vue/StackedPlot.vue.d.ts +48 -0
  238. package/dist/vue/VeloPlot.vue.d.ts +64 -0
  239. package/dist/vue/index.d.ts +250 -0
  240. package/dist/vue/useChartSync.d.ts +52 -0
  241. package/dist/vue/useIndicator.d.ts +23 -0
  242. package/dist/vue/useStackedPlot.d.ts +15 -0
  243. package/dist/vue/useVeloPlot.d.ts +20 -0
  244. package/dist/vue.d.ts +1 -0
  245. package/dist/vue.js +312 -0
  246. package/dist/vue.js.map +1 -0
  247. package/dist/workers/indicatorsAsync.d.ts +26 -0
  248. package/dist/workers/pool.d.ts +9 -0
  249. package/package.json +88 -10
  250. package/dist/ChartCore-BhQ4j7f5.js.map +0 -1
  251. package/dist/SciPlot-GJvw7GJo.js +0 -463
  252. package/dist/SciPlot-GJvw7GJo.js.map +0 -1
  253. package/dist/axisFormat-SPX-CD5s.js.map +0 -1
  254. package/dist/createStackedChart-DJSmqerD.js +0 -706
  255. package/dist/createStackedChart-DJSmqerD.js.map +0 -1
  256. package/dist/index-CUGS98p4.js.map +0 -1
  257. package/dist/index-CWipqOLP.js.map +0 -1
  258. package/dist/index-D7dTq6VB.js.map +0 -1
  259. package/dist/index-DoYxf1cV.js.map +0 -1
  260. package/dist/index.core-fpZ1dYN0.js.map +0 -1
  261. package/dist/mockDatafeed-Cdg5hKEo.js.map +0 -1
  262. package/dist/pool-15HMCNv8.js +0 -88
  263. package/dist/pool-15HMCNv8.js.map +0 -1
  264. package/dist/react/SciPlot.d.ts +0 -60
  265. package/dist/react/useSciPlot.d.ts +0 -56
@@ -1 +1 @@
1
- {"version":3,"file":"annotations.js","sources":["../../src/core/annotations/AnnotationManager.ts","../../src/plugins/annotations/index.ts"],"sourcesContent":["/**\n * AnnotationManager - Manages chart annotations\n * \n * Handles creation, update, removal, and rendering of all annotation types.\n */\n\nimport type { Bounds } from '../../types';\nimport type {\n Annotation,\n HorizontalLineAnnotation,\n VerticalLineAnnotation,\n RectangleAnnotation,\n BandAnnotation,\n TextAnnotation,\n ArrowAnnotation,\n} from './types';\n\n// ============================================\n// Default Styles\n// ============================================\n\nconst DEFAULT_STYLES = {\n line: {\n color: 'rgba(255, 255, 255, 0.7)',\n lineWidth: 1,\n lineDash: [] as number[],\n },\n rectangle: {\n fillColor: 'rgba(100, 100, 255, 0.2)',\n strokeColor: 'rgba(100, 100, 255, 0.5)',\n strokeWidth: 1,\n },\n text: {\n fontSize: 12,\n fontFamily: 'Inter, system-ui, sans-serif',\n color: '#ffffff',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n padding: 4,\n },\n arrow: {\n color: 'rgba(255, 255, 255, 0.7)',\n lineWidth: 2,\n headSize: 10,\n },\n};\n\n// ============================================\n// Plot Area Type\n// ============================================\n\nexport interface PlotArea {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n// ============================================\n// AnnotationManager Class\n// ============================================\n\nexport class AnnotationManager {\n private annotations: Map<string, Annotation> = new Map();\n private idCounter = 0;\n\n // ----------------------------------------\n // CRUD Operations\n // ----------------------------------------\n\n /**\n * Add a new annotation\n * @returns The annotation ID\n */\n add(annotation: Annotation): string {\n const id = annotation.id ?? `annotation-${++this.idCounter}`;\n const resolved: Annotation = {\n ...annotation,\n id,\n visible: annotation.visible ?? true,\n interactive: annotation.interactive ?? false,\n zIndex: annotation.zIndex ?? 0,\n };\n\n this.annotations.set(id, resolved);\n return id;\n }\n\n /**\n * Remove an annotation by ID\n */\n remove(id: string): boolean {\n return this.annotations.delete(id);\n }\n\n /**\n * Update an annotation\n */\n update(id: string, updates: Partial<Annotation>): void {\n const existing = this.annotations.get(id);\n if (existing) {\n this.annotations.set(id, { ...existing, ...updates } as Annotation);\n }\n }\n\n /**\n * Get an annotation by ID\n */\n get(id: string): Annotation | undefined {\n return this.annotations.get(id);\n }\n\n /**\n * Get all annotations\n */\n getAll(): Annotation[] {\n return Array.from(this.annotations.values());\n }\n\n /**\n * Clear all annotations\n */\n clear(): void {\n this.annotations.clear();\n }\n\n /**\n * Get count of annotations\n */\n get count(): number {\n return this.annotations.size;\n }\n\n // ----------------------------------------\n // Rendering\n // ----------------------------------------\n\n /**\n * Render all annotations\n */\n render(\n ctx: CanvasRenderingContext2D,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n // Sort by zIndex\n const sorted = this.getAll()\n .filter(a => a.visible !== false)\n .sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));\n\n ctx.save();\n\n // Clip to plot area\n ctx.beginPath();\n ctx.rect(plotArea.x, plotArea.y, plotArea.width, plotArea.height);\n ctx.clip();\n\n for (const annotation of sorted) {\n this.renderAnnotation(ctx, annotation, plotArea, bounds, latexAPI);\n }\n\n ctx.restore();\n }\n\n /**\n * Helper to draw text or LaTeX\n */\n private drawLatexOrText(\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n options: {\n fontSize: number;\n fontFamily: string;\n fontWeight?: string | number;\n color: string;\n align?: CanvasTextAlign;\n baseline?: CanvasTextBaseline;\n rotation?: number;\n latex?: boolean;\n },\n latexAPI?: any\n ): void {\n const isLatex = (options.latex || text.includes('\\\\') || text.includes('^') || text.includes('_') || (text.includes('{') && text.includes('}'))) &&\n !!latexAPI && (typeof latexAPI.render === 'function');\n\n if (isLatex) {\n ctx.save();\n ctx.translate(x, y);\n if (options.rotation) ctx.rotate((options.rotation * Math.PI) / 180);\n\n const dims = latexAPI.measure(text, {\n fontSize: options.fontSize,\n fontFamily: options.fontFamily,\n color: options.color\n });\n\n let lx = 0;\n let ly = 0;\n\n // Handle Horizontal Alignment\n const align = options.align ?? \"left\";\n if (align === \"center\") lx = -dims.width / 2;\n else if (align === \"right\") lx = -dims.width;\n\n // Handle Vertical Alignment based on alphabetic baseline of the plugin\n // The plugin draws with textBaseline = 'alphabetic' at the provided y\n const baseline = options.baseline ?? \"alphabetic\";\n if (baseline === \"middle\") {\n ly = -dims.height / 2 + dims.baseline;\n } else if (baseline === \"top\" || baseline === \"hanging\") {\n ly = dims.baseline;\n } else if (baseline === \"bottom\" || baseline === \"ideographic\") {\n ly = -(dims.height - dims.baseline);\n } else {\n // 'alphabetic' or default\n ly = 0;\n }\n\n latexAPI.render(text, ctx, lx, ly, {\n fontSize: options.fontSize,\n fontFamily: options.fontFamily,\n color: options.color\n });\n ctx.restore();\n } else {\n ctx.save();\n ctx.font = `${options.fontWeight ?? ''} ${options.fontSize}px ${options.fontFamily}`;\n ctx.fillStyle = options.color;\n ctx.textAlign = options.align ?? \"left\";\n ctx.textBaseline = options.baseline ?? \"alphabetic\";\n ctx.translate(x, y);\n if (options.rotation) ctx.rotate((options.rotation * Math.PI) / 180);\n ctx.fillText(text, 0, 0);\n ctx.restore();\n }\n }\n\n private renderAnnotation(\n ctx: CanvasRenderingContext2D,\n annotation: Annotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n switch (annotation.type) {\n case 'horizontal-line':\n this.renderHorizontalLine(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'vertical-line':\n this.renderVerticalLine(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'rectangle':\n this.renderRectangle(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'band':\n this.renderBand(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'text':\n this.renderText(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'arrow':\n this.renderArrow(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n }\n }\n\n // ----------------------------------------\n // Coordinate Conversion\n // ----------------------------------------\n\n private dataToPixelX(value: number, bounds: Bounds, plotArea: PlotArea): number {\n const normalized = (value - bounds.xMin) / (bounds.xMax - bounds.xMin);\n return plotArea.x + normalized * plotArea.width;\n }\n\n private dataToPixelY(value: number, bounds: Bounds, plotArea: PlotArea): number {\n const normalized = (value - bounds.yMin) / (bounds.yMax - bounds.yMin);\n return plotArea.y + plotArea.height * (1 - normalized);\n }\n\n // ----------------------------------------\n // Render: Horizontal Line\n // ----------------------------------------\n\n private renderHorizontalLine(\n ctx: CanvasRenderingContext2D,\n annotation: HorizontalLineAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const y = this.dataToPixelY(annotation.y, bounds, plotArea);\n\n // Skip if outside visible area\n if (y < plotArea.y || y > plotArea.y + plotArea.height) return;\n\n const xStart = annotation.xMin !== undefined\n ? Math.max(this.dataToPixelX(annotation.xMin, bounds, plotArea), plotArea.x)\n : plotArea.x;\n const xEnd = annotation.xMax !== undefined\n ? Math.min(this.dataToPixelX(annotation.xMax, bounds, plotArea), plotArea.x + plotArea.width)\n : plotArea.x + plotArea.width;\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.line.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.line.lineWidth;\n ctx.setLineDash(annotation.lineDash ?? DEFAULT_STYLES.line.lineDash);\n\n ctx.beginPath();\n ctx.moveTo(xStart, y);\n ctx.lineTo(xEnd, y);\n ctx.stroke();\n\n // Render label if present\n if (annotation.label) {\n this.renderLineLabel(\n ctx,\n annotation.label,\n xStart, xEnd, y,\n annotation.labelPosition ?? 'right',\n 'horizontal',\n annotation.labelBackground,\n latexAPI\n );\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Vertical Line\n // ----------------------------------------\n\n private renderVerticalLine(\n ctx: CanvasRenderingContext2D,\n annotation: VerticalLineAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x = this.dataToPixelX(annotation.x, bounds, plotArea);\n\n // Skip if outside visible area\n if (x < plotArea.x || x > plotArea.x + plotArea.width) return;\n\n const yStart = annotation.yMin !== undefined\n ? Math.min(this.dataToPixelY(annotation.yMin, bounds, plotArea), plotArea.y + plotArea.height)\n : plotArea.y;\n const yEnd = annotation.yMax !== undefined\n ? Math.max(this.dataToPixelY(annotation.yMax, bounds, plotArea), plotArea.y)\n : plotArea.y + plotArea.height;\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.line.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.line.lineWidth;\n ctx.setLineDash(annotation.lineDash ?? DEFAULT_STYLES.line.lineDash);\n\n ctx.beginPath();\n ctx.moveTo(x, yStart);\n ctx.lineTo(x, yEnd);\n ctx.stroke();\n\n // Render label if present\n if (annotation.label) {\n this.renderLineLabel(\n ctx,\n annotation.label,\n yStart, yEnd, x,\n annotation.labelPosition ?? 'top',\n 'vertical',\n annotation.labelBackground,\n latexAPI\n );\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Rectangle\n // ----------------------------------------\n\n private renderRectangle(\n ctx: CanvasRenderingContext2D,\n annotation: RectangleAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x1 = this.dataToPixelX(annotation.xMin, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.xMax, bounds, plotArea);\n const y1 = this.dataToPixelY(annotation.yMax, bounds, plotArea); // Note: Y is inverted\n const y2 = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n\n const x = Math.min(x1, x2);\n const y = Math.min(y1, y2);\n const width = Math.abs(x2 - x1);\n const height = Math.abs(y2 - y1);\n\n ctx.save();\n\n // Fill\n if (annotation.fillColor) {\n ctx.fillStyle = annotation.fillColor;\n ctx.fillRect(x, y, width, height);\n }\n\n // Stroke\n if (annotation.strokeColor) {\n ctx.strokeStyle = annotation.strokeColor;\n ctx.lineWidth = annotation.strokeWidth ?? DEFAULT_STYLES.rectangle.strokeWidth;\n ctx.setLineDash(annotation.strokeDash ?? []);\n ctx.strokeRect(x, y, width, height);\n }\n\n // Label\n if (annotation.label) {\n this.renderCenteredLabel(ctx, annotation.label, x + width / 2, y + height / 2, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Band\n // ----------------------------------------\n\n private renderBand(\n ctx: CanvasRenderingContext2D,\n annotation: BandAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n // Determine band type and calculate bounds\n let x: number, y: number, width: number, height: number;\n\n if (annotation.xMin !== undefined && annotation.xMax !== undefined) {\n // Vertical band (spans full Y)\n const x1 = this.dataToPixelX(annotation.xMin, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.xMax, bounds, plotArea);\n x = Math.min(x1, x2);\n width = Math.abs(x2 - x1);\n y = plotArea.y;\n height = plotArea.height;\n\n if (annotation.yMin !== undefined) {\n const yPixel = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n height = yPixel - y;\n }\n if (annotation.yMax !== undefined) {\n const yPixel = this.dataToPixelY(annotation.yMax, bounds, plotArea);\n y = yPixel;\n height = plotArea.y + plotArea.height - y;\n }\n } else if (annotation.yMin !== undefined && annotation.yMax !== undefined) {\n // Horizontal band (spans full X)\n const y1 = this.dataToPixelY(annotation.yMax, bounds, plotArea);\n const y2 = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n y = Math.min(y1, y2);\n height = Math.abs(y2 - y1);\n x = plotArea.x;\n width = plotArea.width;\n } else {\n // Invalid band configuration\n return;\n }\n\n ctx.save();\n\n // Fill\n ctx.fillStyle = annotation.fillColor ?? DEFAULT_STYLES.rectangle.fillColor;\n ctx.fillRect(x, y, width, height);\n\n // Stroke\n if (annotation.strokeColor) {\n ctx.strokeStyle = annotation.strokeColor;\n ctx.lineWidth = annotation.strokeWidth ?? 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n // Label\n if (annotation.label) {\n let labelX = x + width / 2;\n let labelY = y + height / 2;\n\n switch (annotation.labelPosition) {\n case 'top':\n labelY = y + 15;\n break;\n case 'bottom':\n labelY = y + height - 5;\n break;\n case 'left':\n labelX = x + 10;\n break;\n case 'right':\n labelX = x + width - 10;\n break;\n }\n\n this.renderCenteredLabel(ctx, annotation.label, labelX, labelY, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Text\n // ----------------------------------------\n\n private renderText(\n ctx: CanvasRenderingContext2D,\n annotation: TextAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x = this.dataToPixelX(annotation.x, bounds, plotArea);\n const y = this.dataToPixelY(annotation.y, bounds, plotArea);\n\n ctx.save();\n\n // Apply rotation if specified\n if (annotation.rotation) {\n ctx.translate(x, y);\n ctx.rotate((annotation.rotation * Math.PI) / 180);\n ctx.translate(-x, -y);\n }\n\n const fontSize = annotation.fontSize ?? DEFAULT_STYLES.text.fontSize;\n const fontFamily = annotation.fontFamily ?? DEFAULT_STYLES.text.fontFamily;\n const fontWeight = annotation.fontWeight ?? 'normal';\n const lineHeight = fontSize * 1.2;\n\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Support multi-line text\n const lines = annotation.text.split('\\n');\n const padding = annotation.padding ?? DEFAULT_STYLES.text.padding;\n\n // Measure all lines to find max width\n let maxWidth = 0;\n for (const line of lines) {\n maxWidth = Math.max(maxWidth, ctx.measureText(line).width);\n }\n\n const textWidth = maxWidth + padding * 2;\n const textHeight = (lines.length * lineHeight) - (lineHeight - fontSize) + padding * 2;\n\n // Calculate position based on anchor\n let drawX = x;\n let drawY = y;\n\n switch (annotation.anchor) {\n case 'top-left':\n drawX += textWidth / 2;\n drawY += textHeight / 2;\n break;\n case 'top-right':\n drawX -= textWidth / 2;\n drawY += textHeight / 2;\n break;\n case 'bottom-left':\n drawX += textWidth / 2;\n drawY -= textHeight / 2;\n break;\n case 'bottom-right':\n drawX -= textWidth / 2;\n drawY -= textHeight / 2;\n break;\n case 'top-center':\n drawY += textHeight / 2;\n break;\n case 'bottom-center':\n drawY -= textHeight / 2;\n break;\n case 'left-center':\n drawX += textWidth / 2;\n break;\n case 'right-center':\n drawX -= textWidth / 2;\n break;\n }\n\n // Draw background\n if (annotation.backgroundColor) {\n ctx.fillStyle = annotation.backgroundColor;\n ctx.beginPath();\n ctx.roundRect(\n drawX - textWidth / 2,\n drawY - textHeight / 2,\n textWidth,\n textHeight,\n 4\n );\n ctx.fill();\n }\n\n // Draw text lines\n const color = annotation.color ?? DEFAULT_STYLES.text.color;\n const startY = drawY - (textHeight / 2) + padding + (fontSize / 2);\n\n lines.forEach((line, i) => {\n this.drawLatexOrText(ctx, line, drawX, startY + i * lineHeight, {\n fontSize,\n fontFamily,\n fontWeight,\n color,\n align: 'center',\n baseline: 'middle',\n latex: annotation.latex\n }, latexAPI);\n });\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Arrow\n // ----------------------------------------\n\n private renderArrow(\n ctx: CanvasRenderingContext2D,\n annotation: ArrowAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x1 = this.dataToPixelX(annotation.x1, bounds, plotArea);\n const y1 = this.dataToPixelY(annotation.y1, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.x2, bounds, plotArea);\n const y2 = this.dataToPixelY(annotation.y2, bounds, plotArea);\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.arrow.color;\n ctx.fillStyle = annotation.color ?? DEFAULT_STYLES.arrow.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.arrow.lineWidth;\n\n // Draw line\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(x2, y2);\n ctx.stroke();\n\n // Draw arrow head\n const headSize = annotation.headSize ?? DEFAULT_STYLES.arrow.headSize;\n const angle = Math.atan2(y2 - y1, x2 - x1);\n\n const headStyle = annotation.headStyle ?? 'filled';\n\n if (headStyle !== 'none') {\n ctx.beginPath();\n ctx.moveTo(x2, y2);\n ctx.lineTo(\n x2 - headSize * Math.cos(angle - Math.PI / 6),\n y2 - headSize * Math.sin(angle - Math.PI / 6)\n );\n\n if (headStyle === 'filled') {\n ctx.lineTo(\n x2 - headSize * Math.cos(angle + Math.PI / 6),\n y2 - headSize * Math.sin(angle + Math.PI / 6)\n );\n ctx.closePath();\n ctx.fill();\n } else {\n ctx.moveTo(x2, y2);\n ctx.lineTo(\n x2 - headSize * Math.cos(angle + Math.PI / 6),\n y2 - headSize * Math.sin(angle + Math.PI / 6)\n );\n ctx.stroke();\n }\n }\n\n // Draw tail arrow if specified\n if (annotation.showTail) {\n const tailAngle = angle + Math.PI;\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(\n x1 - headSize * Math.cos(tailAngle - Math.PI / 6),\n y1 - headSize * Math.sin(tailAngle - Math.PI / 6)\n );\n ctx.lineTo(\n x1 - headSize * Math.cos(tailAngle + Math.PI / 6),\n y1 - headSize * Math.sin(tailAngle + Math.PI / 6)\n );\n ctx.closePath();\n ctx.fill();\n }\n\n // Draw label if present\n if (annotation.label) {\n const midX = (x1 + x2) / 2;\n const midY = (y1 + y2) / 2;\n this.renderCenteredLabel(ctx, annotation.label, midX, midY - 10, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Helper: Render Labels\n // ----------------------------------------\n\n private renderLineLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n start: number,\n end: number,\n cross: number,\n position: string,\n orientation: 'horizontal' | 'vertical',\n backgroundColor?: string,\n latexAPI?: any\n ): void {\n ctx.save();\n\n ctx.font = `${DEFAULT_STYLES.text.fontSize}px ${DEFAULT_STYLES.text.fontFamily}`;\n const metrics = ctx.measureText(label);\n const padding = 4;\n const textWidth = metrics.width + padding * 2;\n const textHeight = DEFAULT_STYLES.text.fontSize + padding * 2;\n\n let x: number, y: number;\n\n if (orientation === 'horizontal') {\n y = cross;\n\n switch (position) {\n case 'left':\n x = start + 5;\n ctx.textAlign = 'left';\n break;\n case 'right':\n x = end - 5;\n ctx.textAlign = 'right';\n break;\n default:\n x = (start + end) / 2;\n ctx.textAlign = 'center';\n }\n\n ctx.textBaseline = 'bottom';\n y -= 4;\n } else {\n x = cross;\n\n switch (position) {\n case 'top':\n y = start + textHeight;\n break;\n case 'bottom':\n y = end - 5;\n break;\n default:\n y = (start + end) / 2;\n }\n\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n }\n\n // Background\n if (backgroundColor ?? true) {\n ctx.fillStyle = backgroundColor ?? 'rgba(0, 0, 0, 0.7)';\n const bgX = ctx.textAlign === 'left' ? x - padding\n : ctx.textAlign === 'right' ? x - textWidth + padding\n : x - textWidth / 2;\n ctx.fillRect(bgX, y - textHeight + padding, textWidth, textHeight);\n }\n\n // Text\n this.drawLatexOrText(ctx, label, x, y, {\n fontSize: DEFAULT_STYLES.text.fontSize,\n fontFamily: DEFAULT_STYLES.text.fontFamily,\n color: DEFAULT_STYLES.text.color,\n align: ctx.textAlign,\n baseline: ctx.textBaseline,\n }, latexAPI);\n\n ctx.restore();\n }\n\n private renderCenteredLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n x: number,\n y: number,\n latexAPI?: any\n ): void {\n ctx.save();\n\n ctx.font = `${DEFAULT_STYLES.text.fontSize}px ${DEFAULT_STYLES.text.fontFamily}`;\n const metrics = ctx.measureText(label);\n const padding = 4;\n const textWidth = metrics.width + padding * 2;\n const textHeight = DEFAULT_STYLES.text.fontSize + padding * 2;\n\n // Background\n ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';\n ctx.beginPath();\n ctx.roundRect(x - textWidth / 2, y - textHeight / 2, textWidth, textHeight, 3);\n ctx.fill();\n\n // Text\n this.drawLatexOrText(ctx, label, x, y, {\n fontSize: DEFAULT_STYLES.text.fontSize,\n fontFamily: DEFAULT_STYLES.text.fontFamily,\n color: DEFAULT_STYLES.text.color,\n align: 'center',\n baseline: 'middle',\n }, latexAPI);\n\n ctx.restore();\n }\n}\n","/**\n * Sci Plot - Annotations Plugin\n * \n * Provides annotation capabilities including:\n * - Line, Rectangle, Band, Text, Arrow annotations\n * - Annotation management and rendering\n * \n * @module plugins/annotations\n */\n\nimport { AnnotationManager } from \"../../core/annotations\";\nimport type { Annotation, AnnotationType } from \"../../core/annotations\";\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginAnnotationsConfig {\n /** Default styles for annotations */\n defaultStyles?: Record<string, any>;\n}\n\nconst manifestAnnotations: PluginManifest = {\n name: \"velo-plot-annotations\",\n version: \"1.0.0\",\n description: \"Annotation support for velo-plot\",\n provides: [\"annotation\"],\n tags: [\"annotation\", \"overlay\", \"label\"],\n};\n\n/**\n * SciPlot Annotations Plugin\n * \n * Adds support for drawing lines, shapes, and labels on the chart.\n */\nexport function PluginAnnotations(_config: PluginAnnotationsConfig = {}): ChartPlugin<PluginAnnotationsConfig> {\n let annotationManager: AnnotationManager;\n\n return {\n manifest: manifestAnnotations,\n\n onInit(ctx: PluginContext) {\n annotationManager = new AnnotationManager();\n\n // In a real implementation, we would register this manager in the context\n // so the chart can delegate annotation calls to it.\n // For now, we store it in storage for retrieval.\n ctx.storage.set(\"manager\", annotationManager);\n },\n\n onRenderOverlay(ctx) {\n const plotArea = ctx.render.plotArea;\n const viewBounds = ctx.data.getViewBounds();\n\n // Get LaTeX API if plugin is available\n const latexPlugin = ctx.getPlugin<any>(\"velo-plot-latex\");\n const latexAPI = latexPlugin?.api;\n\n // Render all annotations using the manager and provided contexts\n annotationManager.render(\n ctx.render.ctx2d!,\n plotArea,\n viewBounds,\n latexAPI\n );\n },\n\n onDestroy(_ctx: PluginContext) {\n annotationManager.clear();\n },\n\n api: {\n getManager() {\n return annotationManager;\n },\n add(annotation: Annotation) {\n return annotationManager.add(annotation);\n },\n remove(id: string) {\n return annotationManager.remove(id);\n },\n update(id: string, updates: Partial<Annotation>) {\n return annotationManager.update(id, updates);\n },\n get(id: string) {\n return annotationManager.get(id);\n },\n getAll() {\n return annotationManager.getAll();\n },\n clear() {\n annotationManager.clear();\n }\n }\n };\n}\n\nexport { AnnotationManager };\nexport type { Annotation, AnnotationType };\nexport default PluginAnnotations;\n"],"names":["DEFAULT_STYLES","AnnotationManager","__publicField","annotation","id","resolved","updates","existing","ctx","plotArea","bounds","latexAPI","sorted","a","b","text","x","y","options","dims","lx","ly","align","baseline","value","normalized","xStart","xEnd","yStart","yEnd","x1","x2","y1","y2","width","height","labelX","labelY","fontSize","fontFamily","fontWeight","lineHeight","lines","padding","maxWidth","line","textWidth","textHeight","drawX","drawY","color","startY","i","headSize","angle","headStyle","tailAngle","midX","midY","label","start","end","cross","position","orientation","backgroundColor","metrics","bgX","manifestAnnotations","PluginAnnotations","_config","annotationManager","viewBounds","latexPlugin","_ctx"],"mappings":";;;AAqBA,MAAMA,IAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,WAAW;AAAA,IACX,UAAU,CAAA;AAAA,EAAC;AAAA,EAEb,WAAW;AAAA,IACT,WAAW;AAAA,IAEX,aAAa;AAAA,EAAA;AAAA,EAEf,MAAM;AAAA,IACJ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,OAAO;AAAA,IAEP,SAAS;AAAA,EAAA;AAAA,EAEX,OAAO;AAAA,IACL,OAAO;AAAA,IACP,WAAW;AAAA,IACX,UAAU;AAAA,EAAA;AAEd;AAiBO,MAAMC,EAAkB;AAAA,EAAxB;AACG,IAAAC,EAAA,yCAA2C,IAAA;AAC3C,IAAAA,EAAA,mBAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUpB,IAAIC,GAAgC;AAClC,UAAMC,IAAKD,EAAW,MAAM,cAAc,EAAE,KAAK,SAAS,IACpDE,IAAuB;AAAA,MAC3B,GAAGF;AAAA,MACH,IAAAC;AAAA,MACA,SAASD,EAAW,WAAW;AAAA,MAC/B,aAAaA,EAAW,eAAe;AAAA,MACvC,QAAQA,EAAW,UAAU;AAAA,IAAA;AAG/B,gBAAK,YAAY,IAAIC,GAAIC,CAAQ,GAC1BD;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAOA,GAAqB;AAC1B,WAAO,KAAK,YAAY,OAAOA,CAAE;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAOA,GAAYE,GAAoC;AACrD,UAAMC,IAAW,KAAK,YAAY,IAAIH,CAAE;AACxC,IAAIG,KACF,KAAK,YAAY,IAAIH,GAAI,EAAE,GAAGG,GAAU,GAAGD,GAAuB;AAAA,EAEtE;AAAA;AAAA;AAAA;AAAA,EAKA,IAAIF,GAAoC;AACtC,WAAO,KAAK,YAAY,IAAIA,CAAE;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAuB;AACrB,WAAO,MAAM,KAAK,KAAK,YAAY,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,YAAY,MAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,QAAgB;AAClB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OACEI,GACAC,GACAC,GACAC,GACM;AAEN,UAAMC,IAAS,KAAK,SACjB,OAAO,CAAAC,MAAKA,EAAE,YAAY,EAAK,EAC/B,KAAK,CAACA,GAAGC,OAAOD,EAAE,UAAU,MAAMC,EAAE,UAAU,EAAE;AAEnD,IAAAN,EAAI,KAAA,GAGJA,EAAI,UAAA,GACJA,EAAI,KAAKC,EAAS,GAAGA,EAAS,GAAGA,EAAS,OAAOA,EAAS,MAAM,GAChED,EAAI,KAAA;AAEJ,eAAWL,KAAcS;AACvB,WAAK,iBAAiBJ,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAGnE,IAAAH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAKQ,gBACNA,GACAO,GACAC,GACAC,GACAC,GAUAP,GACM;AAIN,SAHiBO,EAAQ,SAASH,EAAK,SAAS,IAAI,KAAKA,EAAK,SAAS,GAAG,KAAKA,EAAK,SAAS,GAAG,KAAMA,EAAK,SAAS,GAAG,KAAKA,EAAK,SAAS,GAAG,MAC3I,CAAC,CAACJ,KAAa,OAAOA,EAAS,UAAW,YAE/B;AACX,MAAAH,EAAI,KAAA,GACJA,EAAI,UAAUQ,GAAGC,CAAC,GACdC,EAAQ,YAAUV,EAAI,OAAQU,EAAQ,WAAW,KAAK,KAAM,GAAG;AAEnE,YAAMC,IAAOR,EAAS,QAAQI,GAAM;AAAA,QAClC,UAAUG,EAAQ;AAAA,QAClB,YAAYA,EAAQ;AAAA,QACpB,OAAOA,EAAQ;AAAA,MAAA,CAChB;AAED,UAAIE,IAAK,GACLC,IAAK;AAGT,YAAMC,IAAQJ,EAAQ,SAAS;AAC/B,MAAII,MAAU,WAAUF,IAAK,CAACD,EAAK,QAAQ,IAClCG,MAAU,YAASF,IAAK,CAACD,EAAK;AAIvC,YAAMI,IAAWL,EAAQ,YAAY;AACrC,MAAIK,MAAa,WACfF,IAAK,CAACF,EAAK,SAAS,IAAIA,EAAK,WACpBI,MAAa,SAASA,MAAa,YAC5CF,IAAKF,EAAK,WACDI,MAAa,YAAYA,MAAa,gBAC/CF,IAAK,EAAEF,EAAK,SAASA,EAAK,YAG1BE,IAAK,GAGPV,EAAS,OAAOI,GAAMP,GAAKY,GAAIC,GAAI;AAAA,QACjC,UAAUH,EAAQ;AAAA,QAClB,YAAYA,EAAQ;AAAA,QACpB,OAAOA,EAAQ;AAAA,MAAA,CAChB,GACDV,EAAI,QAAA;AAAA,IACN;AACE,MAAAA,EAAI,KAAA,GACJA,EAAI,OAAO,GAAGU,EAAQ,cAAc,EAAE,IAAIA,EAAQ,QAAQ,MAAMA,EAAQ,UAAU,IAClFV,EAAI,YAAYU,EAAQ,OACxBV,EAAI,YAAYU,EAAQ,SAAS,QACjCV,EAAI,eAAeU,EAAQ,YAAY,cACvCV,EAAI,UAAUQ,GAAGC,CAAC,GACdC,EAAQ,YAAUV,EAAI,OAAQU,EAAQ,WAAW,KAAK,KAAM,GAAG,GACnEV,EAAI,SAASO,GAAM,GAAG,CAAC,GACvBP,EAAI,QAAA;AAAA,EAER;AAAA,EAEQ,iBACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,YAAQR,EAAW,MAAA;AAAA,MACjB,KAAK;AACH,aAAK,qBAAqBK,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AACrE;AAAA,MACF,KAAK;AACH,aAAK,mBAAmBH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AACnE;AAAA,MACF,KAAK;AACH,aAAK,gBAAgBH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAChE;AAAA,MACF,KAAK;AACH,aAAK,WAAWH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAC3D;AAAA,MACF,KAAK;AACH,aAAK,WAAWH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAC3D;AAAA,MACF,KAAK;AACH,aAAK,YAAYH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAC5D;AAAA,IAAA;AAAA,EAEN;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAaa,GAAed,GAAgBD,GAA4B;AAC9E,UAAMgB,KAAcD,IAAQd,EAAO,SAASA,EAAO,OAAOA,EAAO;AACjE,WAAOD,EAAS,IAAIgB,IAAahB,EAAS;AAAA,EAC5C;AAAA,EAEQ,aAAae,GAAed,GAAgBD,GAA4B;AAC9E,UAAMgB,KAAcD,IAAQd,EAAO,SAASA,EAAO,OAAOA,EAAO;AACjE,WAAOD,EAAS,IAAIA,EAAS,UAAU,IAAIgB;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAMQ,qBACNjB,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMM,IAAI,KAAK,aAAad,EAAW,GAAGO,GAAQD,CAAQ;AAG1D,QAAIQ,IAAIR,EAAS,KAAKQ,IAAIR,EAAS,IAAIA,EAAS,OAAQ;AAExD,UAAMiB,IAASvB,EAAW,SAAS,SAC/B,KAAK,IAAI,KAAK,aAAaA,EAAW,MAAMO,GAAQD,CAAQ,GAAGA,EAAS,CAAC,IACzEA,EAAS,GACPkB,IAAOxB,EAAW,SAAS,SAC7B,KAAK,IAAI,KAAK,aAAaA,EAAW,MAAMO,GAAQD,CAAQ,GAAGA,EAAS,IAAIA,EAAS,KAAK,IAC1FA,EAAS,IAAIA,EAAS;AAE1B,IAAAD,EAAI,KAAA,GACJA,EAAI,cAAcL,EAAW,SAASH,EAAe,KAAK,OAC1DQ,EAAI,YAAYL,EAAW,aAAaH,EAAe,KAAK,WAC5DQ,EAAI,YAAYL,EAAW,YAAYH,EAAe,KAAK,QAAQ,GAEnEQ,EAAI,UAAA,GACJA,EAAI,OAAOkB,GAAQT,CAAC,GACpBT,EAAI,OAAOmB,GAAMV,CAAC,GAClBT,EAAI,OAAA,GAGAL,EAAW,SACb,KAAK;AAAA,MACHK;AAAA,MACAL,EAAW;AAAA,MACXuB;AAAA,MAAQC;AAAA,MAAMV;AAAA,MACdd,EAAW,iBAAiB;AAAA,MAC5B;AAAA,MACAA,EAAW;AAAA,MACXQ;AAAA,IAAA,GAIJH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,mBACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMK,IAAI,KAAK,aAAab,EAAW,GAAGO,GAAQD,CAAQ;AAG1D,QAAIO,IAAIP,EAAS,KAAKO,IAAIP,EAAS,IAAIA,EAAS,MAAO;AAEvD,UAAMmB,IAASzB,EAAW,SAAS,SAC/B,KAAK,IAAI,KAAK,aAAaA,EAAW,MAAMO,GAAQD,CAAQ,GAAGA,EAAS,IAAIA,EAAS,MAAM,IAC3FA,EAAS,GACPoB,IAAO1B,EAAW,SAAS,SAC7B,KAAK,IAAI,KAAK,aAAaA,EAAW,MAAMO,GAAQD,CAAQ,GAAGA,EAAS,CAAC,IACzEA,EAAS,IAAIA,EAAS;AAE1B,IAAAD,EAAI,KAAA,GACJA,EAAI,cAAcL,EAAW,SAASH,EAAe,KAAK,OAC1DQ,EAAI,YAAYL,EAAW,aAAaH,EAAe,KAAK,WAC5DQ,EAAI,YAAYL,EAAW,YAAYH,EAAe,KAAK,QAAQ,GAEnEQ,EAAI,UAAA,GACJA,EAAI,OAAOQ,GAAGY,CAAM,GACpBpB,EAAI,OAAOQ,GAAGa,CAAI,GAClBrB,EAAI,OAAA,GAGAL,EAAW,SACb,KAAK;AAAA,MACHK;AAAA,MACAL,EAAW;AAAA,MACXyB;AAAA,MAAQC;AAAA,MAAMb;AAAA,MACdb,EAAW,iBAAiB;AAAA,MAC5B;AAAA,MACAA,EAAW;AAAA,MACXQ;AAAA,IAAA,GAIJH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,gBACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMmB,IAAK,KAAK,aAAa3B,EAAW,MAAMO,GAAQD,CAAQ,GACxDsB,IAAK,KAAK,aAAa5B,EAAW,MAAMO,GAAQD,CAAQ,GACxDuB,IAAK,KAAK,aAAa7B,EAAW,MAAMO,GAAQD,CAAQ,GACxDwB,IAAK,KAAK,aAAa9B,EAAW,MAAMO,GAAQD,CAAQ,GAExDO,IAAI,KAAK,IAAIc,GAAIC,CAAE,GACnBd,IAAI,KAAK,IAAIe,GAAIC,CAAE,GACnBC,IAAQ,KAAK,IAAIH,IAAKD,CAAE,GACxBK,IAAS,KAAK,IAAIF,IAAKD,CAAE;AAE/B,IAAAxB,EAAI,KAAA,GAGAL,EAAW,cACbK,EAAI,YAAYL,EAAW,WAC3BK,EAAI,SAASQ,GAAGC,GAAGiB,GAAOC,CAAM,IAI9BhC,EAAW,gBACbK,EAAI,cAAcL,EAAW,aAC7BK,EAAI,YAAYL,EAAW,eAAeH,EAAe,UAAU,aACnEQ,EAAI,YAAYL,EAAW,cAAc,CAAA,CAAE,GAC3CK,EAAI,WAAWQ,GAAGC,GAAGiB,GAAOC,CAAM,IAIhChC,EAAW,SACb,KAAK,oBAAoBK,GAAKL,EAAW,OAAOa,IAAIkB,IAAQ,GAAGjB,IAAIkB,IAAS,GAAGxB,CAAQ,GAGzFH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,WACNA,GACAL,GACAM,GACAC,GACAC,GACM;AAEN,QAAIK,GAAWC,GAAWiB,GAAeC;AAEzC,QAAIhC,EAAW,SAAS,UAAaA,EAAW,SAAS,QAAW;AAElE,YAAM2B,IAAK,KAAK,aAAa3B,EAAW,MAAMO,GAAQD,CAAQ,GACxDsB,IAAK,KAAK,aAAa5B,EAAW,MAAMO,GAAQD,CAAQ;AAC9D,MAAAO,IAAI,KAAK,IAAIc,GAAIC,CAAE,GACnBG,IAAQ,KAAK,IAAIH,IAAKD,CAAE,GACxBb,IAAIR,EAAS,GACb0B,IAAS1B,EAAS,QAEdN,EAAW,SAAS,WAEtBgC,IADe,KAAK,aAAahC,EAAW,MAAMO,GAAQD,CAAQ,IAChDQ,IAEhBd,EAAW,SAAS,WAEtBc,IADe,KAAK,aAAad,EAAW,MAAMO,GAAQD,CAAQ,GAElE0B,IAAS1B,EAAS,IAAIA,EAAS,SAASQ;AAAA,IAE5C,WAAWd,EAAW,SAAS,UAAaA,EAAW,SAAS,QAAW;AAEzE,YAAM6B,IAAK,KAAK,aAAa7B,EAAW,MAAMO,GAAQD,CAAQ,GACxDwB,IAAK,KAAK,aAAa9B,EAAW,MAAMO,GAAQD,CAAQ;AAC9D,MAAAQ,IAAI,KAAK,IAAIe,GAAIC,CAAE,GACnBE,IAAS,KAAK,IAAIF,IAAKD,CAAE,GACzBhB,IAAIP,EAAS,GACbyB,IAAQzB,EAAS;AAAA,IACnB;AAEE;AAiBF,QAdAD,EAAI,KAAA,GAGJA,EAAI,YAAYL,EAAW,aAAaH,EAAe,UAAU,WACjEQ,EAAI,SAASQ,GAAGC,GAAGiB,GAAOC,CAAM,GAG5BhC,EAAW,gBACbK,EAAI,cAAcL,EAAW,aAC7BK,EAAI,YAAYL,EAAW,eAAe,GAC1CK,EAAI,WAAWQ,GAAGC,GAAGiB,GAAOC,CAAM,IAIhChC,EAAW,OAAO;AACpB,UAAIiC,IAASpB,IAAIkB,IAAQ,GACrBG,IAASpB,IAAIkB,IAAS;AAE1B,cAAQhC,EAAW,eAAA;AAAA,QACjB,KAAK;AACH,UAAAkC,IAASpB,IAAI;AACb;AAAA,QACF,KAAK;AACH,UAAAoB,IAASpB,IAAIkB,IAAS;AACtB;AAAA,QACF,KAAK;AACH,UAAAC,IAASpB,IAAI;AACb;AAAA,QACF,KAAK;AACH,UAAAoB,IAASpB,IAAIkB,IAAQ;AACrB;AAAA,MAAA;AAGJ,WAAK,oBAAoB1B,GAAKL,EAAW,OAAOiC,GAAQC,GAAQ1B,CAAQ;AAAA,IAC1E;AAEA,IAAAH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,WACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMK,IAAI,KAAK,aAAab,EAAW,GAAGO,GAAQD,CAAQ,GACpDQ,IAAI,KAAK,aAAad,EAAW,GAAGO,GAAQD,CAAQ;AAE1D,IAAAD,EAAI,KAAA,GAGAL,EAAW,aACbK,EAAI,UAAUQ,GAAGC,CAAC,GAClBT,EAAI,OAAQL,EAAW,WAAW,KAAK,KAAM,GAAG,GAChDK,EAAI,UAAU,CAACQ,GAAG,CAACC,CAAC;AAGtB,UAAMqB,IAAWnC,EAAW,YAAYH,EAAe,KAAK,UACtDuC,IAAapC,EAAW,cAAcH,EAAe,KAAK,YAC1DwC,IAAarC,EAAW,cAAc,UACtCsC,IAAaH,IAAW;AAE9B,IAAA9B,EAAI,OAAO,GAAGgC,CAAU,IAAIF,CAAQ,MAAMC,CAAU,IACpD/B,EAAI,YAAY,UAChBA,EAAI,eAAe;AAGnB,UAAMkC,IAAQvC,EAAW,KAAK,MAAM;AAAA,CAAI,GAClCwC,IAAUxC,EAAW,WAAWH,EAAe,KAAK;AAG1D,QAAI4C,IAAW;AACf,eAAWC,KAAQH;AACjB,MAAAE,IAAW,KAAK,IAAIA,GAAUpC,EAAI,YAAYqC,CAAI,EAAE,KAAK;AAG3D,UAAMC,IAAYF,IAAWD,IAAU,GACjCI,IAAcL,EAAM,SAASD,KAAeA,IAAaH,KAAYK,IAAU;AAGrF,QAAIK,IAAQhC,GACRiC,IAAQhC;AAEZ,YAAQd,EAAW,QAAA;AAAA,MACjB,KAAK;AACH,QAAA6C,KAASF,IAAY,GACrBG,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAC,KAASF,IAAY,GACrBG,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAC,KAASF,IAAY,GACrBG,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAC,KAASF,IAAY,GACrBG,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAE,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAE,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAC,KAASF,IAAY;AACrB;AAAA,MACF,KAAK;AACH,QAAAE,KAASF,IAAY;AACrB;AAAA,IAAA;AAIJ,IAAI3C,EAAW,oBACbK,EAAI,YAAYL,EAAW,iBAC3BK,EAAI,UAAA,GACJA,EAAI;AAAA,MACFwC,IAAQF,IAAY;AAAA,MACpBG,IAAQF,IAAa;AAAA,MACrBD;AAAA,MACAC;AAAA,MACA;AAAA,IAAA,GAEFvC,EAAI,KAAA;AAIN,UAAM0C,IAAQ/C,EAAW,SAASH,EAAe,KAAK,OAChDmD,IAASF,IAASF,IAAa,IAAKJ,IAAWL,IAAW;AAEhE,IAAAI,EAAM,QAAQ,CAACG,GAAMO,MAAM;AACzB,WAAK,gBAAgB5C,GAAKqC,GAAMG,GAAOG,IAASC,IAAIX,GAAY;AAAA,QAC9D,UAAAH;AAAA,QACA,YAAAC;AAAA,QACA,YAAAC;AAAA,QACA,OAAAU;AAAA,QACA,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO/C,EAAW;AAAA,MAAA,GACjBQ,CAAQ;AAAA,IACb,CAAC,GAEDH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,YACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMmB,IAAK,KAAK,aAAa3B,EAAW,IAAIO,GAAQD,CAAQ,GACtDuB,IAAK,KAAK,aAAa7B,EAAW,IAAIO,GAAQD,CAAQ,GACtDsB,IAAK,KAAK,aAAa5B,EAAW,IAAIO,GAAQD,CAAQ,GACtDwB,IAAK,KAAK,aAAa9B,EAAW,IAAIO,GAAQD,CAAQ;AAE5D,IAAAD,EAAI,KAAA,GACJA,EAAI,cAAcL,EAAW,SAASH,EAAe,MAAM,OAC3DQ,EAAI,YAAYL,EAAW,SAASH,EAAe,MAAM,OACzDQ,EAAI,YAAYL,EAAW,aAAaH,EAAe,MAAM,WAG7DQ,EAAI,UAAA,GACJA,EAAI,OAAOsB,GAAIE,CAAE,GACjBxB,EAAI,OAAOuB,GAAIE,CAAE,GACjBzB,EAAI,OAAA;AAGJ,UAAM6C,IAAWlD,EAAW,YAAYH,EAAe,MAAM,UACvDsD,IAAQ,KAAK,MAAMrB,IAAKD,GAAID,IAAKD,CAAE,GAEnCyB,IAAYpD,EAAW,aAAa;AA4B1C,QA1BIoD,MAAc,WAChB/C,EAAI,UAAA,GACJA,EAAI,OAAOuB,GAAIE,CAAE,GACjBzB,EAAI;AAAA,MACFuB,IAAKsB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,MAC5CrB,IAAKoB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,IAAA,GAG1CC,MAAc,YAChB/C,EAAI;AAAA,MACFuB,IAAKsB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,MAC5CrB,IAAKoB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,IAAA,GAE9C9C,EAAI,UAAA,GACJA,EAAI,KAAA,MAEJA,EAAI,OAAOuB,GAAIE,CAAE,GACjBzB,EAAI;AAAA,MACFuB,IAAKsB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,MAC5CrB,IAAKoB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,IAAA,GAE9C9C,EAAI,OAAA,KAKJL,EAAW,UAAU;AACvB,YAAMqD,IAAYF,IAAQ,KAAK;AAC/B,MAAA9C,EAAI,UAAA,GACJA,EAAI,OAAOsB,GAAIE,CAAE,GACjBxB,EAAI;AAAA,QACFsB,IAAKuB,IAAW,KAAK,IAAIG,IAAY,KAAK,KAAK,CAAC;AAAA,QAChDxB,IAAKqB,IAAW,KAAK,IAAIG,IAAY,KAAK,KAAK,CAAC;AAAA,MAAA,GAElDhD,EAAI;AAAA,QACFsB,IAAKuB,IAAW,KAAK,IAAIG,IAAY,KAAK,KAAK,CAAC;AAAA,QAChDxB,IAAKqB,IAAW,KAAK,IAAIG,IAAY,KAAK,KAAK,CAAC;AAAA,MAAA,GAElDhD,EAAI,UAAA,GACJA,EAAI,KAAA;AAAA,IACN;AAGA,QAAIL,EAAW,OAAO;AACpB,YAAMsD,KAAQ3B,IAAKC,KAAM,GACnB2B,KAAQ1B,IAAKC,KAAM;AACzB,WAAK,oBAAoBzB,GAAKL,EAAW,OAAOsD,GAAMC,IAAO,IAAI/C,CAAQ;AAAA,IAC3E;AAEA,IAAAH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,gBACNA,GACAmD,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAtD,GACM;AACN,IAAAH,EAAI,KAAA,GAEJA,EAAI,OAAO,GAAGR,EAAe,KAAK,QAAQ,MAAMA,EAAe,KAAK,UAAU;AAC9E,UAAMkE,IAAU1D,EAAI,YAAYmD,CAAK,GAC/BhB,IAAU,GACVG,IAAYoB,EAAQ,QAAQvB,IAAU,GACtCI,IAAa/C,EAAe,KAAK,WAAW2C,IAAU;AAE5D,QAAI3B,GAAWC;AAEf,QAAI+C,MAAgB,cAAc;AAGhC,cAFA/C,IAAI6C,GAEIC,GAAA;AAAA,QACN,KAAK;AACH,UAAA/C,IAAI4C,IAAQ,GACZpD,EAAI,YAAY;AAChB;AAAA,QACF,KAAK;AACH,UAAAQ,IAAI6C,IAAM,GACVrD,EAAI,YAAY;AAChB;AAAA,QACF;AACE,UAAAQ,KAAK4C,IAAQC,KAAO,GACpBrD,EAAI,YAAY;AAAA,MAAA;AAGpB,MAAAA,EAAI,eAAe,UACnBS,KAAK;AAAA,IACP,OAAO;AAGL,cAFAD,IAAI8C,GAEIC,GAAA;AAAA,QACN,KAAK;AACH,UAAA9C,IAAI2C,IAAQb;AACZ;AAAA,QACF,KAAK;AACH,UAAA9B,IAAI4C,IAAM;AACV;AAAA,QACF;AACE,UAAA5C,KAAK2C,IAAQC,KAAO;AAAA,MAAA;AAGxB,MAAArD,EAAI,YAAY,UAChBA,EAAI,eAAe;AAAA,IACrB;AAGA,QAAIyD,KAAmB,IAAM;AAC3B,MAAAzD,EAAI,YAAYyD,KAAmB;AACnC,YAAME,IAAM3D,EAAI,cAAc,SAASQ,IAAI2B,IACvCnC,EAAI,cAAc,UAAUQ,IAAI8B,IAAYH,IAC1C3B,IAAI8B,IAAY;AACtB,MAAAtC,EAAI,SAAS2D,GAAKlD,IAAI8B,IAAaJ,GAASG,GAAWC,CAAU;AAAA,IACnE;AAGA,SAAK,gBAAgBvC,GAAKmD,GAAO3C,GAAGC,GAAG;AAAA,MACrC,UAAUjB,EAAe,KAAK;AAAA,MAC9B,YAAYA,EAAe,KAAK;AAAA,MAChC,OAAOA,EAAe,KAAK;AAAA,MAC3B,OAAOQ,EAAI;AAAA,MACX,UAAUA,EAAI;AAAA,IAAA,GACbG,CAAQ,GAEXH,EAAI,QAAA;AAAA,EACN;AAAA,EAEQ,oBACNA,GACAmD,GACA3C,GACAC,GACAN,GACM;AACN,IAAAH,EAAI,KAAA,GAEJA,EAAI,OAAO,GAAGR,EAAe,KAAK,QAAQ,MAAMA,EAAe,KAAK,UAAU;AAC9E,UAAMkE,IAAU1D,EAAI,YAAYmD,CAAK,GAC/BhB,IAAU,GACVG,IAAYoB,EAAQ,QAAQvB,IAAU,GACtCI,IAAa/C,EAAe,KAAK,WAAW2C,IAAU;AAG5D,IAAAnC,EAAI,YAAY,sBAChBA,EAAI,UAAA,GACJA,EAAI,UAAUQ,IAAI8B,IAAY,GAAG7B,IAAI8B,IAAa,GAAGD,GAAWC,GAAY,CAAC,GAC7EvC,EAAI,KAAA,GAGJ,KAAK,gBAAgBA,GAAKmD,GAAO3C,GAAGC,GAAG;AAAA,MACrC,UAAUjB,EAAe,KAAK;AAAA,MAC9B,YAAYA,EAAe,KAAK;AAAA,MAChC,OAAOA,EAAe,KAAK;AAAA,MAC3B,OAAO;AAAA,MACP,UAAU;AAAA,IAAA,GACTW,CAAQ,GAEXH,EAAI,QAAA;AAAA,EACN;AACF;ACnyBA,MAAM4D,IAAsC;AAAA,EACxC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,YAAY;AAAA,EACvB,MAAM,CAAC,cAAc,WAAW,OAAO;AAC3C;AAOO,SAASC,EAAkBC,IAAmC,IAA0C;AAC3G,MAAIC;AAEJ,SAAO;AAAA,IACH,UAAUH;AAAA,IAEV,OAAO5D,GAAoB;AACvB,MAAA+D,IAAoB,IAAItE,EAAA,GAKxBO,EAAI,QAAQ,IAAI,WAAW+D,CAAiB;AAAA,IAChD;AAAA,IAEA,gBAAgB/D,GAAK;AACjB,YAAMC,IAAWD,EAAI,OAAO,UACtBgE,IAAahE,EAAI,KAAK,cAAA,GAGtBiE,IAAcjE,EAAI,UAAe,iBAAiB,GAClDG,IAAW8D,KAAA,gBAAAA,EAAa;AAG9B,MAAAF,EAAkB;AAAA,QACd/D,EAAI,OAAO;AAAA,QACXC;AAAA,QACA+D;AAAA,QACA7D;AAAA,MAAA;AAAA,IAER;AAAA,IAEA,UAAU+D,GAAqB;AAC3B,MAAAH,EAAkB,MAAA;AAAA,IACtB;AAAA,IAEA,KAAK;AAAA,MACD,aAAa;AACT,eAAOA;AAAA,MACX;AAAA,MACA,IAAIpE,GAAwB;AACxB,eAAOoE,EAAkB,IAAIpE,CAAU;AAAA,MAC3C;AAAA,MACA,OAAOC,GAAY;AACf,eAAOmE,EAAkB,OAAOnE,CAAE;AAAA,MACtC;AAAA,MACA,OAAOA,GAAYE,GAA8B;AAC7C,eAAOiE,EAAkB,OAAOnE,GAAIE,CAAO;AAAA,MAC/C;AAAA,MACA,IAAIF,GAAY;AACZ,eAAOmE,EAAkB,IAAInE,CAAE;AAAA,MACnC;AAAA,MACA,SAAS;AACL,eAAOmE,EAAkB,OAAA;AAAA,MAC7B;AAAA,MACA,QAAQ;AACJ,QAAAA,EAAkB,MAAA;AAAA,MACtB;AAAA,IAAA;AAAA,EACJ;AAER;"}
1
+ {"version":3,"file":"annotations.js","sources":["../../src/core/annotations/AnnotationManager.ts","../../src/plugins/annotations/index.ts"],"sourcesContent":["/**\n * AnnotationManager - Manages chart annotations\n * \n * Handles creation, update, removal, and rendering of all annotation types.\n */\n\nimport type { Bounds } from '../../types';\nimport type {\n Annotation,\n HorizontalLineAnnotation,\n VerticalLineAnnotation,\n RectangleAnnotation,\n BandAnnotation,\n TextAnnotation,\n ArrowAnnotation,\n} from './types';\n\n// ============================================\n// Default Styles\n// ============================================\n\nconst DEFAULT_STYLES = {\n line: {\n color: 'rgba(255, 255, 255, 0.7)',\n lineWidth: 1,\n lineDash: [] as number[],\n },\n rectangle: {\n fillColor: 'rgba(100, 100, 255, 0.2)',\n strokeColor: 'rgba(100, 100, 255, 0.5)',\n strokeWidth: 1,\n },\n text: {\n fontSize: 12,\n fontFamily: 'Inter, system-ui, sans-serif',\n color: '#ffffff',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n padding: 4,\n },\n arrow: {\n color: 'rgba(255, 255, 255, 0.7)',\n lineWidth: 2,\n headSize: 10,\n },\n};\n\n// ============================================\n// Plot Area Type\n// ============================================\n\nexport interface PlotArea {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n// ============================================\n// AnnotationManager Class\n// ============================================\n\nexport class AnnotationManager {\n private annotations: Map<string, Annotation> = new Map();\n private idCounter = 0;\n\n // ----------------------------------------\n // CRUD Operations\n // ----------------------------------------\n\n /**\n * Add a new annotation\n * @returns The annotation ID\n */\n add(annotation: Annotation): string {\n const id = annotation.id ?? `annotation-${++this.idCounter}`;\n const resolved: Annotation = {\n ...annotation,\n id,\n visible: annotation.visible ?? true,\n interactive: annotation.interactive ?? false,\n zIndex: annotation.zIndex ?? 0,\n };\n\n this.annotations.set(id, resolved);\n return id;\n }\n\n /**\n * Remove an annotation by ID\n */\n remove(id: string): boolean {\n return this.annotations.delete(id);\n }\n\n /**\n * Update an annotation\n */\n update(id: string, updates: Partial<Annotation>): void {\n const existing = this.annotations.get(id);\n if (existing) {\n this.annotations.set(id, { ...existing, ...updates } as Annotation);\n }\n }\n\n /**\n * Get an annotation by ID\n */\n get(id: string): Annotation | undefined {\n return this.annotations.get(id);\n }\n\n /**\n * Get all annotations\n */\n getAll(): Annotation[] {\n return Array.from(this.annotations.values());\n }\n\n /**\n * Clear all annotations\n */\n clear(): void {\n this.annotations.clear();\n }\n\n /**\n * Get count of annotations\n */\n get count(): number {\n return this.annotations.size;\n }\n\n // ----------------------------------------\n // Rendering\n // ----------------------------------------\n\n /**\n * Render all annotations\n */\n render(\n ctx: CanvasRenderingContext2D,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n // Sort by zIndex\n const sorted = this.getAll()\n .filter(a => a.visible !== false)\n .sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));\n\n ctx.save();\n\n // Clip to plot area\n ctx.beginPath();\n ctx.rect(plotArea.x, plotArea.y, plotArea.width, plotArea.height);\n ctx.clip();\n\n for (const annotation of sorted) {\n this.renderAnnotation(ctx, annotation, plotArea, bounds, latexAPI);\n }\n\n ctx.restore();\n }\n\n /**\n * Helper to draw text or LaTeX\n */\n private drawLatexOrText(\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n options: {\n fontSize: number;\n fontFamily: string;\n fontWeight?: string | number;\n color: string;\n align?: CanvasTextAlign;\n baseline?: CanvasTextBaseline;\n rotation?: number;\n latex?: boolean;\n },\n latexAPI?: any\n ): void {\n const isLatex = (options.latex || text.includes('\\\\') || text.includes('^') || text.includes('_') || (text.includes('{') && text.includes('}'))) &&\n !!latexAPI && (typeof latexAPI.render === 'function');\n\n if (isLatex) {\n ctx.save();\n ctx.translate(x, y);\n if (options.rotation) ctx.rotate((options.rotation * Math.PI) / 180);\n\n const dims = latexAPI.measure(text, {\n fontSize: options.fontSize,\n fontFamily: options.fontFamily,\n color: options.color\n });\n\n let lx = 0;\n let ly = 0;\n\n // Handle Horizontal Alignment\n const align = options.align ?? \"left\";\n if (align === \"center\") lx = -dims.width / 2;\n else if (align === \"right\") lx = -dims.width;\n\n // Handle Vertical Alignment based on alphabetic baseline of the plugin\n // The plugin draws with textBaseline = 'alphabetic' at the provided y\n const baseline = options.baseline ?? \"alphabetic\";\n if (baseline === \"middle\") {\n ly = -dims.height / 2 + dims.baseline;\n } else if (baseline === \"top\" || baseline === \"hanging\") {\n ly = dims.baseline;\n } else if (baseline === \"bottom\" || baseline === \"ideographic\") {\n ly = -(dims.height - dims.baseline);\n } else {\n // 'alphabetic' or default\n ly = 0;\n }\n\n latexAPI.render(text, ctx, lx, ly, {\n fontSize: options.fontSize,\n fontFamily: options.fontFamily,\n color: options.color\n });\n ctx.restore();\n } else {\n ctx.save();\n ctx.font = `${options.fontWeight ?? ''} ${options.fontSize}px ${options.fontFamily}`;\n ctx.fillStyle = options.color;\n ctx.textAlign = options.align ?? \"left\";\n ctx.textBaseline = options.baseline ?? \"alphabetic\";\n ctx.translate(x, y);\n if (options.rotation) ctx.rotate((options.rotation * Math.PI) / 180);\n ctx.fillText(text, 0, 0);\n ctx.restore();\n }\n }\n\n private renderAnnotation(\n ctx: CanvasRenderingContext2D,\n annotation: Annotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n switch (annotation.type) {\n case 'horizontal-line':\n this.renderHorizontalLine(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'vertical-line':\n this.renderVerticalLine(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'rectangle':\n this.renderRectangle(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'band':\n this.renderBand(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'text':\n this.renderText(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'arrow':\n this.renderArrow(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n }\n }\n\n // ----------------------------------------\n // Coordinate Conversion\n // ----------------------------------------\n\n private dataToPixelX(value: number, bounds: Bounds, plotArea: PlotArea): number {\n const normalized = (value - bounds.xMin) / (bounds.xMax - bounds.xMin);\n return plotArea.x + normalized * plotArea.width;\n }\n\n private dataToPixelY(value: number, bounds: Bounds, plotArea: PlotArea): number {\n const normalized = (value - bounds.yMin) / (bounds.yMax - bounds.yMin);\n return plotArea.y + plotArea.height * (1 - normalized);\n }\n\n // ----------------------------------------\n // Render: Horizontal Line\n // ----------------------------------------\n\n private renderHorizontalLine(\n ctx: CanvasRenderingContext2D,\n annotation: HorizontalLineAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const y = this.dataToPixelY(annotation.y, bounds, plotArea);\n\n // Skip if outside visible area\n if (y < plotArea.y || y > plotArea.y + plotArea.height) return;\n\n const xStart = annotation.xMin !== undefined\n ? Math.max(this.dataToPixelX(annotation.xMin, bounds, plotArea), plotArea.x)\n : plotArea.x;\n const xEnd = annotation.xMax !== undefined\n ? Math.min(this.dataToPixelX(annotation.xMax, bounds, plotArea), plotArea.x + plotArea.width)\n : plotArea.x + plotArea.width;\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.line.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.line.lineWidth;\n ctx.setLineDash(annotation.lineDash ?? DEFAULT_STYLES.line.lineDash);\n\n ctx.beginPath();\n ctx.moveTo(xStart, y);\n ctx.lineTo(xEnd, y);\n ctx.stroke();\n\n // Render label if present\n if (annotation.label) {\n this.renderLineLabel(\n ctx,\n annotation.label,\n xStart, xEnd, y,\n annotation.labelPosition ?? 'right',\n 'horizontal',\n annotation.labelBackground,\n latexAPI\n );\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Vertical Line\n // ----------------------------------------\n\n private renderVerticalLine(\n ctx: CanvasRenderingContext2D,\n annotation: VerticalLineAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x = this.dataToPixelX(annotation.x, bounds, plotArea);\n\n // Skip if outside visible area\n if (x < plotArea.x || x > plotArea.x + plotArea.width) return;\n\n const yStart = annotation.yMin !== undefined\n ? Math.min(this.dataToPixelY(annotation.yMin, bounds, plotArea), plotArea.y + plotArea.height)\n : plotArea.y;\n const yEnd = annotation.yMax !== undefined\n ? Math.max(this.dataToPixelY(annotation.yMax, bounds, plotArea), plotArea.y)\n : plotArea.y + plotArea.height;\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.line.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.line.lineWidth;\n ctx.setLineDash(annotation.lineDash ?? DEFAULT_STYLES.line.lineDash);\n\n ctx.beginPath();\n ctx.moveTo(x, yStart);\n ctx.lineTo(x, yEnd);\n ctx.stroke();\n\n // Render label if present\n if (annotation.label) {\n this.renderLineLabel(\n ctx,\n annotation.label,\n yStart, yEnd, x,\n annotation.labelPosition ?? 'top',\n 'vertical',\n annotation.labelBackground,\n latexAPI\n );\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Rectangle\n // ----------------------------------------\n\n private renderRectangle(\n ctx: CanvasRenderingContext2D,\n annotation: RectangleAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x1 = this.dataToPixelX(annotation.xMin, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.xMax, bounds, plotArea);\n const y1 = this.dataToPixelY(annotation.yMax, bounds, plotArea); // Note: Y is inverted\n const y2 = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n\n const x = Math.min(x1, x2);\n const y = Math.min(y1, y2);\n const width = Math.abs(x2 - x1);\n const height = Math.abs(y2 - y1);\n\n ctx.save();\n\n // Fill\n if (annotation.fillColor) {\n ctx.fillStyle = annotation.fillColor;\n ctx.fillRect(x, y, width, height);\n }\n\n // Stroke\n if (annotation.strokeColor) {\n ctx.strokeStyle = annotation.strokeColor;\n ctx.lineWidth = annotation.strokeWidth ?? DEFAULT_STYLES.rectangle.strokeWidth;\n ctx.setLineDash(annotation.strokeDash ?? []);\n ctx.strokeRect(x, y, width, height);\n }\n\n // Label\n if (annotation.label) {\n this.renderCenteredLabel(ctx, annotation.label, x + width / 2, y + height / 2, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Band\n // ----------------------------------------\n\n private renderBand(\n ctx: CanvasRenderingContext2D,\n annotation: BandAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n // Determine band type and calculate bounds\n let x: number, y: number, width: number, height: number;\n\n if (annotation.xMin !== undefined && annotation.xMax !== undefined) {\n // Vertical band (spans full Y)\n const x1 = this.dataToPixelX(annotation.xMin, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.xMax, bounds, plotArea);\n x = Math.min(x1, x2);\n width = Math.abs(x2 - x1);\n y = plotArea.y;\n height = plotArea.height;\n\n if (annotation.yMin !== undefined) {\n const yPixel = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n height = yPixel - y;\n }\n if (annotation.yMax !== undefined) {\n const yPixel = this.dataToPixelY(annotation.yMax, bounds, plotArea);\n y = yPixel;\n height = plotArea.y + plotArea.height - y;\n }\n } else if (annotation.yMin !== undefined && annotation.yMax !== undefined) {\n // Horizontal band (spans full X)\n const y1 = this.dataToPixelY(annotation.yMax, bounds, plotArea);\n const y2 = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n y = Math.min(y1, y2);\n height = Math.abs(y2 - y1);\n x = plotArea.x;\n width = plotArea.width;\n } else {\n // Invalid band configuration\n return;\n }\n\n ctx.save();\n\n // Fill\n ctx.fillStyle = annotation.fillColor ?? DEFAULT_STYLES.rectangle.fillColor;\n ctx.fillRect(x, y, width, height);\n\n // Stroke\n if (annotation.strokeColor) {\n ctx.strokeStyle = annotation.strokeColor;\n ctx.lineWidth = annotation.strokeWidth ?? 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n // Label\n if (annotation.label) {\n let labelX = x + width / 2;\n let labelY = y + height / 2;\n\n switch (annotation.labelPosition) {\n case 'top':\n labelY = y + 15;\n break;\n case 'bottom':\n labelY = y + height - 5;\n break;\n case 'left':\n labelX = x + 10;\n break;\n case 'right':\n labelX = x + width - 10;\n break;\n }\n\n this.renderCenteredLabel(ctx, annotation.label, labelX, labelY, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Text\n // ----------------------------------------\n\n private renderText(\n ctx: CanvasRenderingContext2D,\n annotation: TextAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x = this.dataToPixelX(annotation.x, bounds, plotArea);\n const y = this.dataToPixelY(annotation.y, bounds, plotArea);\n\n ctx.save();\n\n // Apply rotation if specified\n if (annotation.rotation) {\n ctx.translate(x, y);\n ctx.rotate((annotation.rotation * Math.PI) / 180);\n ctx.translate(-x, -y);\n }\n\n const fontSize = annotation.fontSize ?? DEFAULT_STYLES.text.fontSize;\n const fontFamily = annotation.fontFamily ?? DEFAULT_STYLES.text.fontFamily;\n const fontWeight = annotation.fontWeight ?? 'normal';\n const lineHeight = fontSize * 1.2;\n\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Support multi-line text\n const lines = annotation.text.split('\\n');\n const padding = annotation.padding ?? DEFAULT_STYLES.text.padding;\n\n // Measure all lines to find max width\n let maxWidth = 0;\n for (const line of lines) {\n maxWidth = Math.max(maxWidth, ctx.measureText(line).width);\n }\n\n const textWidth = maxWidth + padding * 2;\n const textHeight = (lines.length * lineHeight) - (lineHeight - fontSize) + padding * 2;\n\n // Calculate position based on anchor\n let drawX = x;\n let drawY = y;\n\n switch (annotation.anchor) {\n case 'top-left':\n drawX += textWidth / 2;\n drawY += textHeight / 2;\n break;\n case 'top-right':\n drawX -= textWidth / 2;\n drawY += textHeight / 2;\n break;\n case 'bottom-left':\n drawX += textWidth / 2;\n drawY -= textHeight / 2;\n break;\n case 'bottom-right':\n drawX -= textWidth / 2;\n drawY -= textHeight / 2;\n break;\n case 'top-center':\n drawY += textHeight / 2;\n break;\n case 'bottom-center':\n drawY -= textHeight / 2;\n break;\n case 'left-center':\n drawX += textWidth / 2;\n break;\n case 'right-center':\n drawX -= textWidth / 2;\n break;\n }\n\n // Draw background\n if (annotation.backgroundColor) {\n ctx.fillStyle = annotation.backgroundColor;\n ctx.beginPath();\n ctx.roundRect(\n drawX - textWidth / 2,\n drawY - textHeight / 2,\n textWidth,\n textHeight,\n 4\n );\n ctx.fill();\n }\n\n // Draw text lines\n const color = annotation.color ?? DEFAULT_STYLES.text.color;\n const startY = drawY - (textHeight / 2) + padding + (fontSize / 2);\n\n lines.forEach((line, i) => {\n this.drawLatexOrText(ctx, line, drawX, startY + i * lineHeight, {\n fontSize,\n fontFamily,\n fontWeight,\n color,\n align: 'center',\n baseline: 'middle',\n latex: annotation.latex\n }, latexAPI);\n });\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Arrow\n // ----------------------------------------\n\n private renderArrow(\n ctx: CanvasRenderingContext2D,\n annotation: ArrowAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x1 = this.dataToPixelX(annotation.x1, bounds, plotArea);\n const y1 = this.dataToPixelY(annotation.y1, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.x2, bounds, plotArea);\n const y2 = this.dataToPixelY(annotation.y2, bounds, plotArea);\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.arrow.color;\n ctx.fillStyle = annotation.color ?? DEFAULT_STYLES.arrow.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.arrow.lineWidth;\n\n // Draw line\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(x2, y2);\n ctx.stroke();\n\n // Draw arrow head\n const headSize = annotation.headSize ?? DEFAULT_STYLES.arrow.headSize;\n const angle = Math.atan2(y2 - y1, x2 - x1);\n\n const headStyle = annotation.headStyle ?? 'filled';\n\n if (headStyle !== 'none') {\n ctx.beginPath();\n ctx.moveTo(x2, y2);\n ctx.lineTo(\n x2 - headSize * Math.cos(angle - Math.PI / 6),\n y2 - headSize * Math.sin(angle - Math.PI / 6)\n );\n\n if (headStyle === 'filled') {\n ctx.lineTo(\n x2 - headSize * Math.cos(angle + Math.PI / 6),\n y2 - headSize * Math.sin(angle + Math.PI / 6)\n );\n ctx.closePath();\n ctx.fill();\n } else {\n ctx.moveTo(x2, y2);\n ctx.lineTo(\n x2 - headSize * Math.cos(angle + Math.PI / 6),\n y2 - headSize * Math.sin(angle + Math.PI / 6)\n );\n ctx.stroke();\n }\n }\n\n // Draw tail arrow if specified\n if (annotation.showTail) {\n const tailAngle = angle + Math.PI;\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(\n x1 - headSize * Math.cos(tailAngle - Math.PI / 6),\n y1 - headSize * Math.sin(tailAngle - Math.PI / 6)\n );\n ctx.lineTo(\n x1 - headSize * Math.cos(tailAngle + Math.PI / 6),\n y1 - headSize * Math.sin(tailAngle + Math.PI / 6)\n );\n ctx.closePath();\n ctx.fill();\n }\n\n // Draw label if present\n if (annotation.label) {\n const midX = (x1 + x2) / 2;\n const midY = (y1 + y2) / 2;\n this.renderCenteredLabel(ctx, annotation.label, midX, midY - 10, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Helper: Render Labels\n // ----------------------------------------\n\n private renderLineLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n start: number,\n end: number,\n cross: number,\n position: string,\n orientation: 'horizontal' | 'vertical',\n backgroundColor?: string,\n latexAPI?: any\n ): void {\n ctx.save();\n\n ctx.font = `${DEFAULT_STYLES.text.fontSize}px ${DEFAULT_STYLES.text.fontFamily}`;\n const metrics = ctx.measureText(label);\n const padding = 4;\n const textWidth = metrics.width + padding * 2;\n const textHeight = DEFAULT_STYLES.text.fontSize + padding * 2;\n\n let x: number, y: number;\n\n if (orientation === 'horizontal') {\n y = cross;\n\n switch (position) {\n case 'left':\n x = start + 5;\n ctx.textAlign = 'left';\n break;\n case 'right':\n x = end - 5;\n ctx.textAlign = 'right';\n break;\n default:\n x = (start + end) / 2;\n ctx.textAlign = 'center';\n }\n\n ctx.textBaseline = 'bottom';\n y -= 4;\n } else {\n x = cross;\n\n switch (position) {\n case 'top':\n y = start + textHeight;\n break;\n case 'bottom':\n y = end - 5;\n break;\n default:\n y = (start + end) / 2;\n }\n\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n }\n\n // Background\n if (backgroundColor ?? true) {\n ctx.fillStyle = backgroundColor ?? 'rgba(0, 0, 0, 0.7)';\n const bgX = ctx.textAlign === 'left' ? x - padding\n : ctx.textAlign === 'right' ? x - textWidth + padding\n : x - textWidth / 2;\n ctx.fillRect(bgX, y - textHeight + padding, textWidth, textHeight);\n }\n\n // Text\n this.drawLatexOrText(ctx, label, x, y, {\n fontSize: DEFAULT_STYLES.text.fontSize,\n fontFamily: DEFAULT_STYLES.text.fontFamily,\n color: DEFAULT_STYLES.text.color,\n align: ctx.textAlign,\n baseline: ctx.textBaseline,\n }, latexAPI);\n\n ctx.restore();\n }\n\n private renderCenteredLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n x: number,\n y: number,\n latexAPI?: any\n ): void {\n ctx.save();\n\n ctx.font = `${DEFAULT_STYLES.text.fontSize}px ${DEFAULT_STYLES.text.fontFamily}`;\n const metrics = ctx.measureText(label);\n const padding = 4;\n const textWidth = metrics.width + padding * 2;\n const textHeight = DEFAULT_STYLES.text.fontSize + padding * 2;\n\n // Background\n ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';\n ctx.beginPath();\n ctx.roundRect(x - textWidth / 2, y - textHeight / 2, textWidth, textHeight, 3);\n ctx.fill();\n\n // Text\n this.drawLatexOrText(ctx, label, x, y, {\n fontSize: DEFAULT_STYLES.text.fontSize,\n fontFamily: DEFAULT_STYLES.text.fontFamily,\n color: DEFAULT_STYLES.text.color,\n align: 'center',\n baseline: 'middle',\n }, latexAPI);\n\n ctx.restore();\n }\n}\n","/**\n * Velo Plot - Annotations Plugin\n * \n * Provides annotation capabilities including:\n * - Line, Rectangle, Band, Text, Arrow annotations\n * - Annotation management and rendering\n * \n * @module plugins/annotations\n */\n\nimport { AnnotationManager } from \"../../core/annotations\";\nimport type { Annotation, AnnotationType } from \"../../core/annotations\";\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginAnnotationsConfig {\n /** Default styles for annotations */\n defaultStyles?: Record<string, any>;\n}\n\nconst manifestAnnotations: PluginManifest = {\n name: \"velo-plot-annotations\",\n version: \"1.0.0\",\n description: \"Annotation support for velo-plot\",\n provides: [\"annotation\"],\n tags: [\"annotation\", \"overlay\", \"label\"],\n};\n\n/**\n * VeloPlot Annotations Plugin\n * \n * Adds support for drawing lines, shapes, and labels on the chart.\n */\nexport function PluginAnnotations(_config: PluginAnnotationsConfig = {}): ChartPlugin<PluginAnnotationsConfig> {\n let annotationManager: AnnotationManager;\n\n return {\n manifest: manifestAnnotations,\n\n onInit(ctx: PluginContext) {\n annotationManager = new AnnotationManager();\n\n // In a real implementation, we would register this manager in the context\n // so the chart can delegate annotation calls to it.\n // For now, we store it in storage for retrieval.\n ctx.storage.set(\"manager\", annotationManager);\n },\n\n onRenderOverlay(ctx) {\n const plotArea = ctx.render.plotArea;\n const viewBounds = ctx.data.getViewBounds();\n\n // Get LaTeX API if plugin is available\n const latexPlugin = ctx.getPlugin<any>(\"velo-plot-latex\");\n const latexAPI = latexPlugin?.api;\n\n // Render all annotations using the manager and provided contexts\n annotationManager.render(\n ctx.render.ctx2d!,\n plotArea,\n viewBounds,\n latexAPI\n );\n },\n\n onDestroy(_ctx: PluginContext) {\n annotationManager.clear();\n },\n\n api: {\n getManager() {\n return annotationManager;\n },\n add(annotation: Annotation) {\n return annotationManager.add(annotation);\n },\n remove(id: string) {\n return annotationManager.remove(id);\n },\n update(id: string, updates: Partial<Annotation>) {\n return annotationManager.update(id, updates);\n },\n get(id: string) {\n return annotationManager.get(id);\n },\n getAll() {\n return annotationManager.getAll();\n },\n clear() {\n annotationManager.clear();\n }\n }\n };\n}\n\nexport { AnnotationManager };\nexport type { Annotation, AnnotationType };\nexport default PluginAnnotations;\n"],"names":["DEFAULT_STYLES","AnnotationManager","__publicField","annotation","id","resolved","updates","existing","ctx","plotArea","bounds","latexAPI","sorted","a","b","text","x","y","options","dims","lx","ly","align","baseline","value","normalized","xStart","xEnd","yStart","yEnd","x1","x2","y1","y2","width","height","labelX","labelY","fontSize","fontFamily","fontWeight","lineHeight","lines","padding","maxWidth","line","textWidth","textHeight","drawX","drawY","color","startY","i","headSize","angle","headStyle","tailAngle","midX","midY","label","start","end","cross","position","orientation","backgroundColor","metrics","bgX","manifestAnnotations","PluginAnnotations","_config","annotationManager","viewBounds","latexPlugin","_ctx"],"mappings":";;;AAqBA,MAAMA,IAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,WAAW;AAAA,IACX,UAAU,CAAA;AAAA,EAAC;AAAA,EAEb,WAAW;AAAA,IACT,WAAW;AAAA,IAEX,aAAa;AAAA,EAAA;AAAA,EAEf,MAAM;AAAA,IACJ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,OAAO;AAAA,IAEP,SAAS;AAAA,EAAA;AAAA,EAEX,OAAO;AAAA,IACL,OAAO;AAAA,IACP,WAAW;AAAA,IACX,UAAU;AAAA,EAAA;AAEd;AAiBO,MAAMC,EAAkB;AAAA,EAAxB;AACG,IAAAC,EAAA,yCAA2C,IAAA;AAC3C,IAAAA,EAAA,mBAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUpB,IAAIC,GAAgC;AAClC,UAAMC,IAAKD,EAAW,MAAM,cAAc,EAAE,KAAK,SAAS,IACpDE,IAAuB;AAAA,MAC3B,GAAGF;AAAA,MACH,IAAAC;AAAA,MACA,SAASD,EAAW,WAAW;AAAA,MAC/B,aAAaA,EAAW,eAAe;AAAA,MACvC,QAAQA,EAAW,UAAU;AAAA,IAAA;AAG/B,gBAAK,YAAY,IAAIC,GAAIC,CAAQ,GAC1BD;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAOA,GAAqB;AAC1B,WAAO,KAAK,YAAY,OAAOA,CAAE;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAOA,GAAYE,GAAoC;AACrD,UAAMC,IAAW,KAAK,YAAY,IAAIH,CAAE;AACxC,IAAIG,KACF,KAAK,YAAY,IAAIH,GAAI,EAAE,GAAGG,GAAU,GAAGD,GAAuB;AAAA,EAEtE;AAAA;AAAA;AAAA;AAAA,EAKA,IAAIF,GAAoC;AACtC,WAAO,KAAK,YAAY,IAAIA,CAAE;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAuB;AACrB,WAAO,MAAM,KAAK,KAAK,YAAY,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,YAAY,MAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,QAAgB;AAClB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OACEI,GACAC,GACAC,GACAC,GACM;AAEN,UAAMC,IAAS,KAAK,SACjB,OAAO,CAAAC,MAAKA,EAAE,YAAY,EAAK,EAC/B,KAAK,CAACA,GAAGC,OAAOD,EAAE,UAAU,MAAMC,EAAE,UAAU,EAAE;AAEnD,IAAAN,EAAI,KAAA,GAGJA,EAAI,UAAA,GACJA,EAAI,KAAKC,EAAS,GAAGA,EAAS,GAAGA,EAAS,OAAOA,EAAS,MAAM,GAChED,EAAI,KAAA;AAEJ,eAAWL,KAAcS;AACvB,WAAK,iBAAiBJ,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAGnE,IAAAH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAKQ,gBACNA,GACAO,GACAC,GACAC,GACAC,GAUAP,GACM;AAIN,SAHiBO,EAAQ,SAASH,EAAK,SAAS,IAAI,KAAKA,EAAK,SAAS,GAAG,KAAKA,EAAK,SAAS,GAAG,KAAMA,EAAK,SAAS,GAAG,KAAKA,EAAK,SAAS,GAAG,MAC3I,CAAC,CAACJ,KAAa,OAAOA,EAAS,UAAW,YAE/B;AACX,MAAAH,EAAI,KAAA,GACJA,EAAI,UAAUQ,GAAGC,CAAC,GACdC,EAAQ,YAAUV,EAAI,OAAQU,EAAQ,WAAW,KAAK,KAAM,GAAG;AAEnE,YAAMC,IAAOR,EAAS,QAAQI,GAAM;AAAA,QAClC,UAAUG,EAAQ;AAAA,QAClB,YAAYA,EAAQ;AAAA,QACpB,OAAOA,EAAQ;AAAA,MAAA,CAChB;AAED,UAAIE,IAAK,GACLC,IAAK;AAGT,YAAMC,IAAQJ,EAAQ,SAAS;AAC/B,MAAII,MAAU,WAAUF,IAAK,CAACD,EAAK,QAAQ,IAClCG,MAAU,YAASF,IAAK,CAACD,EAAK;AAIvC,YAAMI,IAAWL,EAAQ,YAAY;AACrC,MAAIK,MAAa,WACfF,IAAK,CAACF,EAAK,SAAS,IAAIA,EAAK,WACpBI,MAAa,SAASA,MAAa,YAC5CF,IAAKF,EAAK,WACDI,MAAa,YAAYA,MAAa,gBAC/CF,IAAK,EAAEF,EAAK,SAASA,EAAK,YAG1BE,IAAK,GAGPV,EAAS,OAAOI,GAAMP,GAAKY,GAAIC,GAAI;AAAA,QACjC,UAAUH,EAAQ;AAAA,QAClB,YAAYA,EAAQ;AAAA,QACpB,OAAOA,EAAQ;AAAA,MAAA,CAChB,GACDV,EAAI,QAAA;AAAA,IACN;AACE,MAAAA,EAAI,KAAA,GACJA,EAAI,OAAO,GAAGU,EAAQ,cAAc,EAAE,IAAIA,EAAQ,QAAQ,MAAMA,EAAQ,UAAU,IAClFV,EAAI,YAAYU,EAAQ,OACxBV,EAAI,YAAYU,EAAQ,SAAS,QACjCV,EAAI,eAAeU,EAAQ,YAAY,cACvCV,EAAI,UAAUQ,GAAGC,CAAC,GACdC,EAAQ,YAAUV,EAAI,OAAQU,EAAQ,WAAW,KAAK,KAAM,GAAG,GACnEV,EAAI,SAASO,GAAM,GAAG,CAAC,GACvBP,EAAI,QAAA;AAAA,EAER;AAAA,EAEQ,iBACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,YAAQR,EAAW,MAAA;AAAA,MACjB,KAAK;AACH,aAAK,qBAAqBK,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AACrE;AAAA,MACF,KAAK;AACH,aAAK,mBAAmBH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AACnE;AAAA,MACF,KAAK;AACH,aAAK,gBAAgBH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAChE;AAAA,MACF,KAAK;AACH,aAAK,WAAWH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAC3D;AAAA,MACF,KAAK;AACH,aAAK,WAAWH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAC3D;AAAA,MACF,KAAK;AACH,aAAK,YAAYH,GAAKL,GAAYM,GAAUC,GAAQC,CAAQ;AAC5D;AAAA,IAAA;AAAA,EAEN;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAaa,GAAed,GAAgBD,GAA4B;AAC9E,UAAMgB,KAAcD,IAAQd,EAAO,SAASA,EAAO,OAAOA,EAAO;AACjE,WAAOD,EAAS,IAAIgB,IAAahB,EAAS;AAAA,EAC5C;AAAA,EAEQ,aAAae,GAAed,GAAgBD,GAA4B;AAC9E,UAAMgB,KAAcD,IAAQd,EAAO,SAASA,EAAO,OAAOA,EAAO;AACjE,WAAOD,EAAS,IAAIA,EAAS,UAAU,IAAIgB;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAMQ,qBACNjB,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMM,IAAI,KAAK,aAAad,EAAW,GAAGO,GAAQD,CAAQ;AAG1D,QAAIQ,IAAIR,EAAS,KAAKQ,IAAIR,EAAS,IAAIA,EAAS,OAAQ;AAExD,UAAMiB,IAASvB,EAAW,SAAS,SAC/B,KAAK,IAAI,KAAK,aAAaA,EAAW,MAAMO,GAAQD,CAAQ,GAAGA,EAAS,CAAC,IACzEA,EAAS,GACPkB,IAAOxB,EAAW,SAAS,SAC7B,KAAK,IAAI,KAAK,aAAaA,EAAW,MAAMO,GAAQD,CAAQ,GAAGA,EAAS,IAAIA,EAAS,KAAK,IAC1FA,EAAS,IAAIA,EAAS;AAE1B,IAAAD,EAAI,KAAA,GACJA,EAAI,cAAcL,EAAW,SAASH,EAAe,KAAK,OAC1DQ,EAAI,YAAYL,EAAW,aAAaH,EAAe,KAAK,WAC5DQ,EAAI,YAAYL,EAAW,YAAYH,EAAe,KAAK,QAAQ,GAEnEQ,EAAI,UAAA,GACJA,EAAI,OAAOkB,GAAQT,CAAC,GACpBT,EAAI,OAAOmB,GAAMV,CAAC,GAClBT,EAAI,OAAA,GAGAL,EAAW,SACb,KAAK;AAAA,MACHK;AAAA,MACAL,EAAW;AAAA,MACXuB;AAAA,MAAQC;AAAA,MAAMV;AAAA,MACdd,EAAW,iBAAiB;AAAA,MAC5B;AAAA,MACAA,EAAW;AAAA,MACXQ;AAAA,IAAA,GAIJH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,mBACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMK,IAAI,KAAK,aAAab,EAAW,GAAGO,GAAQD,CAAQ;AAG1D,QAAIO,IAAIP,EAAS,KAAKO,IAAIP,EAAS,IAAIA,EAAS,MAAO;AAEvD,UAAMmB,IAASzB,EAAW,SAAS,SAC/B,KAAK,IAAI,KAAK,aAAaA,EAAW,MAAMO,GAAQD,CAAQ,GAAGA,EAAS,IAAIA,EAAS,MAAM,IAC3FA,EAAS,GACPoB,IAAO1B,EAAW,SAAS,SAC7B,KAAK,IAAI,KAAK,aAAaA,EAAW,MAAMO,GAAQD,CAAQ,GAAGA,EAAS,CAAC,IACzEA,EAAS,IAAIA,EAAS;AAE1B,IAAAD,EAAI,KAAA,GACJA,EAAI,cAAcL,EAAW,SAASH,EAAe,KAAK,OAC1DQ,EAAI,YAAYL,EAAW,aAAaH,EAAe,KAAK,WAC5DQ,EAAI,YAAYL,EAAW,YAAYH,EAAe,KAAK,QAAQ,GAEnEQ,EAAI,UAAA,GACJA,EAAI,OAAOQ,GAAGY,CAAM,GACpBpB,EAAI,OAAOQ,GAAGa,CAAI,GAClBrB,EAAI,OAAA,GAGAL,EAAW,SACb,KAAK;AAAA,MACHK;AAAA,MACAL,EAAW;AAAA,MACXyB;AAAA,MAAQC;AAAA,MAAMb;AAAA,MACdb,EAAW,iBAAiB;AAAA,MAC5B;AAAA,MACAA,EAAW;AAAA,MACXQ;AAAA,IAAA,GAIJH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,gBACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMmB,IAAK,KAAK,aAAa3B,EAAW,MAAMO,GAAQD,CAAQ,GACxDsB,IAAK,KAAK,aAAa5B,EAAW,MAAMO,GAAQD,CAAQ,GACxDuB,IAAK,KAAK,aAAa7B,EAAW,MAAMO,GAAQD,CAAQ,GACxDwB,IAAK,KAAK,aAAa9B,EAAW,MAAMO,GAAQD,CAAQ,GAExDO,IAAI,KAAK,IAAIc,GAAIC,CAAE,GACnBd,IAAI,KAAK,IAAIe,GAAIC,CAAE,GACnBC,IAAQ,KAAK,IAAIH,IAAKD,CAAE,GACxBK,IAAS,KAAK,IAAIF,IAAKD,CAAE;AAE/B,IAAAxB,EAAI,KAAA,GAGAL,EAAW,cACbK,EAAI,YAAYL,EAAW,WAC3BK,EAAI,SAASQ,GAAGC,GAAGiB,GAAOC,CAAM,IAI9BhC,EAAW,gBACbK,EAAI,cAAcL,EAAW,aAC7BK,EAAI,YAAYL,EAAW,eAAeH,EAAe,UAAU,aACnEQ,EAAI,YAAYL,EAAW,cAAc,CAAA,CAAE,GAC3CK,EAAI,WAAWQ,GAAGC,GAAGiB,GAAOC,CAAM,IAIhChC,EAAW,SACb,KAAK,oBAAoBK,GAAKL,EAAW,OAAOa,IAAIkB,IAAQ,GAAGjB,IAAIkB,IAAS,GAAGxB,CAAQ,GAGzFH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,WACNA,GACAL,GACAM,GACAC,GACAC,GACM;AAEN,QAAIK,GAAWC,GAAWiB,GAAeC;AAEzC,QAAIhC,EAAW,SAAS,UAAaA,EAAW,SAAS,QAAW;AAElE,YAAM2B,IAAK,KAAK,aAAa3B,EAAW,MAAMO,GAAQD,CAAQ,GACxDsB,IAAK,KAAK,aAAa5B,EAAW,MAAMO,GAAQD,CAAQ;AAC9D,MAAAO,IAAI,KAAK,IAAIc,GAAIC,CAAE,GACnBG,IAAQ,KAAK,IAAIH,IAAKD,CAAE,GACxBb,IAAIR,EAAS,GACb0B,IAAS1B,EAAS,QAEdN,EAAW,SAAS,WAEtBgC,IADe,KAAK,aAAahC,EAAW,MAAMO,GAAQD,CAAQ,IAChDQ,IAEhBd,EAAW,SAAS,WAEtBc,IADe,KAAK,aAAad,EAAW,MAAMO,GAAQD,CAAQ,GAElE0B,IAAS1B,EAAS,IAAIA,EAAS,SAASQ;AAAA,IAE5C,WAAWd,EAAW,SAAS,UAAaA,EAAW,SAAS,QAAW;AAEzE,YAAM6B,IAAK,KAAK,aAAa7B,EAAW,MAAMO,GAAQD,CAAQ,GACxDwB,IAAK,KAAK,aAAa9B,EAAW,MAAMO,GAAQD,CAAQ;AAC9D,MAAAQ,IAAI,KAAK,IAAIe,GAAIC,CAAE,GACnBE,IAAS,KAAK,IAAIF,IAAKD,CAAE,GACzBhB,IAAIP,EAAS,GACbyB,IAAQzB,EAAS;AAAA,IACnB;AAEE;AAiBF,QAdAD,EAAI,KAAA,GAGJA,EAAI,YAAYL,EAAW,aAAaH,EAAe,UAAU,WACjEQ,EAAI,SAASQ,GAAGC,GAAGiB,GAAOC,CAAM,GAG5BhC,EAAW,gBACbK,EAAI,cAAcL,EAAW,aAC7BK,EAAI,YAAYL,EAAW,eAAe,GAC1CK,EAAI,WAAWQ,GAAGC,GAAGiB,GAAOC,CAAM,IAIhChC,EAAW,OAAO;AACpB,UAAIiC,IAASpB,IAAIkB,IAAQ,GACrBG,IAASpB,IAAIkB,IAAS;AAE1B,cAAQhC,EAAW,eAAA;AAAA,QACjB,KAAK;AACH,UAAAkC,IAASpB,IAAI;AACb;AAAA,QACF,KAAK;AACH,UAAAoB,IAASpB,IAAIkB,IAAS;AACtB;AAAA,QACF,KAAK;AACH,UAAAC,IAASpB,IAAI;AACb;AAAA,QACF,KAAK;AACH,UAAAoB,IAASpB,IAAIkB,IAAQ;AACrB;AAAA,MAAA;AAGJ,WAAK,oBAAoB1B,GAAKL,EAAW,OAAOiC,GAAQC,GAAQ1B,CAAQ;AAAA,IAC1E;AAEA,IAAAH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,WACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMK,IAAI,KAAK,aAAab,EAAW,GAAGO,GAAQD,CAAQ,GACpDQ,IAAI,KAAK,aAAad,EAAW,GAAGO,GAAQD,CAAQ;AAE1D,IAAAD,EAAI,KAAA,GAGAL,EAAW,aACbK,EAAI,UAAUQ,GAAGC,CAAC,GAClBT,EAAI,OAAQL,EAAW,WAAW,KAAK,KAAM,GAAG,GAChDK,EAAI,UAAU,CAACQ,GAAG,CAACC,CAAC;AAGtB,UAAMqB,IAAWnC,EAAW,YAAYH,EAAe,KAAK,UACtDuC,IAAapC,EAAW,cAAcH,EAAe,KAAK,YAC1DwC,IAAarC,EAAW,cAAc,UACtCsC,IAAaH,IAAW;AAE9B,IAAA9B,EAAI,OAAO,GAAGgC,CAAU,IAAIF,CAAQ,MAAMC,CAAU,IACpD/B,EAAI,YAAY,UAChBA,EAAI,eAAe;AAGnB,UAAMkC,IAAQvC,EAAW,KAAK,MAAM;AAAA,CAAI,GAClCwC,IAAUxC,EAAW,WAAWH,EAAe,KAAK;AAG1D,QAAI4C,IAAW;AACf,eAAWC,KAAQH;AACjB,MAAAE,IAAW,KAAK,IAAIA,GAAUpC,EAAI,YAAYqC,CAAI,EAAE,KAAK;AAG3D,UAAMC,IAAYF,IAAWD,IAAU,GACjCI,IAAcL,EAAM,SAASD,KAAeA,IAAaH,KAAYK,IAAU;AAGrF,QAAIK,IAAQhC,GACRiC,IAAQhC;AAEZ,YAAQd,EAAW,QAAA;AAAA,MACjB,KAAK;AACH,QAAA6C,KAASF,IAAY,GACrBG,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAC,KAASF,IAAY,GACrBG,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAC,KAASF,IAAY,GACrBG,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAC,KAASF,IAAY,GACrBG,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAE,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAE,KAASF,IAAa;AACtB;AAAA,MACF,KAAK;AACH,QAAAC,KAASF,IAAY;AACrB;AAAA,MACF,KAAK;AACH,QAAAE,KAASF,IAAY;AACrB;AAAA,IAAA;AAIJ,IAAI3C,EAAW,oBACbK,EAAI,YAAYL,EAAW,iBAC3BK,EAAI,UAAA,GACJA,EAAI;AAAA,MACFwC,IAAQF,IAAY;AAAA,MACpBG,IAAQF,IAAa;AAAA,MACrBD;AAAA,MACAC;AAAA,MACA;AAAA,IAAA,GAEFvC,EAAI,KAAA;AAIN,UAAM0C,IAAQ/C,EAAW,SAASH,EAAe,KAAK,OAChDmD,IAASF,IAASF,IAAa,IAAKJ,IAAWL,IAAW;AAEhE,IAAAI,EAAM,QAAQ,CAACG,GAAMO,MAAM;AACzB,WAAK,gBAAgB5C,GAAKqC,GAAMG,GAAOG,IAASC,IAAIX,GAAY;AAAA,QAC9D,UAAAH;AAAA,QACA,YAAAC;AAAA,QACA,YAAAC;AAAA,QACA,OAAAU;AAAA,QACA,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO/C,EAAW;AAAA,MAAA,GACjBQ,CAAQ;AAAA,IACb,CAAC,GAEDH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,YACNA,GACAL,GACAM,GACAC,GACAC,GACM;AACN,UAAMmB,IAAK,KAAK,aAAa3B,EAAW,IAAIO,GAAQD,CAAQ,GACtDuB,IAAK,KAAK,aAAa7B,EAAW,IAAIO,GAAQD,CAAQ,GACtDsB,IAAK,KAAK,aAAa5B,EAAW,IAAIO,GAAQD,CAAQ,GACtDwB,IAAK,KAAK,aAAa9B,EAAW,IAAIO,GAAQD,CAAQ;AAE5D,IAAAD,EAAI,KAAA,GACJA,EAAI,cAAcL,EAAW,SAASH,EAAe,MAAM,OAC3DQ,EAAI,YAAYL,EAAW,SAASH,EAAe,MAAM,OACzDQ,EAAI,YAAYL,EAAW,aAAaH,EAAe,MAAM,WAG7DQ,EAAI,UAAA,GACJA,EAAI,OAAOsB,GAAIE,CAAE,GACjBxB,EAAI,OAAOuB,GAAIE,CAAE,GACjBzB,EAAI,OAAA;AAGJ,UAAM6C,IAAWlD,EAAW,YAAYH,EAAe,MAAM,UACvDsD,IAAQ,KAAK,MAAMrB,IAAKD,GAAID,IAAKD,CAAE,GAEnCyB,IAAYpD,EAAW,aAAa;AA4B1C,QA1BIoD,MAAc,WAChB/C,EAAI,UAAA,GACJA,EAAI,OAAOuB,GAAIE,CAAE,GACjBzB,EAAI;AAAA,MACFuB,IAAKsB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,MAC5CrB,IAAKoB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,IAAA,GAG1CC,MAAc,YAChB/C,EAAI;AAAA,MACFuB,IAAKsB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,MAC5CrB,IAAKoB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,IAAA,GAE9C9C,EAAI,UAAA,GACJA,EAAI,KAAA,MAEJA,EAAI,OAAOuB,GAAIE,CAAE,GACjBzB,EAAI;AAAA,MACFuB,IAAKsB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,MAC5CrB,IAAKoB,IAAW,KAAK,IAAIC,IAAQ,KAAK,KAAK,CAAC;AAAA,IAAA,GAE9C9C,EAAI,OAAA,KAKJL,EAAW,UAAU;AACvB,YAAMqD,IAAYF,IAAQ,KAAK;AAC/B,MAAA9C,EAAI,UAAA,GACJA,EAAI,OAAOsB,GAAIE,CAAE,GACjBxB,EAAI;AAAA,QACFsB,IAAKuB,IAAW,KAAK,IAAIG,IAAY,KAAK,KAAK,CAAC;AAAA,QAChDxB,IAAKqB,IAAW,KAAK,IAAIG,IAAY,KAAK,KAAK,CAAC;AAAA,MAAA,GAElDhD,EAAI;AAAA,QACFsB,IAAKuB,IAAW,KAAK,IAAIG,IAAY,KAAK,KAAK,CAAC;AAAA,QAChDxB,IAAKqB,IAAW,KAAK,IAAIG,IAAY,KAAK,KAAK,CAAC;AAAA,MAAA,GAElDhD,EAAI,UAAA,GACJA,EAAI,KAAA;AAAA,IACN;AAGA,QAAIL,EAAW,OAAO;AACpB,YAAMsD,KAAQ3B,IAAKC,KAAM,GACnB2B,KAAQ1B,IAAKC,KAAM;AACzB,WAAK,oBAAoBzB,GAAKL,EAAW,OAAOsD,GAAMC,IAAO,IAAI/C,CAAQ;AAAA,IAC3E;AAEA,IAAAH,EAAI,QAAA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMQ,gBACNA,GACAmD,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAtD,GACM;AACN,IAAAH,EAAI,KAAA,GAEJA,EAAI,OAAO,GAAGR,EAAe,KAAK,QAAQ,MAAMA,EAAe,KAAK,UAAU;AAC9E,UAAMkE,IAAU1D,EAAI,YAAYmD,CAAK,GAC/BhB,IAAU,GACVG,IAAYoB,EAAQ,QAAQvB,IAAU,GACtCI,IAAa/C,EAAe,KAAK,WAAW2C,IAAU;AAE5D,QAAI3B,GAAWC;AAEf,QAAI+C,MAAgB,cAAc;AAGhC,cAFA/C,IAAI6C,GAEIC,GAAA;AAAA,QACN,KAAK;AACH,UAAA/C,IAAI4C,IAAQ,GACZpD,EAAI,YAAY;AAChB;AAAA,QACF,KAAK;AACH,UAAAQ,IAAI6C,IAAM,GACVrD,EAAI,YAAY;AAChB;AAAA,QACF;AACE,UAAAQ,KAAK4C,IAAQC,KAAO,GACpBrD,EAAI,YAAY;AAAA,MAAA;AAGpB,MAAAA,EAAI,eAAe,UACnBS,KAAK;AAAA,IACP,OAAO;AAGL,cAFAD,IAAI8C,GAEIC,GAAA;AAAA,QACN,KAAK;AACH,UAAA9C,IAAI2C,IAAQb;AACZ;AAAA,QACF,KAAK;AACH,UAAA9B,IAAI4C,IAAM;AACV;AAAA,QACF;AACE,UAAA5C,KAAK2C,IAAQC,KAAO;AAAA,MAAA;AAGxB,MAAArD,EAAI,YAAY,UAChBA,EAAI,eAAe;AAAA,IACrB;AAGA,QAAIyD,KAAmB,IAAM;AAC3B,MAAAzD,EAAI,YAAYyD,KAAmB;AACnC,YAAME,IAAM3D,EAAI,cAAc,SAASQ,IAAI2B,IACvCnC,EAAI,cAAc,UAAUQ,IAAI8B,IAAYH,IAC1C3B,IAAI8B,IAAY;AACtB,MAAAtC,EAAI,SAAS2D,GAAKlD,IAAI8B,IAAaJ,GAASG,GAAWC,CAAU;AAAA,IACnE;AAGA,SAAK,gBAAgBvC,GAAKmD,GAAO3C,GAAGC,GAAG;AAAA,MACrC,UAAUjB,EAAe,KAAK;AAAA,MAC9B,YAAYA,EAAe,KAAK;AAAA,MAChC,OAAOA,EAAe,KAAK;AAAA,MAC3B,OAAOQ,EAAI;AAAA,MACX,UAAUA,EAAI;AAAA,IAAA,GACbG,CAAQ,GAEXH,EAAI,QAAA;AAAA,EACN;AAAA,EAEQ,oBACNA,GACAmD,GACA3C,GACAC,GACAN,GACM;AACN,IAAAH,EAAI,KAAA,GAEJA,EAAI,OAAO,GAAGR,EAAe,KAAK,QAAQ,MAAMA,EAAe,KAAK,UAAU;AAC9E,UAAMkE,IAAU1D,EAAI,YAAYmD,CAAK,GAC/BhB,IAAU,GACVG,IAAYoB,EAAQ,QAAQvB,IAAU,GACtCI,IAAa/C,EAAe,KAAK,WAAW2C,IAAU;AAG5D,IAAAnC,EAAI,YAAY,sBAChBA,EAAI,UAAA,GACJA,EAAI,UAAUQ,IAAI8B,IAAY,GAAG7B,IAAI8B,IAAa,GAAGD,GAAWC,GAAY,CAAC,GAC7EvC,EAAI,KAAA,GAGJ,KAAK,gBAAgBA,GAAKmD,GAAO3C,GAAGC,GAAG;AAAA,MACrC,UAAUjB,EAAe,KAAK;AAAA,MAC9B,YAAYA,EAAe,KAAK;AAAA,MAChC,OAAOA,EAAe,KAAK;AAAA,MAC3B,OAAO;AAAA,MACP,UAAU;AAAA,IAAA,GACTW,CAAQ,GAEXH,EAAI,QAAA;AAAA,EACN;AACF;ACnyBA,MAAM4D,IAAsC;AAAA,EACxC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,YAAY;AAAA,EACvB,MAAM,CAAC,cAAc,WAAW,OAAO;AAC3C;AAOO,SAASC,EAAkBC,IAAmC,IAA0C;AAC3G,MAAIC;AAEJ,SAAO;AAAA,IACH,UAAUH;AAAA,IAEV,OAAO5D,GAAoB;AACvB,MAAA+D,IAAoB,IAAItE,EAAA,GAKxBO,EAAI,QAAQ,IAAI,WAAW+D,CAAiB;AAAA,IAChD;AAAA,IAEA,gBAAgB/D,GAAK;AACjB,YAAMC,IAAWD,EAAI,OAAO,UACtBgE,IAAahE,EAAI,KAAK,cAAA,GAGtBiE,IAAcjE,EAAI,UAAe,iBAAiB,GAClDG,IAAW8D,KAAA,gBAAAA,EAAa;AAG9B,MAAAF,EAAkB;AAAA,QACd/D,EAAI,OAAO;AAAA,QACXC;AAAA,QACA+D;AAAA,QACA7D;AAAA,MAAA;AAAA,IAER;AAAA,IAEA,UAAU+D,GAAqB;AAC3B,MAAAH,EAAkB,MAAA;AAAA,IACtB;AAAA,IAEA,KAAK;AAAA,MACD,aAAa;AACT,eAAOA;AAAA,MACX;AAAA,MACA,IAAIpE,GAAwB;AACxB,eAAOoE,EAAkB,IAAIpE,CAAU;AAAA,MAC3C;AAAA,MACA,OAAOC,GAAY;AACf,eAAOmE,EAAkB,OAAOnE,CAAE;AAAA,MACtC;AAAA,MACA,OAAOA,GAAYE,GAA8B;AAC7C,eAAOiE,EAAkB,OAAOnE,GAAIE,CAAO;AAAA,MAC/C;AAAA,MACA,IAAIF,GAAY;AACZ,eAAOmE,EAAkB,IAAInE,CAAE;AAAA,MACnC;AAAA,MACA,SAAS;AACL,eAAOmE,EAAkB,OAAA;AAAA,MAC7B;AAAA,MACA,QAAQ;AACJ,QAAAA,EAAkB,MAAA;AAAA,MACtB;AAAA,IAAA;AAAA,EACJ;AAER;"}
@@ -130,7 +130,7 @@ const j = {
130
130
  name: "Anomaly Detection",
131
131
  version: "1.0.0",
132
132
  description: "Real-time anomaly detection with multiple algorithms",
133
- author: "Sci Plot",
133
+ author: "Velo Plot",
134
134
  category: "analysis"
135
135
  };
136
136
  function b(l = {}) {
@@ -1 +1 @@
1
- {"version":3,"file":"anomaly-detection.js","sources":["../../src/plugins/anomaly-detection/algorithms.ts","../../src/plugins/anomaly-detection/index.ts"],"sourcesContent":["/**\n * Anomaly Detection Algorithms\n * Each method has distinct characteristics for different use cases\n */\n\nimport type { AnomalyPoint, AnomalyMethod } from './types';\n\n/**\n * Z-Score method: Standard statistical approach\n * - Uses MEAN and STANDARD DEVIATION (parametric)\n * - Assumes normal distribution\n * - Sensitive to extreme outliers\n * - Best for: Clean, normally distributed data\n */\nexport function detectZScore(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n threshold: number = 3\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 3) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Calculate local MEAN (parametric - sensitive to outliers)\n let localSum = 0;\n let count = 0;\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localSum += y[j];\n count++;\n }\n }\n const localMean = localSum / count;\n \n // Calculate local STANDARD DEVIATION (parametric)\n let localSumSq = 0;\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localSumSq += Math.pow(y[j] - localMean, 2);\n }\n }\n const localStdDev = Math.sqrt(localSumSq / count);\n \n if (localStdDev === 0) continue;\n \n // Z-score: measures how many standard deviations away from mean\n const zScore = Math.abs((y[i] - localMean) / localStdDev);\n \n if (zScore > threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: zScore,\n method: 'zscore'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * MAD (Median Absolute Deviation) method: Robust statistical approach\n * - Uses MEDIAN instead of mean (non-parametric)\n * - Robust to outliers in the window\n * - Doesn't assume normal distribution\n * - Best for: Data with existing outliers, skewed distributions\n */\nexport function detectMAD(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n threshold: number = 3.5\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 3) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Get local window values\n const localValues: number[] = [];\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localValues.push(y[j]);\n }\n }\n \n // Calculate MEDIAN (robust to outliers)\n localValues.sort((a, b) => a - b);\n const localMedian = localValues[Math.floor(localValues.length / 2)];\n \n // Calculate MAD (Median Absolute Deviation - robust measure of spread)\n const deviations = localValues.map(v => Math.abs(v - localMedian));\n deviations.sort((a, b) => a - b);\n const mad = deviations[Math.floor(deviations.length / 2)];\n \n if (mad === 0) continue;\n \n // Modified Z-score using MAD (more robust than standard Z-score)\n // 0.6745 is the consistency constant for normal distribution\n const modifiedZScore = Math.abs((0.6745 * (y[i] - localMedian)) / mad);\n \n if (modifiedZScore > threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: modifiedZScore,\n method: 'mad'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * IQR (Interquartile Range) method: Quartile-based approach\n * - Uses PERCENTILES (25th and 75th)\n * - Classic box-plot outlier detection\n * - Non-parametric, distribution-free\n * - Best for: General purpose, well-understood method\n */\nexport function detectIQR(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n multiplier: number = 1.5\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 4) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Get local window values\n const localValues: number[] = [];\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localValues.push(y[j]);\n }\n }\n \n // Calculate QUARTILES (percentile-based)\n localValues.sort((a, b) => a - b);\n const q1Index = Math.floor(localValues.length * 0.25);\n const q3Index = Math.floor(localValues.length * 0.75);\n const q1 = localValues[q1Index];\n const q3 = localValues[q3Index];\n const iqr = q3 - q1;\n \n if (iqr === 0) continue;\n \n // IQR method: points outside [Q1 - k*IQR, Q3 + k*IQR] are outliers\n // k=1.5 for outliers, k=3.0 for extreme outliers\n const lowerBound = q1 - multiplier * iqr;\n const upperBound = q3 + multiplier * iqr;\n \n if (y[i] < lowerBound || y[i] > upperBound) {\n const score = y[i] < lowerBound \n ? (lowerBound - y[i]) / iqr\n : (y[i] - upperBound) / iqr;\n \n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score,\n method: 'iqr'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * Simplified Isolation Forest: Detects anomalies using random partitioning\n * - Machine learning approach\n * - Isolates anomalies through random splits\n * - Works well with high-dimensional data\n * - Best for: Complex patterns, unknown distributions\n */\nexport function detectIsolationForest(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n contamination: number = 0.05,\n numTrees: number = 10\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 10) return [];\n \n // Calculate anomaly scores for each point\n const scores = new Float32Array(n);\n \n for (let i = 0; i < n; i++) {\n let totalDepth = 0;\n \n // Build multiple trees\n for (let t = 0; t < numTrees; t++) {\n totalDepth += isolationDepth(y, i, 0, 8); // Max depth 8\n }\n \n // Average depth (normalized)\n const avgDepth = totalDepth / numTrees;\n const c = 2 * (Math.log(n - 1) + 0.5772156649) - (2 * (n - 1) / n);\n scores[i] = Math.pow(2, -avgDepth / c);\n }\n \n // Sort scores to find threshold\n const sortedScores = Array.from(scores).sort((a, b) => b - a);\n const thresholdIndex = Math.floor(n * contamination);\n const threshold = sortedScores[thresholdIndex];\n \n // Find anomalies\n const anomalies: AnomalyPoint[] = [];\n for (let i = 0; i < n; i++) {\n if (scores[i] >= threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: scores[i],\n method: 'isolation-forest'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * Helper: Calculate isolation depth for a point\n */\nfunction isolationDepth(\n data: Float32Array | Float64Array,\n pointIndex: number,\n currentDepth: number,\n maxDepth: number\n): number {\n if (currentDepth >= maxDepth) return currentDepth;\n \n // Random split\n const min = Math.min(...Array.from(data));\n const max = Math.max(...Array.from(data));\n const splitValue = min + Math.random() * (max - min);\n \n // Check which side the point falls on\n if (data[pointIndex] < splitValue) {\n return isolationDepth(data, pointIndex, currentDepth + 1, maxDepth);\n } else {\n return isolationDepth(data, pointIndex, currentDepth + 1, maxDepth);\n }\n}\n\n/**\n * Main detection function - routes to appropriate algorithm\n */\nexport function detectAnomalies(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n method: AnomalyMethod,\n sensitivity: number\n): AnomalyPoint[] {\n switch (method) {\n case 'zscore':\n return detectZScore(x, y, sensitivity);\n case 'mad':\n return detectMAD(x, y, sensitivity);\n case 'iqr':\n return detectIQR(x, y, sensitivity);\n case 'isolation-forest':\n return detectIsolationForest(x, y, sensitivity);\n default:\n return detectZScore(x, y, sensitivity);\n }\n}\n","/**\n * Anomaly Detection Plugin\n * \n * Detects anomalies in chart data using statistical methods.\n * This is a simplified version that provides the core API.\n * \n * @module plugins/anomaly-detection\n */\n\nimport type { ChartPlugin, PluginContext } from '../types';\nimport type { \n PluginAnomalyDetectionConfig, \n AnomalyDetectionResult\n} from './types';\nimport { detectAnomalies } from './algorithms';\n\nexport type { \n PluginAnomalyDetectionConfig,\n AnomalyDetectionResult,\n AnomalyPoint,\n AnomalyMethod\n} from './types';\n\nconst DEFAULT_CONFIG: Required<PluginAnomalyDetectionConfig> = {\n method: 'zscore',\n sensitivity: 3,\n realtime: false,\n highlight: true,\n highlightColor: '#ff0000',\n highlightSize: 8,\n minWindowSize: 30,\n rollingWindow: false,\n windowSize: 100,\n seriesIds: []\n};\n\nexport const manifestAnomalyDetection = {\n id: 'anomaly-detection',\n name: 'Anomaly Detection',\n version: '1.0.0' as `${number}.${number}.${number}`,\n description: 'Real-time anomaly detection with multiple algorithms',\n author: 'Sci Plot',\n category: 'analysis' as const\n};\n\n/**\n * Anomaly Detection Plugin Factory\n */\nexport function PluginAnomalyDetection(\n userConfig: PluginAnomalyDetectionConfig = {}\n): ChartPlugin<PluginAnomalyDetectionConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n const detectionResults = new Map<string, AnomalyDetectionResult>();\n \n return {\n manifest: manifestAnomalyDetection,\n \n onInit(pluginCtx: PluginContext) {\n ctx = pluginCtx;\n },\n \n onDestroy() {\n detectionResults.clear();\n ctx = null;\n },\n \n api: {\n /**\n * Run anomaly detection on a specific series\n */\n detect(seriesId: string): AnomalyDetectionResult | null {\n if (!ctx) return null;\n \n const series = ctx.data.getSeries(seriesId);\n if (!series) return null;\n \n const data = series.getData();\n if (!data || data.x.length < config.minWindowSize) return null;\n \n // Use rolling window if enabled\n let x = data.x;\n let y = data.y;\n \n if (config.rollingWindow && data.x.length > config.windowSize) {\n const start = data.x.length - config.windowSize;\n x = data.x.slice(start);\n y = data.y.slice(start);\n }\n \n // Run detection\n const anomalies = detectAnomalies(x, y, config.method, config.sensitivity);\n \n // Store results\n const result: AnomalyDetectionResult = {\n seriesId,\n anomalies,\n totalPoints: y.length,\n method: config.method,\n threshold: config.sensitivity,\n timestamp: Date.now()\n };\n \n detectionResults.set(seriesId, result);\n \n // Emit event\n ctx.events.emit('anomaly:detected', result);\n \n return result;\n },\n \n /**\n * Run detection on all series\n */\n detectAll(): Map<string, AnomalyDetectionResult> {\n if (!ctx) return new Map();\n \n const results = new Map<string, AnomalyDetectionResult>();\n const allSeries = ctx.data.getAllSeries();\n \n allSeries.forEach((_series, seriesId) => {\n const result = (this as any).detect(String(seriesId));\n if (result) {\n results.set(String(seriesId), result);\n }\n });\n \n return results;\n },\n \n /**\n * Get detection results for a specific series\n */\n getResults(seriesId: string): AnomalyDetectionResult | undefined {\n return detectionResults.get(seriesId);\n },\n \n /**\n * Get all detection results\n */\n getAllResults(): Map<string, AnomalyDetectionResult> {\n return new Map(detectionResults);\n },\n \n /**\n * Clear all detection results\n */\n clear(): void {\n detectionResults.clear();\n },\n \n /**\n * Update configuration\n */\n setConfig(newConfig: Partial<PluginAnomalyDetectionConfig>): void {\n Object.assign(config, newConfig);\n },\n \n /**\n * Get current configuration\n */\n getConfig(): PluginAnomalyDetectionConfig {\n return { ...config };\n }\n }\n };\n}\n"],"names":["detectZScore","x","y","threshold","n","anomalies","windowSize","i","start","end","localSum","count","j","localMean","localSumSq","localStdDev","zScore","detectMAD","localValues","a","b","localMedian","deviations","v","mad","modifiedZScore","detectIQR","multiplier","q1Index","q3Index","q1","q3","iqr","lowerBound","upperBound","score","detectIsolationForest","contamination","numTrees","scores","totalDepth","t","isolationDepth","avgDepth","c","sortedScores","thresholdIndex","data","pointIndex","currentDepth","maxDepth","min","max","splitValue","detectAnomalies","method","sensitivity","DEFAULT_CONFIG","manifestAnomalyDetection","PluginAnomalyDetection","userConfig","config","ctx","detectionResults","pluginCtx","seriesId","series","result","results","_series","newConfig"],"mappings":"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"}
1
+ {"version":3,"file":"anomaly-detection.js","sources":["../../src/plugins/anomaly-detection/algorithms.ts","../../src/plugins/anomaly-detection/index.ts"],"sourcesContent":["/**\n * Anomaly Detection Algorithms\n * Each method has distinct characteristics for different use cases\n */\n\nimport type { AnomalyPoint, AnomalyMethod } from './types';\n\n/**\n * Z-Score method: Standard statistical approach\n * - Uses MEAN and STANDARD DEVIATION (parametric)\n * - Assumes normal distribution\n * - Sensitive to extreme outliers\n * - Best for: Clean, normally distributed data\n */\nexport function detectZScore(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n threshold: number = 3\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 3) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Calculate local MEAN (parametric - sensitive to outliers)\n let localSum = 0;\n let count = 0;\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localSum += y[j];\n count++;\n }\n }\n const localMean = localSum / count;\n \n // Calculate local STANDARD DEVIATION (parametric)\n let localSumSq = 0;\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localSumSq += Math.pow(y[j] - localMean, 2);\n }\n }\n const localStdDev = Math.sqrt(localSumSq / count);\n \n if (localStdDev === 0) continue;\n \n // Z-score: measures how many standard deviations away from mean\n const zScore = Math.abs((y[i] - localMean) / localStdDev);\n \n if (zScore > threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: zScore,\n method: 'zscore'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * MAD (Median Absolute Deviation) method: Robust statistical approach\n * - Uses MEDIAN instead of mean (non-parametric)\n * - Robust to outliers in the window\n * - Doesn't assume normal distribution\n * - Best for: Data with existing outliers, skewed distributions\n */\nexport function detectMAD(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n threshold: number = 3.5\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 3) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Get local window values\n const localValues: number[] = [];\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localValues.push(y[j]);\n }\n }\n \n // Calculate MEDIAN (robust to outliers)\n localValues.sort((a, b) => a - b);\n const localMedian = localValues[Math.floor(localValues.length / 2)];\n \n // Calculate MAD (Median Absolute Deviation - robust measure of spread)\n const deviations = localValues.map(v => Math.abs(v - localMedian));\n deviations.sort((a, b) => a - b);\n const mad = deviations[Math.floor(deviations.length / 2)];\n \n if (mad === 0) continue;\n \n // Modified Z-score using MAD (more robust than standard Z-score)\n // 0.6745 is the consistency constant for normal distribution\n const modifiedZScore = Math.abs((0.6745 * (y[i] - localMedian)) / mad);\n \n if (modifiedZScore > threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: modifiedZScore,\n method: 'mad'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * IQR (Interquartile Range) method: Quartile-based approach\n * - Uses PERCENTILES (25th and 75th)\n * - Classic box-plot outlier detection\n * - Non-parametric, distribution-free\n * - Best for: General purpose, well-understood method\n */\nexport function detectIQR(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n multiplier: number = 1.5\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 4) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Get local window values\n const localValues: number[] = [];\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localValues.push(y[j]);\n }\n }\n \n // Calculate QUARTILES (percentile-based)\n localValues.sort((a, b) => a - b);\n const q1Index = Math.floor(localValues.length * 0.25);\n const q3Index = Math.floor(localValues.length * 0.75);\n const q1 = localValues[q1Index];\n const q3 = localValues[q3Index];\n const iqr = q3 - q1;\n \n if (iqr === 0) continue;\n \n // IQR method: points outside [Q1 - k*IQR, Q3 + k*IQR] are outliers\n // k=1.5 for outliers, k=3.0 for extreme outliers\n const lowerBound = q1 - multiplier * iqr;\n const upperBound = q3 + multiplier * iqr;\n \n if (y[i] < lowerBound || y[i] > upperBound) {\n const score = y[i] < lowerBound \n ? (lowerBound - y[i]) / iqr\n : (y[i] - upperBound) / iqr;\n \n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score,\n method: 'iqr'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * Simplified Isolation Forest: Detects anomalies using random partitioning\n * - Machine learning approach\n * - Isolates anomalies through random splits\n * - Works well with high-dimensional data\n * - Best for: Complex patterns, unknown distributions\n */\nexport function detectIsolationForest(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n contamination: number = 0.05,\n numTrees: number = 10\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 10) return [];\n \n // Calculate anomaly scores for each point\n const scores = new Float32Array(n);\n \n for (let i = 0; i < n; i++) {\n let totalDepth = 0;\n \n // Build multiple trees\n for (let t = 0; t < numTrees; t++) {\n totalDepth += isolationDepth(y, i, 0, 8); // Max depth 8\n }\n \n // Average depth (normalized)\n const avgDepth = totalDepth / numTrees;\n const c = 2 * (Math.log(n - 1) + 0.5772156649) - (2 * (n - 1) / n);\n scores[i] = Math.pow(2, -avgDepth / c);\n }\n \n // Sort scores to find threshold\n const sortedScores = Array.from(scores).sort((a, b) => b - a);\n const thresholdIndex = Math.floor(n * contamination);\n const threshold = sortedScores[thresholdIndex];\n \n // Find anomalies\n const anomalies: AnomalyPoint[] = [];\n for (let i = 0; i < n; i++) {\n if (scores[i] >= threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: scores[i],\n method: 'isolation-forest'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * Helper: Calculate isolation depth for a point\n */\nfunction isolationDepth(\n data: Float32Array | Float64Array,\n pointIndex: number,\n currentDepth: number,\n maxDepth: number\n): number {\n if (currentDepth >= maxDepth) return currentDepth;\n \n // Random split\n const min = Math.min(...Array.from(data));\n const max = Math.max(...Array.from(data));\n const splitValue = min + Math.random() * (max - min);\n \n // Check which side the point falls on\n if (data[pointIndex] < splitValue) {\n return isolationDepth(data, pointIndex, currentDepth + 1, maxDepth);\n } else {\n return isolationDepth(data, pointIndex, currentDepth + 1, maxDepth);\n }\n}\n\n/**\n * Main detection function - routes to appropriate algorithm\n */\nexport function detectAnomalies(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n method: AnomalyMethod,\n sensitivity: number\n): AnomalyPoint[] {\n switch (method) {\n case 'zscore':\n return detectZScore(x, y, sensitivity);\n case 'mad':\n return detectMAD(x, y, sensitivity);\n case 'iqr':\n return detectIQR(x, y, sensitivity);\n case 'isolation-forest':\n return detectIsolationForest(x, y, sensitivity);\n default:\n return detectZScore(x, y, sensitivity);\n }\n}\n","/**\n * Anomaly Detection Plugin\n * \n * Detects anomalies in chart data using statistical methods.\n * This is a simplified version that provides the core API.\n * \n * @module plugins/anomaly-detection\n */\n\nimport type { ChartPlugin, PluginContext } from '../types';\nimport type { \n PluginAnomalyDetectionConfig, \n AnomalyDetectionResult\n} from './types';\nimport { detectAnomalies } from './algorithms';\n\nexport type { \n PluginAnomalyDetectionConfig,\n AnomalyDetectionResult,\n AnomalyPoint,\n AnomalyMethod\n} from './types';\n\nconst DEFAULT_CONFIG: Required<PluginAnomalyDetectionConfig> = {\n method: 'zscore',\n sensitivity: 3,\n realtime: false,\n highlight: true,\n highlightColor: '#ff0000',\n highlightSize: 8,\n minWindowSize: 30,\n rollingWindow: false,\n windowSize: 100,\n seriesIds: []\n};\n\nexport const manifestAnomalyDetection = {\n id: 'anomaly-detection',\n name: 'Anomaly Detection',\n version: '1.0.0' as `${number}.${number}.${number}`,\n description: 'Real-time anomaly detection with multiple algorithms',\n author: 'Velo Plot',\n category: 'analysis' as const\n};\n\n/**\n * Anomaly Detection Plugin Factory\n */\nexport function PluginAnomalyDetection(\n userConfig: PluginAnomalyDetectionConfig = {}\n): ChartPlugin<PluginAnomalyDetectionConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n const detectionResults = new Map<string, AnomalyDetectionResult>();\n \n return {\n manifest: manifestAnomalyDetection,\n \n onInit(pluginCtx: PluginContext) {\n ctx = pluginCtx;\n },\n \n onDestroy() {\n detectionResults.clear();\n ctx = null;\n },\n \n api: {\n /**\n * Run anomaly detection on a specific series\n */\n detect(seriesId: string): AnomalyDetectionResult | null {\n if (!ctx) return null;\n \n const series = ctx.data.getSeries(seriesId);\n if (!series) return null;\n \n const data = series.getData();\n if (!data || data.x.length < config.minWindowSize) return null;\n \n // Use rolling window if enabled\n let x = data.x;\n let y = data.y;\n \n if (config.rollingWindow && data.x.length > config.windowSize) {\n const start = data.x.length - config.windowSize;\n x = data.x.slice(start);\n y = data.y.slice(start);\n }\n \n // Run detection\n const anomalies = detectAnomalies(x, y, config.method, config.sensitivity);\n \n // Store results\n const result: AnomalyDetectionResult = {\n seriesId,\n anomalies,\n totalPoints: y.length,\n method: config.method,\n threshold: config.sensitivity,\n timestamp: Date.now()\n };\n \n detectionResults.set(seriesId, result);\n \n // Emit event\n ctx.events.emit('anomaly:detected', result);\n \n return result;\n },\n \n /**\n * Run detection on all series\n */\n detectAll(): Map<string, AnomalyDetectionResult> {\n if (!ctx) return new Map();\n \n const results = new Map<string, AnomalyDetectionResult>();\n const allSeries = ctx.data.getAllSeries();\n \n allSeries.forEach((_series, seriesId) => {\n const result = (this as any).detect(String(seriesId));\n if (result) {\n results.set(String(seriesId), result);\n }\n });\n \n return results;\n },\n \n /**\n * Get detection results for a specific series\n */\n getResults(seriesId: string): AnomalyDetectionResult | undefined {\n return detectionResults.get(seriesId);\n },\n \n /**\n * Get all detection results\n */\n getAllResults(): Map<string, AnomalyDetectionResult> {\n return new Map(detectionResults);\n },\n \n /**\n * Clear all detection results\n */\n clear(): void {\n detectionResults.clear();\n },\n \n /**\n * Update configuration\n */\n setConfig(newConfig: Partial<PluginAnomalyDetectionConfig>): void {\n Object.assign(config, newConfig);\n },\n \n /**\n * Get current configuration\n */\n getConfig(): PluginAnomalyDetectionConfig {\n return { ...config };\n }\n }\n };\n}\n"],"names":["detectZScore","x","y","threshold","n","anomalies","windowSize","i","start","end","localSum","count","j","localMean","localSumSq","localStdDev","zScore","detectMAD","localValues","a","b","localMedian","deviations","v","mad","modifiedZScore","detectIQR","multiplier","q1Index","q3Index","q1","q3","iqr","lowerBound","upperBound","score","detectIsolationForest","contamination","numTrees","scores","totalDepth","t","isolationDepth","avgDepth","c","sortedScores","thresholdIndex","data","pointIndex","currentDepth","maxDepth","min","max","splitValue","detectAnomalies","method","sensitivity","DEFAULT_CONFIG","manifestAnomalyDetection","PluginAnomalyDetection","userConfig","config","ctx","detectionResults","pluginCtx","seriesId","series","result","results","_series","newConfig"],"mappings":"AAcO,SAASA,EACdC,GACAC,GACAC,IAAoB,GACJ;AAChB,QAAMC,IAAIF,EAAE;AACZ,MAAIE,IAAI,EAAG,QAAO,CAAA;AAElB,QAAMC,IAA4B,CAAA,GAC5BC,IAAa,KAAK,IAAI,IAAI,KAAK,MAAMF,IAAI,EAAE,CAAC;AAElD,WAASG,IAAI,GAAGA,IAAIH,GAAGG,KAAK;AAC1B,UAAMC,IAAQ,KAAK,IAAI,GAAGD,IAAID,CAAU,GAClCG,IAAM,KAAK,IAAIL,GAAGG,IAAID,IAAa,CAAC;AAG1C,QAAII,IAAW,GACXC,IAAQ;AACZ,aAASC,IAAIJ,GAAOI,IAAIH,GAAKG;AAC3B,MAAIA,MAAML,MACRG,KAAYR,EAAEU,CAAC,GACfD;AAGJ,UAAME,IAAYH,IAAWC;AAG7B,QAAIG,IAAa;AACjB,aAASF,IAAIJ,GAAOI,IAAIH,GAAKG;AAC3B,MAAIA,MAAML,MACRO,KAAc,KAAK,IAAIZ,EAAEU,CAAC,IAAIC,GAAW,CAAC;AAG9C,UAAME,IAAc,KAAK,KAAKD,IAAaH,CAAK;AAEhD,QAAII,MAAgB,EAAG;AAGvB,UAAMC,IAAS,KAAK,KAAKd,EAAEK,CAAC,IAAIM,KAAaE,CAAW;AAExD,IAAIC,IAASb,KACXE,EAAU,KAAK;AAAA,MACb,OAAOE;AAAA,MACP,GAAGN,EAAEM,CAAC;AAAA,MACN,GAAGL,EAAEK,CAAC;AAAA,MACN,OAAOS;AAAA,MACP,QAAQ;AAAA,IAAA,CACT;AAAA,EAEL;AAEA,SAAOX;AACT;AASO,SAASY,EACdhB,GACAC,GACAC,IAAoB,KACJ;AAChB,QAAMC,IAAIF,EAAE;AACZ,MAAIE,IAAI,EAAG,QAAO,CAAA;AAElB,QAAMC,IAA4B,CAAA,GAC5BC,IAAa,KAAK,IAAI,IAAI,KAAK,MAAMF,IAAI,EAAE,CAAC;AAElD,WAASG,IAAI,GAAGA,IAAIH,GAAGG,KAAK;AAC1B,UAAMC,IAAQ,KAAK,IAAI,GAAGD,IAAID,CAAU,GAClCG,IAAM,KAAK,IAAIL,GAAGG,IAAID,IAAa,CAAC,GAGpCY,IAAwB,CAAA;AAC9B,aAASN,IAAIJ,GAAOI,IAAIH,GAAKG;AAC3B,MAAIA,MAAML,KACRW,EAAY,KAAKhB,EAAEU,CAAC,CAAC;AAKzB,IAAAM,EAAY,KAAK,CAACC,GAAGC,MAAMD,IAAIC,CAAC;AAChC,UAAMC,IAAcH,EAAY,KAAK,MAAMA,EAAY,SAAS,CAAC,CAAC,GAG5DI,IAAaJ,EAAY,IAAI,CAAAK,MAAK,KAAK,IAAIA,IAAIF,CAAW,CAAC;AACjE,IAAAC,EAAW,KAAK,CAACH,GAAGC,MAAMD,IAAIC,CAAC;AAC/B,UAAMI,IAAMF,EAAW,KAAK,MAAMA,EAAW,SAAS,CAAC,CAAC;AAExD,QAAIE,MAAQ,EAAG;AAIf,UAAMC,IAAiB,KAAK,IAAK,UAAUvB,EAAEK,CAAC,IAAIc,KAAgBG,CAAG;AAErE,IAAIC,IAAiBtB,KACnBE,EAAU,KAAK;AAAA,MACb,OAAOE;AAAA,MACP,GAAGN,EAAEM,CAAC;AAAA,MACN,GAAGL,EAAEK,CAAC;AAAA,MACN,OAAOkB;AAAA,MACP,QAAQ;AAAA,IAAA,CACT;AAAA,EAEL;AAEA,SAAOpB;AACT;AASO,SAASqB,EACdzB,GACAC,GACAyB,IAAqB,KACL;AAChB,QAAMvB,IAAIF,EAAE;AACZ,MAAIE,IAAI,EAAG,QAAO,CAAA;AAElB,QAAMC,IAA4B,CAAA,GAC5BC,IAAa,KAAK,IAAI,IAAI,KAAK,MAAMF,IAAI,EAAE,CAAC;AAElD,WAASG,IAAI,GAAGA,IAAIH,GAAGG,KAAK;AAC1B,UAAMC,IAAQ,KAAK,IAAI,GAAGD,IAAID,CAAU,GAClCG,IAAM,KAAK,IAAIL,GAAGG,IAAID,IAAa,CAAC,GAGpCY,IAAwB,CAAA;AAC9B,aAASN,IAAIJ,GAAOI,IAAIH,GAAKG;AAC3B,MAAIA,MAAML,KACRW,EAAY,KAAKhB,EAAEU,CAAC,CAAC;AAKzB,IAAAM,EAAY,KAAK,CAACC,GAAGC,MAAMD,IAAIC,CAAC;AAChC,UAAMQ,IAAU,KAAK,MAAMV,EAAY,SAAS,IAAI,GAC9CW,IAAU,KAAK,MAAMX,EAAY,SAAS,IAAI,GAC9CY,IAAKZ,EAAYU,CAAO,GACxBG,IAAKb,EAAYW,CAAO,GACxBG,IAAMD,IAAKD;AAEjB,QAAIE,MAAQ,EAAG;AAIf,UAAMC,IAAaH,IAAKH,IAAaK,GAC/BE,IAAaH,IAAKJ,IAAaK;AAErC,QAAI9B,EAAEK,CAAC,IAAI0B,KAAc/B,EAAEK,CAAC,IAAI2B,GAAY;AAC1C,YAAMC,IAAQjC,EAAEK,CAAC,IAAI0B,KAChBA,IAAa/B,EAAEK,CAAC,KAAKyB,KACrB9B,EAAEK,CAAC,IAAI2B,KAAcF;AAE1B,MAAA3B,EAAU,KAAK;AAAA,QACb,OAAOE;AAAA,QACP,GAAGN,EAAEM,CAAC;AAAA,QACN,GAAGL,EAAEK,CAAC;AAAA,QACN,OAAA4B;AAAA,QACA,QAAQ;AAAA,MAAA,CACT;AAAA,IACH;AAAA,EACF;AAEA,SAAO9B;AACT;AASO,SAAS+B,EACdnC,GACAC,GACAmC,IAAwB,MACxBC,IAAmB,IACH;AAChB,QAAM,IAAIpC,EAAE;AACZ,MAAI,IAAI,GAAI,QAAO,CAAA;AAGnB,QAAMqC,IAAS,IAAI,aAAa,CAAC;AAEjC,WAAShC,IAAI,GAAGA,IAAI,GAAGA,KAAK;AAC1B,QAAIiC,IAAa;AAGjB,aAASC,IAAI,GAAGA,IAAIH,GAAUG;AAC5B,MAAAD,KAAcE,EAAexC,GAAGK,GAAG,GAAG,CAAC;AAIzC,UAAMoC,IAAWH,IAAaF,GACxBM,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,gBAAiB,KAAK,IAAI,KAAK;AAChE,IAAAL,EAAOhC,CAAC,IAAI,KAAK,IAAI,GAAG,CAACoC,IAAWC,CAAC;AAAA,EACvC;AAGA,QAAMC,IAAe,MAAM,KAAKN,CAAM,EAAE,KAAK,CAACpB,GAAGC,MAAMA,IAAID,CAAC,GACtD2B,IAAiB,KAAK,MAAM,IAAIT,CAAa,GAC7ClC,IAAY0C,EAAaC,CAAc,GAGvCzC,IAA4B,CAAA;AAClC,WAASE,IAAI,GAAGA,IAAI,GAAGA;AACrB,IAAIgC,EAAOhC,CAAC,KAAKJ,KACfE,EAAU,KAAK;AAAA,MACb,OAAOE;AAAA,MACP,GAAGN,EAAEM,CAAC;AAAA,MACN,GAAGL,EAAEK,CAAC;AAAA,MACN,OAAOgC,EAAOhC,CAAC;AAAA,MACf,QAAQ;AAAA,IAAA,CACT;AAIL,SAAOF;AACT;AAKA,SAASqC,EACPK,GACAC,GACAC,GACAC,GACQ;AACR,MAAID,KAAgBC,EAAU,QAAOD;AAGrC,QAAME,IAAM,KAAK,IAAI,GAAG,MAAM,KAAKJ,CAAI,CAAC,GAClCK,IAAM,KAAK,IAAI,GAAG,MAAM,KAAKL,CAAI,CAAC,GAClCM,IAAaF,IAAM,KAAK,OAAA,KAAYC,IAAMD;AAGhD,SAAIJ,EAAKC,CAAU,IAAIK,GACdX,EAAeK,GAAMC,GAAYC,IAAe,GAAGC,CAAQ;AAItE;AAKO,SAASI,EACdrD,GACAC,GACAqD,GACAC,GACgB;AAChB,UAAQD,GAAA;AAAA,IACN,KAAK;AACH,aAAOvD,EAAaC,GAAGC,GAAGsD,CAAW;AAAA,IACvC,KAAK;AACH,aAAOvC,EAAUhB,GAAGC,GAAGsD,CAAW;AAAA,IACpC,KAAK;AACH,aAAO9B,EAAUzB,GAAGC,GAAGsD,CAAW;AAAA,IACpC,KAAK;AACH,aAAOpB,EAAsBnC,GAAGC,GAAGsD,CAAW;AAAA,IAChD;AACE,aAAOxD,EAAaC,GAAGC,GAAGsD,CAAW;AAAA,EAAA;AAE3C;AC3QA,MAAMC,IAAyD;AAAA,EAC7D,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,UAAU;AAAA,EACV,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,WAAW,CAAA;AACb,GAEaC,IAA2B;AAAA,EACtC,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,UAAU;AACZ;AAKO,SAASC,EACdC,IAA2C,IACA;AAC3C,QAAMC,IAAS,EAAE,GAAGJ,GAAgB,GAAGG,EAAA;AACvC,MAAIE,IAA4B;AAChC,QAAMC,wBAAuB,IAAA;AAE7B,SAAO;AAAA,IACL,UAAUL;AAAA,IAEV,OAAOM,GAA0B;AAC/B,MAAAF,IAAME;AAAA,IACR;AAAA,IAEA,YAAY;AACV,MAAAD,EAAiB,MAAA,GACjBD,IAAM;AAAA,IACR;AAAA,IAEA,KAAK;AAAA;AAAA;AAAA;AAAA,MAIH,OAAOG,GAAiD;AACtD,YAAI,CAACH,EAAK,QAAO;AAEjB,cAAMI,IAASJ,EAAI,KAAK,UAAUG,CAAQ;AAC1C,YAAI,CAACC,EAAQ,QAAO;AAEpB,cAAMnB,IAAOmB,EAAO,QAAA;AACpB,YAAI,CAACnB,KAAQA,EAAK,EAAE,SAASc,EAAO,cAAe,QAAO;AAG1D,YAAI5D,IAAI8C,EAAK,GACT7C,IAAI6C,EAAK;AAEb,YAAIc,EAAO,iBAAiBd,EAAK,EAAE,SAASc,EAAO,YAAY;AAC7D,gBAAMrD,IAAQuC,EAAK,EAAE,SAASc,EAAO;AACrC,UAAA5D,IAAI8C,EAAK,EAAE,MAAMvC,CAAK,GACtBN,IAAI6C,EAAK,EAAE,MAAMvC,CAAK;AAAA,QACxB;AAGA,cAAMH,IAAYiD,EAAgBrD,GAAGC,GAAG2D,EAAO,QAAQA,EAAO,WAAW,GAGnEM,IAAiC;AAAA,UACrC,UAAAF;AAAA,UACA,WAAA5D;AAAA,UACA,aAAaH,EAAE;AAAA,UACf,QAAQ2D,EAAO;AAAA,UACf,WAAWA,EAAO;AAAA,UAClB,WAAW,KAAK,IAAA;AAAA,QAAI;AAGtB,eAAAE,EAAiB,IAAIE,GAAUE,CAAM,GAGrCL,EAAI,OAAO,KAAK,oBAAoBK,CAAM,GAEnCA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA,MAKA,YAAiD;AAC/C,YAAI,CAACL,EAAK,QAAO,oBAAI,IAAA;AAErB,cAAMM,wBAAc,IAAA;AAGpB,eAFkBN,EAAI,KAAK,aAAA,EAEjB,QAAQ,CAACO,GAASJ,MAAa;AACvC,gBAAME,IAAU,KAAa,OAAO,OAAOF,CAAQ,CAAC;AACpD,UAAIE,KACFC,EAAQ,IAAI,OAAOH,CAAQ,GAAGE,CAAM;AAAA,QAExC,CAAC,GAEMC;AAAA,MACT;AAAA;AAAA;AAAA;AAAA,MAKA,WAAWH,GAAsD;AAC/D,eAAOF,EAAiB,IAAIE,CAAQ;AAAA,MACtC;AAAA;AAAA;AAAA;AAAA,MAKA,gBAAqD;AACnD,eAAO,IAAI,IAAIF,CAAgB;AAAA,MACjC;AAAA;AAAA;AAAA;AAAA,MAKA,QAAc;AACZ,QAAAA,EAAiB,MAAA;AAAA,MACnB;AAAA;AAAA;AAAA;AAAA,MAKA,UAAUO,GAAwD;AAChE,eAAO,OAAOT,GAAQS,CAAS;AAAA,MACjC;AAAA;AAAA;AAAA;AAAA,MAKA,YAA0C;AACxC,eAAO,EAAE,GAAGT,EAAA;AAAA,MACd;AAAA,IAAA;AAAA,EACF;AAEJ;"}
@@ -1,3 +1,3 @@
1
1
  export * from './broken-axis/index'
2
- import SciPlot from './broken-axis/index'
3
- export default SciPlot
2
+ import VeloPlot from './broken-axis/index'
3
+ export default VeloPlot