velo-plot 1.11.1

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 (370) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/dist/EventEmitter-DAbs2K1C.js +60 -0
  4. package/dist/EventEmitter-DAbs2K1C.js.map +1 -0
  5. package/dist/core/Chart.d.ts +15 -0
  6. package/dist/core/ChartControls.d.ts +41 -0
  7. package/dist/core/ChartInitQueue.d.ts +50 -0
  8. package/dist/core/ChartLegend.d.ts +74 -0
  9. package/dist/core/ChartStatistics.d.ts +18 -0
  10. package/dist/core/EventEmitter.d.ts +30 -0
  11. package/dist/core/InteractionManager.d.ts +96 -0
  12. package/dist/core/OverlayRenderer.d.ts +89 -0
  13. package/dist/core/Series.d.ts +4 -0
  14. package/dist/core/animation/AnimationEngine.d.ts +156 -0
  15. package/dist/core/animation/index.d.ts +6 -0
  16. package/dist/core/annotations/AnnotationManager.d.ts +61 -0
  17. package/dist/core/annotations/index.d.ts +5 -0
  18. package/dist/core/annotations/types.d.ts +159 -0
  19. package/dist/core/chart/ChartAnimatedNavigation.d.ts +53 -0
  20. package/dist/core/chart/ChartAxisManager.d.ts +61 -0
  21. package/dist/core/chart/ChartCore.d.ts +336 -0
  22. package/dist/core/chart/ChartExporter.d.ts +18 -0
  23. package/dist/core/chart/ChartNavigation.d.ts +33 -0
  24. package/dist/core/chart/ChartPluginBridge.d.ts +34 -0
  25. package/dist/core/chart/ChartRenderLoop.d.ts +100 -0
  26. package/dist/core/chart/ChartRenderer.d.ts +52 -0
  27. package/dist/core/chart/ChartScaling.d.ts +31 -0
  28. package/dist/core/chart/ChartSeries.d.ts +4 -0
  29. package/dist/core/chart/ChartSetup.d.ts +67 -0
  30. package/dist/core/chart/ChartStateManager.d.ts +54 -0
  31. package/dist/core/chart/ChartUI.d.ts +40 -0
  32. package/dist/core/chart/exporter/SVGExporter.d.ts +6 -0
  33. package/dist/core/chart/exporter/index.d.ts +5 -0
  34. package/dist/core/chart/index.d.ts +14 -0
  35. package/dist/core/chart/series/SeriesActions.d.ts +7 -0
  36. package/dist/core/chart/series/SeriesBuffer.d.ts +4 -0
  37. package/dist/core/chart/series/index.d.ts +6 -0
  38. package/dist/core/chart/series/types.d.ts +22 -0
  39. package/dist/core/chart/types.d.ts +188 -0
  40. package/dist/core/clipboard/index.d.ts +137 -0
  41. package/dist/core/debug/index.d.ts +143 -0
  42. package/dist/core/index.d.ts +17 -0
  43. package/dist/core/keybindings/index.d.ts +157 -0
  44. package/dist/core/layout/index.d.ts +12 -0
  45. package/dist/core/layout/types.d.ts +165 -0
  46. package/dist/core/loading/index.d.ts +104 -0
  47. package/dist/core/locale/index.d.ts +91 -0
  48. package/dist/core/responsive/ResponsiveManager.d.ts +133 -0
  49. package/dist/core/responsive/index.d.ts +4 -0
  50. package/dist/core/selection/SelectionManager.d.ts +165 -0
  51. package/dist/core/selection/index.d.ts +4 -0
  52. package/dist/core/series/Series.d.ts +73 -0
  53. package/dist/core/series/SeriesBounds.d.ts +3 -0
  54. package/dist/core/series/SeriesDataUtils.d.ts +7 -0
  55. package/dist/core/series/index.d.ts +6 -0
  56. package/dist/core/sync/index.d.ts +147 -0
  57. package/dist/core/theme-editor/index.d.ts +122 -0
  58. package/dist/examples/PluginDemonstration.d.ts +20 -0
  59. package/dist/examples.d.ts +25 -0
  60. package/dist/gpu/adapter/gpuRenderer.d.ts +135 -0
  61. package/dist/gpu/adapter/index.d.ts +7 -0
  62. package/dist/gpu/adapter/seriesAdapter.d.ts +88 -0
  63. package/dist/gpu/backends/webgl/WebGLBackend.d.ts +42 -0
  64. package/dist/gpu/backends/webgl/index.d.ts +5 -0
  65. package/dist/gpu/backends/webgl/programFactory.d.ts +30 -0
  66. package/dist/gpu/backends/webgl/shaders.d.ts +14 -0
  67. package/dist/gpu/backends/webgpu/MassiveDataRenderer.d.ts +111 -0
  68. package/dist/gpu/backends/webgpu/WebGPUBackend.d.ts +58 -0
  69. package/dist/gpu/backends/webgpu/pipelines/bandPipeline.d.ts +24 -0
  70. package/dist/gpu/backends/webgpu/pipelines/heatmapPipeline.d.ts +28 -0
  71. package/dist/gpu/backends/webgpu/pipelines/index.d.ts +10 -0
  72. package/dist/gpu/backends/webgpu/pipelines/instancedLinePipeline.d.ts +23 -0
  73. package/dist/gpu/backends/webgpu/pipelines/instancedPointPipeline.d.ts +25 -0
  74. package/dist/gpu/backends/webgpu/pipelines/linePipeline.d.ts +23 -0
  75. package/dist/gpu/backends/webgpu/pipelines/pointPipeline.d.ts +28 -0
  76. package/dist/gpu/backends/webgpu/pipelines/trianglePipeline.d.ts +5 -0
  77. package/dist/gpu/backends/webgpu/pipelines/triangleShader.d.ts +1 -0
  78. package/dist/gpu/backends/webgpu/shaders/heatmap.wgsl.d.ts +8 -0
  79. package/dist/gpu/backends/webgpu/shaders/index.d.ts +8 -0
  80. package/dist/gpu/backends/webgpu/shaders/instanced.wgsl.d.ts +16 -0
  81. package/dist/gpu/backends/webgpu/shaders/line.wgsl.d.ts +8 -0
  82. package/dist/gpu/backends/webgpu/shaders/point.wgsl.d.ts +9 -0
  83. package/dist/gpu/benchmark/benchmark.d.ts +74 -0
  84. package/dist/gpu/benchmark/index.d.ts +5 -0
  85. package/dist/gpu/compute/gpuCompute.d.ts +72 -0
  86. package/dist/gpu/compute/index.d.ts +6 -0
  87. package/dist/gpu/compute/shaders.d.ts +9 -0
  88. package/dist/gpu/drawList.d.ts +77 -0
  89. package/dist/gpu/examples/gallery.d.ts +20 -0
  90. package/dist/gpu/examples/index.d.ts +3 -0
  91. package/dist/gpu/examples/webgpu-line-demo.d.ts +8 -0
  92. package/dist/gpu/examples/webgpu-triangle.d.ts +1 -0
  93. package/dist/gpu/frame.d.ts +25 -0
  94. package/dist/gpu/index.d.ts +24 -0
  95. package/dist/gpu/resources/bufferStore.d.ts +40 -0
  96. package/dist/gpu/resources/index.d.ts +9 -0
  97. package/dist/gpu/resources/pipelineCache.d.ts +33 -0
  98. package/dist/gpu/resources/textureStore.d.ts +41 -0
  99. package/dist/gpu/types.d.ts +47 -0
  100. package/dist/index-BMiZoKmm.js +536 -0
  101. package/dist/index-BMiZoKmm.js.map +1 -0
  102. package/dist/index-Ce2JgkH_.js +282 -0
  103. package/dist/index-Ce2JgkH_.js.map +1 -0
  104. package/dist/index-D8ifudJH.js +2431 -0
  105. package/dist/index-D8ifudJH.js.map +1 -0
  106. package/dist/index-Dag88bW4.js +499 -0
  107. package/dist/index-Dag88bW4.js.map +1 -0
  108. package/dist/index-qhscKTDy.js +309 -0
  109. package/dist/index-qhscKTDy.js.map +1 -0
  110. package/dist/index-x4stH3jD.js +282 -0
  111. package/dist/index-x4stH3jD.js.map +1 -0
  112. package/dist/index.core-CYu3tydL.js +7252 -0
  113. package/dist/index.core-CYu3tydL.js.map +1 -0
  114. package/dist/index.core.d.ts +20 -0
  115. package/dist/index.d.ts +51 -0
  116. package/dist/overlay/CanvasOverlay.d.ts +102 -0
  117. package/dist/overlay/index.d.ts +4 -0
  118. package/dist/plugins/3d/Area3DRenderer.d.ts +122 -0
  119. package/dist/plugins/3d/Axes3D.d.ts +104 -0
  120. package/dist/plugins/3d/Bubble3DRenderer.d.ts +198 -0
  121. package/dist/plugins/3d/Impulse3DRenderer.d.ts +130 -0
  122. package/dist/plugins/3d/Line3DRenderer.d.ts +118 -0
  123. package/dist/plugins/3d/PointCloud3DRenderer.d.ts +84 -0
  124. package/dist/plugins/3d/Raycaster3D.d.ts +137 -0
  125. package/dist/plugins/3d/Ribbon3DRenderer.d.ts +83 -0
  126. package/dist/plugins/3d/SurfaceBar3DRenderer.d.ts +92 -0
  127. package/dist/plugins/3d/SurfaceMesh3DRenderer.d.ts +130 -0
  128. package/dist/plugins/3d/Tooltip3D.d.ts +71 -0
  129. package/dist/plugins/3d/VectorField3DRenderer.d.ts +86 -0
  130. package/dist/plugins/3d/Voxel3DRenderer.d.ts +89 -0
  131. package/dist/plugins/3d/Waterfall3DRenderer.d.ts +94 -0
  132. package/dist/plugins/3d/camera/OrbitCamera.d.ts +99 -0
  133. package/dist/plugins/3d/camera/index.d.ts +1 -0
  134. package/dist/plugins/3d/colorThemes.d.ts +39 -0
  135. package/dist/plugins/3d/controls/OrbitController.d.ts +69 -0
  136. package/dist/plugins/3d/controls/index.d.ts +1 -0
  137. package/dist/plugins/3d/index.d.ts +50 -0
  138. package/dist/plugins/3d/math/Mat4.d.ts +33 -0
  139. package/dist/plugins/3d/math/Vec3.d.ts +37 -0
  140. package/dist/plugins/3d/math/index.d.ts +4 -0
  141. package/dist/plugins/3d/mesh/InstancedMesh.d.ts +42 -0
  142. package/dist/plugins/3d/mesh/geometry.d.ts +34 -0
  143. package/dist/plugins/3d/mesh/index.d.ts +2 -0
  144. package/dist/plugins/3d/series/Area3D.d.ts +17 -0
  145. package/dist/plugins/3d/series/Column3D.d.ts +20 -0
  146. package/dist/plugins/3d/series/Heatmap3D.d.ts +17 -0
  147. package/dist/plugins/3d/series/Impulse3D.d.ts +16 -0
  148. package/dist/plugins/3d/series/PointLine3D.d.ts +20 -0
  149. package/dist/plugins/3d/series/Ribbon3D.d.ts +17 -0
  150. package/dist/plugins/3d/series/Scatter3D.d.ts +21 -0
  151. package/dist/plugins/3d/series/SurfaceMesh3D.d.ts +35 -0
  152. package/dist/plugins/3d/series/Waterfall3D.d.ts +38 -0
  153. package/dist/plugins/3d/series/index.d.ts +13 -0
  154. package/dist/plugins/3d/series/types.d.ts +143 -0
  155. package/dist/plugins/3d/shader/index.d.ts +2 -0
  156. package/dist/plugins/3d/shader/programs.d.ts +24 -0
  157. package/dist/plugins/3d/shader/sources.d.ts +27 -0
  158. package/dist/plugins/3d/types.d.ts +71 -0
  159. package/dist/plugins/3d.d.ts +3 -0
  160. package/dist/plugins/3d.js +5498 -0
  161. package/dist/plugins/3d.js.map +1 -0
  162. package/dist/plugins/PluginContext.d.ts +53 -0
  163. package/dist/plugins/PluginManager.d.ts +129 -0
  164. package/dist/plugins/PluginRegistry.d.ts +38 -0
  165. package/dist/plugins/analysis/SeriesFit.d.ts +3 -0
  166. package/dist/plugins/analysis/contours.d.ts +20 -0
  167. package/dist/plugins/analysis/fft.d.ts +138 -0
  168. package/dist/plugins/analysis/filters.d.ts +76 -0
  169. package/dist/plugins/analysis/fitting.d.ts +24 -0
  170. package/dist/plugins/analysis/index.d.ts +29 -0
  171. package/dist/plugins/analysis/indicators.d.ts +148 -0
  172. package/dist/plugins/analysis/math.d.ts +32 -0
  173. package/dist/plugins/analysis/statistics.d.ts +78 -0
  174. package/dist/plugins/analysis/utils.d.ts +150 -0
  175. package/dist/plugins/analysis.d.ts +3 -0
  176. package/dist/plugins/analysis.js +1202 -0
  177. package/dist/plugins/analysis.js.map +1 -0
  178. package/dist/plugins/annotations/index.d.ts +16 -0
  179. package/dist/plugins/annotations.d.ts +3 -0
  180. package/dist/plugins/annotations.js +438 -0
  181. package/dist/plugins/annotations.js.map +1 -0
  182. package/dist/plugins/anomaly-detection/algorithms.d.ts +38 -0
  183. package/dist/plugins/anomaly-detection/index.d.ts +16 -0
  184. package/dist/plugins/anomaly-detection/types.d.ts +57 -0
  185. package/dist/plugins/broken-axis/BrokenAxisScale.d.ts +24 -0
  186. package/dist/plugins/broken-axis/exports.d.ts +6 -0
  187. package/dist/plugins/broken-axis/index.d.ts +6 -0
  188. package/dist/plugins/broken-axis/types.d.ts +50 -0
  189. package/dist/plugins/builtins/crosshair/CrosshairPlugin.d.ts +40 -0
  190. package/dist/plugins/builtins/crosshair/index.d.ts +1 -0
  191. package/dist/plugins/builtins/data-logger/DataLoggerPlugin.d.ts +11 -0
  192. package/dist/plugins/builtins/data-logger/index.d.ts +1 -0
  193. package/dist/plugins/builtins/direction-indicator/DirectionIndicatorPlugin.d.ts +17 -0
  194. package/dist/plugins/builtins/direction-indicator/index.d.ts +2 -0
  195. package/dist/plugins/builtins/grid-highlight/GridHighlightPlugin.d.ts +17 -0
  196. package/dist/plugins/builtins/grid-highlight/index.d.ts +1 -0
  197. package/dist/plugins/builtins/index.d.ts +25 -0
  198. package/dist/plugins/builtins/stats/StatsPlugin.d.ts +11 -0
  199. package/dist/plugins/builtins/stats/index.d.ts +1 -0
  200. package/dist/plugins/builtins/watermark/WatermarkPlugin.d.ts +15 -0
  201. package/dist/plugins/builtins/watermark/index.d.ts +1 -0
  202. package/dist/plugins/caching/exports.d.ts +6 -0
  203. package/dist/plugins/caching/index.d.ts +6 -0
  204. package/dist/plugins/caching/types.d.ts +120 -0
  205. package/dist/plugins/clipboard/index.d.ts +20 -0
  206. package/dist/plugins/clipboard.d.ts +3 -0
  207. package/dist/plugins/clipboard.js +270 -0
  208. package/dist/plugins/clipboard.js.map +1 -0
  209. package/dist/plugins/context-menu/index.d.ts +12 -0
  210. package/dist/plugins/context-menu/renderer.d.ts +43 -0
  211. package/dist/plugins/context-menu/types.d.ts +202 -0
  212. package/dist/plugins/context-menu.d.ts +3 -0
  213. package/dist/plugins/context-menu.js +621 -0
  214. package/dist/plugins/context-menu.js.map +1 -0
  215. package/dist/plugins/data-export/formatters.d.ts +34 -0
  216. package/dist/plugins/data-export/index.d.ts +15 -0
  217. package/dist/plugins/data-export/types.d.ts +166 -0
  218. package/dist/plugins/data-export.d.ts +3 -0
  219. package/dist/plugins/data-export.js +463 -0
  220. package/dist/plugins/data-export.js.map +1 -0
  221. package/dist/plugins/data-transform/index.d.ts +6 -0
  222. package/dist/plugins/data-transform/types.d.ts +34 -0
  223. package/dist/plugins/debug/index.d.ts +24 -0
  224. package/dist/plugins/debug.d.ts +3 -0
  225. package/dist/plugins/debug.js +330 -0
  226. package/dist/plugins/debug.js.map +1 -0
  227. package/dist/plugins/drag-edit/exports.d.ts +6 -0
  228. package/dist/plugins/drag-edit/index.d.ts +6 -0
  229. package/dist/plugins/drag-edit/types.d.ts +118 -0
  230. package/dist/plugins/forecasting/algorithms.d.ts +6 -0
  231. package/dist/plugins/forecasting/exports.d.ts +3 -0
  232. package/dist/plugins/forecasting/index.d.ts +11 -0
  233. package/dist/plugins/forecasting/types.d.ts +88 -0
  234. package/dist/plugins/gpu/index.d.ts +24 -0
  235. package/dist/plugins/gpu.d.ts +3 -0
  236. package/dist/plugins/gpu.js +2430 -0
  237. package/dist/plugins/gpu.js.map +1 -0
  238. package/dist/plugins/i18n/index.d.ts +22 -0
  239. package/dist/plugins/i18n.d.ts +3 -0
  240. package/dist/plugins/i18n.js +37 -0
  241. package/dist/plugins/i18n.js.map +1 -0
  242. package/dist/plugins/index.d.ts +110 -0
  243. package/dist/plugins/keyboard/index.d.ts +15 -0
  244. package/dist/plugins/keyboard.d.ts +3 -0
  245. package/dist/plugins/keyboard.js +8 -0
  246. package/dist/plugins/keyboard.js.map +1 -0
  247. package/dist/plugins/latex/exports.d.ts +6 -0
  248. package/dist/plugins/latex/index.d.ts +8 -0
  249. package/dist/plugins/latex/parser.d.ts +6 -0
  250. package/dist/plugins/latex/renderer.d.ts +6 -0
  251. package/dist/plugins/latex/symbols.d.ts +28 -0
  252. package/dist/plugins/latex/types.d.ts +88 -0
  253. package/dist/plugins/lazy-load/exports.d.ts +6 -0
  254. package/dist/plugins/lazy-load/index.d.ts +6 -0
  255. package/dist/plugins/lazy-load/types.d.ts +121 -0
  256. package/dist/plugins/loading/index.d.ts +15 -0
  257. package/dist/plugins/loading.d.ts +3 -0
  258. package/dist/plugins/loading.js +7 -0
  259. package/dist/plugins/loading.js.map +1 -0
  260. package/dist/plugins/ml-integration/exports.d.ts +11 -0
  261. package/dist/plugins/ml-integration/index.d.ts +6 -0
  262. package/dist/plugins/ml-integration/native-algorithms.d.ts +69 -0
  263. package/dist/plugins/ml-integration/types.d.ts +74 -0
  264. package/dist/plugins/offscreen/exports.d.ts +6 -0
  265. package/dist/plugins/offscreen/index.d.ts +6 -0
  266. package/dist/plugins/offscreen/pool.d.ts +32 -0
  267. package/dist/plugins/offscreen/types.d.ts +35 -0
  268. package/dist/plugins/pattern-recognition/index.d.ts +6 -0
  269. package/dist/plugins/pattern-recognition/patterns.d.ts +3 -0
  270. package/dist/plugins/pattern-recognition/types.d.ts +245 -0
  271. package/dist/plugins/radar/index.d.ts +6 -0
  272. package/dist/plugins/radar/types.d.ts +40 -0
  273. package/dist/plugins/regression/algorithms.d.ts +6 -0
  274. package/dist/plugins/regression/index.d.ts +6 -0
  275. package/dist/plugins/regression/types.d.ts +261 -0
  276. package/dist/plugins/roi/exports.d.ts +6 -0
  277. package/dist/plugins/roi/index.d.ts +49 -0
  278. package/dist/plugins/roi/types.d.ts +60 -0
  279. package/dist/plugins/snapshot/index.d.ts +11 -0
  280. package/dist/plugins/snapshot/types.d.ts +38 -0
  281. package/dist/plugins/streaming/index.d.ts +32 -0
  282. package/dist/plugins/streaming.d.ts +3 -0
  283. package/dist/plugins/streaming.js +13 -0
  284. package/dist/plugins/streaming.js.map +1 -0
  285. package/dist/plugins/sync/index.d.ts +22 -0
  286. package/dist/plugins/sync.d.ts +3 -0
  287. package/dist/plugins/sync.js +261 -0
  288. package/dist/plugins/sync.js.map +1 -0
  289. package/dist/plugins/theme-editor/index.d.ts +18 -0
  290. package/dist/plugins/theme-editor.d.ts +3 -0
  291. package/dist/plugins/theme-editor.js +7 -0
  292. package/dist/plugins/theme-editor.js.map +1 -0
  293. package/dist/plugins/tools/delta-tool/index.d.ts +159 -0
  294. package/dist/plugins/tools/index.d.ts +21 -0
  295. package/dist/plugins/tools/peak-tool/index.d.ts +159 -0
  296. package/dist/plugins/tools/tooltip/TooltipManager.d.ts +213 -0
  297. package/dist/plugins/tools/tooltip/TooltipPositioner.d.ts +83 -0
  298. package/dist/plugins/tools/tooltip/TooltipRenderer.d.ts +64 -0
  299. package/dist/plugins/tools/tooltip/index.d.ts +18 -0
  300. package/dist/plugins/tools/tooltip/templates/AnnotationTemplate.d.ts +18 -0
  301. package/dist/plugins/tools/tooltip/templates/CrosshairTemplate.d.ts +39 -0
  302. package/dist/plugins/tools/tooltip/templates/DefaultTemplate.d.ts +30 -0
  303. package/dist/plugins/tools/tooltip/templates/HeatmapTemplate.d.ts +34 -0
  304. package/dist/plugins/tools/tooltip/templates/MinimalTemplate.d.ts +26 -0
  305. package/dist/plugins/tools/tooltip/templates/RangeTemplate.d.ts +18 -0
  306. package/dist/plugins/tools/tooltip/templates/ScientificTemplate.d.ts +34 -0
  307. package/dist/plugins/tools/tooltip/templates/index.d.ts +27 -0
  308. package/dist/plugins/tools/tooltip/themes.d.ts +48 -0
  309. package/dist/plugins/tools/tooltip/types.d.ts +396 -0
  310. package/dist/plugins/tools.d.ts +3 -0
  311. package/dist/plugins/tools.js +9 -0
  312. package/dist/plugins/tools.js.map +1 -0
  313. package/dist/plugins/types.d.ts +451 -0
  314. package/dist/plugins/video-recorder/exports.d.ts +6 -0
  315. package/dist/plugins/video-recorder/index.d.ts +6 -0
  316. package/dist/plugins/video-recorder/types.d.ts +55 -0
  317. package/dist/plugins/virtualization/exports.d.ts +6 -0
  318. package/dist/plugins/virtualization/index.d.ts +6 -0
  319. package/dist/plugins/virtualization/types.d.ts +48 -0
  320. package/dist/react/SciPlot.d.ts +60 -0
  321. package/dist/react/index.d.ts +5 -0
  322. package/dist/react/useSciPlot.d.ts +56 -0
  323. package/dist/renderer/BarRenderer.d.ts +14 -0
  324. package/dist/renderer/CandlestickRenderer.d.ts +12 -0
  325. package/dist/renderer/GaugeRenderer.d.ts +3 -0
  326. package/dist/renderer/HeatmapRenderer.d.ts +15 -0
  327. package/dist/renderer/NativeWebGLRenderer.d.ts +16 -0
  328. package/dist/renderer/PolarRenderer.d.ts +64 -0
  329. package/dist/renderer/RendererInterface.d.ts +70 -0
  330. package/dist/renderer/SankeyRenderer.d.ts +3 -0
  331. package/dist/renderer/WebGPURenderer.d.ts +16 -0
  332. package/dist/renderer/index.d.ts +13 -0
  333. package/dist/renderer/native/NativeWebGLRenderer.d.ts +31 -0
  334. package/dist/renderer/native/bufferStore.d.ts +11 -0
  335. package/dist/renderer/native/draw.d.ts +47 -0
  336. package/dist/renderer/native/programFactory.d.ts +3 -0
  337. package/dist/renderer/native/renderFrame.d.ts +3 -0
  338. package/dist/renderer/native/shaderSources.d.ts +6 -0
  339. package/dist/renderer/native/textureStore.d.ts +8 -0
  340. package/dist/renderer/native/types.d.ts +77 -0
  341. package/dist/renderer/native/utils.d.ts +31 -0
  342. package/dist/renderer/radar/RadarRenderer.d.ts +71 -0
  343. package/dist/renderer/radar/index.d.ts +10 -0
  344. package/dist/renderer/shaders.d.ts +77 -0
  345. package/dist/renderer/ternary/TernaryRenderer.d.ts +39 -0
  346. package/dist/renderer/ternary/index.d.ts +6 -0
  347. package/dist/renderer/ternary/types.d.ts +56 -0
  348. package/dist/scales/index.d.ts +54 -0
  349. package/dist/serialization/index.d.ts +153 -0
  350. package/dist/streaming/backpressure.d.ts +179 -0
  351. package/dist/streaming/index.d.ts +7 -0
  352. package/dist/streaming/mock.d.ts +12 -0
  353. package/dist/streaming/types.d.ts +57 -0
  354. package/dist/streaming/utils.d.ts +19 -0
  355. package/dist/streaming/websocket.d.ts +6 -0
  356. package/dist/testing/index.d.ts +225 -0
  357. package/dist/theme/colorSchemes.d.ts +56 -0
  358. package/dist/theme/index.d.ts +138 -0
  359. package/dist/types.d.ts +753 -0
  360. package/dist/utils-Dbro9-qM.js +254 -0
  361. package/dist/utils-Dbro9-qM.js.map +1 -0
  362. package/dist/velo-plot.d.ts +1 -0
  363. package/dist/velo-plot.full.d.ts +1 -0
  364. package/dist/velo-plot.full.js +5804 -0
  365. package/dist/velo-plot.full.js.map +1 -0
  366. package/dist/velo-plot.js +31 -0
  367. package/dist/velo-plot.js.map +1 -0
  368. package/dist/workers/downsample.d.ts +34 -0
  369. package/dist/workers/downsample.worker.d.ts +46 -0
  370. package/package.json +185 -0
