stream-charts 1.2.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +809 -1022
  3. package/changes.md +36 -0
  4. package/dist/app/charts/Chart.d.ts +35 -139
  5. package/dist/app/charts/Chart.d.ts.map +1 -0
  6. package/dist/app/charts/Chart.js +74 -65
  7. package/dist/app/charts/Chart.js.map +1 -1
  8. package/dist/app/charts/axes/AxesState.d.ts +26 -18
  9. package/dist/app/charts/axes/AxesState.d.ts.map +1 -0
  10. package/dist/app/charts/axes/AxesState.js +26 -24
  11. package/dist/app/charts/axes/AxesState.js.map +1 -1
  12. package/dist/app/charts/axes/AxisInterval.d.ts +44 -26
  13. package/dist/app/charts/axes/AxisInterval.d.ts.map +1 -0
  14. package/dist/app/charts/axes/AxisInterval.js +48 -29
  15. package/dist/app/charts/axes/AxisInterval.js.map +1 -1
  16. package/dist/app/charts/axes/BaseAxisRange.d.ts +46 -22
  17. package/dist/app/charts/axes/BaseAxisRange.d.ts.map +1 -0
  18. package/dist/app/charts/axes/BaseAxisRange.js +17 -12
  19. package/dist/app/charts/axes/BaseAxisRange.js.map +1 -1
  20. package/dist/app/charts/axes/ContinuousAxis.d.ts +47 -6
  21. package/dist/app/charts/axes/ContinuousAxis.d.ts.map +1 -0
  22. package/dist/app/charts/axes/ContinuousAxis.js +160 -27
  23. package/dist/app/charts/axes/ContinuousAxis.js.map +1 -1
  24. package/dist/app/charts/axes/ContinuousAxisRange.d.ts +29 -10
  25. package/dist/app/charts/axes/ContinuousAxisRange.d.ts.map +1 -0
  26. package/dist/app/charts/axes/ContinuousAxisRange.js +29 -11
  27. package/dist/app/charts/axes/ContinuousAxisRange.js.map +1 -1
  28. package/dist/app/charts/axes/EmptyAxis.d.ts +5 -2
  29. package/dist/app/charts/axes/EmptyAxis.d.ts.map +1 -0
  30. package/dist/app/charts/axes/EmptyAxis.js +30 -9
  31. package/dist/app/charts/axes/EmptyAxis.js.map +1 -1
  32. package/dist/app/charts/axes/OrdinalAxis.d.ts +5 -3
  33. package/dist/app/charts/axes/OrdinalAxis.d.ts.map +1 -0
  34. package/dist/app/charts/axes/OrdinalAxis.js +39 -16
  35. package/dist/app/charts/axes/OrdinalAxis.js.map +1 -1
  36. package/dist/app/charts/axes/OrdinalAxisRange.d.ts +76 -13
  37. package/dist/app/charts/axes/OrdinalAxisRange.d.ts.map +1 -0
  38. package/dist/app/charts/axes/OrdinalAxisRange.js +95 -16
  39. package/dist/app/charts/axes/OrdinalAxisRange.js.map +1 -1
  40. package/dist/app/charts/axes/autoScale.d.ts +111 -0
  41. package/dist/app/charts/axes/autoScale.d.ts.map +1 -0
  42. package/dist/app/charts/axes/autoScale.js +188 -0
  43. package/dist/app/charts/axes/autoScale.js.map +1 -0
  44. package/dist/app/charts/axes/axes.d.ts +273 -150
  45. package/dist/app/charts/axes/axes.d.ts.map +1 -0
  46. package/dist/app/charts/axes/axes.js +808 -583
  47. package/dist/app/charts/axes/axes.js.map +1 -1
  48. package/dist/app/charts/d3types.d.ts +40 -11
  49. package/dist/app/charts/d3types.d.ts.map +1 -0
  50. package/dist/app/charts/d3types.js +3 -0
  51. package/dist/app/charts/d3types.js.map +1 -1
  52. package/dist/app/charts/datasources/StreamingDataSource.d.ts +149 -0
  53. package/dist/app/charts/datasources/StreamingDataSource.d.ts.map +1 -0
  54. package/dist/app/charts/datasources/StreamingDataSource.js +110 -0
  55. package/dist/app/charts/datasources/StreamingDataSource.js.map +1 -0
  56. package/dist/app/charts/datasources/iteratesDataSource.d.ts +73 -0
  57. package/dist/app/charts/datasources/iteratesDataSource.d.ts.map +1 -0
  58. package/dist/app/charts/datasources/iteratesDataSource.js +87 -0
  59. package/dist/app/charts/datasources/iteratesDataSource.js.map +1 -0
  60. package/dist/app/charts/datasources/ordinalDataSource.d.ts +75 -0
  61. package/dist/app/charts/datasources/ordinalDataSource.d.ts.map +1 -0
  62. package/dist/app/charts/datasources/ordinalDataSource.js +135 -0
  63. package/dist/app/charts/datasources/ordinalDataSource.js.map +1 -0
  64. package/dist/app/charts/datasources/outlierDataSource.d.ts +53 -0
  65. package/dist/app/charts/datasources/outlierDataSource.d.ts.map +1 -0
  66. package/dist/app/charts/datasources/outlierDataSource.js +57 -0
  67. package/dist/app/charts/datasources/outlierDataSource.js.map +1 -0
  68. package/dist/app/charts/datasources/timeSeriesDataSource.d.ts +77 -0
  69. package/dist/app/charts/datasources/timeSeriesDataSource.d.ts.map +1 -0
  70. package/dist/app/charts/datasources/timeSeriesDataSource.js +85 -0
  71. package/dist/app/charts/datasources/timeSeriesDataSource.js.map +1 -0
  72. package/dist/app/charts/filters/regexFilter.d.ts +31 -4
  73. package/dist/app/charts/filters/regexFilter.d.ts.map +1 -0
  74. package/dist/app/charts/filters/regexFilter.js +38 -4
  75. package/dist/app/charts/filters/regexFilter.js.map +1 -1
  76. package/dist/app/charts/hooks/AxesProvider.d.ts +21 -0
  77. package/dist/app/charts/hooks/AxesProvider.d.ts.map +1 -0
  78. package/dist/app/charts/hooks/AxesProvider.js +213 -0
  79. package/dist/app/charts/hooks/AxesProvider.js.map +1 -0
  80. package/dist/app/charts/hooks/CanvasSurfaceProvider.d.ts +25 -0
  81. package/dist/app/charts/hooks/CanvasSurfaceProvider.d.ts.map +1 -0
  82. package/dist/app/charts/hooks/CanvasSurfaceProvider.js +76 -0
  83. package/dist/app/charts/hooks/CanvasSurfaceProvider.js.map +1 -0
  84. package/dist/app/charts/hooks/ChartProvider.d.ts +40 -0
  85. package/dist/app/charts/hooks/ChartProvider.d.ts.map +1 -0
  86. package/dist/app/charts/hooks/ChartProvider.js +33 -0
  87. package/dist/app/charts/hooks/ChartProvider.js.map +1 -0
  88. package/dist/app/charts/hooks/InteractionProvider.d.ts +23 -0
  89. package/dist/app/charts/hooks/InteractionProvider.d.ts.map +1 -0
  90. package/dist/app/charts/hooks/InteractionProvider.js +60 -0
  91. package/dist/app/charts/hooks/InteractionProvider.js.map +1 -0
  92. package/dist/app/charts/hooks/PlotDimensionsProvider.d.ts +16 -0
  93. package/dist/app/charts/hooks/PlotDimensionsProvider.d.ts.map +1 -0
  94. package/dist/app/charts/hooks/PlotDimensionsProvider.js +76 -0
  95. package/dist/app/charts/hooks/PlotDimensionsProvider.js.map +1 -0
  96. package/dist/app/charts/hooks/defaultAxesValues.d.ts +11 -0
  97. package/dist/app/charts/hooks/defaultAxesValues.d.ts.map +1 -0
  98. package/dist/app/charts/hooks/defaultAxesValues.js +36 -0
  99. package/dist/app/charts/hooks/defaultAxesValues.js.map +1 -0
  100. package/dist/app/charts/hooks/defaultMouseValues.d.ts +9 -0
  101. package/dist/app/charts/hooks/defaultMouseValues.d.ts.map +1 -0
  102. package/dist/app/charts/hooks/defaultMouseValues.js +23 -0
  103. package/dist/app/charts/hooks/defaultMouseValues.js.map +1 -0
  104. package/dist/app/charts/hooks/defaultPlotDimensions.d.ts +13 -0
  105. package/dist/app/charts/hooks/defaultPlotDimensions.d.ts.map +1 -0
  106. package/dist/app/charts/hooks/defaultPlotDimensions.js +23 -0
  107. package/dist/app/charts/hooks/defaultPlotDimensions.js.map +1 -0
  108. package/dist/app/charts/hooks/defaultTooltipValues.d.ts +9 -0
  109. package/dist/app/charts/hooks/defaultTooltipValues.d.ts.map +1 -0
  110. package/dist/app/charts/hooks/defaultTooltipValues.js +21 -0
  111. package/dist/app/charts/hooks/defaultTooltipValues.js.map +1 -0
  112. package/dist/app/charts/hooks/defaultUseChartValues.d.ts +14 -0
  113. package/dist/app/charts/hooks/defaultUseChartValues.d.ts.map +1 -0
  114. package/dist/app/charts/hooks/defaultUseChartValues.js +30 -0
  115. package/dist/app/charts/hooks/defaultUseChartValues.js.map +1 -0
  116. package/dist/app/charts/hooks/useAxes.d.ts +49 -36
  117. package/dist/app/charts/hooks/useAxes.d.ts.map +1 -0
  118. package/dist/app/charts/hooks/useAxes.js +16 -176
  119. package/dist/app/charts/hooks/useAxes.js.map +1 -1
  120. package/dist/app/charts/hooks/useCanvasSurface.d.ts +25 -0
  121. package/dist/app/charts/hooks/useCanvasSurface.d.ts.map +1 -0
  122. package/dist/app/charts/hooks/useCanvasSurface.js +18 -0
  123. package/dist/app/charts/hooks/useCanvasSurface.js.map +1 -0
  124. package/dist/app/charts/hooks/useChart.d.ts +30 -44
  125. package/dist/app/charts/hooks/useChart.d.ts.map +1 -0
  126. package/dist/app/charts/hooks/useChart.js +26 -48
  127. package/dist/app/charts/hooks/useChart.js.map +1 -1
  128. package/dist/app/charts/hooks/useDataSource.d.ts +68 -0
  129. package/dist/app/charts/hooks/useDataSource.d.ts.map +1 -0
  130. package/dist/app/charts/hooks/useDataSource.js +63 -0
  131. package/dist/app/charts/hooks/useDataSource.js.map +1 -0
  132. package/dist/app/charts/hooks/useHoveredSeries.d.ts +25 -0
  133. package/dist/app/charts/hooks/useHoveredSeries.d.ts.map +1 -0
  134. package/dist/app/charts/hooks/useHoveredSeries.js +15 -0
  135. package/dist/app/charts/hooks/useHoveredSeries.js.map +1 -0
  136. package/dist/app/charts/hooks/useMouse.d.ts +46 -22
  137. package/dist/app/charts/hooks/useMouse.d.ts.map +1 -0
  138. package/dist/app/charts/hooks/useMouse.js +12 -56
  139. package/dist/app/charts/hooks/useMouse.js.map +1 -1
  140. package/dist/app/charts/hooks/usePlotDimensions.d.ts +25 -13
  141. package/dist/app/charts/hooks/usePlotDimensions.d.ts.map +1 -0
  142. package/dist/app/charts/hooks/usePlotDimensions.js +6 -62
  143. package/dist/app/charts/hooks/usePlotDimensions.js.map +1 -1
  144. package/dist/app/charts/hooks/useTooltip.d.ts +24 -26
  145. package/dist/app/charts/hooks/useTooltip.d.ts.map +1 -0
  146. package/dist/app/charts/hooks/useTooltip.js +12 -42
  147. package/dist/app/charts/hooks/useTooltip.js.map +1 -1
  148. package/dist/app/charts/index.d.ts +66 -0
  149. package/dist/app/charts/index.d.ts.map +1 -0
  150. package/dist/app/charts/index.js +87 -0
  151. package/dist/app/charts/index.js.map +1 -0
  152. package/dist/app/charts/legends/Legend.d.ts +33 -12
  153. package/dist/app/charts/legends/Legend.d.ts.map +1 -0
  154. package/dist/app/charts/legends/Legend.js +138 -379
  155. package/dist/app/charts/legends/Legend.js.map +1 -1
  156. package/dist/app/charts/legends/constants.d.ts +19 -0
  157. package/dist/app/charts/legends/constants.d.ts.map +1 -0
  158. package/dist/app/charts/legends/constants.js +34 -0
  159. package/dist/app/charts/legends/constants.js.map +1 -0
  160. package/dist/app/charts/observables/ChartData.d.ts +1 -0
  161. package/dist/app/charts/observables/ChartData.d.ts.map +1 -0
  162. package/dist/app/charts/observables/iterates.d.ts +13 -7
  163. package/dist/app/charts/observables/iterates.d.ts.map +1 -0
  164. package/dist/app/charts/observables/iterates.js +42 -9
  165. package/dist/app/charts/observables/iterates.js.map +1 -1
  166. package/dist/app/charts/observables/ordinals.d.ts +70 -12
  167. package/dist/app/charts/observables/ordinals.d.ts.map +1 -0
  168. package/dist/app/charts/observables/ordinals.js +127 -48
  169. package/dist/app/charts/observables/ordinals.js.map +1 -1
  170. package/dist/app/charts/observables/outliers.d.ts +18 -0
  171. package/dist/app/charts/observables/outliers.d.ts.map +1 -0
  172. package/dist/app/charts/observables/outliers.js +2 -0
  173. package/dist/app/charts/observables/outliers.js.map +1 -0
  174. package/dist/app/charts/plots/BarPlot.d.ts +87 -13
  175. package/dist/app/charts/plots/BarPlot.d.ts.map +1 -0
  176. package/dist/app/charts/plots/BarPlot.js +603 -356
  177. package/dist/app/charts/plots/BarPlot.js.map +1 -1
  178. package/dist/app/charts/plots/OutlierPlot.d.ts +123 -0
  179. package/dist/app/charts/plots/OutlierPlot.d.ts.map +1 -0
  180. package/dist/app/charts/plots/OutlierPlot.js +430 -0
  181. package/dist/app/charts/plots/OutlierPlot.js.map +1 -0
  182. package/dist/app/charts/plots/PoincarePlot.d.ts +92 -14
  183. package/dist/app/charts/plots/PoincarePlot.d.ts.map +1 -0
  184. package/dist/app/charts/plots/PoincarePlot.js +523 -364
  185. package/dist/app/charts/plots/PoincarePlot.js.map +1 -1
  186. package/dist/app/charts/plots/RasterPlot.d.ts +31 -10
  187. package/dist/app/charts/plots/RasterPlot.d.ts.map +1 -0
  188. package/dist/app/charts/plots/RasterPlot.js +198 -306
  189. package/dist/app/charts/plots/RasterPlot.js.map +1 -1
  190. package/dist/app/charts/plots/ScatterPlot.d.ts +77 -21
  191. package/dist/app/charts/plots/ScatterPlot.d.ts.map +1 -0
  192. package/dist/app/charts/plots/ScatterPlot.js +359 -302
  193. package/dist/app/charts/plots/ScatterPlot.js.map +1 -1
  194. package/dist/app/charts/plots/autoScaleYAxes.d.ts +43 -0
  195. package/dist/app/charts/plots/autoScaleYAxes.d.ts.map +1 -0
  196. package/dist/app/charts/plots/autoScaleYAxes.js +71 -0
  197. package/dist/app/charts/plots/autoScaleYAxes.js.map +1 -0
  198. package/dist/app/charts/plots/colorizedLine.d.ts +61 -0
  199. package/dist/app/charts/plots/colorizedLine.d.ts.map +1 -0
  200. package/dist/app/charts/plots/colorizedLine.js +157 -0
  201. package/dist/app/charts/plots/colorizedLine.js.map +1 -0
  202. package/dist/app/charts/plots/constants.d.ts +7 -0
  203. package/dist/app/charts/plots/constants.d.ts.map +1 -0
  204. package/dist/app/charts/plots/constants.js +11 -0
  205. package/dist/app/charts/plots/constants.js.map +1 -0
  206. package/dist/app/charts/plots/hitTesting.d.ts +88 -0
  207. package/dist/app/charts/plots/hitTesting.d.ts.map +1 -0
  208. package/dist/app/charts/plots/hitTesting.js +136 -0
  209. package/dist/app/charts/plots/hitTesting.js.map +1 -0
  210. package/dist/app/charts/plots/plot.d.ts +52 -16
  211. package/dist/app/charts/plots/plot.d.ts.map +1 -0
  212. package/dist/app/charts/plots/plot.js +108 -35
  213. package/dist/app/charts/plots/plot.js.map +1 -1
  214. package/dist/app/charts/plots/useCanvasZoomPan.d.ts +119 -0
  215. package/dist/app/charts/plots/useCanvasZoomPan.d.ts.map +1 -0
  216. package/dist/app/charts/plots/useCanvasZoomPan.js +113 -0
  217. package/dist/app/charts/plots/useCanvasZoomPan.js.map +1 -0
  218. package/dist/app/charts/plots/useStreamingTimeAxes.d.ts +103 -0
  219. package/dist/app/charts/plots/useStreamingTimeAxes.d.ts.map +1 -0
  220. package/dist/app/charts/plots/useStreamingTimeAxes.js +257 -0
  221. package/dist/app/charts/plots/useStreamingTimeAxes.js.map +1 -0
  222. package/dist/app/charts/series/baseSeries.d.ts +60 -8
  223. package/dist/app/charts/series/baseSeries.d.ts.map +1 -0
  224. package/dist/app/charts/series/baseSeries.js +53 -8
  225. package/dist/app/charts/series/baseSeries.js.map +1 -1
  226. package/dist/app/charts/series/iterateSeries.d.ts +9 -8
  227. package/dist/app/charts/series/iterateSeries.d.ts.map +1 -0
  228. package/dist/app/charts/series/iterateSeries.js +7 -7
  229. package/dist/app/charts/series/iterateSeries.js.map +1 -1
  230. package/dist/app/charts/series/ordinalSeries.d.ts +27 -13
  231. package/dist/app/charts/series/ordinalSeries.d.ts.map +1 -0
  232. package/dist/app/charts/series/ordinalSeries.js +29 -15
  233. package/dist/app/charts/series/ordinalSeries.js.map +1 -1
  234. package/dist/app/charts/series/outlierSeries.d.ts +142 -0
  235. package/dist/app/charts/series/outlierSeries.d.ts.map +1 -0
  236. package/dist/app/charts/series/outlierSeries.js +82 -0
  237. package/dist/app/charts/series/outlierSeries.js.map +1 -0
  238. package/dist/app/charts/series/timeSeries.d.ts +13 -9
  239. package/dist/app/charts/series/timeSeries.d.ts.map +1 -0
  240. package/dist/app/charts/series/timeSeries.js +6 -3
  241. package/dist/app/charts/series/timeSeries.js.map +1 -1
  242. package/dist/app/charts/series/timeSeriesChartData.d.ts +18 -10
  243. package/dist/app/charts/series/timeSeriesChartData.d.ts.map +1 -0
  244. package/dist/app/charts/series/timeSeriesChartData.js +28 -14
  245. package/dist/app/charts/series/timeSeriesChartData.js.map +1 -1
  246. package/dist/app/charts/styling/barPlotStyle.d.ts +46 -2
  247. package/dist/app/charts/styling/barPlotStyle.d.ts.map +1 -0
  248. package/dist/app/charts/styling/barPlotStyle.js +37 -3
  249. package/dist/app/charts/styling/barPlotStyle.js.map +1 -1
  250. package/dist/app/charts/styling/canvasStyle.d.ts +53 -0
  251. package/dist/app/charts/styling/canvasStyle.d.ts.map +1 -0
  252. package/dist/app/charts/styling/canvasStyle.js +71 -0
  253. package/dist/app/charts/styling/canvasStyle.js.map +1 -0
  254. package/dist/app/charts/styling/margins.d.ts +21 -2
  255. package/dist/app/charts/styling/margins.d.ts.map +1 -0
  256. package/dist/app/charts/styling/margins.js +25 -4
  257. package/dist/app/charts/styling/margins.js.map +1 -1
  258. package/dist/app/charts/styling/svgStyle.d.ts +10 -56
  259. package/dist/app/charts/styling/svgStyle.d.ts.map +1 -0
  260. package/dist/app/charts/styling/svgStyle.js +3 -78
  261. package/dist/app/charts/styling/svgStyle.js.map +1 -1
  262. package/dist/app/charts/subscriptions/viewDrivers.d.ts +124 -0
  263. package/dist/app/charts/subscriptions/viewDrivers.d.ts.map +1 -0
  264. package/dist/app/charts/subscriptions/viewDrivers.js +338 -0
  265. package/dist/app/charts/subscriptions/viewDrivers.js.map +1 -0
  266. package/dist/app/charts/tooltips/BarPlotTooltipContent.d.ts +12 -78
  267. package/dist/app/charts/tooltips/BarPlotTooltipContent.d.ts.map +1 -0
  268. package/dist/app/charts/tooltips/BarPlotTooltipContent.js +65 -257
  269. package/dist/app/charts/tooltips/BarPlotTooltipContent.js.map +1 -1
  270. package/dist/app/charts/tooltips/DefaultOutlierTooltipContent.d.ts +9 -0
  271. package/dist/app/charts/tooltips/DefaultOutlierTooltipContent.d.ts.map +1 -0
  272. package/dist/app/charts/tooltips/DefaultOutlierTooltipContent.js +16 -0
  273. package/dist/app/charts/tooltips/DefaultOutlierTooltipContent.js.map +1 -0
  274. package/dist/app/charts/tooltips/OutlierPlotTooltipContent.d.ts +30 -0
  275. package/dist/app/charts/tooltips/OutlierPlotTooltipContent.d.ts.map +1 -0
  276. package/dist/app/charts/tooltips/OutlierPlotTooltipContent.js +26 -0
  277. package/dist/app/charts/tooltips/OutlierPlotTooltipContent.js.map +1 -0
  278. package/dist/app/charts/tooltips/PoincarePlotTooltipContent.d.ts +22 -72
  279. package/dist/app/charts/tooltips/PoincarePlotTooltipContent.d.ts.map +1 -0
  280. package/dist/app/charts/tooltips/PoincarePlotTooltipContent.js +104 -171
  281. package/dist/app/charts/tooltips/PoincarePlotTooltipContent.js.map +1 -1
  282. package/dist/app/charts/tooltips/RasterPlotTooltipContent.d.ts +32 -8
  283. package/dist/app/charts/tooltips/RasterPlotTooltipContent.d.ts.map +1 -0
  284. package/dist/app/charts/tooltips/RasterPlotTooltipContent.js +62 -115
  285. package/dist/app/charts/tooltips/RasterPlotTooltipContent.js.map +1 -1
  286. package/dist/app/charts/tooltips/ScatterPlotTooltipContent.d.ts +39 -12
  287. package/dist/app/charts/tooltips/ScatterPlotTooltipContent.d.ts.map +1 -0
  288. package/dist/app/charts/tooltips/ScatterPlotTooltipContent.js +162 -134
  289. package/dist/app/charts/tooltips/ScatterPlotTooltipContent.js.map +1 -1
  290. package/dist/app/charts/tooltips/Tooltip.d.ts +27 -32
  291. package/dist/app/charts/tooltips/Tooltip.d.ts.map +1 -0
  292. package/dist/app/charts/tooltips/Tooltip.js +37 -81
  293. package/dist/app/charts/tooltips/Tooltip.js.map +1 -1
  294. package/dist/app/charts/tooltips/TooltipContent.d.ts +81 -0
  295. package/dist/app/charts/tooltips/TooltipContent.d.ts.map +1 -0
  296. package/dist/app/charts/tooltips/TooltipContent.js +99 -0
  297. package/dist/app/charts/tooltips/TooltipContent.js.map +1 -0
  298. package/dist/app/charts/tooltips/tooltipUtils.d.ts +186 -36
  299. package/dist/app/charts/tooltips/tooltipUtils.d.ts.map +1 -0
  300. package/dist/app/charts/tooltips/tooltipUtils.js +277 -48
  301. package/dist/app/charts/tooltips/tooltipUtils.js.map +1 -1
  302. package/dist/app/charts/tooltips/useOutlierTooltip.d.ts +59 -0
  303. package/dist/app/charts/tooltips/useOutlierTooltip.d.ts.map +1 -0
  304. package/dist/app/charts/tooltips/useOutlierTooltip.js +16 -0
  305. package/dist/app/charts/tooltips/useOutlierTooltip.js.map +1 -0
  306. package/dist/app/charts/tooltips/useTooltipPlacement.d.ts +51 -0
  307. package/dist/app/charts/tooltips/useTooltipPlacement.d.ts.map +1 -0
  308. package/dist/app/charts/tooltips/useTooltipPlacement.js +52 -0
  309. package/dist/app/charts/tooltips/useTooltipPlacement.js.map +1 -0
  310. package/dist/app/charts/tooltips/useTooltipStyle.d.ts +11 -0
  311. package/dist/app/charts/tooltips/useTooltipStyle.d.ts.map +1 -0
  312. package/dist/app/charts/tooltips/useTooltipStyle.js +14 -0
  313. package/dist/app/charts/tooltips/useTooltipStyle.js.map +1 -0
  314. package/dist/app/charts/trackers/Tracker.d.ts +22 -6
  315. package/dist/app/charts/trackers/Tracker.d.ts.map +1 -0
  316. package/dist/app/charts/trackers/Tracker.js +36 -22
  317. package/dist/app/charts/trackers/Tracker.js.map +1 -1
  318. package/dist/app/charts/trackers/trackerUtils.d.ts +40 -18
  319. package/dist/app/charts/trackers/trackerUtils.d.ts.map +1 -0
  320. package/dist/app/charts/trackers/trackerUtils.js +213 -300
  321. package/dist/app/charts/trackers/trackerUtils.js.map +1 -1
  322. package/dist/app/charts/utils.d.ts +72 -33
  323. package/dist/app/charts/utils.d.ts.map +1 -0
  324. package/dist/app/charts/utils.js +87 -42
  325. package/dist/app/charts/utils.js.map +1 -1
  326. package/dist/index.d.ts +2 -45
  327. package/dist/index.d.ts.map +1 -0
  328. package/dist/index.js +2 -72
  329. package/dist/index.js.map +1 -1
  330. package/package.json +87 -46
  331. package/src/app/charts/Chart.tsx +132 -168
  332. package/src/app/charts/axes/AxesState.ts +27 -29
  333. package/src/app/charts/axes/AxisInterval.ts +57 -32
  334. package/src/app/charts/axes/BaseAxisRange.ts +47 -27
  335. package/src/app/charts/axes/ContinuousAxis.tsx +235 -39
  336. package/src/app/charts/axes/ContinuousAxisRange.ts +29 -11
  337. package/src/app/charts/axes/EmptyAxis.tsx +52 -17
  338. package/src/app/charts/axes/OrdinalAxis.tsx +54 -28
  339. package/src/app/charts/axes/OrdinalAxisRange.ts +96 -16
  340. package/src/app/charts/axes/autoScale.ts +244 -0
  341. package/src/app/charts/axes/axes.ts +954 -735
  342. package/src/app/charts/d3types.ts +42 -13
  343. package/src/app/charts/datasources/StreamingDataSource.ts +214 -0
  344. package/src/app/charts/datasources/iteratesDataSource.ts +122 -0
  345. package/src/app/charts/datasources/ordinalDataSource.ts +205 -0
  346. package/src/app/charts/datasources/outlierDataSource.ts +90 -0
  347. package/src/app/charts/datasources/timeSeriesDataSource.ts +133 -0
  348. package/src/app/charts/filters/regexFilter.ts +45 -5
  349. package/src/app/charts/hooks/AxesProvider.tsx +301 -0
  350. package/src/app/charts/hooks/CanvasSurfaceProvider.tsx +117 -0
  351. package/src/app/charts/hooks/ChartProvider.tsx +79 -0
  352. package/src/app/charts/hooks/InteractionProvider.tsx +88 -0
  353. package/src/app/charts/hooks/PlotDimensionsProvider.tsx +109 -0
  354. package/src/app/charts/hooks/defaultAxesValues.ts +40 -0
  355. package/src/app/charts/hooks/defaultMouseValues.ts +24 -0
  356. package/src/app/charts/hooks/defaultPlotDimensions.ts +27 -0
  357. package/src/app/charts/hooks/defaultTooltipValues.tsx +23 -0
  358. package/src/app/charts/hooks/defaultUseChartValues.tsx +36 -0
  359. package/src/app/charts/hooks/useAxes.tsx +60 -228
  360. package/src/app/charts/hooks/useCanvasSurface.tsx +35 -0
  361. package/src/app/charts/hooks/useChart.tsx +47 -106
  362. package/src/app/charts/hooks/useDataSource.tsx +106 -0
  363. package/src/app/charts/hooks/useHoveredSeries.tsx +33 -0
  364. package/src/app/charts/hooks/useMouse.tsx +58 -82
  365. package/src/app/charts/hooks/usePlotDimensions.tsx +25 -89
  366. package/src/app/charts/hooks/useTooltip.tsx +32 -63
  367. package/src/app/charts/index.ts +213 -0
  368. package/src/app/charts/legends/Legend.tsx +198 -479
  369. package/src/app/charts/legends/constants.ts +37 -0
  370. package/src/app/charts/observables/iterates.ts +32 -12
  371. package/src/app/charts/observables/ordinals.ts +141 -67
  372. package/src/app/charts/observables/outliers.ts +20 -0
  373. package/src/app/charts/plots/BarPlot.tsx +784 -666
  374. package/src/app/charts/plots/OutlierPlot.tsx +685 -0
  375. package/src/app/charts/plots/PoincarePlot.tsx +707 -489
  376. package/src/app/charts/plots/RasterPlot.tsx +253 -445
  377. package/src/app/charts/plots/ScatterPlot.tsx +480 -463
  378. package/src/app/charts/plots/autoScaleYAxes.ts +102 -0
  379. package/src/app/charts/plots/colorizedLine.ts +185 -0
  380. package/src/app/charts/plots/constants.ts +16 -0
  381. package/src/app/charts/plots/hitTesting.ts +198 -0
  382. package/src/app/charts/plots/plot.ts +138 -44
  383. package/src/app/charts/plots/useCanvasZoomPan.ts +240 -0
  384. package/src/app/charts/plots/useStreamingTimeAxes.ts +384 -0
  385. package/src/app/charts/series/baseSeries.ts +81 -14
  386. package/src/app/charts/series/iterateSeries.ts +8 -8
  387. package/src/app/charts/series/ordinalSeries.ts +35 -20
  388. package/src/app/charts/series/outlierSeries.ts +188 -0
  389. package/src/app/charts/series/timeSeries.ts +14 -12
  390. package/src/app/charts/series/timeSeriesChartData.ts +31 -17
  391. package/src/app/charts/styling/barPlotStyle.ts +48 -5
  392. package/src/app/charts/styling/canvasStyle.ts +86 -0
  393. package/src/app/charts/styling/margins.ts +28 -4
  394. package/src/app/charts/styling/svgStyle.ts +10 -91
  395. package/src/app/charts/subscriptions/viewDrivers.ts +447 -0
  396. package/src/app/charts/tooltips/BarPlotTooltipContent.tsx +156 -380
  397. package/src/app/charts/tooltips/DefaultOutlierTooltipContent.tsx +40 -0
  398. package/src/app/charts/tooltips/OutlierPlotTooltipContent.tsx +67 -0
  399. package/src/app/charts/tooltips/PoincarePlotTooltipContent.tsx +229 -292
  400. package/src/app/charts/tooltips/RasterPlotTooltipContent.tsx +164 -217
  401. package/src/app/charts/tooltips/ScatterPlotTooltipContent.tsx +373 -236
  402. package/src/app/charts/tooltips/Tooltip.tsx +58 -124
  403. package/src/app/charts/tooltips/TooltipContent.tsx +177 -0
  404. package/src/app/charts/tooltips/tooltipUtils.ts +359 -61
  405. package/src/app/charts/tooltips/useOutlierTooltip.tsx +68 -0
  406. package/src/app/charts/tooltips/useTooltipPlacement.ts +86 -0
  407. package/src/app/charts/tooltips/useTooltipStyle.ts +15 -0
  408. package/src/app/charts/trackers/Tracker.tsx +68 -33
  409. package/src/app/charts/trackers/trackerUtils.ts +263 -376
  410. package/src/app/charts/utils.ts +90 -48
  411. package/src/index.ts +2 -322
  412. package/dist/app/charts/axes/AxesState.test.d.ts +0 -1
  413. package/dist/app/charts/axes/AxesState.test.js +0 -30
  414. package/dist/app/charts/axes/AxesState.test.js.map +0 -1
  415. package/dist/app/charts/axes/AxisInterval.test.d.ts +0 -1
  416. package/dist/app/charts/axes/AxisInterval.test.js +0 -120
  417. package/dist/app/charts/axes/AxisInterval.test.js.map +0 -1
  418. package/dist/app/charts/axes/ContinuousAxisRange.test.d.ts +0 -1
  419. package/dist/app/charts/axes/ContinuousAxisRange.test.js +0 -47
  420. package/dist/app/charts/axes/ContinuousAxisRange.test.js.map +0 -1
  421. package/dist/app/charts/axes/OrdinalAxisRange.test.d.ts +0 -1
  422. package/dist/app/charts/axes/OrdinalAxisRange.test.js +0 -48
  423. package/dist/app/charts/axes/OrdinalAxisRange.test.js.map +0 -1
  424. package/dist/app/charts/filters/regexFilter.test.d.ts +0 -1
  425. package/dist/app/charts/filters/regexFilter.test.js +0 -11
  426. package/dist/app/charts/filters/regexFilter.test.js.map +0 -1
  427. package/dist/app/charts/hooks/useDataObservable.d.ts +0 -72
  428. package/dist/app/charts/hooks/useDataObservable.js +0 -74
  429. package/dist/app/charts/hooks/useDataObservable.js.map +0 -1
  430. package/dist/app/charts/hooks/useInitialData.d.ts +0 -36
  431. package/dist/app/charts/hooks/useInitialData.js +0 -28
  432. package/dist/app/charts/hooks/useInitialData.js.map +0 -1
  433. package/dist/app/charts/observables/iterates.test.d.ts +0 -1
  434. package/dist/app/charts/observables/iterates.test.js +0 -180
  435. package/dist/app/charts/observables/iterates.test.js.map +0 -1
  436. package/dist/app/charts/observables/ordinals.test.d.ts +0 -1
  437. package/dist/app/charts/observables/ordinals.test.js +0 -102
  438. package/dist/app/charts/observables/ordinals.test.js.map +0 -1
  439. package/dist/app/charts/series/datumSeries.test.d.ts +0 -1
  440. package/dist/app/charts/series/datumSeries.test.js +0 -50
  441. package/dist/app/charts/series/datumSeries.test.js.map +0 -1
  442. package/dist/app/charts/styling/margins.test.d.ts +0 -1
  443. package/dist/app/charts/styling/margins.test.js +0 -19
  444. package/dist/app/charts/styling/margins.test.js.map +0 -1
  445. package/dist/app/charts/subscriptions/subscription.test.d.ts +0 -1
  446. package/dist/app/charts/subscriptions/subscription.test.js +0 -395
  447. package/dist/app/charts/subscriptions/subscription.test.js.map +0 -1
  448. package/dist/app/charts/subscriptions/subscriptions.d.ts +0 -100
  449. package/dist/app/charts/subscriptions/subscriptions.js +0 -449
  450. package/dist/app/charts/subscriptions/subscriptions.js.map +0 -1
  451. package/src/app/charts/axes/AxesState.test.ts +0 -34
  452. package/src/app/charts/axes/AxisInterval.test.ts +0 -143
  453. package/src/app/charts/axes/ContinuousAxisRange.test.ts +0 -55
  454. package/src/app/charts/axes/OrdinalAxisRange.test.ts +0 -55
  455. package/src/app/charts/filters/regexFilter.test.ts +0 -13
  456. package/src/app/charts/hooks/useDataObservable.tsx +0 -170
  457. package/src/app/charts/hooks/useInitialData.tsx +0 -64
  458. package/src/app/charts/observables/iterates.test.ts +0 -201
  459. package/src/app/charts/observables/ordinals.test.ts +0 -135
  460. package/src/app/charts/series/datumSeries.test.ts +0 -60
  461. package/src/app/charts/styling/margins.test.ts +0 -22
  462. package/src/app/charts/subscriptions/subscription.test.ts +0 -499
  463. package/src/app/charts/subscriptions/subscriptions.ts +0 -635
