stream-charts 1.2.0 → 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 +40 -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,146 +1,128 @@
1
- import { useCallback, useEffect, useMemo, useRef } from 'react';
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ import { useStreamingTimeAxes } from "./useStreamingTimeAxes";
3
+ import { useHoveredSeries } from "../hooks/useHoveredSeries";
2
4
  import { useChart } from "../hooks/useChart";
5
+ import { scatterTooltipPointList, scatterTooltipPoints } from "../tooltips/tooltipUtils";
3
6
  import * as d3 from "d3";
4
- import { setClipPathG } from "./plot";
5
- import { axesForSeriesGen, continuousAxisIntervals, continuousAxisRanges, continuousAxisZoomHandler, defaultLineStyle, panHandler } from "../axes/axes";
6
- import { noop } from "../utils";
7
- import { subscriptionTimeSeriesFor, subscriptionTimeSeriesWithCadenceFor, TimeWindowBehavior } from "../subscriptions/subscriptions";
8
- import { useDataObservable } from "../hooks/useDataObservable";
7
+ import { clipToArea } from "./plot";
8
+ import { AxisType, checkAxisType, defaultLineStyle } from "../axes/axes";
9
+ import { seriesAt, canvasLocalPoint } from "./hitTesting";
10
+ import { firstIndexAtOrAfter, noop } from "../utils";
11
+ import { NoCurveFactory } from "./constants";
12
+ import { timeSeriesAxisTimes, TimeWindowBehavior } from "../subscriptions/viewDrivers";
13
+ import { useDataSource, useDataSourceRunning, useInitialData } from "../hooks/useDataSource";
14
+ import { extentWith, visibleExtent } from "../axes/autoScale";
15
+ import { growAutoScaledYAxes, useAutoScaleRestart } from "./autoScaleYAxes";
9
16
  import { usePlotDimensions } from "../hooks/usePlotDimensions";
10
- import { useInitialData } from "../hooks/useInitialData";
11
- import { Optional } from "result-fn";
12
- import { ContinuousAxisRange } from "../axes/ContinuousAxisRange";
17
+ // how close (in pixels) the mouse must be to a data point to be over that point (rather than over a
18
+ // line segment) -- at least this, or a little more than the markers' radius when they're larger
19
+ const MIN_POINT_HOVER_RADIUS = 6;
20
+ // the radii of the highlights on the points the tooltip shows: the hovered point, and the others
21
+ const TOOLTIP_POINT_RADIUS = 5;
22
+ const TOOLTIP_NEIGHBOR_RADIUS = 3.5;
13
23
  /**
14
- * Renders a streaming scatter plot for the series in the initial data and those sourced by the
15
- * observable specified as a property in the {@link Chart}. This component uses the {@link useChart}
16
- * hook, and therefore must be a child of the {@link Chart} in order to be plugged in to the
17
- * chart ecosystem (axes, tracker, tooltip).
24
+ * Renders a streaming scatter plot for the series held by the {@link StreamingDataSource} handed
25
+ * to the {@link Chart} (its `dataSource` prop). This component uses the {@link useChart} hook, and
26
+ * therefore must be a child of the {@link Chart} in order to be plugged in to the chart ecosystem
27
+ * (axes, tracker, tooltip).
28
+ *
29
+ * The plot never subscribes to the data stream itself: the application owns the data source (and
30
+ * starts/stops it), and the data source keeps ingesting even while this plot is unmounted. While
31
+ * the data source is running, this plot listens to its updates through a view driver that only
32
+ * advances the plot's own view (auto-scroll, cadence) and redraws -- created when the plot mounts
33
+ * (or the data source starts) and always torn down when it unmounts (or the data source stops).
34
+ *
35
+ * Internally, this no longer creates/updates SVG `<path>`/`<circle>` elements. Instead, it
36
+ * registers a single draw function with the chart's {@link CanvasContext} that redraws every
37
+ * series from scratch each time the canvas repaints. Mouse hover (for the tooltip) is handled by
38
+ * hit-testing the mouse position against the last-drawn series geometry (see `hitTesting.ts`) on a
39
+ * `mousemove` listener attached directly to the canvas, since canvas has no per-shape events.
40
+ *
41
+ * When the data source is paused, hovering over a series shows the tooltip (when there's one),
42
+ * and highlights the points it shows; a y-axis with `autoScale` set grows to fit the data on screen.
18
43
  *
19
44
  * @param props The properties associated with the scatter plot
45
+ * @return `null` (the plot draws onto the chart's canvas)
20
46
  * @example
21
- <ScatterPlot
22
- interpolation={interpolation}
23
- axisAssignments={new Map([
24
- ['test2', assignAxes("x-axis-2", "y-axis-2")],
25
- ])}
26
- dropDataAfter={10000}
27
- panEnabled={true}
28
- zoomEnabled={true}
29
- zoomKeyModifiersRequired={true}
30
- />
47
+ * <ScatterPlot
48
+ * interpolation={interpolation}
49
+ * axisAssignments={new Map([
50
+ * ['test2', assignAxes("x-axis-2", "y-axis-2")],
51
+ * ])}
52
+ * panEnabled={true}
53
+ * zoomEnabled={true}
54
+ * zoomKeyModifiersRequired={true}
55
+ * />
31
56
  */