@@ -0,0 +1,2431 @@
1
+ var st = Object.defineProperty;
2
+ var nt = (f, t, i) => t in f ? st(f, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : f[t] = i;
3
+ var u = (f, t, i) => nt(f, typeof t != "symbol" ? t + "" : t, i);
4
+ import { E as at } from "./EventEmitter-DAbs2K1C.js";
5
+ class lt {
6
+ constructor(t, i) {
7
+ u(this, "ctx");
8
+ u(this, "options");
9
+ u(this, "state", {
10
+ enabled: !1,
11
+ selectionState: "idle",
12
+ point1: null,
13
+ point2: null,
14
+ hoveredPoint: null,
15
+ lastMeasurement: null
16
+ });
17
+ u(this, "overlayCanvas", null);
18
+ u(this, "overlayCtx", null);
19
+ // Label dragging
20
+ u(this, "labelOffset", { x: 15, y: 0 });
21
+ u(this, "isDraggingLabel", !1);
22
+ u(this, "labelBounds", null);
23
+ u(this, "dragStart", { x: 0, y: 0 });
24
+ u(this, "crosshairPosition", null);
25
+ // Bound handlers
26
+ u(this, "boundMouseMove");
27
+ u(this, "boundClick");
28
+ u(this, "boundKeyDown");
29
+ u(this, "boundMouseDown");
30
+ u(this, "boundMouseUp");
31
+ u(this, "boundResize");
32
+ this.ctx = t, this.options = {
33
+ lineColor: "#ff6b6b",
34
+ lineWidth: 2,
35
+ showLabels: !0,
36
+ labelFontSize: 12,
37
+ labelBackground: "rgba(0, 0, 0, 0.85)",
38
+ labelColor: "#ffffff",
39
+ showDelta: !0,
40
+ precision: 4,
41
+ showSlope: !0,
42
+ showDistance: !0,
43
+ className: "velo-plot-delta-tool",
44
+ highlightSize: 12,
45
+ highlightColor: "#00f2ff",
46
+ snapRadius: 30,
47
+ ...i
48
+ }, this.boundMouseMove = this.handleMouseMove.bind(this), this.boundClick = this.handleClick.bind(this), this.boundKeyDown = this.handleKeyDown.bind(this), this.boundMouseDown = this.handleLabelMouseDown.bind(this), this.boundMouseUp = this.handleLabelMouseUp.bind(this), this.boundResize = this.resizeOverlay.bind(this);
49
+ }
50
+ /**
51
+ * Enable the delta measurement tool
52
+ */
53
+ enable() {
54
+ this.state.enabled || (this.state.enabled = !0, this.state.selectionState = "idle", this.createOverlay(), this.attachListeners(), this.ctx.container.style.cursor = "crosshair");
55
+ }
56
+ /**
57
+ * Disable the delta measurement tool
58
+ */
59
+ disable() {
60
+ this.state.enabled && (this.state.enabled = !1, this.state.selectionState = "idle", this.state.point1 = null, this.state.point2 = null, this.state.hoveredPoint = null, this.detachListeners(), this.destroyOverlay(), this.ctx.container.style.cursor = "");
61
+ }
62
+ /**
63
+ * Toggle the tool on/off
64
+ */
65
+ toggle() {
66
+ this.state.enabled ? this.disable() : this.enable();
67
+ }
68
+ /**
69
+ * Check if tool is enabled
70
+ */
71
+ isEnabled() {
72
+ return this.state.enabled;
73
+ }
74
+ /**
75
+ * Get the current state
76
+ */
77
+ getState() {
78
+ return { ...this.state };
79
+ }
80
+ /**
81
+ * Get the last completed measurement
82
+ */
83
+ getMeasurement() {
84
+ return this.state.lastMeasurement;
85
+ }
86
+ /**
87
+ * Clear the current measurement
88
+ */
89
+ clear() {
90
+ this.state.point1 = null, this.state.point2 = null, this.state.selectionState = "idle", this.state.lastMeasurement = null, this.labelBounds = null, this.labelOffset = { x: 15, y: 0 }, this.renderOverlay();
91
+ }
92
+ /**
93
+ * Destroy the tool and cleanup
94
+ */
95
+ destroy() {
96
+ this.disable(), this.state.lastMeasurement = null;
97
+ }
98
+ /**
99
+ * Recalculate measurements (useful if data changes)
100
+ */
101
+ recalculate() {
102
+ if (!this.state.point1 || !this.state.point2) return;
103
+ const t = this.ctx.getSeries ? this.ctx.getSeries() : [], i = (o) => {
104
+ const s = t.find((l) => l.id === o.seriesId);
105
+ if (s && o.index < s.x.length) {
106
+ o.x = s.x[o.index], o.y = s.y[o.index], o.yAxisId = s.yAxisId;
107
+ const l = this.ctx.getPlotArea(), h = this.ctx.getViewBounds(), a = this.ctx.getYBounds ? this.ctx.getYBounds(s.yAxisId) : { yMin: h.yMin, yMax: h.yMax };
108
+ return o.pixelX = l.x + (o.x - h.xMin) / (h.xMax - h.xMin) * l.width, o.pixelY = l.y + (1 - (o.y - a.yMin) / (a.yMax - a.yMin)) * l.height, !0;
109
+ }
110
+ return !1;
111
+ }, e = i(this.state.point1), n = i(this.state.point2);
112
+ e && n ? (this.state.lastMeasurement = this.calculateMeasurement(), this.ctx.onMeasure && this.ctx.onMeasure(this.state.lastMeasurement)) : this.clear(), this.renderOverlay();
113
+ }
114
+ // ============================================
115
+ // Private Methods
116
+ // ============================================
117
+ createOverlay() {
118
+ this.overlayCanvas || (this.overlayCanvas = document.createElement("canvas"), this.overlayCanvas.className = this.options.className, this.overlayCanvas.style.cssText = `
119
+ position: absolute;
120
+ top: 0;
121
+ left: 0;
122
+ width: 100%;
123
+ height: 100%;
124
+ pointer-events: none;
125
+ z-index: 1000;
126
+ `, this.resizeOverlay(), this.overlayCtx = this.overlayCanvas.getContext("2d"), this.ctx.container.appendChild(this.overlayCanvas));
127
+ }
128
+ resizeOverlay() {
129
+ if (!this.overlayCanvas) return;
130
+ const t = this.ctx.container.getBoundingClientRect(), i = window.devicePixelRatio || 1;
131
+ this.overlayCanvas.width = t.width * i, this.overlayCanvas.height = t.height * i, this.overlayCtx && (this.overlayCtx.setTransform(1, 0, 0, 1, 0, 0), this.overlayCtx.scale(i, i));
132
+ }
133
+ destroyOverlay() {
134
+ this.overlayCanvas && this.overlayCanvas.parentNode && this.overlayCanvas.parentNode.removeChild(this.overlayCanvas), this.overlayCanvas = null, this.overlayCtx = null;
135
+ }
136
+ attachListeners() {
137
+ this.ctx.container.addEventListener("mousemove", this.boundMouseMove, !0), this.ctx.container.addEventListener("mousedown", this.boundClick, !0), this.ctx.container.addEventListener("mousedown", this.boundMouseDown, !0), this.ctx.container.addEventListener("mouseup", this.boundMouseUp, !0), window.addEventListener("resize", this.boundResize), document.addEventListener("keydown", this.boundKeyDown);
138
+ }
139
+ detachListeners() {
140
+ this.ctx.container.removeEventListener("mousemove", this.boundMouseMove, !0), this.ctx.container.removeEventListener("mousedown", this.boundClick, !0), this.ctx.container.removeEventListener("mousedown", this.boundMouseDown, !0), this.ctx.container.removeEventListener("mouseup", this.boundMouseUp, !0), window.removeEventListener("resize", this.boundResize), document.removeEventListener("keydown", this.boundKeyDown);
141
+ }
142
+ handleMouseMove(t) {
143
+ if (!this.state.enabled) return;
144
+ const i = this.ctx.container.getBoundingClientRect(), e = this.ctx.getPlotArea(), n = this.ctx.getViewBounds(), o = t.clientX - i.left, s = t.clientY - i.top;
145
+ if (this.isDraggingLabel) {
146
+ this.labelOffset.x += o - this.dragStart.x, this.labelOffset.y += s - this.dragStart.y, this.dragStart = { x: o, y: s }, this.renderOverlay();
147
+ return;
148
+ }
149
+ if (this.labelBounds && o >= this.labelBounds.x && o <= this.labelBounds.x + this.labelBounds.width && s >= this.labelBounds.y && s <= this.labelBounds.y + this.labelBounds.height ? this.ctx.container.style.cursor = "move" : this.ctx.container.style.cursor = "crosshair", o < e.x || o > e.x + e.width || s < e.y || s > e.y + e.height) {
150
+ this.state.hoveredPoint = null, this.crosshairPosition = null, this.renderOverlay();
151
+ return;
152
+ }
153
+ this.crosshairPosition = { x: o, y: s };
154
+ const l = this.findNearestPoint(o, s, e, n);
155
+ this.state.hoveredPoint = l, this.renderOverlay();
156
+ }
157
+ handleLabelMouseDown(t) {
158
+ if (!this.state.enabled || !this.labelBounds) return;
159
+ const i = this.ctx.container.getBoundingClientRect(), e = t.clientX - i.left, n = t.clientY - i.top;
160
+ e >= this.labelBounds.x && e <= this.labelBounds.x + this.labelBounds.width && n >= this.labelBounds.y && n <= this.labelBounds.y + this.labelBounds.height && (this.isDraggingLabel = !0, this.dragStart = { x: e, y: n }, t.stopPropagation(), t.preventDefault());
161
+ }
162
+ handleLabelMouseUp() {
163
+ this.isDraggingLabel = !1;
164
+ }
165
+ async handleClick(t) {
166
+ var h;
167
+ if (!this.state.enabled) return;
168
+ (h = this.ctx.animationEngine) != null && h.isAnimating() && await this.ctx.animationEngine.waitForIdle(), t.stopPropagation(), t.preventDefault();
169
+ const i = this.ctx.container.getBoundingClientRect(), e = this.ctx.getPlotArea(), n = this.ctx.getViewBounds(), o = t.clientX - i.left, s = t.clientY - i.top;
170
+ if (o < e.x || o > e.x + e.width || s < e.y || s > e.y + e.height)
171
+ return;
172
+ const l = this.findNearestPoint(o, s, e, n);
173
+ if (l) {
174
+ if (t.preventDefault(), t.stopPropagation(), this.state.selectionState === "idle" || this.state.selectionState === "complete")
175
+ this.state.point1 = l, this.state.point2 = null, this.state.selectionState = "waitingSecond", this.state.lastMeasurement = null;
176
+ else if (this.state.selectionState === "waitingSecond") {
177
+ this.state.point2 = l, this.state.selectionState = "complete";
178
+ const a = this.calculateMeasurement();
179
+ this.state.lastMeasurement = a, this.ctx.onMeasure && this.ctx.onMeasure(a);
180
+ }
181
+ this.renderOverlay();
182
+ }
183
+ }
184
+ handleKeyDown(t) {
185
+ t.key === "Escape" && this.state.enabled && this.clear();
186
+ }
187
+ findNearestPoint(t, i, e, n) {
188
+ if (!this.ctx.getSeries) return null;
189
+ const o = this.ctx.getSeries();
190
+ let s = null, l = this.options.snapRadius;
191
+ for (const h of o) {
192
+ const a = h.x, r = h.y, d = Math.min(a.length, r.length), p = this.ctx.getYBounds ? this.ctx.getYBounds(h.yAxisId) : { yMin: n.yMin, yMax: n.yMax };
193
+ for (let c = 0; c < d; c++) {
194
+ const g = a[c], y = r[c], b = e.x + (g - n.xMin) / (n.xMax - n.xMin) * e.width, x = e.y + (1 - (y - p.yMin) / (p.yMax - p.yMin)) * e.height;
195
+ if (b < e.x || b > e.x + e.width || x < e.y || x > e.y + e.height) continue;
196
+ const S = Math.sqrt((t - b) ** 2 + (i - x) ** 2);
197
+ S < l && (l = S, s = {
198
+ x: g,
199
+ y,
200
+ seriesId: h.id,
201
+ yAxisId: h.yAxisId,
202
+ index: c,
203
+ pixelX: b,
204
+ pixelY: x
205
+ });
206
+ }
207
+ }
208
+ return s;
209
+ }
210
+ calculateMeasurement() {
211
+ const t = this.state.point1, i = this.state.point2, e = i.x - t.x, n = i.y - t.y, o = e !== 0 ? n / e : 1 / 0, s = Math.sqrt(e * e + n * n);
212
+ return {
213
+ x1: t.x,
214
+ y1: t.y,
215
+ x2: i.x,
216
+ y2: i.y,
217
+ deltaX: e,
218
+ deltaY: n,
219
+ slope: o,
220
+ distance: s,
221
+ pixelX1: t.pixelX,
222
+ pixelY1: t.pixelY,
223
+ pixelX2: i.pixelX,
224
+ pixelY2: i.pixelY
225
+ };
226
+ }
227
+ renderOverlay() {
228
+ if (!this.overlayCtx || !this.overlayCanvas) return;
229
+ this.resizeOverlay();
230
+ const t = this.ctx.container.getBoundingClientRect();
231
+ this.overlayCtx.clearRect(0, 0, t.width, t.height);
232
+ const i = this.options, e = this.overlayCtx, n = this.ctx.getPlotArea(), o = this.ctx.getViewBounds();
233
+ if (this.state.point1) {
234
+ const s = this.state.point1, l = this.ctx.getYBounds ? this.ctx.getYBounds(s.yAxisId) : { yMin: o.yMin, yMax: o.yMax };
235
+ s.pixelX = n.x + (s.x - o.xMin) / (o.xMax - o.xMin) * n.width, s.pixelY = n.y + (1 - (s.y - l.yMin) / (l.yMax - l.yMin)) * n.height;
236
+ }
237
+ if (this.state.point2) {
238
+ const s = this.state.point2, l = this.ctx.getYBounds ? this.ctx.getYBounds(s.yAxisId) : { yMin: o.yMin, yMax: o.yMax };
239
+ s.pixelX = n.x + (s.x - o.xMin) / (o.xMax - o.xMin) * n.width, s.pixelY = n.y + (1 - (s.y - l.yMin) / (l.yMax - l.yMin)) * n.height;
240
+ }
241
+ if (this.crosshairPosition && this.state.selectionState !== "complete") {
242
+ const s = this.crosshairPosition.x, l = this.crosshairPosition.y;
243
+ e.save(), e.setLineDash([4, 4]), e.strokeStyle = "rgba(150, 150, 150, 0.7)", e.lineWidth = 1, e.beginPath(), e.moveTo(s, n.y), e.lineTo(s, n.y + n.height), e.stroke(), e.beginPath(), e.moveTo(n.x, l), e.lineTo(n.x + n.width, l), e.stroke(), e.restore();
244
+ }
245
+ if (this.state.hoveredPoint && this.state.selectionState !== "complete") {
246
+ const s = this.state.hoveredPoint;
247
+ e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize + 4, 0, Math.PI * 2), e.fillStyle = i.highlightColor + "30", e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize, 0, Math.PI * 2), e.strokeStyle = i.highlightColor, e.lineWidth = 2, e.stroke(), e.beginPath(), e.arc(s.pixelX, s.pixelY, 4, 0, Math.PI * 2), e.fillStyle = i.highlightColor, e.fill(), this.drawPointTooltip(e, s, "Hover");
248
+ }
249
+ if (this.state.point1) {
250
+ const s = this.state.point1;
251
+ e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize, 0, Math.PI * 2), e.fillStyle = i.lineColor, e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize - 3, 0, Math.PI * 2), e.fillStyle = "#ffffff", e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, 3, 0, Math.PI * 2), e.fillStyle = i.lineColor, e.fill(), this.drawPointLabel(e, s.pixelX, s.pixelY - i.highlightSize - 8, "P1", i.lineColor);
252
+ }
253
+ if (this.state.point2) {
254
+ const s = this.state.point2;
255
+ e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize, 0, Math.PI * 2), e.fillStyle = "#4ade80", e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize - 3, 0, Math.PI * 2), e.fillStyle = "#ffffff", e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, 3, 0, Math.PI * 2), e.fillStyle = "#4ade80", e.fill(), this.drawPointLabel(e, s.pixelX, s.pixelY - i.highlightSize - 8, "P2", "#4ade80");
256
+ }
257
+ if (this.state.point1 && this.state.point2) {
258
+ const s = this.state.point1, l = this.state.point2;
259
+ e.beginPath(), e.moveTo(s.pixelX, s.pixelY), e.lineTo(l.pixelX, l.pixelY), e.strokeStyle = i.lineColor, e.lineWidth = i.lineWidth, e.setLineDash([6, 4]), e.stroke(), e.setLineDash([]), e.beginPath(), e.moveTo(s.pixelX, s.pixelY), e.lineTo(l.pixelX, s.pixelY), e.lineTo(l.pixelX, l.pixelY), e.strokeStyle = "rgba(255, 107, 107, 0.4)", e.lineWidth = 1, e.setLineDash([3, 3]), e.stroke(), e.setLineDash([]), i.showLabels && this.state.lastMeasurement && this.drawMeasurementLabel(e, s, l, this.state.lastMeasurement);
260
+ }
261
+ this.drawStatusIndicator(e);
262
+ }
263
+ drawPointTooltip(t, i, e) {
264
+ const n = this.options, o = `${e}: (${this.formatValue(i.x)}, ${this.formatValue(i.y)})`;
265
+ t.font = `${n.labelFontSize}px system-ui, sans-serif`;
266
+ const s = t.measureText(o), l = 6, h = s.width + l * 2, a = n.labelFontSize + l * 2;
267
+ let r = i.pixelX + 15, d = i.pixelY - a / 2;
268
+ const p = this.ctx.container.getBoundingClientRect();
269
+ r + h > p.width && (r = i.pixelX - h - 15), d < 0 && (d = 5), d + a > p.height && (d = p.height - a - 5), t.fillStyle = n.labelBackground, this.roundRect(t, r, d, h, a, 4), t.fill(), t.fillStyle = n.labelColor, t.textAlign = "left", t.textBaseline = "middle", t.fillText(o, r + l, d + a / 2);
270
+ }
271
+ drawPointLabel(t, i, e, n, o) {
272
+ const s = this.options;
273
+ t.font = `bold ${s.labelFontSize}px system-ui, sans-serif`, t.textAlign = "center", t.textBaseline = "bottom";
274
+ const l = t.measureText(n), h = 4, a = l.width + h * 2, r = s.labelFontSize + h;
275
+ t.fillStyle = o, this.roundRect(t, i - a / 2, e - r, a, r, 3), t.fill(), t.fillStyle = "#ffffff", t.fillText(n, i, e - 2);
276
+ }
277
+ drawMeasurementLabel(t, i, e, n) {
278
+ const o = this.options, s = (i.pixelX + e.pixelX) / 2, l = (i.pixelY + e.pixelY) / 2, h = [];
279
+ o.showDelta && (h.push(`ΔX: ${this.formatValue(n.deltaX)}`), h.push(`ΔY: ${this.formatValue(n.deltaY)}`)), o.showSlope && isFinite(n.slope) && h.push(`Slope: ${this.formatValue(n.slope)}`), o.showDistance && h.push(`Distance: ${this.formatValue(n.distance)}`);
280
+ const a = o.labelFontSize + 4, r = 10, d = 170, p = h.length * a + r * 2;
281
+ let c = s + this.labelOffset.x, g = l + this.labelOffset.y;
282
+ const y = this.ctx.container.getBoundingClientRect();
283
+ c < 0 && (c = 0), c + d > y.width && (c = y.width - d), g < 0 && (g = 0), g + p > y.height && (g = y.height - p), this.labelBounds = { x: c, y: g, width: d, height: p }, t.fillStyle = o.labelBackground, t.strokeStyle = o.lineColor, t.lineWidth = 2, this.roundRect(t, c, g, d, p, 8), t.fill(), t.stroke(), t.fillStyle = o.labelColor, t.font = `${o.labelFontSize}px system-ui, sans-serif`, t.textAlign = "left", t.textBaseline = "top", h.forEach((b, x) => {
284
+ t.fillText(b, c + r, g + r + x * a);
285
+ });
286
+ }
287
+ drawStatusIndicator(t) {
288
+ const i = this.options, e = this.ctx.getPlotArea();
289
+ let n = "", o = "#666";
290
+ if (this.state.selectionState === "idle" ? (n = "📏 Click a point to start measuring", o = i.highlightColor) : this.state.selectionState === "waitingSecond" ? (n = "📏 Click second point to complete", o = "#f59e0b") : this.state.selectionState === "complete" && (n = "📏 Measurement complete (ESC to clear)", o = "#4ade80"), !n) return;
291
+ t.font = "12px system-ui, sans-serif";
292
+ const h = t.measureText(n).width + 8 * 2, a = 24, r = e.x + 10, d = e.y + 10;
293
+ t.fillStyle = "rgba(0, 0, 0, 0.75)", this.roundRect(t, r, d, h, a, 4), t.fill(), t.beginPath(), t.arc(r + 16, d + a / 2, 4, 0, Math.PI * 2), t.fillStyle = o, t.fill(), t.fillStyle = "#fff", t.textAlign = "left", t.textBaseline = "middle", t.fillText(n, r + 26, d + a / 2);
294
+ }
295
+ roundRect(t, i, e, n, o, s) {
296
+ t.beginPath(), t.moveTo(i + s, e), t.lineTo(i + n - s, e), t.quadraticCurveTo(i + n, e, i + n, e + s), t.lineTo(i + n, e + o - s), t.quadraticCurveTo(i + n, e + o, i + n - s, e + o), t.lineTo(i + s, e + o), t.quadraticCurveTo(i, e + o, i, e + o - s), t.lineTo(i, e + s), t.quadraticCurveTo(i, e, i + s, e), t.closePath();
297
+ }
298
+ formatValue(t) {
299
+ const i = Math.abs(t);
300
+ return i === 0 ? "0" : i >= 1e6 || i < 1e-3 ? t.toExponential(this.options.precision - 1) : t.toPrecision(this.options.precision);
301
+ }
302
+ }
303
+ class rt {
304
+ constructor(t, i) {
305
+ u(this, "ctx");
306
+ u(this, "options");
307
+ u(this, "state", {
308
+ enabled: !1,
309
+ selectionState: "idle",
310
+ point1: null,
311
+ point2: null,
312
+ hoveredPoint: null,
313
+ lastMeasurement: null
314
+ });
315
+ u(this, "overlayCanvas", null);
316
+ u(this, "overlayCtx", null);
317
+ // Label dragging
318
+ u(this, "labelOffset", { x: 15, y: 0 });
319
+ u(this, "isDraggingLabel", !1);
320
+ u(this, "labelBounds", null);
321
+ u(this, "dragStart", { x: 0, y: 0 });
322
+ u(this, "crosshairPosition", null);
323
+ // Bound handlers
324
+ u(this, "boundMouseMove");
325
+ u(this, "boundClick");
326
+ u(this, "boundKeyDown");
327
+ u(this, "boundMouseDown");
328
+ u(this, "boundMouseUp");
329
+ u(this, "boundResize");
330
+ this.ctx = t, this.options = {
331
+ lineColor: "#ff6b6b",
332
+ lineWidth: 2,
333
+ showLabels: !0,
334
+ labelFontSize: 12,
335
+ labelBackground: "rgba(0, 0, 0, 0.85)",
336
+ labelColor: "#ffffff",
337
+ showPeak: !0,
338
+ precision: 4,
339
+ className: "velo-plot-peak-tool",
340
+ highlightSize: 12,
341
+ highlightColor: "#00f2ff",
342
+ snapRadius: 30,
343
+ baselineWindow: 10,
344
+ areaFill: "rgba(255, 107, 107, 0.3)",
345
+ ...i
346
+ }, this.boundMouseMove = this.handleMouseMove.bind(this), this.boundClick = this.handleClick.bind(this), this.boundKeyDown = this.handleKeyDown.bind(this), this.boundMouseDown = this.handleLabelMouseDown.bind(this), this.boundMouseUp = this.handleLabelMouseUp.bind(this), this.boundResize = this.resizeOverlay.bind(this);
347
+ }
348
+ /**
349
+ * Enable the peak measurement tool
350
+ */
351
+ enable() {
352
+ this.state.enabled || (this.state.enabled = !0, this.state.selectionState = "idle", this.createOverlay(), this.attachListeners(), this.ctx.container.style.cursor = "crosshair");
353
+ }
354
+ /**
355
+ * Disable the peak measurement tool
356
+ */
357
+ disable() {
358
+ this.state.enabled && (this.state.enabled = !1, this.state.selectionState = "idle", this.state.point1 = null, this.state.point2 = null, this.state.hoveredPoint = null, this.detachListeners(), this.destroyOverlay(), this.ctx.container.style.cursor = "");
359
+ }
360
+ /**
361
+ * Toggle the tool on/off
362
+ */
363
+ toggle() {
364
+ this.state.enabled ? this.disable() : this.enable();
365
+ }
366
+ /**
367
+ * Check if tool is enabled
368
+ */
369
+ isEnabled() {
370
+ return this.state.enabled;
371
+ }
372
+ /**
373
+ * Get the current state
374
+ */
375
+ getState() {
376
+ return { ...this.state };
377
+ }
378
+ /**
379
+ * Get the last completed measurement
380
+ */
381
+ getMeasurement() {
382
+ return this.state.lastMeasurement;
383
+ }
384
+ /**
385
+ * Clear the current measurement
386
+ */
387
+ clear() {
388
+ this.state.point1 = null, this.state.point2 = null, this.state.selectionState = "idle", this.state.lastMeasurement = null, this.labelBounds = null, this.labelOffset = { x: 15, y: 0 }, this.renderOverlay();
389
+ }
390
+ /**
391
+ * Destroy the tool and cleanup
392
+ */
393
+ destroy() {
394
+ this.disable(), this.state.lastMeasurement = null;
395
+ }
396
+ /**
397
+ * Recalculate measurements (useful if data changes)
398
+ */
399
+ recalculate() {
400
+ if (!this.state.point1 || !this.state.point2) return;
401
+ const t = this.ctx.getSeries ? this.ctx.getSeries() : [], i = (o) => {
402
+ const s = t.find((l) => l.id === o.seriesId);
403
+ if (s && o.index < s.x.length) {
404
+ o.x = s.x[o.index], o.y = s.y[o.index], o.yAxisId = s.yAxisId;
405
+ const l = this.ctx.getPlotArea(), h = this.ctx.getViewBounds(), a = this.ctx.getYBounds ? this.ctx.getYBounds(s.yAxisId) : { yMin: h.yMin, yMax: h.yMax };
406
+ return o.pixelX = l.x + (o.x - h.xMin) / (h.xMax - h.xMin) * l.width, o.pixelY = l.y + (1 - (o.y - a.yMin) / (a.yMax - a.yMin)) * l.height, !0;
407
+ }
408
+ return !1;
409
+ }, e = i(this.state.point1), n = i(this.state.point2);
410
+ e && n ? (this.state.lastMeasurement = this.calculateMeasurement(), this.ctx.onMeasure && this.ctx.onMeasure(this.state.lastMeasurement)) : this.clear(), this.renderOverlay();
411
+ }
412
+ // ============================================
413
+ // Private Methods
414
+ // ============================================
415
+ createOverlay() {
416
+ this.overlayCanvas || (this.overlayCanvas = document.createElement("canvas"), this.overlayCanvas.className = this.options.className, this.overlayCanvas.style.cssText = `
417
+ position: absolute;
418
+ top: 0;
419
+ left: 0;
420
+ width: 100%;
421
+ height: 100%;
422
+ pointer-events: none;
423
+ z-index: 1000;
424
+ `, this.resizeOverlay(), this.overlayCtx = this.overlayCanvas.getContext("2d"), this.ctx.container.appendChild(this.overlayCanvas));
425
+ }
426
+ resizeOverlay() {
427
+ if (!this.overlayCanvas) return;
428
+ const t = this.ctx.container.getBoundingClientRect(), i = window.devicePixelRatio || 1;
429
+ this.overlayCanvas.width = t.width * i, this.overlayCanvas.height = t.height * i, this.overlayCtx && (this.overlayCtx.setTransform(1, 0, 0, 1, 0, 0), this.overlayCtx.scale(i, i));
430
+ }
431
+ destroyOverlay() {
432
+ this.overlayCanvas && this.overlayCanvas.parentNode && this.overlayCanvas.parentNode.removeChild(this.overlayCanvas), this.overlayCanvas = null, this.overlayCtx = null;
433
+ }
434
+ attachListeners() {
435
+ this.ctx.container.addEventListener("mousemove", this.boundMouseMove, !0), this.ctx.container.addEventListener("mousedown", this.boundClick, !0), this.ctx.container.addEventListener("mousedown", this.boundMouseDown, !0), this.ctx.container.addEventListener("mouseup", this.boundMouseUp, !0), window.addEventListener("resize", this.boundResize), document.addEventListener("keydown", this.boundKeyDown);
436
+ }
437
+ detachListeners() {
438
+ this.ctx.container.removeEventListener("mousemove", this.boundMouseMove, !0), this.ctx.container.removeEventListener("mousedown", this.boundClick, !0), this.ctx.container.removeEventListener("mousedown", this.boundMouseDown, !0), this.ctx.container.removeEventListener("mouseup", this.boundMouseUp, !0), window.removeEventListener("resize", this.boundResize), document.removeEventListener("keydown", this.boundKeyDown);
439
+ }
440
+ handleMouseMove(t) {
441
+ if (!this.state.enabled) return;
442
+ const i = this.ctx.container.getBoundingClientRect(), e = this.ctx.getPlotArea(), n = this.ctx.getViewBounds(), o = t.clientX - i.left, s = t.clientY - i.top;
443
+ if (this.isDraggingLabel) {
444
+ this.labelOffset.x += o - this.dragStart.x, this.labelOffset.y += s - this.dragStart.y, this.dragStart = { x: o, y: s }, this.renderOverlay();
445
+ return;
446
+ }
447
+ if (this.labelBounds && o >= this.labelBounds.x && o <= this.labelBounds.x + this.labelBounds.width && s >= this.labelBounds.y && s <= this.labelBounds.y + this.labelBounds.height ? this.ctx.container.style.cursor = "move" : this.ctx.container.style.cursor = "crosshair", o < e.x || o > e.x + e.width || s < e.y || s > e.y + e.height) {
448
+ this.state.hoveredPoint = null, this.crosshairPosition = null, this.renderOverlay();
449
+ return;
450
+ }
451
+ this.crosshairPosition = { x: o, y: s };
452
+ const l = this.state.selectionState === "waitingSecond" && this.state.point1 ? this.state.point1.seriesId : void 0, h = this.findNearestPoint(o, s, e, n, l);
453
+ this.state.hoveredPoint = h, this.renderOverlay();
454
+ }
455
+ handleLabelMouseDown(t) {
456
+ if (!this.state.enabled || !this.labelBounds) return;
457
+ const i = this.ctx.container.getBoundingClientRect(), e = t.clientX - i.left, n = t.clientY - i.top;
458
+ e >= this.labelBounds.x && e <= this.labelBounds.x + this.labelBounds.width && n >= this.labelBounds.y && n <= this.labelBounds.y + this.labelBounds.height && (this.isDraggingLabel = !0, this.dragStart = { x: e, y: n }, t.stopPropagation(), t.preventDefault());
459
+ }
460
+ handleLabelMouseUp() {
461
+ this.isDraggingLabel = !1;
462
+ }
463
+ async handleClick(t) {
464
+ var a;
465
+ if (!this.state.enabled) return;
466
+ (a = this.ctx.animationEngine) != null && a.isAnimating() && await this.ctx.animationEngine.waitForIdle(), t.stopPropagation(), t.preventDefault();
467
+ const i = this.ctx.container.getBoundingClientRect(), e = this.ctx.getPlotArea(), n = this.ctx.getViewBounds(), o = t.clientX - i.left, s = t.clientY - i.top;
468
+ if (o < e.x || o > e.x + e.width || s < e.y || s > e.y + e.height)
469
+ return;
470
+ const l = this.state.selectionState === "waitingSecond" && this.state.point1 ? this.state.point1.seriesId : void 0, h = this.findNearestPoint(o, s, e, n, l);
471
+ if (h) {
472
+ if (t.preventDefault(), t.stopPropagation(), this.state.selectionState === "idle" || this.state.selectionState === "complete")
473
+ this.state.point1 = h, this.state.point2 = null, this.state.selectionState = "waitingSecond", this.state.lastMeasurement = null;
474
+ else if (this.state.selectionState === "waitingSecond") {
475
+ if (this.state.point1 && h.seriesId !== this.state.point1.seriesId)
476
+ return;
477
+ this.state.point2 = h, this.state.selectionState = "complete";
478
+ const r = this.calculateMeasurement();
479
+ this.state.lastMeasurement = r, this.ctx.onMeasure && this.ctx.onMeasure(r);
480
+ }
481
+ this.renderOverlay();
482
+ }
483
+ }
484
+ handleKeyDown(t) {
485
+ t.key === "Escape" && this.state.enabled && this.clear();
486
+ }
487
+ findNearestPoint(t, i, e, n, o) {
488
+ if (!this.ctx.getSeries) return null;
489
+ const s = this.ctx.getSeries();
490
+ let l = null, h = this.options.snapRadius;
491
+ for (const a of s) {
492
+ if (o && a.id !== o) continue;
493
+ const r = a.x, d = a.y, p = Math.min(r.length, d.length), c = this.ctx.getYBounds ? this.ctx.getYBounds(a.yAxisId) : { yMin: n.yMin, yMax: n.yMax };
494
+ for (let g = 0; g < p; g++) {
495
+ const y = r[g], b = d[g], x = e.x + (y - n.xMin) / (n.xMax - n.xMin) * e.width, S = e.y + (1 - (b - c.yMin) / (c.yMax - c.yMin)) * e.height;
496
+ if (x < e.x || x > e.x + e.width || S < e.y || S > e.y + e.height) continue;
497
+ const w = Math.sqrt((t - x) ** 2 + (i - S) ** 2);
498
+ w < h && (h = w, l = {
499
+ x: y,
500
+ y: b,
501
+ seriesId: a.id,
502
+ yAxisId: a.yAxisId,
503
+ index: g,
504
+ pixelX: x,
505
+ pixelY: S
506
+ });
507
+ }
508
+ }
509
+ return l;
510
+ }
511
+ calculateMeasurement() {
512
+ const t = this.state.point1, i = this.state.point2, n = (this.ctx.getSeries ? this.ctx.getSeries() : []).find((T) => T.id === t.seriesId);
513
+ if (!n)
514
+ return {
515
+ x1: t.x,
516
+ y1: t.y,
517
+ x2: i.x,
518
+ y2: i.y,
519
+ area: 0,
520
+ integral: 0,
521
+ baselineSlope: 0,
522
+ baselineIntercept: 0,
523
+ peakHeight: 0,
524
+ peakX: 0,
525
+ peakY: 0,
526
+ pixelX1: t.pixelX,
527
+ pixelY1: t.pixelY,
528
+ pixelX2: i.pixelX,
529
+ pixelY2: i.pixelY
530
+ };
531
+ const o = n.x, s = n.y, l = Math.min(t.index, i.index), h = Math.max(t.index, i.index), a = this.options.baselineWindow, r = [], d = [];
532
+ for (let T = Math.max(0, l - Math.floor(a / 2)); T <= Math.min(o.length - 1, l + Math.floor(a / 2)); T++)
533
+ r.push(o[T]), d.push(s[T]);
534
+ for (let T = Math.max(0, h - Math.floor(a / 2)); T <= Math.min(o.length - 1, h + Math.floor(a / 2)); T++)
535
+ r.push(o[T]), d.push(s[T]);
536
+ const p = r.length;
537
+ let c = 0, g = 0, y = 0, b = 0;
538
+ for (let T = 0; T < p; T++)
539
+ c += r[T], g += d[T], y += r[T] * d[T], b += r[T] * r[T];
540
+ const x = (p * y - c * g) / (p * b - c * c), S = (g - x * c) / p;
541
+ let w = 0, C = 0, m = -1 / 0, I = 0, v = 0;
542
+ for (let T = l; T < h; T++) {
543
+ const z = o[T], $ = s[T], D = o[T + 1], B = s[T + 1], V = D - z, _ = ($ + B) / 2;
544
+ C += _ * V;
545
+ const K = x * z + S, it = x * D + S, ot = (K + it) / 2;
546
+ w += (_ - ot) * V;
547
+ const U = $ - K;
548
+ U > m && (m = U, I = z, v = $);
549
+ }
550
+ return {
551
+ x1: t.x,
552
+ y1: t.y,
553
+ x2: i.x,
554
+ y2: i.y,
555
+ area: w,
556
+ integral: C,
557
+ baselineSlope: x,
558
+ baselineIntercept: S,
559
+ peakHeight: m,
560
+ peakX: I,
561
+ peakY: v,
562
+ pixelX1: t.pixelX,
563
+ pixelY1: t.pixelY,
564
+ pixelX2: i.pixelX,
565
+ pixelY2: i.pixelY
566
+ };
567
+ }
568
+ renderOverlay() {
569
+ if (!this.overlayCtx || !this.overlayCanvas) return;
570
+ this.resizeOverlay();
571
+ const t = this.ctx.container.getBoundingClientRect();
572
+ this.overlayCtx.clearRect(0, 0, t.width, t.height);
573
+ const i = this.options, e = this.overlayCtx, n = this.ctx.getPlotArea(), o = this.ctx.getViewBounds();
574
+ if (this.state.point1) {
575
+ const s = this.state.point1, l = this.ctx.getYBounds ? this.ctx.getYBounds(s.yAxisId) : { yMin: o.yMin, yMax: o.yMax };
576
+ s.pixelX = n.x + (s.x - o.xMin) / (o.xMax - o.xMin) * n.width, s.pixelY = n.y + (1 - (s.y - l.yMin) / (l.yMax - l.yMin)) * n.height;
577
+ }
578
+ if (this.state.point2) {
579
+ const s = this.state.point2, l = this.ctx.getYBounds ? this.ctx.getYBounds(s.yAxisId) : { yMin: o.yMin, yMax: o.yMax };
580
+ s.pixelX = n.x + (s.x - o.xMin) / (o.xMax - o.xMin) * n.width, s.pixelY = n.y + (1 - (s.y - l.yMin) / (l.yMax - l.yMin)) * n.height;
581
+ }
582
+ if (this.crosshairPosition && this.state.selectionState !== "complete") {
583
+ const s = this.crosshairPosition.x, l = this.crosshairPosition.y;
584
+ e.save(), e.setLineDash([4, 4]), e.strokeStyle = "rgba(150, 150, 150, 0.7)", e.lineWidth = 1, e.beginPath(), e.moveTo(s, n.y), e.lineTo(s, n.y + n.height), e.stroke(), e.beginPath(), e.moveTo(n.x, l), e.lineTo(n.x + n.width, l), e.stroke(), e.restore();
585
+ }
586
+ if (this.state.hoveredPoint && this.state.selectionState !== "complete") {
587
+ const s = this.state.hoveredPoint;
588
+ e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize + 4, 0, Math.PI * 2), e.fillStyle = i.highlightColor + "30", e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize, 0, Math.PI * 2), e.strokeStyle = i.highlightColor, e.lineWidth = 2, e.stroke(), e.beginPath(), e.arc(s.pixelX, s.pixelY, 4, 0, Math.PI * 2), e.fillStyle = i.highlightColor, e.fill(), this.drawPointTooltip(e, s, "Hover");
589
+ }
590
+ if (this.state.point1) {
591
+ const s = this.state.point1;
592
+ e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize, 0, Math.PI * 2), e.fillStyle = i.lineColor, e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize - 3, 0, Math.PI * 2), e.fillStyle = "#ffffff", e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, 3, 0, Math.PI * 2), e.fillStyle = i.lineColor, e.fill(), this.drawPointLabel(e, s.pixelX, s.pixelY - i.highlightSize - 8, "P1", i.lineColor);
593
+ }
594
+ if (this.state.point2) {
595
+ const s = this.state.point2;
596
+ e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize, 0, Math.PI * 2), e.fillStyle = "#4ade80", e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, i.highlightSize - 3, 0, Math.PI * 2), e.fillStyle = "#ffffff", e.fill(), e.beginPath(), e.arc(s.pixelX, s.pixelY, 3, 0, Math.PI * 2), e.fillStyle = "#4ade80", e.fill(), this.drawPointLabel(e, s.pixelX, s.pixelY - i.highlightSize - 8, "P2", "#4ade80");
597
+ }
598
+ if (this.state.point1 && this.state.point2 && this.state.lastMeasurement) {
599
+ const s = this.state.point1, l = this.state.point2, h = this.state.lastMeasurement, a = this.ctx.getPlotArea(), r = this.ctx.getViewBounds(), p = (this.ctx.getSeries ? this.ctx.getSeries() : []).find((S) => S.id === s.seriesId);
600
+ if (p) {
601
+ const S = p.x, w = p.y, C = Math.min(s.index, l.index), m = Math.max(s.index, l.index), I = this.ctx.getYBounds ? this.ctx.getYBounds(p.yAxisId) : { yMin: r.yMin, yMax: r.yMax };
602
+ e.beginPath(), e.moveTo(s.pixelX, s.pixelY);
603
+ for (let v = C; v <= m; v++) {
604
+ const T = a.x + (S[v] - r.xMin) / (r.xMax - r.xMin) * a.width, z = a.y + (1 - (w[v] - I.yMin) / (I.yMax - I.yMin)) * a.height;
605
+ e.lineTo(T, z);
606
+ }
607
+ e.lineTo(l.pixelX, l.pixelY), e.closePath(), e.fillStyle = i.areaFill, e.fill();
608
+ }
609
+ e.beginPath(), e.moveTo(s.pixelX, s.pixelY), e.lineTo(l.pixelX, l.pixelY), e.strokeStyle = i.lineColor, e.lineWidth = 1, e.stroke();
610
+ const c = this.ctx.getYBounds ? this.ctx.getYBounds(s.yAxisId) : { yMin: r.yMin, yMax: r.yMax }, g = a.x + (h.peakX - r.xMin) / (r.xMax - r.xMin) * a.width, y = a.y + (1 - (h.peakY - c.yMin) / (c.yMax - c.yMin)) * a.height, b = h.baselineSlope * h.peakX + h.baselineIntercept, x = a.y + (1 - (b - c.yMin) / (c.yMax - c.yMin)) * a.height;
611
+ e.beginPath(), e.moveTo(g, y), e.lineTo(g, x), e.strokeStyle = i.lineColor, e.setLineDash([2, 2]), e.stroke(), e.setLineDash([]), i.showLabels && this.drawMeasurementLabel(e, s, l, h);
612
+ }
613
+ this.drawStatusIndicator(e);
614
+ }
615
+ drawPointTooltip(t, i, e) {
616
+ const n = this.options, o = `${e}: (${this.formatValue(i.x)}, ${this.formatValue(i.y)})`;
617
+ t.font = `${n.labelFontSize}px system-ui, sans-serif`;
618
+ const s = t.measureText(o), l = 6, h = s.width + l * 2, a = n.labelFontSize + l * 2;
619
+ let r = i.pixelX + 15, d = i.pixelY - a / 2;
620
+ const p = this.ctx.container.getBoundingClientRect();
621
+ r + h > p.width && (r = i.pixelX - h - 15), d < 0 && (d = 5), d + a > p.height && (d = p.height - a - 5), t.fillStyle = n.labelBackground, this.roundRect(t, r, d, h, a, 4), t.fill(), t.fillStyle = n.labelColor, t.textAlign = "left", t.textBaseline = "middle", t.fillText(o, r + l, d + a / 2);
622
+ }
623
+ drawPointLabel(t, i, e, n, o) {
624
+ const s = this.options;
625
+ t.font = `bold ${s.labelFontSize}px system-ui, sans-serif`, t.textAlign = "center", t.textBaseline = "bottom";
626
+ const l = t.measureText(n), h = 4, a = l.width + h * 2, r = s.labelFontSize + h;
627
+ t.fillStyle = o, this.roundRect(t, i - a / 2, e - r, a, r, 3), t.fill(), t.fillStyle = "#ffffff", t.fillText(n, i, e - 2);
628
+ }
629
+ drawMeasurementLabel(t, i, e, n) {
630
+ const o = this.options, s = (i.pixelX + e.pixelX) / 2, l = (i.pixelY + e.pixelY) / 2, h = [];
631
+ o.showPeak && (h.push(`Peak Area: ${this.formatValue(n.area)}`), h.push(`Peak Height: ${this.formatValue(n.peakHeight)}`), h.push(`Integral: ${this.formatValue(n.integral)}`));
632
+ const a = o.labelFontSize + 4, r = 10, d = 170, p = h.length * a + r * 2;
633
+ let c = s + this.labelOffset.x, g = l + this.labelOffset.y;
634
+ const y = this.ctx.container.getBoundingClientRect();
635
+ c < 0 && (c = 0), c + d > y.width && (c = y.width - d), g < 0 && (g = 0), g + p > y.height && (g = y.height - p), this.labelBounds = { x: c, y: g, width: d, height: p }, t.fillStyle = o.labelBackground, t.strokeStyle = o.lineColor, t.lineWidth = 2, this.roundRect(t, c, g, d, p, 8), t.fill(), t.stroke(), t.fillStyle = o.labelColor, t.font = `${o.labelFontSize}px system-ui, sans-serif`, t.textAlign = "left", t.textBaseline = "top", h.forEach((b, x) => {
636
+ t.fillText(b, c + r, g + r + x * a);
637
+ });
638
+ }
639
+ drawStatusIndicator(t) {
640
+ const i = this.options, e = this.ctx.getPlotArea();
641
+ let n = "", o = "#666";
642
+ if (this.state.selectionState === "idle" ? (n = "📏 Click a point to start measuring", o = i.highlightColor) : this.state.selectionState === "waitingSecond" ? (n = "📏 Click second point to complete", o = "#f59e0b") : this.state.selectionState === "complete" && (n = "📏 Measurement complete (ESC to clear)", o = "#4ade80"), !n) return;
643
+ t.font = "12px system-ui, sans-serif";
644
+ const h = t.measureText(n).width + 8 * 2, a = 24, r = e.x + 10, d = e.y + 10;
645
+ t.fillStyle = "rgba(0, 0, 0, 0.75)", this.roundRect(t, r, d, h, a, 4), t.fill(), t.beginPath(), t.arc(r + 16, d + a / 2, 4, 0, Math.PI * 2), t.fillStyle = o, t.fill(), t.fillStyle = "#fff", t.textAlign = "left", t.textBaseline = "middle", t.fillText(n, r + 26, d + a / 2);
646
+ }
647
+ roundRect(t, i, e, n, o, s) {
648
+ t.beginPath(), t.moveTo(i + s, e), t.lineTo(i + n - s, e), t.quadraticCurveTo(i + n, e, i + n, e + s), t.lineTo(i + n, e + o - s), t.quadraticCurveTo(i + n, e + o, i + n - s, e + o), t.lineTo(i + s, e + o), t.quadraticCurveTo(i, e + o, i, e + o - s), t.lineTo(i, e + s), t.quadraticCurveTo(i, e, i + s, e), t.closePath();
649
+ }
650
+ formatValue(t) {
651
+ const i = Math.abs(t);
652
+ return i === 0 ? "0" : i >= 1e6 || i < 1e-3 ? t.toExponential(this.options.precision - 1) : t.toPrecision(this.options.precision);
653
+ }
654
+ }
655
+ const W = {
656
+ top: 10,
657
+ right: 12,
658
+ bottom: 10,
659
+ left: 12
660
+ }, L = {
661
+ // Container
662
+ backgroundColor: "rgba(15, 18, 25, 0.95)",
663
+ backgroundGradient: "rgba(25, 30, 40, 0.90)",
664
+ borderColor: "rgba(255, 255, 255, 0.12)",
665
+ borderWidth: 1,
666
+ borderRadius: 8,
667
+ backdropBlur: 12,
668
+ shadow: {
669
+ color: "rgba(0, 0, 0, 0.4)",
670
+ offsetX: 0,
671
+ offsetY: 4,
672
+ blur: 16
673
+ },
674
+ // Typography
675
+ fontFamily: "Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
676
+ textColor: "#ffffff",
677
+ textSecondaryColor: "rgba(255, 255, 255, 0.6)",
678
+ titleFontSize: 12,
679
+ titleFontWeight: 600,
680
+ contentFontSize: 11,
681
+ lineHeight: 1.4,
682
+ // Spacing
683
+ padding: W,
684
+ itemGap: 4,
685
+ headerGap: 8,
686
+ // Decorations
687
+ showSeriesIndicator: !0,
688
+ seriesIndicatorSize: 8,
689
+ showHeaderSeparator: !0,
690
+ separatorColor: "rgba(255, 255, 255, 0.1)",
691
+ showArrow: !0,
692
+ arrowSize: 6
693
+ }, J = {
694
+ // Container
695
+ backgroundColor: "rgba(255, 255, 255, 0.98)",
696
+ borderColor: "rgba(0, 0, 0, 0.12)",
697
+ borderWidth: 1,
698
+ borderRadius: 8,
699
+ backdropBlur: 8,
700
+ shadow: {
701
+ color: "rgba(0, 0, 0, 0.12)",
702
+ offsetX: 0,
703
+ offsetY: 4,
704
+ blur: 12
705
+ },
706
+ // Typography
707
+ fontFamily: "Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
708
+ textColor: "#1a1a1a",
709
+ textSecondaryColor: "rgba(0, 0, 0, 0.55)",
710
+ titleFontSize: 12,
711
+ titleFontWeight: 600,
712
+ contentFontSize: 11,
713
+ lineHeight: 1.4,
714
+ // Spacing
715
+ padding: W,
716
+ itemGap: 4,
717
+ headerGap: 8,
718
+ // Decorations
719
+ showSeriesIndicator: !0,
720
+ seriesIndicatorSize: 8,
721
+ showHeaderSeparator: !0,
722
+ separatorColor: "rgba(0, 0, 0, 0.08)",
723
+ showArrow: !0,
724
+ arrowSize: 6
725
+ }, ht = {
726
+ // Container
727
+ backgroundColor: "rgba(255, 255, 255, 0.08)",
728
+ backgroundGradient: "rgba(255, 255, 255, 0.04)",
729
+ borderColor: "rgba(255, 255, 255, 0.2)",
730
+ borderWidth: 1,
731
+ borderRadius: 12,
732
+ backdropBlur: 20,
733
+ shadow: {
734
+ color: "rgba(0, 0, 0, 0.3)",
735
+ offsetX: 0,
736
+ offsetY: 8,
737
+ blur: 32
738
+ },
739
+ // Typography
740
+ fontFamily: "Inter, system-ui, sans-serif",
741
+ textColor: "rgba(255, 255, 255, 0.95)",
742
+ textSecondaryColor: "rgba(255, 255, 255, 0.6)",
743
+ titleFontSize: 12,
744
+ titleFontWeight: 600,
745
+ contentFontSize: 11,
746
+ lineHeight: 1.5,
747
+ // Spacing
748
+ padding: { top: 12, right: 14, bottom: 12, left: 14 },
749
+ itemGap: 5,
750
+ headerGap: 10,
751
+ // Decorations
752
+ showSeriesIndicator: !0,
753
+ seriesIndicatorSize: 8,
754
+ showHeaderSeparator: !0,
755
+ separatorColor: "rgba(255, 255, 255, 0.15)",
756
+ showArrow: !0,
757
+ arrowSize: 7
758
+ }, Q = {
759
+ // Container
760
+ backgroundColor: "rgba(10, 15, 30, 0.95)",
761
+ backgroundGradient: "rgba(20, 25, 50, 0.90)",
762
+ borderColor: "rgba(100, 120, 255, 0.25)",
763
+ borderWidth: 1,
764
+ borderRadius: 8,
765
+ backdropBlur: 15,
766
+ shadow: {
767
+ color: "rgba(50, 70, 150, 0.25)",
768
+ offsetX: 0,
769
+ offsetY: 4,
770
+ blur: 20
771
+ },
772
+ // Typography
773
+ fontFamily: "Inter, system-ui, sans-serif",
774
+ textColor: "#e0e8ff",
775
+ textSecondaryColor: "rgba(180, 190, 255, 0.6)",
776
+ titleFontSize: 12,
777
+ titleFontWeight: 600,
778
+ contentFontSize: 11,
779
+ lineHeight: 1.4,
780
+ // Spacing
781
+ padding: W,
782
+ itemGap: 4,
783
+ headerGap: 8,
784
+ // Decorations
785
+ showSeriesIndicator: !0,
786
+ seriesIndicatorSize: 8,
787
+ showHeaderSeparator: !0,
788
+ separatorColor: "rgba(100, 120, 255, 0.15)",
789
+ showArrow: !0,
790
+ arrowSize: 6
791
+ }, Z = {
792
+ // Container
793
+ backgroundColor: "rgba(8, 20, 40, 0.96)",
794
+ backgroundGradient: "rgba(15, 35, 60, 0.92)",
795
+ borderColor: "rgba(30, 136, 229, 0.35)",
796
+ borderWidth: 1,
797
+ borderRadius: 6,
798
+ backdropBlur: 10,
799
+ shadow: {
800
+ color: "rgba(30, 136, 229, 0.2)",
801
+ offsetX: 0,
802
+ offsetY: 4,
803
+ blur: 16
804
+ },
805
+ // Typography
806
+ fontFamily: '"JetBrains Mono", "Fira Code", monospace',
807
+ textColor: "#bbdefb",
808
+ textSecondaryColor: "rgba(144, 202, 249, 0.7)",
809
+ titleFontSize: 11,
810
+ titleFontWeight: 600,
811
+ contentFontSize: 11,
812
+ lineHeight: 1.5,
813
+ // Spacing
814
+ padding: { top: 8, right: 10, bottom: 8, left: 10 },
815
+ itemGap: 3,
816
+ headerGap: 6,
817
+ // Decorations
818
+ showSeriesIndicator: !0,
819
+ seriesIndicatorSize: 6,
820
+ showHeaderSeparator: !0,
821
+ separatorColor: "rgba(30, 136, 229, 0.2)",
822
+ showArrow: !0,
823
+ arrowSize: 5
824
+ }, dt = {
825
+ // Container
826
+ backgroundColor: "rgba(0, 0, 0, 0.92)",
827
+ borderColor: "#00ffff",
828
+ borderWidth: 1,
829
+ borderRadius: 4,
830
+ backdropBlur: 0,
831
+ shadow: {
832
+ color: "rgba(0, 255, 255, 0.35)",
833
+ offsetX: 0,
834
+ offsetY: 0,
835
+ blur: 20
836
+ },
837
+ // Typography
838
+ fontFamily: '"Orbitron", "Exo 2", sans-serif',
839
+ textColor: "#00ffff",
840
+ textSecondaryColor: "rgba(0, 255, 255, 0.6)",
841
+ titleFontSize: 11,
842
+ titleFontWeight: 700,
843
+ contentFontSize: 10,
844
+ lineHeight: 1.4,
845
+ // Spacing
846
+ padding: { top: 8, right: 12, bottom: 8, left: 12 },
847
+ itemGap: 4,
848
+ headerGap: 6,
849
+ // Decorations
850
+ showSeriesIndicator: !0,
851
+ seriesIndicatorSize: 6,
852
+ showHeaderSeparator: !0,
853
+ separatorColor: "rgba(0, 255, 255, 0.3)",
854
+ showArrow: !1,
855
+ arrowSize: 0
856
+ }, ct = {
857
+ // Container
858
+ backgroundColor: "rgba(30, 35, 45, 0.9)",
859
+ borderColor: "transparent",
860
+ borderWidth: 0,
861
+ borderRadius: 4,
862
+ backdropBlur: 8,
863
+ shadow: {
864
+ color: "rgba(0, 0, 0, 0.3)",
865
+ offsetX: 0,
866
+ offsetY: 2,
867
+ blur: 8
868
+ },
869
+ // Typography
870
+ fontFamily: "Inter, system-ui, sans-serif",
871
+ textColor: "#ffffff",
872
+ textSecondaryColor: "rgba(255, 255, 255, 0.7)",
873
+ titleFontSize: 10,
874
+ titleFontWeight: 500,
875
+ contentFontSize: 10,
876
+ lineHeight: 1.3,
877
+ // Spacing
878
+ padding: { top: 6, right: 8, bottom: 6, left: 8 },
879
+ itemGap: 2,
880
+ headerGap: 4,
881
+ // Decorations
882
+ showSeriesIndicator: !1,
883
+ seriesIndicatorSize: 0,
884
+ showHeaderSeparator: !1,
885
+ separatorColor: "transparent",
886
+ showArrow: !1,
887
+ arrowSize: 0
888
+ }, ut = {
889
+ dark: L,
890
+ light: J,
891
+ glass: ht,
892
+ midnight: Q,
893
+ electrochemistry: Z,
894
+ neon: dt,
895
+ minimal: ct
896
+ };
897
+ function ft(f) {
898
+ const t = ut[f];
899
+ return t || (console.warn(`[Tooltip] Unknown theme "${f}", using dark`), L);
900
+ }
901
+ function pt(f, t) {
902
+ const i = typeof f == "string" ? ft(f) : f;
903
+ return {
904
+ ...i,
905
+ ...t,
906
+ padding: { ...i.padding, ...t.padding },
907
+ shadow: { ...i.shadow, ...t.shadow }
908
+ };
909
+ }
910
+ function k(f) {
911
+ switch (f.toLowerCase()) {
912
+ case "light":
913
+ return J;
914
+ case "midnight":
915
+ return Q;
916
+ case "electrochemistry":
917
+ case "electrochem":
918
+ return Z;
919
+ case "dark":
920
+ default:
921
+ return L;
922
+ }
923
+ }
924
+ const gt = L, yt = {
925
+ offset: { x: 12, y: 12 },
926
+ preferredPosition: "auto",
927
+ constrainToPlotArea: !0,
928
+ constrainToContainer: !0,
929
+ autoFlip: !0,
930
+ showArrow: !0,
931
+ arrowSize: 6
932
+ };
933
+ class xt {
934
+ constructor(t = {}) {
935
+ u(this, "config");
936
+ u(this, "containerWidth", 0);
937
+ u(this, "containerHeight", 0);
938
+ u(this, "plotArea", null);
939
+ this.config = { ...yt, ...t };
940
+ }
941
+ /**
942
+ * Update container dimensions
943
+ */
944
+ setContainerSize(t, i) {
945
+ this.containerWidth = t, this.containerHeight = i;
946
+ }
947
+ /**
948
+ * Update plot area bounds
949
+ */
950
+ setPlotArea(t) {
951
+ this.plotArea = t;
952
+ }
953
+ /**
954
+ * Update configuration
955
+ */
956
+ configure(t) {
957
+ this.config = { ...this.config, ...t };
958
+ }
959
+ /**
960
+ * Calculate optimal tooltip position
961
+ *
962
+ * @param targetX - Target X coordinate (where tooltip points to)
963
+ * @param targetY - Target Y coordinate
964
+ * @param measurement - Tooltip dimensions
965
+ * @returns Calculated position with arrow configuration
966
+ */
967
+ calculatePosition(t, i, e) {
968
+ const { offset: n, preferredPosition: o, autoFlip: s, showArrow: l, arrowSize: h } = this.config, a = e.width + e.padding.left + e.padding.right, r = e.height + e.padding.top + e.padding.bottom;
969
+ let d = this.determinePosition(
970
+ t,
971
+ i,
972
+ a,
973
+ r,
974
+ o
975
+ ), { x: p, y: c, arrowPosition: g } = this.calculateCoordinates(
976
+ t,
977
+ i,
978
+ a,
979
+ r,
980
+ d,
981
+ n,
982
+ l ? h : 0
983
+ ), y = !1;
984
+ if (s && !this.fitsInBounds(p, c, a, r)) {
985
+ const S = this.flipPosition(d), w = this.calculateCoordinates(
986
+ t,
987
+ i,
988
+ a,
989
+ r,
990
+ S,
991
+ n,
992
+ l ? h : 0
993
+ );
994
+ this.fitsInBounds(w.x, w.y, a, r) && (p = w.x, c = w.y, g = w.arrowPosition, y = !0);
995
+ }
996
+ const b = this.constrainToBounds(p, c, a, r);
997
+ let x = 0;
998
+ if (l) {
999
+ if (g === "top" || g === "bottom") {
1000
+ const S = t - b.x;
1001
+ x = Math.max(h + 4, Math.min(a - h - 4, S));
1002
+ } else if (g === "left" || g === "right") {
1003
+ const S = i - b.y;
1004
+ x = Math.max(h + 4, Math.min(r - h - 4, S));
1005
+ }
1006
+ }
1007
+ return {
1008
+ x: b.x,
1009
+ y: b.y,
1010
+ arrowPosition: l ? g : "none",
1011
+ arrowOffset: x,
1012
+ wasFlipped: y
1013
+ };
1014
+ }
1015
+ /**
1016
+ * Determine best position based on available space
1017
+ */
1018
+ determinePosition(t, i, e, n, o) {
1019
+ if (o !== "auto")
1020
+ return o;
1021
+ const s = this.getConstraintBounds(), l = i - s.top, h = s.bottom - i, a = t - s.left, r = s.right - t, d = l >= n + this.config.offset.y, p = h >= n + this.config.offset.y, c = r >= e + this.config.offset.x, g = a >= e + this.config.offset.x;
1022
+ return d && l >= h ? "top" : p ? "bottom" : c && r >= a ? "right" : g ? "left" : [
1023
+ { pos: "top", space: l },
1024
+ { pos: "bottom", space: h },
1025
+ { pos: "right", space: r },
1026
+ { pos: "left", space: a }
1027
+ ].sort((b, x) => x.space - b.space)[0].pos;
1028
+ }
1029
+ /**
1030
+ * Calculate tooltip coordinates for a given position
1031
+ */
1032
+ calculateCoordinates(t, i, e, n, o, s, l) {
1033
+ let h, a, r;
1034
+ switch (o) {
1035
+ case "top":
1036
+ h = t - e / 2, a = i - n - s.y - l, r = "bottom";
1037
+ break;
1038
+ case "bottom":
1039
+ h = t - e / 2, a = i + s.y + l, r = "top";
1040
+ break;
1041
+ case "right":
1042
+ h = t + s.x + l, a = i - n / 2, r = "left";
1043
+ break;
1044
+ case "left":
1045
+ h = t - e - s.x - l, a = i - n / 2, r = "right";
1046
+ break;
1047
+ }
1048
+ return { x: h, y: a, arrowPosition: r };
1049
+ }
1050
+ /**
1051
+ * Get the opposite position for flipping
1052
+ */
1053
+ flipPosition(t) {
1054
+ switch (t) {
1055
+ case "top":
1056
+ return "bottom";
1057
+ case "bottom":
1058
+ return "top";
1059
+ case "left":
1060
+ return "right";
1061
+ case "right":
1062
+ return "left";
1063
+ }
1064
+ }
1065
+ /**
1066
+ * Check if tooltip fits within bounds
1067
+ */
1068
+ fitsInBounds(t, i, e, n) {
1069
+ const o = this.getConstraintBounds();
1070
+ return t >= o.left && i >= o.top && t + e <= o.right && i + n <= o.bottom;
1071
+ }
1072
+ /**
1073
+ * Constrain position to stay within bounds
1074
+ */
1075
+ constrainToBounds(t, i, e, n) {
1076
+ const o = this.getConstraintBounds(), s = 4;
1077
+ let l = t, h = i;
1078
+ return l < o.left + s ? l = o.left + s : l + e > o.right - s && (l = o.right - e - s), h < o.top + s ? h = o.top + s : h + n > o.bottom - s && (h = o.bottom - n - s), { x: l, y: h };
1079
+ }
1080
+ /**
1081
+ * Get the bounds to constrain tooltip within
1082
+ */
1083
+ getConstraintBounds() {
1084
+ let t = {
1085
+ top: 0,
1086
+ left: 0,
1087
+ right: this.containerWidth,
1088
+ bottom: this.containerHeight
1089
+ };
1090
+ return this.config.constrainToPlotArea && this.plotArea && (t = {
1091
+ top: Math.max(t.top, this.plotArea.y),
1092
+ left: Math.max(t.left, this.plotArea.x),
1093
+ right: Math.min(t.right, this.plotArea.x + this.plotArea.width),
1094
+ bottom: Math.min(t.bottom, this.plotArea.y + this.plotArea.height)
1095
+ }), t;
1096
+ }
1097
+ /**
1098
+ * Calculate position for crosshair tooltip (follows cursor vertically)
1099
+ */
1100
+ calculateCrosshairPosition(t, i, e) {
1101
+ const { offset: n } = this.config, o = this.getConstraintBounds(), s = e.width + e.padding.left + e.padding.right, l = e.height + e.padding.top + e.padding.bottom;
1102
+ let h = t + n.x, a = "left";
1103
+ h + s > o.right - 4 && (h = t - s - n.x, a = "right");
1104
+ let r = i - l / 2;
1105
+ r = Math.max(o.top + 4, Math.min(o.bottom - l - 4, r));
1106
+ const d = i - r;
1107
+ return {
1108
+ x: h,
1109
+ y: r,
1110
+ arrowPosition: a,
1111
+ arrowOffset: Math.max(8, Math.min(l - 8, d)),
1112
+ wasFlipped: a === "right"
1113
+ };
1114
+ }
1115
+ }
1116
+ class bt {
1117
+ constructor(t, i) {
1118
+ u(this, "ctx");
1119
+ u(this, "theme");
1120
+ this.ctx = t, this.theme = i;
1121
+ }
1122
+ /**
1123
+ * Update the theme
1124
+ */
1125
+ setTheme(t) {
1126
+ this.theme = t;
1127
+ }
1128
+ /**
1129
+ * Render a tooltip with the given template
1130
+ */
1131
+ render(t, i, e) {
1132
+ const n = e.measure(this.ctx, t, this.theme), o = n.width + n.padding.left + n.padding.right, s = n.height + n.padding.top + n.padding.bottom;
1133
+ this.ctx.save(), this.drawBackground(i.x, i.y, o, s, i.arrowPosition || "none"), i.arrowPosition && i.arrowPosition !== "none" && this.drawArrow(
1134
+ i.x,
1135
+ i.y,
1136
+ o,
1137
+ s,
1138
+ i.arrowPosition,
1139
+ i.arrowOffset || 0
1140
+ ), e.render(this.ctx, t, i, n, this.theme), this.ctx.restore();
1141
+ }
1142
+ /**
1143
+ * Draw tooltip background with all effects
1144
+ */
1145
+ drawBackground(t, i, e, n, o) {
1146
+ const { ctx: s, theme: l } = this, h = l.borderRadius;
1147
+ if (s.save(), l.shadow.blur > 0 && (s.shadowColor = l.shadow.color, s.shadowOffsetX = l.shadow.offsetX, s.shadowOffsetY = l.shadow.offsetY, s.shadowBlur = l.shadow.blur), s.beginPath(), this.roundRect(t, i, e, n, h), l.backgroundGradient) {
1148
+ const a = s.createLinearGradient(t, i, t, i + n);
1149
+ a.addColorStop(0, l.backgroundColor), a.addColorStop(1, l.backgroundGradient), s.fillStyle = a;
1150
+ } else
1151
+ s.fillStyle = l.backgroundColor;
1152
+ s.fill(), s.shadowColor = "transparent", l.borderWidth > 0 && (s.strokeStyle = l.borderColor, s.lineWidth = l.borderWidth, s.stroke()), s.restore();
1153
+ }
1154
+ /**
1155
+ * Draw arrow pointing to target
1156
+ */
1157
+ drawArrow(t, i, e, n, o, s) {
1158
+ const { ctx: l, theme: h } = this, a = h.arrowSize;
1159
+ if (!(a <= 0 || o === "none")) {
1160
+ switch (l.save(), l.fillStyle = h.backgroundColor, l.strokeStyle = h.borderColor, l.lineWidth = h.borderWidth, l.beginPath(), o) {
1161
+ case "top":
1162
+ const r = t + s;
1163
+ l.moveTo(r - a, i), l.lineTo(r, i - a), l.lineTo(r + a, i);
1164
+ break;
1165
+ case "bottom":
1166
+ const d = t + s, p = i + n;
1167
+ l.moveTo(d - a, p), l.lineTo(d, p + a), l.lineTo(d + a, p);
1168
+ break;
1169
+ case "left":
1170
+ const c = i + s;
1171
+ l.moveTo(t, c - a), l.lineTo(t - a, c), l.lineTo(t, c + a);
1172
+ break;
1173
+ case "right":
1174
+ const g = t + e, y = i + s;
1175
+ l.moveTo(g, y - a), l.lineTo(g + a, y), l.lineTo(g, y + a);
1176
+ break;
1177
+ }
1178
+ l.closePath(), l.fill(), h.borderWidth > 0 && l.stroke(), l.restore();
1179
+ }
1180
+ }
1181
+ /**
1182
+ * Draw a rounded rectangle path
1183
+ */
1184
+ roundRect(t, i, e, n, o) {
1185
+ const { ctx: s } = this, l = Math.min(o, e / 2, n / 2);
1186
+ s.moveTo(t + l, i), s.lineTo(t + e - l, i), s.arcTo(t + e, i, t + e, i + l, l), s.lineTo(t + e, i + n - l), s.arcTo(t + e, i + n, t + e - l, i + n, l), s.lineTo(t + l, i + n), s.arcTo(t, i + n, t, i + n - l, l), s.lineTo(t, i + l), s.arcTo(t, i, t + l, i, l), s.closePath();
1187
+ }
1188
+ /**
1189
+ * Draw a horizontal separator line
1190
+ */
1191
+ drawSeparator(t, i, e) {
1192
+ const { ctx: n, theme: o } = this;
1193
+ o.showHeaderSeparator && (n.save(), n.strokeStyle = o.separatorColor, n.lineWidth = 1, n.beginPath(), n.moveTo(t, i), n.lineTo(t + e, i), n.stroke(), n.restore());
1194
+ }
1195
+ /**
1196
+ * Draw a series color indicator (small circle or square)
1197
+ */
1198
+ drawSeriesIndicator(t, i, e) {
1199
+ const { ctx: n, theme: o } = this;
1200
+ if (!o.showSeriesIndicator) return;
1201
+ const l = o.seriesIndicatorSize / 2;
1202
+ n.save(), n.fillStyle = e, n.beginPath(), n.arc(t + l, i, l, 0, Math.PI * 2), n.fill(), n.restore();
1203
+ }
1204
+ /**
1205
+ * Measure text width
1206
+ */
1207
+ measureText(t, i, e = 400) {
1208
+ const { ctx: n, theme: o } = this;
1209
+ return n.font = `${e} ${i}px ${o.fontFamily}`, n.measureText(t).width;
1210
+ }
1211
+ /**
1212
+ * Draw text with theme styling
1213
+ */
1214
+ drawText(t, i, e, n = {}) {
1215
+ const { ctx: o, theme: s } = this, {
1216
+ fontSize: l = s.contentFontSize,
1217
+ fontWeight: h = 400,
1218
+ color: a = s.textColor,
1219
+ align: r = "left",
1220
+ baseline: d = "top"
1221
+ } = n;
1222
+ o.save(), o.font = `${h} ${l}px ${s.fontFamily}`, o.fillStyle = a, o.textAlign = r, o.textBaseline = d, o.fillText(t, i, e), o.restore();
1223
+ }
1224
+ /**
1225
+ * Draw a label-value pair
1226
+ */
1227
+ drawLabelValue(t, i, e, n, o) {
1228
+ const { theme: s } = this;
1229
+ this.drawText(e, t, i, {
1230
+ color: s.textSecondaryColor,
1231
+ fontSize: s.contentFontSize
1232
+ }), this.drawText(n, t + o, i, {
1233
+ color: s.textColor,
1234
+ fontSize: s.contentFontSize,
1235
+ align: "right"
1236
+ });
1237
+ }
1238
+ /**
1239
+ * Get theme for external use
1240
+ */
1241
+ getTheme() {
1242
+ return this.theme;
1243
+ }
1244
+ }
1245
+ function Y(f, t = 4) {
1246
+ if (f == null || isNaN(f))
1247
+ return "N/A";
1248
+ const i = Math.abs(f);
1249
+ return i !== 0 && (i < 1e-4 || i >= 1e4) ? f.toExponential(2) : i < 0.01 ? f.toPrecision(t) : i < 1 ? f.toFixed(4) : i < 100 ? f.toFixed(3) : f.toFixed(1);
1250
+ }
1251
+ class St {
1252
+ constructor() {
1253
+ u(this, "id", "default");
1254
+ u(this, "name", "Default Data Point");
1255
+ u(this, "supportedTypes", ["datapoint"]);
1256
+ // Cached measurements
1257
+ u(this, "cachedKey", "");
1258
+ u(this, "cachedMeasurement", null);
1259
+ }
1260
+ /**
1261
+ * Measure tooltip dimensions
1262
+ */
1263
+ measure(t, i, e) {
1264
+ const n = `${i.seriesId}-${i.dataIndex}-${i.dataX}-${i.dataY}`;
1265
+ if (n === this.cachedKey && this.cachedMeasurement)
1266
+ return this.cachedMeasurement;
1267
+ t.font = `${e.titleFontWeight} ${e.titleFontSize}px ${e.fontFamily}`;
1268
+ const o = t.measureText(i.seriesName).width;
1269
+ t.font = `400 ${e.contentFontSize}px ${e.fontFamily}`;
1270
+ const s = 35, l = t.measureText(Y(i.dataX)).width, h = t.measureText(Y(i.dataY)).width;
1271
+ let a = s + Math.max(l, h), r = e.contentFontSize * e.lineHeight * 2;
1272
+ if (i.yError) {
1273
+ const g = `± ${Y(i.yError[0])} / ${Y(i.yError[1])}`;
1274
+ a = Math.max(a, t.measureText(g).width), r += e.contentFontSize * e.lineHeight;
1275
+ }
1276
+ if (i.cycle !== void 0) {
1277
+ const g = `Cycle: ${i.cycle}`;
1278
+ a = Math.max(a, t.measureText(g).width), r += e.contentFontSize * e.lineHeight;
1279
+ }
1280
+ const d = e.showSeriesIndicator ? e.seriesIndicatorSize + 6 : 0, p = Math.max(o + d, a), c = e.titleFontSize * e.lineHeight + e.headerGap + r;
1281
+ return this.cachedMeasurement = {
1282
+ width: p + 2,
1283
+ // Tiny buffer
1284
+ height: c + 4,
1285
+ padding: e.padding,
1286
+ arrow: e.showArrow ? { width: e.arrowSize * 2, height: e.arrowSize } : void 0
1287
+ }, this.cachedKey = n, this.cachedMeasurement;
1288
+ }
1289
+ /**
1290
+ * Render the tooltip
1291
+ */
1292
+ render(t, i, e, n, o) {
1293
+ const { x: s, y: l } = e, { padding: h } = o;
1294
+ let a = s + h.left, r = l + h.top;
1295
+ if (t.save(), t.textAlign = "left", t.textBaseline = "top", o.showSeriesIndicator) {
1296
+ const p = r + o.titleFontSize / 2;
1297
+ t.save(), t.fillStyle = i.seriesColor, t.beginPath(), t.arc(a + o.seriesIndicatorSize / 2, p, o.seriesIndicatorSize / 2, 0, Math.PI * 2), t.fill(), t.restore(), a += o.seriesIndicatorSize + 6;
1298
+ }
1299
+ if (t.font = `${o.titleFontWeight} ${o.titleFontSize}px ${o.fontFamily}`, t.fillStyle = o.textColor, t.fillText(i.seriesName, a, r), r += o.titleFontSize * o.lineHeight + 2, o.showHeaderSeparator) {
1300
+ const p = n.width;
1301
+ t.save(), t.strokeStyle = o.separatorColor, t.lineWidth = 1, t.globalAlpha = 0.4, t.beginPath(), t.moveTo(s + h.left, r + o.headerGap / 2), t.lineTo(s + h.left + p, r + o.headerGap / 2), t.stroke(), t.restore();
1302
+ }
1303
+ r += o.headerGap + 2, a = s + h.left, t.font = `400 ${o.contentFontSize}px ${o.fontFamily}`, t.fillStyle = o.textSecondaryColor, t.fillText("X:", a, r), t.fillStyle = o.textColor;
1304
+ const d = 35;
1305
+ if (t.fillText(Y(i.dataX), a + d, r), r += o.contentFontSize * o.lineHeight + 2, t.fillStyle = o.textSecondaryColor, t.fillText("Y:", a, r), t.fillStyle = o.textColor, t.fillText(Y(i.dataY), a + d, r), r += o.contentFontSize * o.lineHeight + 2, i.yError) {
1306
+ t.fillStyle = o.textSecondaryColor;
1307
+ const p = `± ${Y(i.yError[0])} / +${Y(i.yError[1])}`;
1308
+ t.fillText(p, a, r), r += o.contentFontSize * o.lineHeight;
1309
+ }
1310
+ i.cycle !== void 0 && (t.fillStyle = o.textSecondaryColor, t.fillText("Cycle:", a, r), t.fillStyle = o.textColor, t.fillText(String(i.cycle), a + 45, r)), t.restore();
1311
+ }
1312
+ }
1313
+ const E = new St();
1314
+ function H(f) {
1315
+ if (f == null || isNaN(f))
1316
+ return "N/A";
1317
+ const t = Math.abs(f);
1318
+ return t === 0 ? "0" : t >= 1e9 ? (f / 1e9).toFixed(1) + "G" : t >= 1e6 ? (f / 1e6).toFixed(1) + "M" : t >= 1e3 ? (f / 1e3).toFixed(1) + "k" : t >= 1 ? f.toFixed(2) : t >= 1e-3 ? (f * 1e3).toFixed(1) + "m" : t >= 1e-6 ? (f * 1e6).toFixed(1) + "µ" : t >= 1e-9 ? (f * 1e9).toFixed(1) + "n" : f.toExponential(1);
1319
+ }
1320
+ class Tt {
1321
+ constructor() {
1322
+ u(this, "id", "minimal");
1323
+ u(this, "name", "Minimal");
1324
+ u(this, "supportedTypes", ["datapoint"]);
1325
+ // Cached measurements
1326
+ u(this, "cachedKey", "");
1327
+ u(this, "cachedMeasurement", null);
1328
+ }
1329
+ /**
1330
+ * Measure tooltip dimensions
1331
+ */
1332
+ measure(t, i, e) {
1333
+ const n = `${i.seriesId}-${i.dataIndex}-${i.dataX}-${i.dataY}-${e.fontFamily}`;
1334
+ if (n === this.cachedKey && this.cachedMeasurement)
1335
+ return this.cachedMeasurement;
1336
+ t.font = `${e.contentFontSize}px ${e.fontFamily}`;
1337
+ const o = `${H(i.dataX)} ▪ ${H(i.dataY)}`, s = t.measureText(o).width;
1338
+ return this.cachedMeasurement = {
1339
+ width: s,
1340
+ height: e.contentFontSize * e.lineHeight,
1341
+ padding: {
1342
+ top: 6,
1343
+ right: 8,
1344
+ bottom: 6,
1345
+ left: 8
1346
+ }
1347
+ }, this.cachedKey = n, this.cachedMeasurement;
1348
+ }
1349
+ /**
1350
+ * Render the tooltip
1351
+ */
1352
+ render(t, i, e, n, o) {
1353
+ const { padding: s } = n, l = e.x + s.left, h = e.y + s.top, a = H(i.dataX), r = H(i.dataY);
1354
+ t.save(), t.font = `${o.contentFontSize}px ${o.fontFamily}`, t.textAlign = "left", t.textBaseline = "top", t.fillStyle = o.textSecondaryColor, t.fillText(a, l, h);
1355
+ const d = t.measureText(a).width;
1356
+ t.fillStyle = i.seriesColor, t.fillText(" ▪ ", l + d, h);
1357
+ const p = t.measureText(" ▪ ").width;
1358
+ t.fillStyle = o.textColor, t.fillText(r, l + d + p, h), t.restore();
1359
+ }
1360
+ }
1361
+ const tt = new Tt(), F = {
1362
+ INDICATOR_MARGIN: 8,
1363
+ MIN_LABEL_WIDTH: 60,
1364
+ LINE_SPACING: 2,
1365
+ SAFETY_BUFFER: 4,
1366
+ HEADER_SPACING: 2,
1367
+ GAP_SPACING: 2
1368
+ };
1369
+ function q(f) {
1370
+ if (f == null || isNaN(f))
1371
+ return "N/A";
1372
+ const t = Math.abs(f);
1373
+ return t === 0 ? "0" : t < 1e-4 || t >= 1e4 ? f.toExponential(2) : t < 0.01 ? f.toPrecision(3) : t < 1 ? f.toFixed(4) : t < 100 ? f.toFixed(3) : f.toFixed(1);
1374
+ }
1375
+ class wt {
1376
+ constructor() {
1377
+ u(this, "id", "crosshair");
1378
+ u(this, "name", "Multi-Series Crosshair");
1379
+ u(this, "supportedTypes", ["crosshair"]);
1380
+ // Cached measurements
1381
+ u(this, "cachedKey", "");
1382
+ u(this, "cachedMeasurement", null);
1383
+ u(this, "formattedData", null);
1384
+ }
1385
+ /**
1386
+ * Generate cache key from data and theme
1387
+ */
1388
+ getCacheKey(t, i) {
1389
+ const e = t.interpolatedValues.map((n) => `${n.seriesName}-${n.y}`).join("|");
1390
+ return [
1391
+ t.dataX,
1392
+ e,
1393
+ i.fontFamily,
1394
+ i.titleFontSize,
1395
+ i.contentFontSize,
1396
+ i.showSeriesIndicator,
1397
+ i.seriesIndicatorSize,
1398
+ `${i.padding.top}-${i.padding.right}-${i.padding.bottom}-${i.padding.left}`
1399
+ ].join(":");
1400
+ }
1401
+ /**
1402
+ * Format data for rendering
1403
+ */
1404
+ formatData(t) {
1405
+ return {
1406
+ header: `⌖ X = ${q(t.dataX)}`,
1407
+ series: t.interpolatedValues.map((i) => ({
1408
+ name: i.seriesName,
1409
+ value: q(i.y),
1410
+ color: i.seriesColor,
1411
+ isInterpolated: i.isInterpolated
1412
+ }))
1413
+ };
1414
+ }
1415
+ /**
1416
+ * Measure tooltip dimensions
1417
+ */
1418
+ measure(t, i, e) {
1419
+ if (!i.interpolatedValues || i.interpolatedValues.length === 0)
1420
+ return {
1421
+ width: 100,
1422
+ height: e.titleFontSize * e.lineHeight,
1423
+ padding: e.padding
1424
+ };
1425
+ const n = this.getCacheKey(i, e);
1426
+ if (n === this.cachedKey && this.cachedMeasurement)
1427
+ return this.cachedMeasurement;
1428
+ this.formattedData = this.formatData(i), t.font = `${e.titleFontWeight} ${e.titleFontSize}px ${e.fontFamily}`;
1429
+ let o = t.measureText(this.formattedData.header).width;
1430
+ t.font = `400 ${e.contentFontSize}px ${e.fontFamily}`;
1431
+ const s = e.showSeriesIndicator ? e.seriesIndicatorSize + F.INDICATOR_MARGIN : 0;
1432
+ for (const r of this.formattedData.series) {
1433
+ const d = t.measureText(`${r.name}:`).width, p = t.measureText(r.value).width, c = s + Math.max(d, F.MIN_LABEL_WIDTH) + p;
1434
+ o = Math.max(o, c);
1435
+ }
1436
+ const l = e.titleFontSize * e.lineHeight, a = this.formattedData.series.length * (e.contentFontSize * e.lineHeight + F.LINE_SPACING);
1437
+ return this.cachedMeasurement = {
1438
+ width: o + F.SAFETY_BUFFER,
1439
+ height: l + e.headerGap + a,
1440
+ padding: e.padding
1441
+ }, this.cachedKey = n, this.cachedMeasurement;
1442
+ }
1443
+ /**
1444
+ * Render the tooltip
1445
+ */
1446
+ render(t, i, e, n, o) {
1447
+ if (!i.interpolatedValues || i.interpolatedValues.length === 0)
1448
+ return;
1449
+ const s = this.formattedData || this.formatData(i), { x: l, y: h } = e, { padding: a } = o;
1450
+ let r = h + a.top;
1451
+ const d = l + a.left;
1452
+ t.save(), t.textAlign = "left", t.textBaseline = "top", t.font = `${o.titleFontWeight} ${o.titleFontSize}px ${o.fontFamily}`, t.fillStyle = o.textColor, t.fillText(s.header, d, r), r += o.titleFontSize * o.lineHeight + F.HEADER_SPACING, o.showHeaderSeparator && (t.strokeStyle = o.separatorColor, t.lineWidth = 1, t.globalAlpha = 0.4, t.beginPath(), t.moveTo(d, r + o.headerGap / 2), t.lineTo(d + n.width, r + o.headerGap / 2), t.stroke(), t.globalAlpha = 1), r += o.headerGap + F.GAP_SPACING, t.font = `400 ${o.contentFontSize}px ${o.fontFamily}`;
1453
+ for (const p of s.series) {
1454
+ let c = d;
1455
+ if (o.showSeriesIndicator && o.seriesIndicatorSize > 0) {
1456
+ const b = r + o.contentFontSize / 2, x = o.seriesIndicatorSize / 2;
1457
+ t.save(), t.beginPath(), t.arc(c + x, b, x, 0, Math.PI * 2), p.isInterpolated ? (t.strokeStyle = p.color, t.lineWidth = 1.5, t.stroke()) : (t.fillStyle = p.color, t.fill()), t.restore(), c += o.seriesIndicatorSize + F.INDICATOR_MARGIN;
1458
+ }
1459
+ t.fillStyle = o.textSecondaryColor, t.fillText(`${p.name}:`, c, r);
1460
+ const g = t.measureText(`${p.name}: `).width, y = Math.max(g, F.MIN_LABEL_WIDTH);
1461
+ t.fillStyle = o.textColor, t.fillText(p.value, c + y, r), r += o.contentFontSize * o.lineHeight + F.LINE_SPACING;
1462
+ }
1463
+ t.restore();
1464
+ }
1465
+ }
1466
+ const R = new wt();
1467
+ function P(f) {
1468
+ if (f == null || isNaN(f))
1469
+ return "N/A";
1470
+ const t = Math.abs(f);
1471
+ return t === 0 ? "0" : t < 1e-4 || t >= 1e4 ? f.toExponential(3) : t < 0.01 ? f.toPrecision(4) : t < 1 ? f.toFixed(4) : t < 100 ? f.toFixed(3) : f.toFixed(2);
1472
+ }
1473
+ class mt {
1474
+ constructor() {
1475
+ u(this, "id", "heatmap");
1476
+ u(this, "name", "Heatmap Value");
1477
+ u(this, "supportedTypes", ["heatmap"]);
1478
+ // Color swatch dimensions
1479
+ u(this, "swatchSize", 14);
1480
+ u(this, "swatchGap", 8);
1481
+ // Cached measurements
1482
+ u(this, "cachedKey", "");
1483
+ u(this, "cachedMeasurement", null);
1484
+ }
1485
+ /**
1486
+ * Measure tooltip dimensions
1487
+ */
1488
+ measure(t, i, e) {
1489
+ const n = `${i.seriesId}-${i.xIndex}-${i.yIndex}-${e.fontFamily}-${e.titleFontSize}`;
1490
+ if (n === this.cachedKey && this.cachedMeasurement)
1491
+ return this.cachedMeasurement;
1492
+ t.font = `${e.titleFontWeight} ${e.titleFontSize}px ${e.fontFamily}`;
1493
+ const o = `Grid [${i.xIndex}, ${i.yIndex}]`;
1494
+ let s = t.measureText(o).width;
1495
+ t.font = `400 ${e.contentFontSize}px ${e.fontFamily}`;
1496
+ const l = `Value: ${P(i.zValue)}`, h = this.swatchSize + this.swatchGap + t.measureText(l).width;
1497
+ if (s = Math.max(s, h), i.colorScale) {
1498
+ const y = `Min: ${P(i.colorScale.min)} Max: ${P(i.colorScale.max)}`;
1499
+ s = Math.max(s, this.swatchSize + this.swatchGap + t.measureText(y).width);
1500
+ }
1501
+ const a = 25, r = a + t.measureText(P(i.dataX)).width, d = a + t.measureText(P(i.dataY)).width;
1502
+ s = Math.max(s, r, d);
1503
+ const p = e.titleFontSize * e.lineHeight, g = (i.colorScale ? 4 : 3) * e.contentFontSize * e.lineHeight;
1504
+ return this.cachedMeasurement = {
1505
+ width: s + 4,
1506
+ // Small buffer
1507
+ height: p + e.headerGap + g + e.itemGap,
1508
+ padding: e.padding
1509
+ }, this.cachedKey = n, this.cachedMeasurement;
1510
+ }
1511
+ /**
1512
+ * Render the tooltip
1513
+ */
1514
+ render(t, i, e, n, o) {
1515
+ const { x: s, y: l } = e, { padding: h } = o;
1516
+ let a = l + h.top;
1517
+ const r = s + h.left;
1518
+ t.save(), t.textAlign = "left", t.textBaseline = "top", t.font = `${o.titleFontWeight} ${o.titleFontSize}px ${o.fontFamily}`, t.fillStyle = o.textColor;
1519
+ const d = `Grid [${i.xIndex}, ${i.yIndex}]`;
1520
+ t.fillText(d, r, a), a += o.titleFontSize * o.lineHeight + 2, o.showHeaderSeparator && (t.strokeStyle = o.separatorColor, t.lineWidth = 1, t.globalAlpha = 0.4, t.beginPath(), t.moveTo(r, a + o.headerGap / 2), t.lineTo(r + n.width, a + o.headerGap / 2), t.stroke(), t.globalAlpha = 1), a += o.headerGap + 2, t.font = `400 ${o.contentFontSize}px ${o.fontFamily}`;
1521
+ const p = a + (o.contentFontSize * o.lineHeight - this.swatchSize) / 2;
1522
+ t.fillStyle = i.mappedColor || o.textColor, t.fillRect(r, p, this.swatchSize, this.swatchSize), t.strokeStyle = o.separatorColor, t.lineWidth = 1, t.strokeRect(r, p, this.swatchSize, this.swatchSize), t.fillStyle = o.textSecondaryColor, t.fillText("Value:", r + this.swatchSize + this.swatchGap, a), t.fillStyle = o.textColor;
1523
+ const c = t.measureText("Value: ").width;
1524
+ if (t.fillText(P(i.zValue), r + this.swatchSize + this.swatchGap + c, a), a += o.contentFontSize * o.lineHeight, i.colorScale) {
1525
+ t.fillStyle = o.textSecondaryColor, t.font = `400 ${o.contentFontSize - 1}px ${o.fontFamily}`;
1526
+ const g = `Min: ${P(i.colorScale.min)} Max: ${P(i.colorScale.max)}`;
1527
+ t.fillText(g, r + this.swatchSize + this.swatchGap, a), a += o.contentFontSize * o.lineHeight;
1528
+ }
1529
+ a += o.itemGap + 2, t.font = `400 ${o.contentFontSize}px ${o.fontFamily}`, t.fillStyle = o.textSecondaryColor, t.fillText("X:", r, a), t.fillStyle = o.textColor, t.fillText(P(i.dataX), r + 25, a), a += o.contentFontSize * o.lineHeight + 2, t.fillStyle = o.textSecondaryColor, t.fillText("Y:", r, a), t.fillStyle = o.textColor, t.fillText(P(i.dataY), r + 25, a), t.restore();
1530
+ }
1531
+ }
1532
+ const N = new mt();
1533
+ function X(f, t = 3) {
1534
+ if (f == null || isNaN(f))
1535
+ return "N/A";
1536
+ if (f === 0) return "0";
1537
+ const i = Math.floor(Math.log10(Math.abs(f))), e = f / Math.pow(10, i);
1538
+ if (Math.abs(i) <= 2)
1539
+ return f.toPrecision(t);
1540
+ const n = {
1541
+ 0: "⁰",
1542
+ 1: "¹",
1543
+ 2: "²",
1544
+ 3: "³",
1545
+ 4: "⁴",
1546
+ 5: "⁵",
1547
+ 6: "⁶",
1548
+ 7: "⁷",
1549
+ 8: "⁸",
1550
+ 9: "⁹",
1551
+ "-": "⁻",
1552
+ "+": "⁺"
1553
+ }, o = i.toString();
1554
+ let s = "";
1555
+ for (const l of o)
1556
+ s += n[l] || l;
1557
+ return `${e.toFixed(t - 1)} × 10${s}`;
1558
+ }
1559
+ class Mt {
1560
+ constructor() {
1561
+ u(this, "id", "scientific");
1562
+ u(this, "name", "Scientific Notation");
1563
+ u(this, "supportedTypes", ["datapoint"]);
1564
+ // Cached measurements
1565
+ u(this, "cachedKey", "");
1566
+ u(this, "cachedMeasurement", null);
1567
+ }
1568
+ /**
1569
+ * Measure tooltip dimensions
1570
+ */
1571
+ measure(t, i, e) {
1572
+ const n = `${i.seriesId}-${i.dataIndex}-${i.dataX}-${i.dataY}-${e.fontFamily}-${e.titleFontSize}`;
1573
+ if (n === this.cachedKey && this.cachedMeasurement)
1574
+ return this.cachedMeasurement;
1575
+ t.font = `${e.titleFontWeight} ${e.titleFontSize}px ${e.fontFamily}`;
1576
+ const o = t.measureText(i.seriesName).width + (e.showSeriesIndicator ? e.seriesIndicatorSize + 8 : 0);
1577
+ t.font = `400 ${e.contentFontSize}px ${e.fontFamily}`;
1578
+ const s = 28, l = X(i.dataX);
1579
+ let h = Math.max(o, s + t.measureText(l).width);
1580
+ const a = X(i.dataY);
1581
+ let r = s + t.measureText(a).width;
1582
+ i.yError && (r += t.measureText(` ± ${X(i.yError[0])}`).width), h = Math.max(h, r);
1583
+ let d = `Index: ${i.dataIndex}`;
1584
+ i.cycle !== void 0 && (d += ` │ Cycle: ${i.cycle}`), h = Math.max(h, t.measureText(d).width);
1585
+ let p = 3;
1586
+ (i.cycle !== void 0 || i.yError) && (p += 1);
1587
+ const c = e.titleFontSize * e.lineHeight + e.headerGap, g = (p - 1) * e.contentFontSize * e.lineHeight, y = i.cycle !== void 0 ? e.itemGap : 0;
1588
+ return this.cachedMeasurement = {
1589
+ width: h,
1590
+ height: c + g + y,
1591
+ padding: e.padding
1592
+ }, this.cachedKey = n, this.cachedMeasurement;
1593
+ }
1594
+ /**
1595
+ * Render the tooltip
1596
+ */
1597
+ render(t, i, e, n, o) {
1598
+ const { x: s, y: l } = e, { padding: h } = o;
1599
+ let a = l + h.top, r = s + h.left;
1600
+ if (t.save(), t.textAlign = "left", t.textBaseline = "top", o.showSeriesIndicator) {
1601
+ const c = a + o.titleFontSize / 2;
1602
+ t.fillStyle = i.seriesColor, t.beginPath(), t.arc(r + o.seriesIndicatorSize / 2, c, o.seriesIndicatorSize / 2, 0, Math.PI * 2), t.fill(), r += o.seriesIndicatorSize + 8;
1603
+ }
1604
+ t.font = `${o.titleFontWeight} ${o.titleFontSize}px ${o.fontFamily}`, t.fillStyle = o.textColor, t.fillText(i.seriesName, r, a), a += o.titleFontSize * o.lineHeight + 2, r = s + h.left, o.showHeaderSeparator && (t.strokeStyle = o.separatorColor, t.lineWidth = 1, t.globalAlpha = 0.4, t.beginPath(), t.moveTo(r, a + o.headerGap / 2), t.lineTo(r + n.width, a + o.headerGap / 2), t.stroke(), t.globalAlpha = 1), a += o.headerGap + 2, t.font = `400 ${o.contentFontSize}px ${o.fontFamily}`;
1605
+ const d = 28;
1606
+ t.fillStyle = o.textSecondaryColor, t.fillText("X:", r, a), t.fillStyle = o.textColor, t.fillText(X(i.dataX), r + d, a), a += o.contentFontSize * o.lineHeight + 2, t.fillStyle = o.textSecondaryColor, t.fillText("Y:", r, a), t.fillStyle = o.textColor;
1607
+ let p = X(i.dataY);
1608
+ if (t.fillText(p, r + d, a), i.yError) {
1609
+ const c = t.measureText(p).width;
1610
+ t.fillStyle = o.textSecondaryColor, t.fillText(` ± ${X(i.yError[0])}`, r + d + c, a);
1611
+ }
1612
+ if (a += o.contentFontSize * o.lineHeight + 2, i.cycle !== void 0) {
1613
+ a += o.itemGap, t.strokeStyle = o.separatorColor, t.globalAlpha = 0.3, t.beginPath(), t.moveTo(r, a - o.itemGap / 2), t.lineTo(r + n.width, a - o.itemGap / 2), t.stroke(), t.globalAlpha = 1, t.fillStyle = o.textSecondaryColor, t.font = `400 ${o.contentFontSize - 1}px ${o.fontFamily}`;
1614
+ let c = `Index: ${i.dataIndex}`;
1615
+ i.cycle !== void 0 && (c += ` │ Cycle: ${i.cycle}`), t.fillText(c, r, a);
1616
+ }
1617
+ t.restore();
1618
+ }
1619
+ }
1620
+ const et = new Mt();
1621
+ function A(f) {
1622
+ if (f == null || isNaN(f))
1623
+ return "N/A";
1624
+ const t = Math.abs(f);
1625
+ return t === 0 ? "0" : t < 1e-4 || t >= 1e4 ? f.toExponential(2) : t < 1 ? f.toFixed(4) : f.toFixed(2);
1626
+ }
1627
+ class Ct {
1628
+ constructor() {
1629
+ u(this, "id", "annotation");
1630
+ u(this, "name", "Annotation Info");
1631
+ u(this, "supportedTypes", ["annotation"]);
1632
+ // Cache
1633
+ u(this, "cachedKey", "");
1634
+ u(this, "cachedMeasurement", null);
1635
+ }
1636
+ /**
1637
+ * Measure tooltip dimensions
1638
+ */
1639
+ measure(t, i, e) {
1640
+ const n = `${i.annotationId}-${i.label}-${e.fontFamily}-${e.titleFontSize}`;
1641
+ if (n === this.cachedKey && this.cachedMeasurement)
1642
+ return this.cachedMeasurement;
1643
+ t.font = `${e.titleFontWeight} ${e.titleFontSize}px ${e.fontFamily}`;
1644
+ const o = i.label || `Annotation: ${i.annotationType}`;
1645
+ let s = t.measureText(o).width;
1646
+ t.font = `400 ${e.contentFontSize}px ${e.fontFamily}`;
1647
+ let l = 0;
1648
+ const h = 50;
1649
+ if (i.value !== void 0) {
1650
+ const r = A(i.value);
1651
+ s = Math.max(s, h + t.measureText(r).width), l += e.contentFontSize * e.lineHeight;
1652
+ }
1653
+ if (i.valueX !== void 0 && i.valueY !== void 0) {
1654
+ const r = A(i.valueX), d = A(i.valueY);
1655
+ s = Math.max(s, h + t.measureText(r).width, h + t.measureText(d).width), l += e.contentFontSize * e.lineHeight * 2;
1656
+ }
1657
+ const a = e.titleFontSize * e.lineHeight + e.headerGap;
1658
+ return this.cachedMeasurement = {
1659
+ width: s + 10,
1660
+ height: a + l + 4,
1661
+ padding: e.padding
1662
+ }, this.cachedKey = n, this.cachedMeasurement;
1663
+ }
1664
+ /**
1665
+ * Render the tooltip
1666
+ */
1667
+ render(t, i, e, n, o) {
1668
+ const { x: s, y: l } = e, { padding: h } = o;
1669
+ let a = l + h.top;
1670
+ const r = s + h.left;
1671
+ t.save(), t.textAlign = "left", t.textBaseline = "top", t.font = `${o.titleFontWeight} ${o.titleFontSize}px ${o.fontFamily}`, t.fillStyle = o.textColor;
1672
+ const d = i.label || `${i.annotationType.toUpperCase()}`;
1673
+ t.fillText(d, r, a), a += o.titleFontSize * o.lineHeight + 2, o.showHeaderSeparator && (t.strokeStyle = o.separatorColor, t.globalAlpha = 0.4, t.beginPath(), t.moveTo(r, a + o.headerGap / 2), t.lineTo(r + n.width, a + o.headerGap / 2), t.stroke(), t.globalAlpha = 1), a += o.headerGap + 2, t.font = `400 ${o.contentFontSize}px ${o.fontFamily}`;
1674
+ const p = 50;
1675
+ i.value !== void 0 && (t.fillStyle = o.textSecondaryColor, t.fillText("Value:", r, a), t.fillStyle = o.textColor, t.fillText(A(i.value), r + p, a), a += o.contentFontSize * o.lineHeight), i.valueX !== void 0 && i.valueY !== void 0 && (t.fillStyle = o.textSecondaryColor, t.fillText("X:", r, a), t.fillStyle = o.textColor, t.fillText(A(i.valueX), r + p, a), a += o.contentFontSize * o.lineHeight, t.fillStyle = o.textSecondaryColor, t.fillText("Y:", r, a), t.fillStyle = o.textColor, t.fillText(A(i.valueY), r + p, a)), t.restore();
1676
+ }
1677
+ }
1678
+ const O = new Ct();
1679
+ function M(f) {
1680
+ if (f == null || isNaN(f))
1681
+ return "N/A";
1682
+ const t = Math.abs(f);
1683
+ return t === 0 ? "0" : t < 1e-4 || t >= 1e4 ? f.toExponential(3) : t < 1 ? f.toFixed(4) : f.toFixed(3);
1684
+ }
1685
+ class vt {
1686
+ constructor() {
1687
+ u(this, "id", "range");
1688
+ u(this, "name", "Range Statistics");
1689
+ u(this, "supportedTypes", ["range"]);
1690
+ // Cache
1691
+ u(this, "cachedKey", "");
1692
+ u(this, "cachedMeasurement", null);
1693
+ }
1694
+ /**
1695
+ * Measure tooltip dimensions
1696
+ */
1697
+ measure(t, i, e) {
1698
+ const n = i.statistics, o = `${i.xMin}-${i.xMax}-${n.count}-${n.mean}-${e.fontFamily}`;
1699
+ if (o === this.cachedKey && this.cachedMeasurement)
1700
+ return this.cachedMeasurement;
1701
+ t.font = `${e.titleFontWeight} ${e.titleFontSize}px ${e.fontFamily}`;
1702
+ let l = t.measureText("Range Statistics").width;
1703
+ t.font = `400 ${e.contentFontSize}px ${e.fontFamily}`;
1704
+ let h = e.contentFontSize * e.lineHeight * 2;
1705
+ const a = [
1706
+ `Range: ${M(i.xMin)} to ${M(i.xMax)}`,
1707
+ `Count: ${n.count}`
1708
+ ];
1709
+ n.min !== void 0 && a.push(`Min: ${M(n.min)}`), n.max !== void 0 && a.push(`Max: ${M(n.max)}`), n.mean !== void 0 && a.push(`Mean: ${M(n.mean)}`), n.area !== void 0 && a.push(`Area: ${M(n.area)}`);
1710
+ for (const d of a)
1711
+ l = Math.max(l, t.measureText(d).width + 10);
1712
+ h = a.length * e.contentFontSize * e.lineHeight;
1713
+ const r = e.titleFontSize * e.lineHeight + e.headerGap;
1714
+ return this.cachedMeasurement = {
1715
+ width: Math.max(l, 140),
1716
+ height: r + h + 10,
1717
+ padding: e.padding
1718
+ }, this.cachedKey = o, this.cachedMeasurement;
1719
+ }
1720
+ /**
1721
+ * Render the tooltip
1722
+ */
1723
+ render(t, i, e, n, o) {
1724
+ const { x: s, y: l } = e, { padding: h } = o, a = i.statistics;
1725
+ let r = l + h.top;
1726
+ const d = s + h.left;
1727
+ t.save(), t.textAlign = "left", t.textBaseline = "top", t.font = `${o.titleFontWeight} ${o.titleFontSize}px ${o.fontFamily}`, t.fillStyle = o.textColor, t.fillText("Range Statistics", d, r), r += o.titleFontSize * o.lineHeight + 2, o.showHeaderSeparator && (t.strokeStyle = o.separatorColor, t.globalAlpha = 0.4, t.beginPath(), t.moveTo(d, r + o.headerGap / 2), t.lineTo(d + n.width, r + o.headerGap / 2), t.stroke(), t.globalAlpha = 1), r += o.headerGap + 2, t.font = `400 ${o.contentFontSize}px ${o.fontFamily}`;
1728
+ const p = 60, c = (g, y) => {
1729
+ t.fillStyle = o.textSecondaryColor, t.fillText(g, d, r), t.fillStyle = o.textColor, t.fillText(String(y), d + p, r), r += o.contentFontSize * o.lineHeight;
1730
+ };
1731
+ c("Points:", a.count), a.min !== void 0 && c("Min:", M(a.min)), a.max !== void 0 && c("Max:", M(a.max)), a.mean !== void 0 && c("Mean:", M(a.mean)), a.stdDev !== void 0 && c("StdDev:", M(a.stdDev)), a.area !== void 0 && c("Area:", M(a.area)), a.peakX !== void 0 && (r += 4, t.fillStyle = o.textSecondaryColor, t.font = `italic ${o.contentFontSize - 1}px ${o.fontFamily}`, t.fillText(`Peak: ${M(a.peakY ?? 0)} at X=${M(a.peakX)}`, d, r)), t.restore();
1732
+ }
1733
+ }
1734
+ const G = new vt(), Pt = [
1735
+ E,
1736
+ tt,
1737
+ R,
1738
+ N,
1739
+ et,
1740
+ O,
1741
+ G
1742
+ ];
1743
+ function It(f) {
1744
+ return Pt.find((t) => t.id === f);
1745
+ }
1746
+ function j(f) {
1747
+ switch (f) {
1748
+ case "datapoint":
1749
+ return E;
1750
+ case "crosshair":
1751
+ return R;
1752
+ case "heatmap":
1753
+ return N;
1754
+ case "annotation":
1755
+ return O;
1756
+ case "range":
1757
+ return G;
1758
+ default:
1759
+ return E;
1760
+ }
1761
+ }
1762
+ class Ft {
1763
+ constructor(t) {
1764
+ u(this, "ctx");
1765
+ u(this, "getPlotArea");
1766
+ u(this, "getSeries");
1767
+ u(this, "pixelToDataX");
1768
+ u(this, "pixelToDataY");
1769
+ u(this, "getXScale");
1770
+ u(this, "getYScales");
1771
+ u(this, "options");
1772
+ u(this, "theme");
1773
+ u(this, "positioner");
1774
+ u(this, "renderer");
1775
+ u(this, "templates", /* @__PURE__ */ new Map());
1776
+ u(this, "events", new at());
1777
+ u(this, "activeTooltips", /* @__PURE__ */ new Map());
1778
+ u(this, "tooltipIdCounter", 0);
1779
+ u(this, "showTimeoutId", null);
1780
+ u(this, "hideTimeoutId", null);
1781
+ u(this, "lastCursorX", null);
1782
+ u(this, "lastCursorY", null);
1783
+ u(this, "hoveredSeriesId", null);
1784
+ u(this, "hoveredDataIndex", null);
1785
+ u(this, "cachedNearestResult", null);
1786
+ // Large dataset optimizations
1787
+ u(this, "snapMode", "auto");
1788
+ u(this, "largeDatasetThreshold", 5e4);
1789
+ u(this, "lastKnownDataSize", 0);
1790
+ // Hysteresis factor: new point must be this much closer to switch (2 = 2x closer)
1791
+ u(this, "hysteresisRatio", 2);
1792
+ // Suspended state - used during drag operations to hide tooltip
1793
+ u(this, "suspended", !1);
1794
+ var i;
1795
+ this.ctx = t.overlayCtx, this.getPlotArea = t.getPlotArea, this.getSeries = t.getSeries, this.pixelToDataX = t.pixelToDataX, this.pixelToDataY = t.pixelToDataY, this.getXScale = t.getXScale, this.getYScales = t.getYScales, this.options = {
1796
+ enabled: !0,
1797
+ showDelay: 50,
1798
+ hideDelay: 100,
1799
+ followCursor: !1,
1800
+ offset: { x: 12, y: 12 },
1801
+ dataPoint: {
1802
+ enabled: !0,
1803
+ templateId: "default",
1804
+ snapToPoint: !0,
1805
+ hitRadius: 20
1806
+ },
1807
+ crosshair: {
1808
+ enabled: !1,
1809
+ templateId: "crosshair",
1810
+ interpolate: !0,
1811
+ visibleSeriesOnly: !0
1812
+ },
1813
+ range: {
1814
+ enabled: !1,
1815
+ templateId: "default",
1816
+ calculateStats: !0
1817
+ },
1818
+ annotation: {
1819
+ enabled: !0,
1820
+ templateId: "default"
1821
+ },
1822
+ heatmap: {
1823
+ enabled: !0,
1824
+ templateId: "heatmap",
1825
+ showColorInfo: !0
1826
+ },
1827
+ positioning: "auto",
1828
+ preferredPosition: "auto",
1829
+ constrainToPlotArea: !0,
1830
+ constrainToContainer: !0,
1831
+ autoFlip: !0
1832
+ }, this.theme = (i = t.options) != null && i.theme ? typeof t.options.theme == "string" ? k(t.options.theme) : pt(gt, t.options.theme) : k(t.chartTheme.name), this.positioner = new xt({
1833
+ offset: this.options.offset,
1834
+ preferredPosition: this.options.preferredPosition,
1835
+ constrainToPlotArea: this.options.constrainToPlotArea,
1836
+ constrainToContainer: this.options.constrainToContainer,
1837
+ autoFlip: this.options.autoFlip,
1838
+ showArrow: this.theme.showArrow,
1839
+ arrowSize: this.theme.arrowSize
1840
+ }), this.renderer = new bt(this.ctx, this.theme), this.registerBuiltinTemplates(), t.options && this.configure(t.options);
1841
+ }
1842
+ /**
1843
+ * Register built-in templates
1844
+ */
1845
+ registerBuiltinTemplates() {
1846
+ this.templates.set(
1847
+ "default",
1848
+ E
1849
+ ), this.templates.set(
1850
+ "minimal",
1851
+ tt
1852
+ ), this.templates.set(
1853
+ "crosshair",
1854
+ R
1855
+ ), this.templates.set(
1856
+ "heatmap",
1857
+ N
1858
+ ), this.templates.set(
1859
+ "scientific",
1860
+ et
1861
+ ), this.templates.set(
1862
+ "annotation",
1863
+ O
1864
+ ), this.templates.set(
1865
+ "range",
1866
+ G
1867
+ );
1868
+ }
1869
+ /**
1870
+ * Configure tooltip options
1871
+ */
1872
+ configure(t) {
1873
+ t.enabled !== void 0 && (this.options.enabled = t.enabled), t.showDelay !== void 0 && (this.options.showDelay = t.showDelay), t.hideDelay !== void 0 && (this.options.hideDelay = t.hideDelay), t.followCursor !== void 0 && (this.options.followCursor = t.followCursor), t.offset && (this.options.offset = { ...this.options.offset, ...t.offset }), t.dataPoint && (this.options.dataPoint = {
1874
+ ...this.options.dataPoint,
1875
+ ...t.dataPoint
1876
+ }), t.crosshair && (this.options.crosshair = {
1877
+ ...this.options.crosshair,
1878
+ ...t.crosshair
1879
+ }), t.heatmap && (this.options.heatmap = { ...this.options.heatmap, ...t.heatmap }), t.preferredPosition && (this.options.preferredPosition = t.preferredPosition), t.constrainToPlotArea !== void 0 && (this.options.constrainToPlotArea = t.constrainToPlotArea), t.constrainToContainer !== void 0 && (this.options.constrainToContainer = t.constrainToContainer), t.autoFlip !== void 0 && (this.options.autoFlip = t.autoFlip), t.snapMode !== void 0 && (this.snapMode = t.snapMode), t.largeDatasetThreshold !== void 0 && (this.largeDatasetThreshold = Math.max(
1880
+ 1e3,
1881
+ t.largeDatasetThreshold
1882
+ )), this.positioner.configure({
1883
+ offset: this.options.offset,
1884
+ preferredPosition: this.options.preferredPosition,
1885
+ constrainToPlotArea: this.options.constrainToPlotArea,
1886
+ constrainToContainer: this.options.constrainToContainer,
1887
+ autoFlip: this.options.autoFlip
1888
+ });
1889
+ }
1890
+ /**
1891
+ * Get current options
1892
+ */
1893
+ getOptions() {
1894
+ return { ...this.options };
1895
+ }
1896
+ /**
1897
+ * Enable/disable tooltips
1898
+ */
1899
+ setEnabled(t) {
1900
+ this.options.enabled = t, t || this.hideAll();
1901
+ }
1902
+ /**
1903
+ * Check if tooltips are enabled
1904
+ */
1905
+ isEnabled() {
1906
+ return this.options.enabled;
1907
+ }
1908
+ /**
1909
+ * Suspend tooltip display (used during drag operations)
1910
+ * When suspended, tooltips are immediately hidden and cursor movements are ignored
1911
+ */
1912
+ setSuspended(t) {
1913
+ this.suspended = t, t && this.hideAll();
1914
+ }
1915
+ /**
1916
+ * Check if tooltips are suspended
1917
+ */
1918
+ isSuspended() {
1919
+ return this.suspended;
1920
+ }
1921
+ /**
1922
+ * Set tooltip theme
1923
+ */
1924
+ setTheme(t) {
1925
+ this.theme = typeof t == "string" ? k(t) : t, this.renderer.setTheme(this.theme), this.positioner.configure({
1926
+ showArrow: this.theme.showArrow,
1927
+ arrowSize: this.theme.arrowSize
1928
+ });
1929
+ }
1930
+ /**
1931
+ * Update theme based on chart theme
1932
+ */
1933
+ updateChartTheme(t) {
1934
+ this.options.theme || (this.theme = k(t.name), this.renderer.setTheme(this.theme));
1935
+ }
1936
+ /**
1937
+ * Get current theme
1938
+ */
1939
+ getTheme() {
1940
+ return this.theme;
1941
+ }
1942
+ /**
1943
+ * Register a custom template
1944
+ */
1945
+ registerTemplate(t) {
1946
+ this.templates.set(t.id, t);
1947
+ }
1948
+ /**
1949
+ * Get a template by ID
1950
+ */
1951
+ getTemplate(t) {
1952
+ return this.templates.get(t) || It(t);
1953
+ }
1954
+ /**
1955
+ * Handle cursor movement - main entry point for hover detection
1956
+ * Optimized with hysteresis to prevent jumping between nearby points
1957
+ */
1958
+ handleCursorMove(t, i) {
1959
+ if (!this.options.enabled || this.suspended) return;
1960
+ this.lastCursorX = t, this.lastCursorY = i;
1961
+ const e = this.getPlotArea();
1962
+ if (!(t >= e.x && t <= e.x + e.width && i >= e.y && i <= e.y + e.height)) {
1963
+ this.cachedNearestResult = null, this.scheduleHide();
1964
+ return;
1965
+ }
1966
+ this.positioner.setContainerSize(
1967
+ this.ctx.canvas.width / (window.devicePixelRatio || 1),
1968
+ this.ctx.canvas.height / (window.devicePixelRatio || 1)
1969
+ ), this.positioner.setPlotArea(e), this.lastKnownDataSize = this.getTotalDataPoints(), this.performTooltipUpdateWithHysteresis(t, i);
1970
+ }
1971
+ /**
1972
+ * Handle cursor leave
1973
+ */
1974
+ handleCursorLeave() {
1975
+ this.lastCursorX = null, this.lastCursorY = null, this.cachedNearestResult = null, this.scheduleHide();
1976
+ }
1977
+ /**
1978
+ * Get total number of data points across all visible series
1979
+ */
1980
+ getTotalDataPoints() {
1981
+ let t = 0;
1982
+ const i = this.getSeries();
1983
+ for (const e of i) {
1984
+ if (!e.isVisible()) continue;
1985
+ const n = e.getData();
1986
+ n.x && (t += n.x.length);
1987
+ }
1988
+ return t;
1989
+ }
1990
+ /**
1991
+ * Determine the effective snap mode based on configuration and data size
1992
+ */
1993
+ getEffectiveSnapMode() {
1994
+ return this.snapMode === "x-only" ? "x-only" : this.snapMode === "nearest" ? "nearest" : this.lastKnownDataSize > this.largeDatasetThreshold ? "x-only" : "nearest";
1995
+ }
1996
+ /**
1997
+ * Perform tooltip update with hysteresis to prevent jumping.
1998
+ * The tooltip "sticks" to the current point unless the cursor is
1999
+ * significantly closer to a new point.
2000
+ */
2001
+ performTooltipUpdateWithHysteresis(t, i) {
2002
+ var o;
2003
+ if (!((o = this.options.dataPoint) != null && o.enabled)) {
2004
+ this.performFallbackTooltipUpdate(t, i);
2005
+ return;
2006
+ }
2007
+ const n = this.getEffectiveSnapMode() === "x-only" ? this.findDataPointByXOnly(t) : this.findNearestDataPointOptimized(t, i);
2008
+ if (!n) {
2009
+ this.performFallbackTooltipUpdate(t, i);
2010
+ return;
2011
+ }
2012
+ if (this.cachedNearestResult && this.hoveredSeriesId !== null) {
2013
+ const s = this.cachedNearestResult, l = s.pixelX - t, h = s.pixelY - i, a = l * l + h * h, r = n.pixelX - t, d = n.pixelY - i;
2014
+ if ((r * r + d * d) * this.hysteresisRatio >= a) {
2015
+ this.updateTooltipPosition(this.cachedNearestResult);
2016
+ return;
2017
+ }
2018
+ }
2019
+ this.cachedNearestResult = n, this.scheduleShow(n);
2020
+ }
2021
+ /**
2022
+ * Handle heatmap and crosshair tooltip types (fallback)
2023
+ */
2024
+ performFallbackTooltipUpdate(t, i) {
2025
+ var e, n;
2026
+ if ((e = this.options.heatmap) != null && e.enabled) {
2027
+ const o = this.findHeatmapCell(t, i);
2028
+ if (o) {
2029
+ this.scheduleShow(o);
2030
+ return;
2031
+ }
2032
+ }
2033
+ if ((n = this.options.crosshair) != null && n.enabled) {
2034
+ const o = this.buildCrosshairTooltip(t, i);
2035
+ if (o) {
2036
+ this.scheduleShow(o);
2037
+ return;
2038
+ }
2039
+ }
2040
+ this.cachedNearestResult = null, this.scheduleHide();
2041
+ }
2042
+ /**
2043
+ * Find data point by X coordinate only (O(log n) - fastest method)
2044
+ * Best for very large datasets where precision is less important than speed
2045
+ */
2046
+ findDataPointByXOnly(t) {
2047
+ var h, a;
2048
+ const i = this.getSeries().filter(
2049
+ (r) => r.isVisible() && r.getType() !== "heatmap"
2050
+ );
2051
+ if (i.length === 0) return null;
2052
+ const e = this.getXScale(), n = this.getYScales(), o = this.pixelToDataX(t);
2053
+ let s = null, l = 1 / 0;
2054
+ for (const r of i) {
2055
+ const d = r.getData();
2056
+ if (!d.x || d.x.length === 0) continue;
2057
+ const p = n.get(((h = r.getYAxisId) == null ? void 0 : h.call(r)) || "default") || n.values().next().value;
2058
+ if (!p) continue;
2059
+ const c = this.binarySearchClosest(d.x, o), g = Math.abs(d.x[c] - o);
2060
+ if (g < l) {
2061
+ l = g;
2062
+ const y = r.getStyle(), b = e.transform(d.x[c]), x = p.transform(d.y[c]);
2063
+ s = {
2064
+ type: "datapoint",
2065
+ seriesId: r.getId(),
2066
+ seriesName: r.getId(),
2067
+ seriesColor: y.color || "#ff0055",
2068
+ dataIndex: c,
2069
+ dataX: d.x[c],
2070
+ dataY: d.y[c],
2071
+ pixelX: b,
2072
+ pixelY: x,
2073
+ cycle: (a = r.getCycle) == null ? void 0 : a.call(r)
2074
+ };
2075
+ const S = r.getYError(c);
2076
+ S && (s.yError = S);
2077
+ }
2078
+ }
2079
+ return s;
2080
+ }
2081
+ /**
2082
+ * Optimized nearest data point finder
2083
+ */
2084
+ findNearestDataPointOptimized(t, i) {
2085
+ var r, d, p;
2086
+ const e = this.getSeries().filter((c) => c.isVisible()), n = ((r = this.options.dataPoint) == null ? void 0 : r.hitRadius) ?? 20, o = this.getXScale(), s = this.getYScales();
2087
+ let l = n * n, h = null;
2088
+ const a = this.pixelToDataX(t);
2089
+ for (const c of e) {
2090
+ if (c.getType() === "heatmap") continue;
2091
+ const g = c.getData(), y = s.get(((d = c.getYAxisId) == null ? void 0 : d.call(c)) || "default") || s.values().next().value;
2092
+ if (!y || !g.x || g.x.length === 0) continue;
2093
+ const b = this.binarySearchClosest(g.x, a), x = g.x.length, S = x > 1e5 ? 2 : x > 1e4 ? 3 : 5, w = Math.max(0, b - S), C = Math.min(x, b + S + 1);
2094
+ for (let m = w; m < C; m++) {
2095
+ const I = o.transform(g.x[m]), v = y.transform(g.y[m]), T = I - t, z = v - i, $ = T * T + z * z;
2096
+ if ($ < l) {
2097
+ l = $;
2098
+ const D = c.getStyle();
2099
+ h = {
2100
+ type: "datapoint",
2101
+ seriesId: c.getId(),
2102
+ seriesName: c.getId(),
2103
+ seriesColor: D.color || "#ff0055",
2104
+ dataIndex: m,
2105
+ dataX: g.x[m],
2106
+ dataY: g.y[m],
2107
+ pixelX: I,
2108
+ pixelY: v,
2109
+ cycle: (p = c.getCycle) == null ? void 0 : p.call(c)
2110
+ };
2111
+ const B = c.getYError(m);
2112
+ B && (h.yError = B);
2113
+ }
2114
+ }
2115
+ }
2116
+ return h;
2117
+ }
2118
+ /**
2119
+ * Find heatmap cell under cursor
2120
+ */
2121
+ findHeatmapCell(t, i) {
2122
+ var h, a;
2123
+ const e = this.getSeries().filter(
2124
+ (r) => r.isVisible() && r.getType() === "heatmap"
2125
+ );
2126
+ if (e.length === 0) return null;
2127
+ const n = this.getXScale(), o = this.getYScales(), s = this.pixelToDataX(t), l = this.pixelToDataY(i);
2128
+ for (const r of e) {
2129
+ const d = r.getHeatmapData();
2130
+ if (!d || !d.xValues || !d.yValues || !d.zValues) continue;
2131
+ const p = this.binarySearchClosest(d.xValues, s), c = this.binarySearchClosest(d.yValues, l), g = d.xValues[p], y = d.yValues[c], b = o.get(((h = r.getYAxisId) == null ? void 0 : h.call(r)) || "default") || o.values().next().value;
2132
+ if (!b) continue;
2133
+ const x = n.transform(g), S = b.transform(y), w = d.zValues[c * d.xValues.length + p], C = ((a = r.getHeatmapStyle) == null ? void 0 : a.call(r)) || {};
2134
+ return {
2135
+ type: "heatmap",
2136
+ seriesId: r.getId(),
2137
+ seriesName: r.getId(),
2138
+ xIndex: p,
2139
+ yIndex: c,
2140
+ dataX: g,
2141
+ dataY: y,
2142
+ zValue: w,
2143
+ pixelX: x,
2144
+ pixelY: S,
2145
+ colorScale: C.colorScale
2146
+ };
2147
+ }
2148
+ return null;
2149
+ }
2150
+ /**
2151
+ * Binary search for closest value
2152
+ */
2153
+ binarySearchClosest(t, i) {
2154
+ let e = 0, n = t.length - 1;
2155
+ for (; e < n; ) {
2156
+ const o = Math.floor((e + n) / 2);
2157
+ t[o] < i ? e = o + 1 : n = o;
2158
+ }
2159
+ return e > 0 && Math.abs(t[e - 1] - i) < Math.abs(t[e] - i) ? e - 1 : e;
2160
+ }
2161
+ /**
2162
+ * Build crosshair tooltip data
2163
+ */
2164
+ buildCrosshairTooltip(t, i) {
2165
+ var l, h;
2166
+ const e = this.getSeries().filter(
2167
+ (a) => a.isVisible() && a.getType() !== "heatmap"
2168
+ );
2169
+ if (e.length === 0) return null;
2170
+ const n = this.pixelToDataX(t), o = this.getYScales(), s = [];
2171
+ for (const a of e) {
2172
+ const r = a.getData();
2173
+ if (!r.x || r.x.length === 0 || !(o.get(((l = a.getYAxisId) == null ? void 0 : l.call(a)) || "default") || o.values().next().value)) continue;
2174
+ const p = this.binarySearchClosest(r.x, n);
2175
+ let c, g = !1;
2176
+ if (p === 0 || p >= r.x.length - 1 || r.x[p] === n)
2177
+ c = r.y[p];
2178
+ else if ((h = this.options.crosshair) != null && h.interpolate) {
2179
+ const b = r.x[p - 1], x = r.x[p], S = r.y[p - 1], w = r.y[p], C = (n - b) / (x - b);
2180
+ c = S + C * (w - S), g = !0;
2181
+ } else
2182
+ c = r.y[p];
2183
+ const y = a.getStyle();
2184
+ s.push({
2185
+ seriesId: a.getId(),
2186
+ seriesName: a.getId(),
2187
+ seriesColor: y.color || "#ff0055",
2188
+ x: n,
2189
+ y: c,
2190
+ isInterpolated: g
2191
+ });
2192
+ }
2193
+ return s.length === 0 ? null : {
2194
+ type: "crosshair",
2195
+ cursorX: t,
2196
+ cursorY: i,
2197
+ dataX: n,
2198
+ interpolatedValues: s
2199
+ };
2200
+ }
2201
+ /**
2202
+ * Schedule showing a tooltip
2203
+ */
2204
+ scheduleShow(t) {
2205
+ if (this.clearHideTimeout(), t.type === "datapoint") {
2206
+ const e = t;
2207
+ if (this.hoveredSeriesId === e.seriesId && this.hoveredDataIndex === e.dataIndex) {
2208
+ this.updateTooltipPosition(t);
2209
+ return;
2210
+ }
2211
+ this.hoveredSeriesId = e.seriesId, this.hoveredDataIndex = e.dataIndex;
2212
+ }
2213
+ this.clearShowTimeout();
2214
+ const i = this.activeTooltips.size > 0 ? 0 : this.options.showDelay;
2215
+ i > 0 ? this.showTimeoutId = window.setTimeout(() => {
2216
+ this.showTooltip(t);
2217
+ }, i) : this.showTooltip(t);
2218
+ }
2219
+ /**
2220
+ * Schedule hiding tooltips
2221
+ */
2222
+ scheduleHide() {
2223
+ this.clearShowTimeout(), this.hoveredSeriesId = null, this.hoveredDataIndex = null, this.options.hideDelay > 0 ? this.hideTimeoutId = window.setTimeout(() => {
2224
+ this.hideAll();
2225
+ }, this.options.hideDelay) : this.hideAll();
2226
+ }
2227
+ clearShowTimeout() {
2228
+ this.showTimeoutId !== null && (clearTimeout(this.showTimeoutId), this.showTimeoutId = null);
2229
+ }
2230
+ clearHideTimeout() {
2231
+ this.hideTimeoutId !== null && (clearTimeout(this.hideTimeoutId), this.hideTimeoutId = null);
2232
+ }
2233
+ /**
2234
+ * Show a tooltip with the given data
2235
+ */
2236
+ showTooltip(t) {
2237
+ const i = this.getTemplateIdForType(t.type), e = this.templates.get(i) || j(t.type), n = t.pixelX ?? this.lastCursorX ?? 0, o = t.pixelY ?? this.lastCursorY ?? 0, s = e.measure(this.ctx, t, this.theme), l = this.positioner.calculatePosition(
2238
+ n,
2239
+ o,
2240
+ s
2241
+ ), h = "main";
2242
+ this.activeTooltips.set(h, {
2243
+ id: h,
2244
+ data: t,
2245
+ position: l,
2246
+ template: e
2247
+ });
2248
+ }
2249
+ /**
2250
+ * Update tooltip position
2251
+ */
2252
+ updateTooltipPosition(t) {
2253
+ const i = this.activeTooltips.get("main");
2254
+ if (!i) return;
2255
+ const e = t || i.data, n = e.pixelX ?? this.lastCursorX ?? 0, o = e.pixelY ?? this.lastCursorY ?? 0, s = i.template.measure(
2256
+ this.ctx,
2257
+ e,
2258
+ this.theme
2259
+ );
2260
+ i.position = this.positioner.calculatePosition(
2261
+ n,
2262
+ o,
2263
+ s
2264
+ ), i.data = e;
2265
+ }
2266
+ /**
2267
+ * Get template ID for a tooltip type
2268
+ */
2269
+ getTemplateIdForType(t) {
2270
+ var i, e, n;
2271
+ switch (t) {
2272
+ case "datapoint":
2273
+ return ((i = this.options.dataPoint) == null ? void 0 : i.templateId) || "default";
2274
+ case "crosshair":
2275
+ return ((e = this.options.crosshair) == null ? void 0 : e.templateId) || "crosshair";
2276
+ case "heatmap":
2277
+ return ((n = this.options.heatmap) == null ? void 0 : n.templateId) || "heatmap";
2278
+ default:
2279
+ return "default";
2280
+ }
2281
+ }
2282
+ /**
2283
+ * Show a tooltip programmatically
2284
+ */
2285
+ show(t, i) {
2286
+ const e = `tooltip-${++this.tooltipIdCounter}`, n = (i == null ? void 0 : i.templateId) || this.getTemplateIdForType(t.type), o = this.templates.get(n) || j(t.type);
2287
+ let s;
2288
+ if (i != null && i.position) {
2289
+ const l = o.measure(this.ctx, t, this.theme);
2290
+ s = this.positioner.calculatePosition(
2291
+ i.position.x,
2292
+ i.position.y,
2293
+ l
2294
+ );
2295
+ } else {
2296
+ const l = t.pixelX ?? 0, h = t.pixelY ?? 0, a = o.measure(this.ctx, t, this.theme);
2297
+ s = this.positioner.calculatePosition(
2298
+ l,
2299
+ h,
2300
+ a
2301
+ );
2302
+ }
2303
+ return this.activeTooltips.set(e, {
2304
+ id: e,
2305
+ data: t,
2306
+ position: s,
2307
+ template: o
2308
+ }), i != null && i.duration && i.duration > 0 && setTimeout(() => this.hide(e), i.duration), e;
2309
+ }
2310
+ /**
2311
+ * Hide a specific tooltip
2312
+ */
2313
+ hide(t) {
2314
+ this.activeTooltips.delete(t);
2315
+ }
2316
+ /**
2317
+ * Hide all tooltips immediately
2318
+ */
2319
+ hideAll() {
2320
+ this.activeTooltips.clear(), this.hoveredSeriesId = null, this.hoveredDataIndex = null;
2321
+ }
2322
+ /**
2323
+ * Render all active tooltips
2324
+ */
2325
+ render() {
2326
+ if (!(!this.options.enabled || this.activeTooltips.size === 0))
2327
+ for (const t of this.activeTooltips.values())
2328
+ this.renderer.render(t.data, t.position, t.template);
2329
+ }
2330
+ /**
2331
+ * Check if any tooltip is currently visible
2332
+ */
2333
+ hasActiveTooltip() {
2334
+ return this.activeTooltips.size > 0;
2335
+ }
2336
+ /**
2337
+ * Subscribe to tooltip events
2338
+ */
2339
+ on(t, i) {
2340
+ this.events.on(t, i);
2341
+ }
2342
+ /**
2343
+ * Unsubscribe from tooltip events
2344
+ */
2345
+ off(t, i) {
2346
+ this.events.off(t, i);
2347
+ }
2348
+ /**
2349
+ * Destroy the tooltip manager
2350
+ */
2351
+ destroy() {
2352
+ this.clearShowTimeout(), this.clearHideTimeout(), this.activeTooltips.clear(), this.templates.clear(), this.events.clear();
2353
+ }
2354
+ }
2355
+ const zt = {
2356
+ name: "velo-plot-tools",
2357
+ version: "1.0.0",
2358
+ description: "Advanced interaction and measurement tools for velo-plot",
2359
+ provides: ["interaction"],
2360
+ tags: ["delta-tool", "peak-tool", "tooltip"]
2361
+ };
2362
+ function Xt(f = {}) {
2363
+ let t = null, i = null, e = null;
2364
+ return {
2365
+ manifest: zt,
2366
+ onInit(n) {
2367
+ var s;
2368
+ const o = {
2369
+ container: n.ui.container,
2370
+ getPlotArea: () => n.render.plotArea,
2371
+ getViewBounds: () => n.data.getViewBounds(),
2372
+ getYBounds: (l) => n.data.getYAxisBounds(l),
2373
+ requestRender: () => n.requestRender(),
2374
+ getSeries: () => n.data.getAllSeries().map((l) => {
2375
+ var a;
2376
+ const h = l.getData();
2377
+ return {
2378
+ id: l.getId(),
2379
+ x: h.x,
2380
+ y: h.y,
2381
+ yAxisId: ((a = l.getYAxisId) == null ? void 0 : a.call(l)) || void 0
2382
+ };
2383
+ }),
2384
+ onMeasure: (l) => n.events.emit("measure", l)
2385
+ };
2386
+ if ((f.enableDeltaTool ?? !0) && (t = new lt(o)), (f.enablePeakTool ?? !0) && (i = new rt(o)), f.useEnhancedTooltips ?? !0) {
2387
+ const l = n.chart;
2388
+ n.log.debug("TooltipManager init - checking deps:", {
2389
+ hasCtx2d: !!n.render.ctx2d,
2390
+ hasXScale: !!l.xScale,
2391
+ hasYScales: !!l.yScales,
2392
+ seriesCount: n.data.getAllSeries().length
2393
+ }), n.render.ctx2d ? e = new Ft({
2394
+ overlayCtx: n.render.ctx2d,
2395
+ chartTheme: n.ui.theme,
2396
+ getPlotArea: () => n.render.plotArea,
2397
+ getSeries: () => n.data.getAllSeries(),
2398
+ pixelToDataX: (h) => n.coords.pixelToDataX(h),
2399
+ pixelToDataY: (h) => n.coords.pixelToDataY(h),
2400
+ getXScale: () => l.xScale,
2401
+ getYScales: () => l.yScales,
2402
+ getViewBounds: () => n.data.getViewBounds(),
2403
+ options: (s = l.initialOptions) == null ? void 0 : s.tooltip
2404
+ }) : n.log.warn("TooltipManager: No 2D context available, tooltips disabled");
2405
+ }
2406
+ },
2407
+ onRenderOverlay(n) {
2408
+ e == null || e.render(), t == null || t.renderOverlay(), i == null || i.renderOverlay();
2409
+ },
2410
+ onDestroy(n) {
2411
+ t == null || t.destroy(), i == null || i.destroy(), e == null || e.destroy(), t = null, i = null, e = null;
2412
+ },
2413
+ api: {
2414
+ setMode(n) {
2415
+ t == null || t.disable(), i == null || i.disable(), n === "delta" && (t == null || t.enable()), n === "peak" && (i == null || i.enable());
2416
+ },
2417
+ getDeltaTool: () => t,
2418
+ getPeakTool: () => i,
2419
+ getTooltipManager: () => e
2420
+ }
2421
+ };
2422
+ }
2423
+ export {
2424
+ lt as D,
2425
+ Xt as P,
2426
+ Ft as T,
2427
+ ut as a,
2428
+ rt as b,
2429
+ k as g
2430
+ };
2431
+ //# sourceMappingURL=index-D8ifudJH.js.map