@@ -1,21 +1,21 @@
1
1
  import {
2
- addOrdinalStringAxis,
3
- AxesFont,
2
+ type AxesFont,
4
3
  AxisLocation,
5
- AxisTickStyle, ContinuousNumericAxis,
6
- defaultAxesFont,
4
+ type AxisTickStyle, defaultAxesFont,
7
5
  defaultAxisTickStyle,
8
- labelIdFor,
9
- OrdinalStringAxis
6
+ addOrdinalStringAxis,
7
+ removeOrdinalXAxis,
8
+ removeOrdinalYAxis,
9
+ type OrdinalStringAxis,
10
+ type SeriesStyle
10
11
  } from "./axes"
11
- import * as d3 from "d3";
12
- import {ScaleBand} from "d3";
13
- import {useChart} from "../hooks/useChart";
12
+ import type {ScaleBand} from "d3";
13
+ import {type NoTooltipMetadata, useChart} from "../hooks/useChart";
14
14
  import {useEffect, useRef} from "react";
15
- import {Dimensions} from "../styling/margins";
15
+ import type {Dimensions} from "../styling/margins";
16
16
  import {usePlotDimensions} from "../hooks/usePlotDimensions";
17
17
  import {OrdinalAxisRange} from "./OrdinalAxisRange";