32
57
  export function ScatterPlot(props) {
33
- const { chartId, container, mainG, axes, color, seriesStyles, seriesFilter, mouse, hoveredSeriesRef, } = useChart();
58
+ var _a;
59
+ const { chartId, canvasContext, axes, color, seriesStyles, seriesFilter, mouse, backgroundColor, } = useChart();
60
+ const { hoveredSeriesName } = useHoveredSeries();
34
61
  const { initialData } = useInitialData();
35
- const { xAxesState, yAxesState, setAxisIntervalFor, updateAxisRanges = noop, onUpdateAxesInterval, axesRanges, } = axes;
62
+ const { xAxesState, yAxesState, updateAxisRanges = noop, axisRangeFor, } = axes;
36
63
  const { mouseOverHandlerFor, mouseLeaveHandlerFor } = mouse;
37
64
  const { plotDimensions, margin } = usePlotDimensions();
38
- const { seriesObservable, windowingTime = 100, shouldSubscribe, onSubscribe = noop, onUpdateData, } = useDataObservable();
39
- const { axisAssignments = new Map(), interpolation = d3.curveLinear, dropDataAfter = Infinity, panEnabled = false, zoomEnabled = false, zoomKeyModifiersRequired = true, withCadenceOf, timeWindowBehavior = TimeWindowBehavior.SCROLL, } = props;
40
- const initialTimes = useMemo(() => {
41
- return new Map(Array.from(axesRanges().entries())
42
- .map(([axisId, range]) => ([axisId, range.original.start])));
43
- }, [axesRanges]);
65
+ // the application-owned source of the data, and whether it's running (streaming)
66
+ const dataSource = useDataSource();
67
+ const running = useDataSourceRunning(dataSource);
68
+ const { axisAssignments = new Map(), interpolation = d3.curveLinear, panEnabled = false, zoomEnabled = false, zoomKeyModifiersRequired = true, withCadenceOf, timeWindowBehavior = TimeWindowBehavior.SCROLL, markerRadius, hideMarkersWhileRunning = true, highlightAxesOnMouseOver = false, onZoomReset = noop, } = props;
44
69
  // why do "dataRef" and "seriesRef" both hold on to the same underlying data? for performance.
45
70
  //
46
71
  // the "dataRef" and "seriesRef" both point to the same underlying data, a collection
47
- // of series. The series in "dataRef" are bound to the DOM elements through d3. The "seriesRef" series
48
- // are the ones that are updated as new data is streamed in.
72
+ // of series (held, and updated as new data is streamed in, by the data source). The "dataRef"
73
+ // array is what the draw function iterates over, and the "seriesRef" map is for looking a
74
+ // series up by its name.
49
75
  //
50
76
  // the "dataRef" object holds on to a copy of the initial data (which is an array of
51
- // time-series, e.i. an array of BaseSeries<OrdinalDatum> objects). The slice just creates a copy of
77
+ // time-series, e.i. an array of BaseSeries<Datum> objects). The slice just creates a copy of
52
78
  // the array, but the references to the BaseSeries objects are the same and still point to the same
53
79
  // data as the "initialData" array.
54
80
  //
55
- // the "seriesRef" object is a reference to a map (series_name -> BaseSeries<OrdinalDatum>) which is
56
- // used to update the data in the series. When new data enters, it is appended to one or more series.
81
+ // the "seriesRef" object is a reference to a map (series_name -> BaseSeries<Datum>), used to find
82
+ // the series under the mouse (for the tooltip).
57
83
  //
58
- // the series in the "dataRef" object are the ones bound to the DOM elements in d3, and so as these
59
- // are updated, d3 will update the DOM elements (the elements in this plot).
84
+ // the series in the "dataRef" object are the ones read by the canvas draw function, and so as
85
+ // these are updated, the new data is picked up the next time the canvas redraws.
60
86
  const dataRef = useRef(initialData.slice());
61
87
  const seriesRef = useRef(new Map(initialData.map(series => [series.name, series])));
62
- // map(axis_id -> current_time) -- maps the axis ID to the current time for that axis
63
- const currentTimeRef = useRef(new Map());
64
- const subscriptionRef = useRef(undefined);
65
- const isSubscriptionClosed = () => subscriptionRef.current === undefined || subscriptionRef.current.closed;
66
- const allowTooltip = useRef(isSubscriptionClosed());
67
- useEffect(() => {
68
- currentTimeRef.current = new Map(Array.from(xAxesState.axes.keys()).map(id => [id, 0]));
69
- }, [xAxesState]);
70
- // calculates the distinct series IDs that cover all the series in the plot
71
- const axesForSeries = useMemo(() => axesForSeriesGen(initialData, axisAssignments, xAxesState), [initialData, axisAssignments, xAxesState]);
72
- // updates the timing using the onUpdateTime and updatePlot references. This and the references
73
- // defined above allow the axes' times to be updated properly by avoid stale reference to these
74
- // functions.
75
- const updateTimingAndPlot = useCallback((ranges) => {
76
- if (mainG !== null) {
77
- onUpdateTimeRef.current(ranges);
78
- updatePlotRef.current(ranges, mainG);
79
- if (onUpdateAxesInterval) {
80
- setTimeout(() => {
81
- const times = new Map();
82
- ranges.forEach((range, name) => times.set(name, range.current));
83
- onUpdateAxesInterval(times);
84
- }, 0);
85
- }
86
- }
87
- }, [mainG, onUpdateAxesInterval]);
88
- // todo find better way
89
- // when the initial data changes, then reset the plot. note that the initial data doesn't change
90
- // during the normal course of updates from the observable, only when the plot is restarted.
91
- useEffect(() => {
92
- dataRef.current = initialData.slice();
93
- seriesRef.current = new Map(initialData.map(series => [series.name, series]));
94
- currentTimeRef.current = new Map(Array.from(xAxesState.axes.keys()).map(id => [id, 0]));
95
- updateTimingAndPlot(new Map(Array.from(continuousAxisRanges(xAxesState.axes).entries())
96
- .map(([id, range]) => {
97
- // grab the current range, then calculate the minimum time from the initial data, and
98
- // set that as the start, and then add the range to it for the end time
99
- const [start, end] = range.original.asTuple();
100
- const minTime = initialData
101
- .filter(srs => { var _a; return ((_a = axisAssignments.get(srs.name)) === null || _a === void 0 ? void 0 : _a.xAxis) === id; })
102
- .reduce((tMin, series) => Math.min(tMin, !series.isEmpty() ? series.data[0].time : tMin), Infinity);
103
- const startTime = minTime === Infinity ? 0 : minTime;
104
- return [id, ContinuousAxisRange.from(startTime, startTime + end - start)];
105
- })));
106
- },
107
- // ** not happy about this **
108
- // only want this effect to run when the initial data is changed, which mean all the
109
- // other dependencies are recalculated anyway.
110
- // eslint-disable-next-line react-hooks/exhaustive-deps
111
- [initialData]);
112
- /**
113
- * Adjusts the time-range and updates the plot when the plot is dragged to the left or right
114
- * @param deltaX The amount that the plot is dragged
115
- * @param plotDimensions The dimensions of the plot
116
- * @param ranges A map holding the axis ID and its associated time range
117
- */
118
- const onPan = useCallback((x, plotDimensions, ranges) => panHandler(axesForSeries, margin, setAxisIntervalFor, xAxesState)(x, plotDimensions, ranges), [axesForSeries, margin, setAxisIntervalFor, xAxesState]);
119
- /**
120
- * Called when the user uses the scroll wheel (or scroll gesture) to zoom in or out. Zooms in/out
121
- * at the location of the mouse when the scroll wheel or gesture was applied.
122
- * @param transform The d3 zoom transformation information
123
- * @param x The x-position of the mouse when the scroll wheel or gesture is used
124
- * @param plotDimensions The dimensions of the plot
125
- * @param series An array of series names
126
- * @param ranges A map holding the axis ID and its associated time-range
127
- */
128
- const onZoom = useCallback((transform, x, plotDimensions, ranges) => continuousAxisZoomHandler(axesForSeries, margin, setAxisIntervalFor, xAxesState)(transform, x, plotDimensions, ranges), [axesForSeries, margin, setAxisIntervalFor, xAxesState]);
88
+ // the last-drawn geometry for each series, in canvas coordinates, used for hit-testing mouse
89
+ // hover on `mousemove` (see the effect below that wires up the listener)
90
+ const geometryRef = useRef(new Map());
91
+ // the name of the series the mouse was over on the previous `mousemove`, so we know when to
92
+ // fire a "leave" for the old series before firing an "over" for the new one
93
+ const lastHoveredRef = useRef(undefined);
94
+ // the points the tooltip is showing (for the hovered series), which the plot highlights -- set
95
+ // on mouse-over while a tooltip is shown, and cleared when the mouse leaves the series
96
+ const tooltipPointsRef = useRef(undefined);
97
+ // tooltips are only shown while the data source is paused (and not while panning)
98
+ const allowTooltip = useRef(!((_a = dataSource === null || dataSource === void 0 ? void 0 : dataSource.running) !== null && _a !== void 0 ? _a : false));
129
99
  const updatePlot = useCallback(
130
100
  /**
131
- * Updates the plot data for the specified time-range, which may have changed due to zoom or pan
132
- * @param timeRanges The current time range
133
- * @param mainGElem The main <g> element selection for that holds the plot
101
+ * (Re-)registers this plot's draw function with the canvas context and requests a redraw.
102
+ * Replaces the old version, which directly mutated SVG `<path>`/`<circle>` elements bound
103
+ * via d3's enter/update/exit join. Canvas has no persistent elements to join against, so
104
+ * the draw function just redraws every series from its current data/scale state each time
105
+ * it's invoked -- there's no separate "update" case to handle.
106
+ *
107
+ * Pan/zoom behavior setup lives in a separate effect (see below), not here -- this
108
+ * function runs on every data tick (each `windowingTime` interval), and recreating/
109
+ * reattaching a `d3.drag()`/`d3.zoom()` behavior that often is pure overhead with no
110
+ * benefit, since panEnabled/zoomEnabled/plotDimensions/margin change far less often than
111
+ * the data does.
112
+ * @param cc The canvas context to register the draw function with
134
113
  */
135
- (timeRanges, mainGElem) => {
136
- if (container) {
137
- // select the svg element bind the data to them
138
- const svg = d3.select(container);
139
- // create a map associating series-names to their time-series.
114
+ (cc) => {
115
+ const draw = (context) => {
116
+ var _a;
117
+ // const __drawStart = performance.now()
118
+ // let __totalRetained = 0
119
+ // let __totalProcessed = 0
120
+ const { context2D } = context;
121
+ // create a map associating series-names with their time-series.
140
122
  //
141
- // performance-related confusion: wondering where the dataRef is updated? well it isn't
142
- // directly. The dataRef holds on to an array of references to the Series. And so does the
143
- // seriesRef, though is uses a map(series_name -> series). The seriesRef is use to append
123
+ // performance-related confusion: wondering where the dataRef is updated? well, it isn't
124
+ // updated directly. The dataRef holds on to an array of references to the Series. And so does the
125
+ // seriesRef, though it uses a map(series_name -> series). The seriesRef is use to append
144
126
  // data to the underlying Series, and the dataRef is used so that we can just use
145
127
  // dataRef.current and don't have to do Array.from(seriesRef.current.values()) which
146
128
  // creates a temporary array
@@ -148,44 +130,10 @@ export function ScatterPlot(props) {
148
130
  series.name,
149
131
  series.data
150
132
  ]));
151
- // set up panning
152
- if (panEnabled) {
153
- const drag = d3.drag()
154
- .on("start", () => {
155
- d3.select(container).style("cursor", "move");
156
- // during panning, we need to disable viewing the tooltip to prevent
157
- // tooltips from rendering but not getting removed
158
- allowTooltip.current = false;
159
- })
160
- .on("drag", (event) => {
161
- onPan(event.dx, plotDimensions,
162
- // Array.from(boundedSeries.keys()),
163
- timeRanges);
164
- updatePlotRef.current(timeRanges, mainGElem);
165
- })
166
- .on("end", () => {
167
- d3.select(container).style("cursor", "auto");
168
- // during panning, we disabled viewing the tooltip to prevent
169
- // tooltips from rendering but not getting removed, now that panning
170
- // is over, allow tooltips to render again
171
- allowTooltip.current = isSubscriptionClosed();
172
- });
173
- svg.call(drag);
174
- }
175
- // set up for zooming
176
- if (zoomEnabled) {
177
- const zoom = d3.zoom()
178
- .filter(event => !zoomKeyModifiersRequired || event.shiftKey || event.ctrlKey)
179
- .scaleExtent([0, 10])
180
- .translateExtent([[margin.left, margin.top], [plotDimensions.width, plotDimensions.height]])
181
- .on("zoom", event => {
182
- onZoom(event.transform, event.sourceEvent.offsetX - margin.left, plotDimensions, timeRanges);
183
- updatePlotRef.current(timeRanges, mainGElem);
184
- });
185
- svg.call(zoom);
186
- }
187
- // define the clip-path so that the series lines don't go beyond the plot area
188
- const clipPathId = setClipPathG(chartId, mainGElem, plotDimensions);
133
+ context2D.save();
134
+ clipToArea(context, plotDimensions, { x: margin.left, y: margin.top });
135
+ context2D.translate(margin.left, margin.top);
136
+ const newGeometry = new Map();
189
137
  boundedSeries.forEach((data, name) => {
190
138
  // grab the x and y axes assigned to the series, and if either or both
191
139
  // axes aren't found, then give up and return
@@ -193,186 +141,295 @@ export function ScatterPlot(props) {
193
141
  if (xAxisLinear === undefined || yAxisLinear === undefined)
194
142
  return;
195
143
  // grab the style for the series
196
- const { color, lineWidth, highlightColor, highlightWidth } = seriesStyles.get(name) || defaultLineStyle();
144
+ const { color: seriesColor, lineWidth, highlightColor, highlightWidth } = seriesStyles.get(name) || defaultLineStyle();
197
145
  // only show the data for which the filter matches
198
146
  const plotData = (name.match(seriesFilter)) ? data : [];
199
- // create the time-series paths
200
- mainGElem
201
- .selectAll(`#${name}-${chartId}-scatter`)
202
- .data([[], plotData], () => `${name}`)
203
- .join(enter => enter
204
- .append("path")
205
- .attr("class", 'time-series-lines')
206
- .attr("id", `${name}-${chartId}-scatter`)
207
- .attr("data-series-name", name)
208
- .attr("d", d3.line()
209
- .x((d) => xAxisLinear.scale(d.time) || 0)
210
- .y((d) => yAxisLinear.scale(d.value) || 0)
211
- .curve(interpolation))
212
- .attr("fill", "none")
213
- .attr("stroke", hoveredSeriesRef.current === name ? highlightColor : color)
214
- .attr("stroke-width", hoveredSeriesRef.current === name ? highlightWidth : lineWidth)
215
- .attr('transform', `translate(${margin.left}, ${margin.top})`)
216
- .attr("clip-path", `url(#${clipPathId})`)
217
- .on("mouseover", (event, datumArray) =>
218
- // recall that this handler is passed down via the "useChart" hook
219
- handleMouseOverSeries(container, xAxisLinear, name, datumArray, event, margin, seriesStyles, allowTooltip.current, mouseOverHandlerFor(`tooltip-${chartId}`)))
220
- .on("mouseleave", event => handleMouseLeaveSeries(name, event.currentTarget, seriesStyles, mouseLeaveHandlerFor(`tooltip-${chartId}`))), update => update, exit => exit.remove());
147
+ const isHovered = hoveredSeriesName === name;
148
+ // skip the expensive per-point work below for retained-but-off-screen data:
149
+ // `plotData` can hold far more history than is ever visible (dropDataAfter is
150
+ // independent of, and often much larger than, the axis's current scrolling
151
+ // window), so iterating the *full* retained array every frame does a lot of
152
+ // work whose result is immediately thrown away as off-screen. Binary-search
153
+ // for where the visible domain begins, and only process from there on --
154
+ // backing up by one point so a line entering from off-screen still renders
155
+ // correctly across the boundary.
156
+ const [domainStart] = xAxisLinear.scale.domain();
157
+ const startIndex = Math.max(0, firstIndexAtOrAfter(plotData, domainStart, (d) => d.x) - 1);
158
+ const showMarkers = markerRadius != null && markerRadius >= 0 && (!running || !hideMarkersWhileRunning);
159
+ const markerRadiusResolved = isHovered ? markerRadius + 2 : markerRadius;
160
+ const segments = [];
161
+ let currentSegment = [];
162
+ const screenPoints = [];
163
+ context2D.fillStyle = isHovered ? highlightColor : seriesColor;
164
+ for (let i = startIndex; i < plotData.length; i++) {
165
+ const d = plotData[i];
166
+ const x = xAxisLinear.scale(d.x);
167
+ const y = yAxisLinear.scale(d.y);
168
+ // record geometry (outer/canvas coordinate space, margin baked in) for
169
+ // mousemove hit-testing, regardless of on/off-screen -- a point just past
170
+ // the edge should still be hoverable at the boundary
171
+ screenPoints.push([x + margin.left, y + margin.top]);
172
+ // the first point in this loop is the one deliberately backed up before
173
+ // the visible domain (see startIndex above); include it in the segment so
174
+ // the interpolated line entering from the left is smoothly clipped by the
175
+ // canvas's clip region as the plot scrolls, rather than the line abruptly
176
+ // popping into/out of existence right at the boundary
177
+ const isLeftEdgeContinuationPoint = i === startIndex && x < 0;
178
+ if (!isLeftEdgeContinuationPoint && (x < 0 || x > plotDimensions.width)) {
179
+ if (currentSegment.length > 0) {
180
+ segments.push(currentSegment);
181
+ currentSegment = [];
182
+ }
183
+ continue;
184
+ }
185
+ currentSegment.push([x, y]);
186
+ // point markers (one circle per datum) -- suppressed while streaming
187
+ // because redrawing many circles every frame is more work than a single
188
+ // line path
189
+ if (showMarkers) {
190
+ context2D.beginPath();
191
+ context2D.arc(x, y, markerRadiusResolved, 0, 2 * Math.PI);
192
+ context2D.fill();
193
+ }
194
+ }
195
+ if (currentSegment.length > 0)
196
+ segments.push(currentSegment);
197
+ // draw the series line (interpolation is applied via a Path2D built through a
198
+ // d3 line generator so that custom curve factories -- e.g. curveBasis,
199
+ // curveStep -- keep working exactly as they did with the SVG path)
200
+ context2D.strokeStyle = isHovered ? highlightColor : seriesColor;
201
+ context2D.lineWidth = isHovered ? highlightWidth : lineWidth;
202
+ segments.forEach(segment => {
203
+ var _a;
204
+ const path = new Path2D((_a = d3.line().curve(interpolation)(segment)) !== null && _a !== void 0 ? _a : "");
205
+ context2D.stroke(path);
206
+ });
207
+ newGeometry.set(name, {
208
+ points: screenPoints,
209
+ asLine: true,
210
+ hitRadius: Math.max(6, (isHovered ? highlightWidth : lineWidth) + 4)
211
+ });
212
+ if (showMarkers) {
213
+ // markers get their own, generously-sized hit target keyed under a
214
+ // derived name so a marker hover can be distinguished from a line hover
215
+ // if the caller ever wants to (currently treated the same on mousemove)
216
+ newGeometry.set(`${name}-markers`, {
217
+ points: screenPoints,
218
+ hitRadius: markerRadiusResolved + 3
219
+ });
220
+ }
221
221
  });
222
- }
222
+ // highlights the points the tooltip is showing (on top of the series): the
223
+ // hovered point is drawn larger than its neighbors (or than a segment's ends)
224
+ const tooltipPoints = tooltipPointsRef.current;
225
+ if (tooltipPoints !== undefined && !running && tooltipPoints.seriesName.match(seriesFilter)) {
226
+ const [xAxisLinear, yAxisLinear] = axesFor(tooltipPoints.seriesName, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
227
+ if (xAxisLinear !== undefined && yAxisLinear !== undefined) {
228
+ const { highlightColor = color } = (_a = seriesStyles.get(tooltipPoints.seriesName)) !== null && _a !== void 0 ? _a : {};
229
+ const { points } = tooltipPoints;
230
+ scatterTooltipPointList(points).forEach(datum => {
231
+ const isHoveredPoint = points.kind === 'point' && datum === points.point;
232
+ context2D.beginPath();
233
+ context2D.arc(xAxisLinear.scale(datum.x), yAxisLinear.scale(datum.y), isHoveredPoint ? TOOLTIP_POINT_RADIUS : TOOLTIP_NEIGHBOR_RADIUS, 0, 2 * Math.PI);
234
+ context2D.fillStyle = highlightColor;
235
+ context2D.fill();
236
+ // outlined in the background color, so it stands out from the line
237
+ context2D.lineWidth = 1.5;
238
+ context2D.strokeStyle = backgroundColor;
239
+ context2D.stroke();
240
+ });
241
+ }
242
+ }
243
+ geometryRef.current = newGeometry;
244
+ context2D.restore();
245
+ };
246
+ /**
247
+ * Grows the auto-scaling y-axes (see `ContinuousAxis`'s `autoScale` prop) to fit the
248
+ * data that's on screen: the data of the shown series (those matching the filter)
249
+ * within their x-axis' current window, including where their lines cross the window's
250
+ * edges (see `visibleExtent`). Since an axis only ever grows, the data that has
251
+ * scrolled off screen was already accounted for while it was on screen, so only the
252
+ * visible data needs checking each frame. Registered to run before the axes draw
253
+ * (they're at z-index 0), so the axes and the series are drawn with the grown domain
254
+ * in the same frame.
255
+ */
256
+ const autoScaleYAxes = () => {
257
+ const withLine = interpolation !== NoCurveFactory;
258
+ const extents = new Map();
259
+ dataRef.current.forEach(series => {
260
+ if (!series.name.match(seriesFilter))
261
+ return;
262
+ const [xAxisLinear, yAxisLinear] = axesFor(series.name, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
263
+ if (xAxisLinear === undefined || (yAxisLinear === null || yAxisLinear === void 0 ? void 0 : yAxisLinear.autoScale) === undefined)
264
+ return;
265
+ const [start, end] = xAxisLinear.scale.domain();
266
+ const seriesExtent = visibleExtent(series.data, [start, end], yAxisLinear.scale, withLine);
267
+ if (seriesExtent === undefined)
268
+ return;
269
+ const extent = extents.get(yAxisLinear.axisId);
270
+ extents.set(yAxisLinear.axisId, extent === undefined ? seriesExtent : extentWith(extentWith(extent, seriesExtent[0]), seriesExtent[1]));
271
+ });
272
+ growAutoScaledYAxes(extents, { yAxes: yAxesState.axes, axisRangeFor, updateAxisRanges });
273
+ };
274
+ cc.register(`scatter-plot-autoscale-${chartId}`, autoScaleYAxes, -10);
275
+ cc.register(`scatter-plot-${chartId}`, draw, 10);
276
+ cc.requestRedraw();
223
277
  }, [
224
- container, panEnabled, zoomEnabled, chartId, plotDimensions, margin, onPan,
225
- zoomKeyModifiersRequired, onZoom, axisAssignments,
226
- xAxesState, yAxesState,
227
- seriesStyles, seriesFilter, interpolation,
228
- mouseOverHandlerFor, mouseLeaveHandlerFor,
229
- hoveredSeriesRef
278
+ chartId, plotDimensions, axisAssignments, xAxesState, yAxesState, seriesStyles, seriesFilter,
279
+ interpolation, hoveredSeriesName, markerRadius, running, hideMarkersWhileRunning, axisRangeFor,
280
+ updateAxisRanges, color, backgroundColor, margin.left, margin.top
230
281
  ]);
231
- // need to keep the function references for use by the subscription, which forms a closure
232
- // on them. without the references, the closures become stale, and resizing during streaming
233
- // doesn't work properly
234
- const updatePlotRef = useRef(noop);
235
- useEffect(() => {
236
- updatePlotRef.current = updatePlot;
237
- }, [updatePlot]);
238
- const onUpdateTimeRef = useRef(updateAxisRanges);
239
- useEffect(() => {
240
- onUpdateTimeRef.current = updateAxisRanges;
241
- }, [updateAxisRanges]);
242
- // memoized function for subscribing to the chart-data observable
243
- const subscribe = useCallback(() => {
244
- if (seriesObservable === undefined || mainG === null)
245
- return undefined;
246
- if (withCadenceOf !== undefined) {
247
- return subscriptionTimeSeriesWithCadenceFor(seriesObservable, onSubscribe, windowingTime, axisAssignments, xAxesState, onUpdateData, dropDataAfter, updateTimingAndPlot,
248
- // as new data flows into the subscription, the subscription
249
- // updates this map directly (for performance)
250
- seriesRef.current, (axisId, end) => currentTimeRef.current.set(axisId, end), withCadenceOf);
251
- }
252
- return subscriptionTimeSeriesFor(seriesObservable, onSubscribe, windowingTime, axisAssignments, xAxesState, onUpdateData, dropDataAfter, updateTimingAndPlot,
253
- // as new data flows into the subscription, the subscription
254
- // updates this map directly (for performance)
255
- seriesRef.current, (axisId, end) => currentTimeRef.current.set(axisId, end), timeWindowBehavior, initialTimes);
256
- }, [
257
- axisAssignments, dropDataAfter, mainG,
258
- onSubscribe, onUpdateData,
259
- seriesObservable, updateTimingAndPlot, windowingTime, xAxesState,
282
+ // the time axes: their ranges, the view driver, panning and zooming, highlighting, and
283
+ // reporting the axes' intervals -- see `useStreamingTimeAxes`
284
+ useStreamingTimeAxes({
285
+ canvasContext,
286
+ dataSource,
287
+ running,
288
+ initialData,
289
+ timeOf: datum => datum.x,
290
+ axisTimesFor: timeSeriesAxisTimes(axisAssignments, xAxesState),
291
+ axisAssignments,
292
+ updatePlot,
293
+ onDataReset: () => {
294
+ dataRef.current = initialData.slice();
295
+ seriesRef.current = new Map(initialData.map(series => [series.name, series]));
296
+ },
297
+ allowTooltipRef: allowTooltip,
298
+ panEnabled,
299
+ zoomEnabled,
300
+ zoomKeyModifiersRequired,
301
+ onZoomReset,
260
302
  withCadenceOf,
261
- initialTimes, timeWindowBehavior
262
- ]);
263
- const timeRangesRef = useRef(new Map());
303
+ timeWindowBehavior,
304
+ highlightAxesOnMouseOver,
305
+ });
306
+ // wires up a single mousemove/mouseleave listener on the shared canvas to replace the old
307
+ // per-element SVG mouseover/mouseleave handlers. Hit-tests the mouse position against the
308
+ // last-drawn geometry (see `geometryRef`, populated by the draw function above).
264
309
  useEffect(() => {
265
- if (container && mainG) {
266
- // so this gets a bit complicated. the time-ranges need to be updated whenever the time-ranges
267
- // change. for example, as data is streamed in, the times change, and then we need to update the
268
- // time-range. however, we want to keep the time-ranges to reflect their original scale so that
269
- // we can zoom properly (so the updates can't fuck with the scale). At the same time, when the
270
- // interpolation changes, then the update plot changes, and the time-ranges must maintain their
271
- // original scale as well.
272
- if (timeRangesRef.current.size === 0) {
273
- // when no time-ranges have yet been created, then create them and hold on to a mutable
274
- // reference to them
275
- timeRangesRef.current = continuousAxisRanges(xAxesState.axes);
310
+ if (!canvasContext)
311
+ return;
312
+ const canvas = canvasContext.canvas;
313
+ const handleMove = (event) => {
314
+ if (!allowTooltip.current)
315
+ return;
316
+ const [x, y] = canvasLocalPoint(event, canvas);
317
+ const hit = seriesAt(x, y, geometryRef.current);
318
+ // markers are recorded under a "<name>-markers" key; normalize back to the
319
+ // underlying series name so callers only ever see the real series name.
320
+ // NOTE: `hit?.name.endsWith(...)` here would be unsafe -- `?.` only protects the
321
+ // `.name` access, not the chained `.endsWith(...)` call, so it would throw a
322
+ // TypeError on every mousemove where `hit` is undefined (i.e. most of them).
323
+ const hitName = hit !== undefined
324
+ ? (hit.name.endsWith('-markers') ? hit.name.slice(0, -'-markers'.length) : hit.name)
325
+ : undefined;
326
+ // only fire enter/leave transitions when the hovered series actually changes --
327
+ // but always recompute and re-report the tooltip content below for the *current*
328
+ // mouse position, even while still hovering the same series, so the tooltip keeps
329
+ // tracking the mouse as it moves across a series instead of freezing at wherever
330
+ // the hover was first detected.
331
+ if (hitName !== lastHoveredRef.current) {
332
+ if (lastHoveredRef.current !== undefined) {
333
+ handleMouseLeaveSeries(lastHoveredRef.current, mouseLeaveHandlerFor(`tooltip-${chartId}`));
334
+ }
335
+ lastHoveredRef.current = hitName;
276
336
  }
277
- else {
278
- // when the time-ranges already exist, then we want to update the time-ranges for each
279
- // existing time-range in a way that maintains the original scale.
280
- const intervals = continuousAxisIntervals(xAxesState.axes);
281
- timeRangesRef.current
282
- .forEach((range, id, rangesMap) => {
283
- const [start, end] = Optional.ofNullable(intervals.get(id))
284
- .map(interval => interval.asTuple())
285
- .getOrThrow(() => new Error(`Unable to retrieve interval for axis; axis_id: ${id}`));
286
- // .getOrElse([NaN, NaN])
287
- if (!isNaN(start) && !isNaN(end)) {
288
- // update the reference map with the new (start, end) portion of the range,
289
- // while keeping the original scale intact
290
- rangesMap.set(id, range.update(start, end));
291
- }
292
- });
337
+ // the points the tooltip shows (and the plot highlights): the point under the mouse
338
+ // and its neighbors, or the two ends of the segment under the mouse
339
+ let tooltipPoints = undefined;
340
+ if (hitName !== undefined) {
341
+ const series = seriesRef.current.get(hitName);
342
+ const mouseOverHandler = mouseOverHandlerFor(`tooltip-${chartId}`);
343
+ const [xAxisLinear, yAxisLinear] = axesFor(hitName, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
344
+ if (series !== undefined && xAxisLinear !== undefined && yAxisLinear !== undefined && mouseOverHandler !== undefined) {
345
+ const points = scatterTooltipPoints(series.data, [x - margin.left, y - margin.top], xAxisLinear.scale, yAxisLinear.scale, Math.max(MIN_POINT_HOVER_RADIUS, (markerRadius !== null && markerRadius !== void 0 ? markerRadius : 0) + 3));
346
+ tooltipPoints = { seriesName: hitName, points };
347
+ const time = Math.round(xAxisLinear.scale.invert(x - margin.left));
348
+ mouseOverHandler(hitName, time, { series: series.data, metadata: { points } }, [x, y]);
349
+ }
293
350
  }
294
- updatePlot(timeRangesRef.current, mainG);
295
- }
296
- }, [chartId, color, container, mainG, plotDimensions, updatePlot, xAxesState]);
297
- // subscribe/unsubscribe to the observable chart data. when the `shouldSubscribe`
298
- // is changed to `true` and we haven't subscribed yet, then subscribe. when the
299
- // `shouldSubscribe` is `false` and we had subscribed, then unsubscribe. otherwise,
300
- // do nothing.
351
+ updateTooltipPoints(tooltipPoints);
352
+ };
353
+ // remembers the points the tooltip shows, and redraws (to highlight them) when they change
354
+ const updateTooltipPoints = (tooltipPoints) => {
355
+ const previous = tooltipPointsRef.current;
356
+ if (previous === undefined && tooltipPoints === undefined)
357
+ return;
358
+ if (previous !== undefined && tooltipPoints !== undefined &&
359
+ previous.seriesName === tooltipPoints.seriesName &&
360
+ previous.points.kind === tooltipPoints.points.kind) {
361
+ const previousList = scatterTooltipPointList(previous.points);
362
+ const list = scatterTooltipPointList(tooltipPoints.points);
363
+ if (previousList.length === list.length && previousList.every((datum, index) => datum === list[index]))
364
+ return;
365
+ }
366
+ tooltipPointsRef.current = tooltipPoints;
367
+ canvasContext.requestRedraw();
368
+ };
369
+ const handleLeaveCanvas = () => {
370
+ if (lastHoveredRef.current !== undefined) {
371
+ handleMouseLeaveSeries(lastHoveredRef.current, mouseLeaveHandlerFor(`tooltip-${chartId}`));
372
+ lastHoveredRef.current = undefined;
373
+ }
374
+ updateTooltipPoints(undefined);
375
+ };
376
+ canvas.addEventListener('mousemove', handleMove);
377
+ canvas.addEventListener('mouseleave', handleLeaveCanvas);
378
+ return () => {
379
+ canvas.removeEventListener('mousemove', handleMove);
380
+ canvas.removeEventListener('mouseleave', handleLeaveCanvas);
381
+ };
382
+ }, [canvasContext, chartId, margin, axisAssignments, xAxesState, yAxesState, mouseOverHandlerFor, mouseLeaveHandlerFor, markerRadius]);
383
+ // this plot needs a data source (see the `Chart`'s `dataSource` prop)
301
384
  useEffect(() => {
302
- var _a;
303
- if (shouldSubscribe && subscriptionRef.current === undefined) {
304
- subscriptionRef.current = subscribe();
305
- allowTooltip.current = false;
385
+ if (dataSource === undefined) {
386
+ console.error("ScatterPlot requires a data source; set the enclosing Chart's `dataSource` prop");
306
387
  }
307
- else if (!shouldSubscribe && subscriptionRef.current !== undefined) {
308
- (_a = subscriptionRef.current) === null || _a === void 0 ? void 0 : _a.unsubscribe();
309
- subscriptionRef.current = undefined;
310
- allowTooltip.current = true;
311
- }
312
- }, [shouldSubscribe, subscribe]);
388
+ }, [dataSource]);
389
+ // unregister this plot's draw function (and its auto-scaling step) on unmount
390
+ useEffect(() => {
391
+ return () => {
392
+ if (canvasContext) {
393
+ canvasContext.unregister(`scatter-plot-autoscale-${chartId}`);
394
+ canvasContext.unregister(`scatter-plot-${chartId}`);
395
+ }
396
+ };
397
+ }, [canvasContext, chartId]);
398
+ // new data, new scale: restarts the auto-scaling y-axes when the data source is replaced
399
+ useAutoScaleRestart(dataSource, { yAxes: yAxesState.axes, axisRangeFor, updateAxisRanges });
313
400
  return null;
314
401
  }
315
402
  /**
316
- * Attempts to locate the x- and y-axes for the specified series. If no axis is found for the
317
- * series name, then uses the default returned by the useChart() hook
403
+ * Attempts to locate the x- and y-axes for the specified series. If the series has no axis
404
+ * assignment, then uses the default (first) x- and y-axes.
318
405
  * @param seriesName Name of the series for which to retrieve the axis
319
406
  * @param axisAssignments A map holding the series name and the associated x- and y-axes assigned
320
407
  * to that series. Note that the series in the axis-assignment map is merely a subset of the set
321
408
  * of series names.
322
409
  * @param xAxisFor The function that accepts an axis ID and returns the corresponding x-axis
323
410
  * @param yAxisFor The function that accepts an axis ID and returns the corresponding y-axis
411
+ * @return The x- and y-axes (either is actually `undefined` when it isn't found, despite the type)
412
+ * @throws Error when either axis isn't a continuous numeric axis
324
413
  */
325
414
  function axesFor(seriesName, axisAssignments, xAxisFor, yAxisFor) {
326
415
  const axes = axisAssignments.get(seriesName);
327
416
  const xAxis = xAxisFor((axes === null || axes === void 0 ? void 0 : axes.xAxis) || "");
328
- const xAxisLinear = xAxis;
329
417
  const yAxis = yAxisFor((axes === null || axes === void 0 ? void 0 : axes.yAxis) || "");
418
+ checkAxisType("ScatterPlot", "x", xAxis, AxisType.ContinuousNumeric);
419
+ checkAxisType("ScatterPlot", "y", yAxis, AxisType.ContinuousNumeric);
420
+ const xAxisLinear = xAxis;
330
421
  const yAxisLinear = yAxis;
331
- if (xAxis && !xAxisLinear) {
332
- throw Error("Scatter plot requires that x-axis be of type LinearAxis");
333
- }
334
- if (yAxis && !yAxisLinear) {
335
- throw Error("Scatter plot requires that y-axis be of type LinearAxis");
336
- }
337
422
  return [xAxisLinear, yAxisLinear];
338
423
  }
339
424
  /**
340
- * Renders a tooltip showing the neuron, spike time, and the spike strength when the mouse hovers over a spike.
341
- * @param container The chart container
342
- * @param xAxis The x-axis
343
- * @param seriesName The name of the series (i.e. the neuron ID)
344
- * @param series The time series
345
- * @param event The mouse-over series event
346
- * @param margin The plot margin
347
- * @param seriesStyles The series style information (needed for (un)highlighting)
348
- * @param allowTooltip When set to `false` won't show tooltip, even if it is visible (used by pan)
349
- * @param mouseOverHandlerFor The handler for the mouse over (registered by the <Tooltip/>)
350
- */
351
- function handleMouseOverSeries(container, xAxis, seriesName, series, event, margin, seriesStyles, allowTooltip, mouseOverHandlerFor) {
352
- // grab the time needed for the tooltip ID
353
- const [x, y] = d3.pointer(event, container);
354
- const time = Math.round(xAxis.scale.invert(x - margin.left));
355
- const { highlightColor, highlightWidth } = seriesStyles.get(seriesName) || defaultLineStyle();
356
- // Use d3 to select element, change color and size
357
- d3.select(event.currentTarget)
358
- .attr('stroke', highlightColor)
359
- .attr('stroke-width', highlightWidth);
360
- if (mouseOverHandlerFor && allowTooltip) {
361
- mouseOverHandlerFor(seriesName, time, { series, metadata: {} }, [x, y]);
362
- }
363
- }
364
- /**
365
- * Unselects the time series and calls the mouse-leave-series handler registered for this series.
425
+ * Calls the mouse-leave-series handler registered for this series. Replaces the old version, which
426
+ * also reset the hovered SVG element's stroke color/width directly; that reset is now implicit --
427
+ * once `hoveredSeriesName` is cleared, the next redraw simply paints the series in its normal
428
+ * (non-highlighted) style.
366
429
  * @param seriesName The name of the series (i.e. the neuron ID)
367
- * @param segment The SVG line element representing the spike, over which the mouse is hovering.
368
- * @param seriesStyles The styles for the series (for (un)highlighting)
369
430
  * @param mouseLeaverHandlerFor Registered handler for the series when the mouse leaves
370
431
  */
371
- function handleMouseLeaveSeries(seriesName, segment, seriesStyles, mouseLeaverHandlerFor) {
372
- const { color, lineWidth } = seriesStyles.get(seriesName) || defaultLineStyle();
373
- d3.select(segment)
374
- .attr('stroke', color)
375
- .attr('stroke-width', lineWidth);
432
+ function handleMouseLeaveSeries(seriesName, mouseLeaverHandlerFor) {
376
433
  if (mouseLeaverHandlerFor) {
377
434
  mouseLeaverHandlerFor(seriesName);
378
435
  }