18
- import {Datum} from "../series/timeSeries";
18
+ import type {Datum} from "../series/timeSeries";
19
19
  import {AxisInterval} from "./AxisInterval";
20
20
 
21
21
  export interface Props {
@@ -56,17 +56,18 @@ export interface Props {
56
56
  * Category axis that represents the x-axis when its location is either on the bottom or the top.
57
57
  * When the axis location is left or right, then the category axis represents the y-axis. The category
58
58
  * axis requires a set of categories that will form the axis. Generally, these categories should
59
- * be the name of the series used to represent each category.
59
+ * be the name of the series used to represent each category. This component returns null, meaning
60
+ * React won't render it because we are drawing directly onto the chart's shared canvas.
60
61
  * @param props The properties for the component
61
62
  * @return null
62
63
  */
63
64
  export function OrdinalAxis(props: Props): null {
64
65
  const {
65
66
  chartId,
66
- container,
67
+ canvasContext,
67
68
  axes,
68
69
  color,
69
- } = useChart<Datum, any, any, OrdinalAxisRange, OrdinalStringAxis>()
70
+ } = useChart<Datum, SeriesStyle, NoTooltipMetadata, OrdinalAxisRange, OrdinalStringAxis>()
70
71
 
71
72
  const {
72
73
  xAxesState,
@@ -103,18 +104,16 @@ export function OrdinalAxis(props: Props): null {
103
104
  // handles plot size changes by updating the range of the axis and the original range of the axis
104
105
  useEffect(
105
106
  () => {
106
- if (container) {
107
- const svg = d3.select<SVGSVGElement, any>(container)
107
+ if (canvasContext) {
108
108
  const font: AxesFont = {...defaultAxesFont(), color, ...props.font}
109
109
  const axisTickStyle = {...defaultAxisTickStyle(), ...props.axisTickStyle}
110
110
 
111
-
112
111
  // lambda that gets called when the axes need to be updated
113
112
  const handleRangeUpdates = (updates: Map<string, OrdinalAxisRange>, plotDim: Dimensions): void => {
114
113
  if (rangeUpdateHandlerIdRef.current && axis) {
115
114
  const range = updates.get(axisId)
116
115
  if (range) {
117
- axis.update(range.current, range.original, plotDim, margin)
116
+ axis.update(categories, range.current, range.original, plotDim, margin)
118
117
  }
119
118
  }
120
119
  }
@@ -126,13 +125,13 @@ export function OrdinalAxis(props: Props): null {
126
125
  case AxisLocation.Top:
127
126
  case AxisLocation.Bottom: {
128
127
  const xAxis = addOrdinalStringAxis(
129
- chartId, axisId, svg, location, categories,
128
+ canvasContext, axisId, location, categories,
130
129
  label, font, axisTickStyle, plotDimensions, margin,
131
130
  setAxisIntervalFor, setOriginalAxisIntervalFor
132
131
  )
133
132
 
134
133
  // add the x-axis to the chart context
135
- const [start, end] = AxisInterval.as(xAxis.scale.range()).asTuple()
134
+ const [start, end] = AxisInterval.as(xAxis.scale.range() as [number, number]).asTuple()
136
135
  addXAxis(xAxis, axisId, OrdinalAxisRange.from(start, end))
137
136
 
138
137
  // add an update handler
@@ -144,12 +143,12 @@ export function OrdinalAxis(props: Props): null {
144
143
  case AxisLocation.Left:
145
144
  case AxisLocation.Right: {
146
145
  const yAxis = addOrdinalStringAxis(
147
- chartId, axisId, svg, location, categories,
146
+ canvasContext, axisId, location, categories,
148
147
  label, font, axisTickStyle, plotDimensions, margin,
149
148
  setAxisIntervalFor, setOriginalAxisIntervalFor
150
149
  )
151
150
  // add the y-axis to the chart context
152
- const [start, end] = AxisInterval.as(yAxis.scale.range()).asTuple()
151
+ const [start, end] = AxisInterval.as(yAxis.scale.range() as [number, number]).asTuple()
153
152
  addYAxis(yAxis, axisId, OrdinalAxisRange.from(start, end))
154
153
  // add an update handler
155
154
  rangeUpdateHandlerIdRef.current = `y-axis-${chartId}-${axisId}-${location.valueOf()}`
@@ -161,15 +160,20 @@ export function OrdinalAxis(props: Props): null {
161
160
  .map(range => ([range.current, range.original]))
162
161
  .getOrElse([AxisInterval.empty(), AxisInterval.empty()])
163
162
  if (range && originalRange) {
164
- axis.update(range, originalRange, plotDimensions, margin)
163
+ axis.update(categories, range, originalRange, plotDimensions, margin)
165
164
  }
166
165
 
167
- svg.select(`#${labelIdFor(chartId, location)}`).attr('fill', color)
166
+ // keep the axis *label's* color in sync with the chart's color (e.g. on theme
167
+ // change), without recreating the axis or touching its domain. Note: tick label
168
+ // color is intentionally NOT touched here -- it stays fixed at whatever
169
+ // axisTickStyle.font was at creation, matching the original SVG version, which
170
+ // only ever updated the label's `fill`, not the ticks'.
171
+ axis.updateFont(font)
168
172
  }
169
173
  }
170
174
  },
171
175
  [
172
- container,
176
+ canvasContext,
173
177
  axis,
174
178
  addXAxis, addYAxis,
175
179
  addAxesRangesUpdateHandler,
@@ -193,7 +197,10 @@ export function OrdinalAxis(props: Props): null {
193
197
  const {current, original} = OrdinalAxisRange
194
198
  .from(start, end, 0, oldDimension.width)
195
199
  .zoom(oldDimension.width, newDimension.width)
196
- axis.update(current, original, plotDimensions, margin)
200
+ // a resize never changes the set of categories -- read the axis's own
201
+ // current domain rather than `categories` from props, since `categories`
202
+ // isn't in this effect's dependency array and so may be stale here
203
+ axis.update(axis.scale.domain(), current, original, plotDimensions, margin)
197
204
  }
198
205
  if (location === AxisLocation.Left || location === AxisLocation.Right) {
199
206
  const [start, end] = axisRangeFor(axisId)
@@ -202,7 +209,7 @@ export function OrdinalAxis(props: Props): null {
202
209
  const {current, original} = OrdinalAxisRange
203
210
  .from(start, end, 0, oldDimension.height)
204
211
  .zoom(oldDimension.height, newDimension.height)
205
- axis.update(current, original, plotDimensions, margin)
212
+ axis.update(axis.scale.domain(), current, original, plotDimensions, margin)
206
213
  }
207
214
  }
208
215
  })
@@ -229,6 +236,25 @@ export function OrdinalAxis(props: Props): null {
229
236
  [removeAxesRangesUpdateHandler]
230
237
  )
231
238
 
239
+ // unregister the axis' draw function when the axis unmounts
240
+ useEffect(
241
+ () => {
242
+ return () => {
243
+ if (canvasContext) {
244
+ switch (location) {
245
+ case AxisLocation.Top:
246
+ case AxisLocation.Bottom:
247
+ removeOrdinalXAxis(canvasContext, axisId)
248
+ break
249
+ case AxisLocation.Left:
250
+ case AxisLocation.Right:
251
+ removeOrdinalYAxis(canvasContext, axisId)
252
+ }
253
+ }
254
+ }
255
+ },
256
+ [canvasContext, axisId, location]
257
+ )
258
+
232
259
  return null
233
260
  }
234
-
@@ -6,6 +6,13 @@ import {BaseAxisRange} from "./BaseAxisRange";
6
6
  */
7
7
  export class OrdinalAxisRange extends BaseAxisRange {
8
8
 
9
+ /**
10
+ * Use {@link OrdinalAxisRange.from} to create an instance
11
+ * @param start The start of the axis-range
12
+ * @param end The end of the axis-range
13
+ * @param [originalStart=start] The original start of the axis-range
14
+ * @param [originalEnd=end] The original end of the axis-range
15
+ */
9
16
  private constructor(start: number, end: number, originalStart: number = start, originalEnd: number = end) {
10
17
  super(start, end, originalStart, originalEnd)
11
18
  }
@@ -18,36 +25,100 @@ export class OrdinalAxisRange extends BaseAxisRange {
18
25
  * Defaults to the start value if not specified.)
19
26
  * @param [originalEnd=end] The optional original end of the axis-range (e.g. before any zooming or panning.
20
27
  * Defaults to the end value if not specified.)
21
- * @return A new continuous-axis range instance.
28
+ * @return A new ordinal-axis range instance.
22
29
  */
23
30
  static from(start: number, end: number, originalStart: number = start, originalEnd: number = end): OrdinalAxisRange {
24
31
  return new OrdinalAxisRange(start, end, originalStart, originalEnd)
25
32
  }
26
33
 
27
34
  /**
28
- * Scales the axis-range by the specified scale factor from the specified value. The equations
29
- * are written so that the zooming (scaling) occurs at the specified value, and expands/contracts equally
30
- * from that value. This operation does not modify the original range.
31
- * @param factor The scale factor
35
+ * Scales the axis-range by the specified *cumulative* scale factor (d3-zoom's own
36
+ * `event.transform.k`, taken as-is -- NOT converted to an incremental, relative-to-the-
37
+ * previous-event factor), pivoting on `value`.
38
+ *
39
+ * Two cases, because neither a purely incremental nor a purely cumulative-from-`.original`
40
+ * formula is correct on its own for a bounded ordinal domain:
41
+ *
42
+ * - `factor === 1` (fully zoomed out): returns `.original` directly, bypassing the pivot math
43
+ * entirely. An ordinal axis's domain (the fixed set of categories) is bounded, so "zoomed all
44
+ * the way back out" has exactly one correct answer -- `.current` must equal `.original`
45
+ * *exactly*, regardless of how many different pivots were used to get there. d3-zoom's own
46
+ * `.scaleExtent` clamps `k` to *exactly* 1 at the zoom floor (not just asymptotically close),
47
+ * so this equality check reliably detects that boundary.
48
+ * - Otherwise: scales from `.current` using the *incremental* step implied by the cumulative
49
+ * factor (`factor` divided by the range's own current/original width ratio) -- the same
50
+ * pivot-preserving composition `ContinuousAxisRange` uses (see `BaseAxisRange.scaledRange`).
51
+ * This composes correctly across any sequence of differing pivots without jumping.
52
+ *
53
+ * Why not just always scale from `.original` by the cumulative factor (a prior version of this
54
+ * method did exactly that)? Composing pivot-preserving zooms at *different* pivots is not
55
+ * itself position-preserving -- zooming in at one spot and back out at another nets a
56
+ * translation, same as any pinch-zoom or map UI, verified live: zoom in at pivot A to k=5, then
57
+ * zoom out at a different pivot B to k=1, lands `.current` at `[400, 1400]` instead of
58
+ * `[0, 1000]` even under the mathematically-correct incremental composition. Scaling
59
+ * `.original` directly by the raw cumulative factor "fixes" that only by recomputing the
60
+ * *entire* zoom from scratch at the current pivot on every single event -- which is correct
61
+ * only when the pivot never changes since the last identity reset, and otherwise discards all
62
+ * zoom history, producing a visible jump the moment the pivot changes at any *non-identity* zoom
63
+ * level (confirmed live: continuing to zoom in from k=5 at pivot A to k=6 at a different pivot B
64
+ * jumped from the correct, continuous `[-1600, 4400]` to `[-4000, 2000]`). The `factor === 1`
65
+ * special case gets the position-preserving guarantee only where it's actually needed -- the
66
+ * one canonical "fully zoomed out" state -- without sacrificing composability everywhere else.
67
+ * A continuous/scrolling axis (`ContinuousAxisRange`) never needs the equivalent of this special
68
+ * case, since it has no fixed domain edge for translational drift to visibly clip against.
69
+ * @param factor The cumulative scale factor (`event.transform.k`, unmodified)
32
70
  * @param value The value from which to scale the interval
33
- * @return A new continuous-axis range with updated values
71
+ * @return The new range, as a plain {start, end} pair
72
+ */
73
+ private scaledCumulative(factor: number, value: number): {start: number, end: number} {
74
+ // when the factor is 1 or the original measure is 0, return the original range
75
+ if (factor === 1 || this.original.measure() === 0) {
76
+ return {start: this.original.start, end: this.original.end}
77
+ }
78
+ const scaleFactor = this.current.measure() / this.original.measure()
79
+ const incrementalFactor = factor / scaleFactor
80
+ const dtStart = value - this.current.start
81
+ const dtEnd = this.current.end - value
82
+ return {start: value - dtStart * incrementalFactor, end: value + dtEnd * incrementalFactor}
83
+ }
84
+
85
+ /**
86
+ * Scales the axis-range by the specified *cumulative* scale factor (see
87
+ * `scaledCumulative` for why this must be cumulative, not incremental) from the
88
+ * specified value. The equations are written so that the zooming (scaling) occurs at the
89
+ * specified value, and expands/contracts equally from that value. This operation does not
90
+ * modify the original range.
91
+ * @param factor The cumulative scale factor
92
+ * @param value The value from which to scale the interval
93
+ * @return A new ordinal-axis range with updated values
34
94
  */
35
95
  scale(factor: number, value: number): OrdinalAxisRange {
36
- const scaledInterval = this.scaledRange(factor, value)
96
+ const scaledInterval = this.scaledCumulative(factor, value)
37
97
  return new OrdinalAxisRange(scaledInterval.start, scaledInterval.end, this.original.start, this.original.end)
38
98
  }
39
99
 
40
100
  /**
41
- * Scales the axis-range by the specified scale factor from the specified value, while keeping
42
- * the range within the constraints (start, end). The equations are written so that the zooming
43
- * (scaling) occurs at the specified value, and expands/contracts equally from that value.
44
- * @param factor The scale factor
101
+ * Scales the axis-range by the specified *cumulative* scale factor (see
102
+ * `scaledCumulative` for why this must be cumulative, not incremental) from the
103
+ * specified value, while keeping the range within the constraints (start, end). The equations
104
+ * are written so that the zooming (scaling) occurs at the specified value, and
105
+ * expands/contracts equally from that value.
106
+ *
107
+ * Widens the scaled result to *cover* `constraint` (never narrower than it) -- `constraint`
108
+ * is the domain that must be fully visible once zoomed all the way out, and widening rather
109
+ * than clamping is exactly what fixes the pivot-drift bug described on
110
+ * `scaledCumulative` (zooming in at one pivot and back out at another must never leave
111
+ * part of the domain clipped). This is the opposite direction from
112
+ * {@link ContinuousAxisRange.constrainedScale}, which *clamps* its result inside `constraint`
113
+ * instead -- see that method's doc comment for why a continuous axis needs the opposite
114
+ * behavior. Do not "fix" this difference without reading both.
115
+ * @param factor The cumulative scale factor
45
116
  * @param value The value from which to scale the interval
46
117
  * @param constraint The minimum and maximum values that range bounds can be
47
- * @return A new continuous-axis range with updated values
118
+ * @return A new ordinal-axis range with updated values
48
119
  */
49
120
  constrainedScale(factor: number, value: number, constraint: [min: number, max: number]): OrdinalAxisRange {
50
- const scaledInterval = this.scaledRange(factor, value)
121
+ const scaledInterval = this.scaledCumulative(factor, value)
51
122
  const [min, max] = constraint
52
123
  return new OrdinalAxisRange(
53
124
  Math.min(min, scaledInterval.start),
@@ -57,14 +128,16 @@ export class OrdinalAxisRange extends BaseAxisRange {
57
128
  )
58
129
  }
59
130
  /**
60
- * Translates the axis-range by the specified amount
131
+ * Translates the axis-range by the specified amount, unless that would take it outside the
132
+ * constraint interval (when both ends of the constraint are infinite, there's no constraint)
61
133
  * @param amount The amount by which to translate the axis-range
62
134
  * @param [constraint=[-Infinity, Infinity]] Optional constraint interval in which the axis range must be within
63
- * @return An updated {@link OrdinalAxisRange} that has been translated by the specified amount
135
+ * @return An updated {@link OrdinalAxisRange} that has been translated by the specified amount (or an
136
+ * unchanged copy, when the translation would leave the constraint interval)
64
137
  */
65
138
  translate(amount: number, constraint: [start: number, end: number] = [-Infinity, Infinity]): OrdinalAxisRange {
66
139
  const [cs, ce] = constraint
67
- // when either of the constraints is infinite, or the pan keeps the new axis range
140
+ // when both of the constraints are infinite, or the pan keeps the new axis range
68
141
  // within the origin axis range (i.e. zoomed in and the panned), then allow the pan,
69
142
  // otherwise don't update
70
143
  if ((!isFinite(cs) && !isFinite(ce)) || (this.current.start + amount >= cs && this.current.end + amount <= ce)) {
@@ -83,6 +156,13 @@ export class OrdinalAxisRange extends BaseAxisRange {
83
156
  * the dimensions.
84
157
  */
85
158
  zoom(beforeDimension: number, afterDimension: number): OrdinalAxisRange {
159
+ // a zero `beforeDimension` (e.g. a chart mounted inside a collapsed/hidden container that
160
+ // later becomes visible) would otherwise divide by zero below, producing a NaN/Infinity
161
+ // range that corrupts this axis until remount. There's no proportional "before" range to
162
+ // scale from in that case, so just take the new dimension as the fresh, un-zoomed range.
163
+ if (beforeDimension === 0) {
164
+ return new OrdinalAxisRange(0, afterDimension, 0, afterDimension)
165
+ }
86
166
  const [start, end] = this.current.asTuple()
87
167
  const delta = (end - start ) * (afterDimension - beforeDimension) / beforeDimension
88
168
  const lowerBound = start / (end - start) * delta + start
@@ -0,0 +1,244 @@
1
+ import type {ScaleContinuousNumeric} from "d3";
2
+ import {firstIndexAtOrAfter} from "../utils";
3
+
4
+ /**
5
+ * The auto-scaling settings of a (y-) axis whose domain grows to fit the data plotted against it
6
+ * (see `ContinuousAxis`'s `autoScale`, `autoScaleMin`, `autoScaleMax`, and `autoScalePadding` props)
7
+ */
8
+ export type AutoScale = {
9
+ /**
10
+ * Where the axis' domain starts out: its `domain` prop, clamped to the limits. It's what the
11
+ * domain is restored to when its plot's data is replaced (e.g. on a reset).
12
+ */
13
+ domain: [min: number, max: number]
14
+ /**
15
+ * The smallest value the axis' domain may reach
16
+ */
17
+ min: number
18
+ /**
19
+ * The largest value the axis' domain may reach
20
+ */
21
+ max: number
22
+ /**
23
+ * The fraction of the axis' length left beyond the data's extreme on a side that grows (so
24
+ * the extreme point isn't drawn right on the edge), from 0 to 0.45
25
+ */
26
+ padding: number
27
+ }
28
+
29
+ /**
30
+ * Clamps a domain to the auto-scaling limits, so that an auto-scaling axis never starts out past
31
+ * them. (When the domain lies entirely beyond a limit, it collapses onto that limit.)
32
+ * @param domain The domain
33
+ * @param min The smallest value the domain may reach
34
+ * @param max The largest value the domain may reach
35
+ * @return The domain, clamped to the limits
36
+ */
37
+ export function clampedDomain(
38
+ domain: [min: number, max: number],
39
+ min: number,
40
+ max: number
41
+ ): [min: number, max: number] {
42
+ const clamp = (value: number) => Math.min(max, Math.max(min, value))
43
+ return [clamp(domain[0]), clamp(domain[1])]
44
+ }
45
+
46
+ /**
47
+ * Whether two auto-scaling settings are the same (`undefined` means "not auto-scaling")
48
+ * @param a The first settings
49
+ * @param b The second settings
50
+ * @return `true` when they're the same; `false` otherwise
51
+ */
52
+ export function sameAutoScale(a: AutoScale | undefined, b: AutoScale | undefined): boolean {
53
+ if (a === undefined || b === undefined) return a === b
54
+ return a.domain[0] === b.domain[0] && a.domain[1] === b.domain[1] &&
55
+ a.min === b.min && a.max === b.max && a.padding === b.padding
56
+ }
57
+
58
+ /**
59
+ * Grows an axis' domain to include the specified extent of the data, with the padding beyond it,
60
+ * without going past the auto-scaling limits. A side grows when the data reaches into its padding
61
+ * (not only when the data goes past the edge), so that the data always has the padding's room to
62
+ * spare (until a limit is reached), and it grows so that the data's extreme sits exactly the
63
+ * padding from the edge. The domain only ever grows: an extent that's within the domain, and
64
+ * clear of its padding, leaves the domain as it is.
65
+ *
66
+ * The padding is applied in the scale's own space (e.g. logarithmically, for a log scale), as a
67
+ * fraction of the axis' length.
68
+ * @param domain The axis' current domain
69
+ * @param extent The [min, max] of the data plotted against the axis, or `undefined` when there's
70
+ * no data
71
+ * @param autoScale The auto-scaling settings (the limits, and the padding)
72
+ * @param scale The axis' scale (only its kind matters: linear, log, ...)
73
+ * @return The grown domain (or the current domain, when there's nothing to grow for)
74
+ */
75
+ export function grownDomain(
76
+ domain: [min: number, max: number],
77
+ extent: [min: number, max: number] | undefined,
78
+ autoScale: Pick<AutoScale, 'min' | 'max' | 'padding'>,
79
+ scale: ScaleContinuousNumeric<number, number>
80
+ ): [min: number, max: number] {
81
+ if (extent === undefined) return domain
82
+ const [domainMin, domainMax] = domain
83
+ const padding = Math.min(0.45, Math.max(0, autoScale.padding))
84
+
85
+ // a side grows when the data reaches into its padding (or past its edge). Where the data sits
86
+ // within the current domain is measured in the scale's own space, with a little tolerance, so
87
+ // that an extreme that sits exactly the padding from the edge (as growing leaves it) doesn't
88
+ // grow the domain again by rounding errors on every frame.
89
+ const tolerance = 1e-9
90
+ const current = scale.copy().domain([domainMin, domainMax]).range([0, 1])
91
+ const growsDown = extent[0] < domainMin || current(extent[0]) < padding - tolerance
92
+ const growsUp = extent[1] > domainMax || current(extent[1]) > 1 - padding + tolerance
93
+ if (!growsDown && !growsUp) return domain
94
+
95
+ let min = growsDown ? extent[0] : domainMin
96
+ let max = growsUp ? extent[1] : domainMax
97
+ if (padding > 0 && min < max) {
98
+ // the normalized scale over the grown domain, extended on each growing side so that the
99
+ // extreme sits `padding` of the (extended) axis' length from that edge: with n growing
100
+ // sides, each extension e satisfies e / (1 + n e) = padding
101
+ const normalized = scale.copy().domain([min, max]).range([0, 1])
102
+ const growingSides = (growsDown ? 1 : 0) + (growsUp ? 1 : 0)
103
+ const extension = padding / (1 - growingSides * padding)
104
+ if (growsDown) min = normalized.invert(-extension)
105
+ if (growsUp) max = normalized.invert(1 + extension)
106
+ }
107
+ // (never past the limits -- and never shrinking a side, should the domain already be past one)
108
+ return [
109
+ growsDown ? Math.min(domainMin, Math.max(autoScale.min, min)) : domainMin,
110
+ growsUp ? Math.max(domainMax, Math.min(autoScale.max, max)) : domainMax,
111
+ ]
112
+ }
113
+
114
+ /**
115
+ * Extends an extent to include the specified value
116
+ * @param extent The extent so far, or `undefined` when there's none yet
117
+ * @param value The value to include
118
+ * @return The extent, including the value
119
+ */
120
+ export function extentWith(
121
+ extent: [min: number, max: number] | undefined,
122
+ value: number
123
+ ): [min: number, max: number] {
124
+ if (extent === undefined) return [value, value]
125
+ return [Math.min(extent[0], value), Math.max(extent[1], value)]
126
+ }
127
+
128
+ /**
129
+ * Calculates the extent (the [min, max]) of the specified values, skipping those the y-scale
130
+ * can't show (e.g. values <= 0 on a log scale, or NaN)
131
+ * @param values The values
132
+ * @param yScale The y-axis' scale
133
+ * @return The extent of the values, or `undefined` when there are none (that can be shown)
134
+ */
135
+ export function extentOf(
136
+ values: Iterable<number>,
137
+ yScale: ScaleContinuousNumeric<number, number>
138
+ ): [min: number, max: number] | undefined {
139
+ let extent: [min: number, max: number] | undefined = undefined
140
+ for (const value of values) {
141
+ if (Number.isFinite(yScale(value))) extent = extentWith(extent, value)
142
+ }
143
+ return extent
144
+ }
145
+
146
+ /**
147
+ * Calculates the extent (the [min, max] of the y-values) of a series' data that's visible within
148
+ * the x-axis' window: the values of the points within the window, and -- when the series is drawn
149
+ * with lines -- the lines' heights where they cross the window's left and right edges (a line from
150
+ * a point just off screen can reach higher, or lower, within the window than any point that's on
151
+ * screen). Values the y-scale can't show (e.g. values <= 0 on a log scale) are skipped.
152
+ *
153
+ * A point can have several values, each drawn as its own line across the points (e.g. an outlier
154
+ * series' value, and its bands' lower and upper bounds), so the crossings are calculated for each.
155
+ * They're calculated in the y-scale's own space (as the lines are drawn), so they're exact for
156
+ * straight lines, on any kind of scale.
157
+ * @param data The series' data, ordered by x
158
+ * @param window The x-axis' [start, end]
159
+ * @param yScale The y-axis' scale
160
+ * @param withLines Whether the series is drawn with lines (rather than just points)
161
+ * @param xOf The point's x-value (defaults to its `x`)
162
+ * @param valuesOf The point's y-values, each drawn as its own line (defaults to its `y`)
163
+ * @return The extent of the visible data, or `undefined` when nothing is visible
164
+ * @template P The type of the data's points
165
+ */
166
+ export function visibleExtent<P>(
167
+ data: { length: number, [index: number]: P },
168
+ window: [start: number, end: number],
169
+ yScale: ScaleContinuousNumeric<number, number>,
170
+ withLines: boolean,
171
+ xOf: (point: P) => number = point => (point as { x: number }).x,
172
+ valuesOf: (point: P) => Array<number> = point => [(point as { y: number }).y],
173
+ ): [min: number, max: number] | undefined {
174
+ const [start, end] = window
175
+ const showable = (value: number) => Number.isFinite(yScale(value))
176
+ // includes the heights where the lines between the two points cross x
177
+ const withCrossings = (
178
+ extent: [min: number, max: number] | undefined,
179
+ from: P,
180
+ to: P,
181
+ x: number
182
+ ): [min: number, max: number] | undefined => {
183
+ const fromValues = valuesOf(from)
184
+ const toValues = valuesOf(to)
185
+ const fraction = xOf(to) === xOf(from) ? 1 : (x - xOf(from)) / (xOf(to) - xOf(from))
186
+ fromValues.forEach((fromValue, index) => {
187
+ const toValue = toValues[index]
188
+ if (toValue === undefined || !showable(fromValue) || !showable(toValue)) return
189
+ const fromY = yScale(fromValue)
190
+ extent = extentWith(extent, yScale.invert(fromY + (yScale(toValue) - fromY) * fraction))
191
+ })
192
+ return extent
193
+ }
194
+
195
+ let extent: [min: number, max: number] | undefined = undefined
196
+ let index = firstIndexAtOrAfter(data, start, xOf)
197
+
198
+ // the lines entering through the window's left edge
199
+ if (withLines && index > 0 && index < data.length && xOf(data[index]) <= end) {
200
+ extent = withCrossings(extent, data[index - 1], data[index], start)
201
+ }
202
+
203
+ // the points within the window
204
+ for (; index < data.length && xOf(data[index]) <= end; index++) {
205
+ valuesOf(data[index]).forEach(value => {
206
+ if (showable(value)) extent = extentWith(extent, value)
207
+ })
208
+ }
209
+
210
+ // the lines leaving through the window's right edge (or, when no point is within the window,
211
+ // passing straight across it)
212
+ if (withLines && index > 0 && index < data.length && xOf(data[index - 1]) < end) {
213
+ extent = withCrossings(extent, data[index - 1], data[index], end)
214
+ if (xOf(data[index - 1]) < start) extent = withCrossings(extent, data[index - 1], data[index], start)
215
+ }
216
+ return extent
217
+ }
218
+
219
+ // the warnings already issued (each is only issued once)
220
+ const issuedWarnings = new Set<string>()
221
+
222
+ /**
223
+ * Issues a warning to the console, once (e.g. about auto-scaling settings that are ignored)
224
+ * @param message The warning
225
+ */
226
+ export function warnOnce(message: string): void {
227
+ if (issuedWarnings.has(message)) return
228
+ issuedWarnings.add(message)
229
+ console.warn(message)
230
+ }
231
+
232
+ /**
233
+ * Warns (once per axis) about the auto-scaling y-axes of a plot that doesn't support auto-scaling,
234
+ * whose `autoScale` setting is therefore ignored
235
+ * @param plotName The name of the plot (e.g. "BarPlot")
236
+ * @param yAxes The plot's y-axes, by their IDs
237
+ */
238
+ export function warnAboutIgnoredAutoScale(plotName: string, yAxes: Map<string, object>): void {
239
+ yAxes.forEach((axis, axisId) => {
240
+ if ((axis as { autoScale?: AutoScale }).autoScale !== undefined) {
241
+ warnOnce(`The ${plotName} doesn't support auto-scaling y-axes, so the "autoScale" setting of y-axis "${axisId}" is ignored`)
242
+ }
243
+ })
244
+ }