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,35 +1,34 @@
1
- import {AxesAssignment, setClipPathG} from "./plot";
2
- import * as d3 from "d3";
3
- import {ZoomTransform} from "d3";
1
+ import {type AxesAssignment, clipToArea, type Series} from "./plot";
2
+ import {useStreamingTimeAxes} from "./useStreamingTimeAxes";
3
+ import {useHoveredSeries} from "../hooks/useHoveredSeries";
4
4
  import {noop} from "../utils";
5
- import {NoTooltipMetadata, useChart} from "../hooks/useChart";
6
- import React, {useCallback, useEffect, useMemo, useRef} from "react";
7
- import {Datum, PixelDatum, TimeSeries} from "../series/timeSeries";
8
- import {GSelection} from "../d3types";
5
+ import {useChart} from "../hooks/useChart";
6
+ import type {RasterTooltipMetadata} from "../tooltips/tooltipUtils";
7
+ import {useCallback, useEffect, useRef} from "react";
8
+ import type {Datum, TimeSeries} from "../series/timeSeries";
9
9
  import {
10
- axesForSeriesGen,
11
- BaseAxis,
12
- continuousAxisIntervals,
13
- continuousAxisRanges,
14
- continuousAxisZoomHandler,
15
- ContinuousNumericAxis,
10
+ type BaseAxis,
11
+ AxisType,
12
+ checkAxisType,
13
+ type ContinuousNumericAxis,
16
14
  defaultLineStyle,
17
- OrdinalStringAxis,
18
- panHandler,
19
- SeriesLineStyle
15
+ type OrdinalStringAxis,
16
+ type SeriesLineStyle
20
17
  } from "../axes/axes";
21
- import {Observable, Subscription} from "rxjs";
22
- import {Dimensions, Margin} from "../styling/margins";
23
- import {subscriptionTimeSeriesFor, subscriptionTimeSeriesWithCadenceFor} from "../subscriptions/subscriptions";
24
- import {useDataObservable} from "../hooks/useDataObservable";
25
- import {TimeSeriesChartData} from "../series/timeSeriesChartData";
18
+ import type {CanvasContext} from "../d3types";
19
+ import {seriesAt, canvasLocalPoint, type SeriesGeometry} from "./hitTesting";
20
+ import type {Margin} from "../styling/margins";
21
+ import {timeSeriesAxisTimes} from "../subscriptions/viewDrivers";
22
+ import {useDataSource, useDataSourceRunning, useInitialData} from "../hooks/useDataSource";
23
+ import type {TimeSeriesChartData} from "../series/timeSeriesChartData";
26
24
  import {usePlotDimensions} from "../hooks/usePlotDimensions";
27
- import {useInitialData} from "../hooks/useInitialData";
28
- import {TooltipData} from "../hooks/useTooltip";
29
- import {AxisInterval} from "../axes/AxisInterval";
30
- import {Optional} from "result-fn";
25
+ import type {TooltipData} from "../hooks/useTooltip";
31
26
  import {ContinuousAxisRange} from "../axes/ContinuousAxisRange";
27
+ import {FastShiftArray} from "fast-shift-array";
32
28
 
29
+ /**
30
+ * The properties of the {@link RasterPlot}
31
+ */
33
32
  export interface Props {
34
33
  /**
35
34
  * Holds the mapping between a series and the axis it uses (is assigned). The
@@ -37,11 +36,6 @@ export interface Props {
37
36
  * object holding the ID of the assigned x-axis and y-axis.
38
37
  */
39
38
  axisAssignments?: Map<string, AxesAssignment>
40
- /**
41
- * The number of milliseconds of data to hold in memory before dropping it. Defaults to
42
- * infinity (i.e. no data is dropped)
43
- */
44
- dropDataAfter?: number
45
39
  /**
46
40
  * Enables panning (default is false)
47
41
  */
@@ -66,18 +60,41 @@ export interface Props {
66
60
  withCadenceOf?: number
67
61
  /**
68
62
  * The (optional, default = 2 pixels) top and bottom margin (in pixels) for the spike lines in the plot.
69
- * Margins on individual series can also be set through the {@link Chart.seriesStyles} property.
63
+ * Margins on individual series can also be set through the {@link ChartProps.seriesStyles} property.
70
64
  */
71
65
  spikeMargin?: number
66
+ /**
67
+ * When true, hovering over a series also highlights the x- and y-axes it is plotted
68
+ * against (in the series' own highlight color/width). Defaults to `false`.
69
+ */
70
+ highlightAxesOnMouseOver?: boolean
71
+ /**
72
+ * Called whenever this plot (re)creates its zoom behavior, handing
73
+ * the caller a `resetZoom` function that programmatically clears d3-zoom's own accumulated
74
+ * scale/pan state back to identity. See {@link ScatterPlot}'s identical prop for the full
75
+ * explanation of why this is needed. Only meaningful (called) while `zoomEnabled` is true.
76
+ */
77
+ onZoomReset?: (resetZoom: () => void) => void
72
78
  }
73
79
 
74
80
  /**
75
- * Renders a streaming neuron raster plot for the series in the initial data and those sourced by the
76
- * observable specified as a property in the {@link Chart}. This component uses the {@link useChart}
81
+ * Renders a streaming neuron raster plot for the series held by the {@link StreamingDataSource}
82
+ * handed to the {@link Chart} (its `dataSource` prop). This component uses the {@link useChart}
77
83
  * hook, and therefore must be a child of the {@link Chart} in order to be plugged in to the
78
84
  * chart ecosystem (axes, tracker, tooltip).
79
85
  *
86
+ * The plot never subscribes to the data stream itself -- see {@link ScatterPlot} for how the
87
+ * application-owned data source and this plot's mount-scoped view driver divide the work.
88
+ *
89
+ * Internally, this no longer creates/updates SVG `<line>` elements. Instead, it registers a single
90
+ * draw function with the chart's {@link CanvasContext} that redraws every series' spikes from
91
+ * scratch each time the canvas repaints. Mouse hover (for the tooltip) is handled by hit-testing
92
+ * the mouse position against the last-drawn spike geometry -- as *disjoint* segments, since unlike
93
+ * a scatter series, consecutive spikes are not connected by a line (see `hitTesting.ts`). When
94
+ * the data source is paused, hovering over a spike shows the tooltip (when there's one).
95
+ *
80
96
  * @param props The properties associated with the raster plot
97
+ * @return `null` (the plot draws onto the chart's canvas)
81
98
  * @example
82
99
  <RasterPlot
83
100
  axisAssignments={new Map([
@@ -85,7 +102,6 @@ export interface Props {
85
102
  ['neuron2', assignAxes("x-axis-2", "y-axis-2")],
86
103
  ])}
87
104
  spikeMargin={1}
88
- dropDataAfter={5000}
89
105
  panEnabled={true}
90
106
  zoomEnabled={true}
91
107
  zoomKeyModifiersRequired={true}
@@ -94,151 +110,75 @@ export interface Props {
94
110
  export function RasterPlot(props: Props): null {
95
111
  const {
96
112
  chartId,
97
- container,
98
- mainG,
113
+ canvasContext,
99
114
  axes,
100
- color,
101
115
  seriesStyles,
102
116
  seriesFilter,
103
117
  mouse,
104
- hoveredSeriesRef,
105
- } = useChart<Datum, SeriesLineStyle, NoTooltipMetadata, ContinuousAxisRange, ContinuousNumericAxis>()
118
+ } = useChart<Datum, SeriesLineStyle, RasterTooltipMetadata, ContinuousAxisRange, ContinuousNumericAxis>()
119
+ const {hoveredSeriesName} = useHoveredSeries()
106
120
 
107
121
  const {
108
122
  xAxesState,
109
123
  yAxesState,
110
124
  setAxisAssignments,
111
- setAxisIntervalFor,
112
- updateAxisRanges = noop,
113
- onUpdateAxesInterval,
114
125
  } = axes
115
126
 
116
127
  const {mouseOverHandlerFor, mouseLeaveHandlerFor} = mouse
117
128
 
118
129
  const {plotDimensions, margin} = usePlotDimensions()
119
130
 
120
- const {
121
- seriesObservable,
122
- windowingTime = 100,
123
- shouldSubscribe,
124
-
125
- onSubscribe = noop,
126
- onUpdateData,
127
- } = useDataObservable()
131
+ // the application-owned source of the data, and whether it's running (streaming)
132
+ const dataSource = useDataSource<TimeSeriesChartData, Datum, TimeSeries>()
133
+ const running = useDataSourceRunning(dataSource)
128
134
 
129
- const {initialData} = useInitialData<TimeSeriesChartData, Datum>()
135
+ const {initialData} = useInitialData<Datum>()
130
136
 
131
137
  const {
132
138
  axisAssignments = new Map<string, AxesAssignment>(),
133
- dropDataAfter = Infinity,
134
139
  panEnabled = false,
135
140
  zoomEnabled = false,
136
141
  zoomKeyModifiersRequired = true,
137
142
  withCadenceOf,
138
143
  spikeMargin = 2,
144
+ highlightAxesOnMouseOver = false,
145
+ onZoomReset = noop,
139
146
  } = props
140
147
 
141
148
  // why do "dataRef" and "seriesRef" both hold on to the same underlying data? for performance.
142
149
  //
143
150
  // the "dataRef" and "seriesRef" both point to the same underlying data, a collection
144
- // of series. The series in "dataRef" are bound to the DOM elements through d3. The "seriesRef" series
145
- // are the ones that are updated as new data is streamed in.
151
+ // of series (held, and updated as new data is streamed in, by the data source). The series in
152
+ // "dataRef" are read by the canvas draw function, and the "seriesRef" map is for looking a
153
+ // series up by its name.
146
154
  //
147
155
  // the "dataRef" object holds on to a copy of the initial data (which is an array of
148
- // time-series, e.i. an array of BaseSeries<OrdinalDatum> objects). The slice just creates a copy of
156
+ // time-series, e.i. an array of BaseSeries<Datum> objects). The slice just creates a copy of
149
157
  // the array, but the references to the BaseSeries objects are the same and still point to the same
150
158
  // data as the "initialData" array.
151
159
  //
152
- // the "seriesRef" object is a reference to a map (series_name -> BaseSeries<OrdinalDatum>) which is
153
- // used to update the data in the series. When new data enters, it is appended to one or more series.
160
+ // the "seriesRef" object is a reference to a map (series_name -> BaseSeries<Datum>), used to find
161
+ // the series under the mouse (for the tooltip).
154
162
  //
155
- // the series in the "dataRef" object are the ones bound to the DOM elements in d3, and so as these
156
- // are updated, d3 will update the DOM elements (the elements in this plot).
157
- const dataRef = useRef<Array<TimeSeries>>(initialData.slice() as Array<TimeSeries>)
158
- const seriesRef = useRef<Map<string, TimeSeries>>(new Map(initialData.map(series => [series.name, series as TimeSeries])))
159
- // map(axis_id -> current_time) -- maps the axis ID to the current time for that axis
160
- const currentTimeRef = useRef<Map<string, number>>(new Map())
161
-
162
- const subscriptionRef = useRef<Subscription>(undefined)
163
-
164
- const isSubscriptionClosed = () => subscriptionRef.current === undefined || subscriptionRef.current.closed
165
-
166
- const allowTooltipRef = useRef<boolean>(isSubscriptionClosed())
167
-
168
- useEffect(
169
- () => {
170
- currentTimeRef.current = new Map(Array.from<string>(xAxesState.axes.keys()).map(id => [id, 0]))
171
- },
172
- [xAxesState]
173
- )
174
-
175
- // set the axis assignments needed if a tooltip is being used
176
- useEffect(
177
- () => {
178
- setAxisAssignments(axisAssignments)
179
- },
180
- [axisAssignments, setAxisAssignments]
163
+ // the series in the "dataRef" object are the ones read by the next redraw, so as these are
164
+ // updated, the next canvas repaint picks up the new data.
165
+ const dataRef = useRef<Array<TimeSeries>>(initialData.slice())
166
+ const seriesRef = useRef<Map<string, TimeSeries>>(
167
+ new Map(initialData.map(
168
+ series => [series.name, series]
169
+ )
170
+ )
181
171
  )
182
172
 
183
- // calculates the distinct series IDs that cover all the series in the plot
184
- const axesForSeries = useMemo(
185
- () => axesForSeriesGen<Datum, ContinuousNumericAxis>(initialData, axisAssignments, xAxesState),
186
- [initialData, axisAssignments, xAxesState]
187
- )
173
+ // the last-drawn geometry for each series' spikes, in canvas coordinates, used for
174
+ // hit-testing mouse hover on `mousemove` (see the effect below that wires up the listener)
175
+ const geometryRef = useRef<Map<string, SeriesGeometry>>(new Map())
176
+ // the name of the series the mouse was over on the previous `mousemove`, so we know when to
177
+ // fire a "leave" for the old series before firing an "over" for the new one
178
+ const lastHoveredRef = useRef<string | undefined>(undefined)
188
179
 
189
- // updates the timing using the onUpdateTime and updatePlot references. This and the references
190
- // defined above allow the axes' times to be update properly by avoid stale reference to these
191
- // functions.
192
- const updateTimingAndPlot = useCallback((ranges: Map<string, ContinuousAxisRange>): void => {
193
- if (mainG !== null) {
194
- onUpdateTimeRef.current(ranges)
195
- updatePlotRef.current(ranges, mainG)
196
- if (onUpdateAxesInterval) {
197
- setTimeout(() => {
198
- const times = new Map<string, AxisInterval>()
199
- ranges.forEach((range, name) => times.set(name, range.current))
200
- onUpdateAxesInterval(times)
201
- }, 0)
202
- }
203
- }
204
- },
205
- [mainG, onUpdateAxesInterval]
206
- )
207
-
208
- // todo find better way
209
- // when the initial data changes, then reset the plot. note that the initial data doesn't change
210
- // during the normal course of updates from the observable, only when the plot is restarted.
211
- useEffect(
212
- () => {
213
- dataRef.current = initialData.slice() as Array<TimeSeries>
214
- seriesRef.current = new Map(initialData.map(series => [series.name, series as TimeSeries]))
215
- currentTimeRef.current = new Map(Array.from<string>(xAxesState.axes.keys()).map(id => [id, 0]))
216
- updateTimingAndPlot(new Map(Array.from(continuousAxisRanges(xAxesState.axes as Map<string, ContinuousNumericAxis>).entries())
217
- .map(([id, range]) => {
218
- // grab the current range, then calculate the minimum time from the initial data, and
219
- // set that as the start, and then add the range to it for the end time
220
- const [start, end] = range.original.asTuple()
221
- const minTime = (initialData as Array<TimeSeries>)
222
- .filter(srs => axisAssignments.get(srs.name)?.xAxis === id)
223
- .reduce(
224
- (tMin: number, series: TimeSeries) => Math.min(
225
- tMin,
226
- !series.isEmpty() ? series.data[0].time : tMin
227
- ),
228
- Infinity
229
- )
230
- const startTime = minTime === Infinity ? 0 : minTime
231
- return [id, ContinuousAxisRange.from(startTime, startTime + end - start)]
232
- })
233
- )
234
- )
235
- },
236
- // ** not happy about this **
237
- // only want this effect to run when the initial data is changed, which mean all the
238
- // other dependencies are recalculated anyway.
239
- // eslint-disable-next-line react-hooks/exhaustive-deps
240
- [initialData]
241
- )
180
+ // tooltips are only shown while the data source is paused (and not while panning)
181
+ const allowTooltipRef = useRef<boolean>(!(dataSource?.running ?? false))
242
182
 
243
183
  /**
244
184
  * Calculates the upper and lower y-coordinate for the spike line
@@ -261,88 +201,27 @@ export function RasterPlot(props: Props): null {
261
201
  }
262
202
 
263
203
  /**
264
- * Adjusts the time-range and updates the plot when the plot is dragged to the left or right
265
- * @param deltaX The amount that the plot is dragged
266
- * @param plotDimensions The dimensions of the plot
267
- * @param series An array of series names
268
- * @param ranges A map holding the axis ID and its associated time range
269
- */
270
- const onPan = useCallback(
271
- (x: number,
272
- plotDimensions: Dimensions,
273
- ranges: Map<string, ContinuousAxisRange>
274
- ) => panHandler(axesForSeries, margin, setAxisIntervalFor, xAxesState)(x, plotDimensions, ranges),
275
- [axesForSeries, margin, setAxisIntervalFor, xAxesState]
276
- )
277
-
278
- /**
279
- * Called when the user uses the scroll wheel (or scroll gesture) to zoom in or out. Zooms in/out
280
- * at the location of the mouse when the scroll wheel or gesture was applied.
281
- * @param transform The d3 zoom transformation information
282
- * @param x The x-position of the mouse when the scroll wheel or gesture is used
283
- * @param plotDimensions The dimensions of the plot
284
- * @param series An array of series names
285
- * @param ranges A map holding the axis ID and its associated time-range
286
- */
287
- const onZoom = useCallback(
288
- (
289
- transform: ZoomTransform,
290
- x: number,
291
- plotDimensions: Dimensions,
292
- ranges: Map<string, ContinuousAxisRange>,
293
- ) => continuousAxisZoomHandler(axesForSeries, margin, setAxisIntervalFor, xAxesState)(transform, x, plotDimensions, ranges),
294
- [axesForSeries, margin, setAxisIntervalFor, xAxesState]
295
- )
296
-
297
- /**
298
- * @param timeRanges
299
- * @param mainGElem
204
+ * (Re-)registers this plot's draw function with the canvas context and requests a redraw.
205
+ * Replaces the old version, which directly mutated SVG `<line>` elements bound via d3's
206
+ * enter/update/exit join. Canvas has no persistent elements to join against, so the draw
207
+ * function just redraws every spike from current data/scale state each time it's invoked.
208
+ *
209
+ * Pan/zoom behavior setup lives in a separate effect (see below), not here -- this function
210
+ * runs on every data tick (each `windowingTime` interval), and recreating/reattaching a
211
+ * `d3.drag()`/`d3.zoom()` behavior that often is pure overhead unrelated to drawing the new
212
+ * data.
213
+ * @param cc The canvas context to register the draw function with
300
214
  */
301
215
  const updatePlot = useCallback(
302
- (timeRanges: Map<string, ContinuousAxisRange>, mainGElem: GSelection) => {
303
- if (container) {
304
- // select the svg element bind the data to them
305
- const svg = d3.select<SVGSVGElement, any>(container)
306
-
307
- // set up panning
308
- if (panEnabled) {
309
- const drag = d3.drag<SVGSVGElement, Datum>()
310
- .on("start", () => {
311
- d3.select(container).style("cursor", "move")
312
- allowTooltipRef.current = false
313
- })
314
- .on("drag", (event: any) => {
315
- onPan(event.dx, plotDimensions, timeRanges)
316
- // need to update the plot with the new time-ranges
317
- updatePlotRef.current(timeRanges, mainGElem)
318
- })
319
- .on("end", () => {
320
- d3.select(container).style("cursor", "auto")
321
- allowTooltipRef.current = isSubscriptionClosed()
322
- })
323
-
324
- svg.call(drag)
325
- }
216
+ (cc: CanvasContext) => {
217
+ const draw = (context: CanvasContext) => {
218
+ const {context2D} = context
326
219
 
327
- // set up for zooming
328
- if (zoomEnabled) {
329
- const zoom = d3.zoom<SVGSVGElement, Datum>()
330
- .filter((event: any) => !zoomKeyModifiersRequired || event.shiftKey || event.ctrlKey)
331
- .scaleExtent([0, 10])
332
- .translateExtent([[margin.left, margin.top], [plotDimensions.width, plotDimensions.height]])
333
- .on("zoom", (event: any) => {
334
- onZoom(
335
- event.transform,
336
- event.sourceEvent.offsetX - margin.left,
337
- plotDimensions,
338
- timeRanges,
339
- )
340
- updatePlotRef.current(timeRanges, mainGElem)
341
- }
342
- )
220
+ context2D.save()
221
+ clipToArea(context, plotDimensions, {x: margin.left, y: margin.top})
222
+ context2D.translate(margin.left, margin.top)
343
223
 
344
- svg.call(zoom)
345
- }
224
+ const newGeometry = new Map<string, SeriesGeometry>()
346
225
 
347
226
  // enter, update, delete the raster data
348
227
  dataRef.current.forEach(series => {
@@ -352,10 +231,11 @@ export function RasterPlot(props: Props): null {
352
231
  axisId => xAxesState.axisFor(axisId).getOrUndefined(),
353
232
  axisId => yAxesState.axisFor(axisId).getOrUndefined()
354
233
  )
234
+ if (xAxis === undefined || yAxis === undefined) return
355
235
 
356
236
  // grab the series styles, or the defaults if none exist
357
237
  const {
358
- color,
238
+ color: seriesColor,
359
239
  lineWidth,
360
240
  highlightColor,
361
241
  highlightWidth,
@@ -365,234 +245,178 @@ export function RasterPlot(props: Props): null {
365
245
  highlightColor: defaultLineStyle().color
366
246
  }
367
247
 
368
- const isHovered = hoveredSeriesRef.current === series.name
369
- const strokeColor = isHovered ? highlightColor : color
248
+ const isHovered = hoveredSeriesName === series.name
249
+ const strokeColor = isHovered ? highlightColor : seriesColor
370
250
  const strokeWidth = isHovered ? (highlightWidth || lineWidth) : lineWidth
371
251
 
372
252
  // only show the data for which the regex filter matches
373
- const plotData = (series.name.match(seriesFilter)) ? series.data : []
374
-
375
- const seriesContainer = svg
376
- .select<SVGGElement>(`#${series.name}-${chartId}-raster`)
377
- .selectAll<SVGLineElement, PixelDatum>('line')
378
- .data(plotData as PixelDatum[])
253
+ const plotData: FastShiftArray<Datum> = (series.name.match(seriesFilter)) ? series.data : FastShiftArray.empty<Datum>()
379
254
 
380
- //
381
- // enter new elements
255
+ // grab the functions that are used to determine the lower and upper coordinates of
256
+ // the raster line (y1, y2) and then calculate the values (y1, y2) using those functions
382
257
  const {yUpper, yLower} = yCoordsFn(yAxis.scale.bandwidth(), lineWidth, spikeLineMargin)
383
-
384
- // grab the value (index) associated with the series name (this is a category axis)
385
258
  const y = yAxis.scale(series.name) || 0
386
- // enter
387
- seriesContainer
388
- .enter()
389
- .append<SVGLineElement>('line')
390
- .attr('x1', datum => datum.x)
391
- .attr('x2', datum => datum.x)
392
- .attr('y1', _ => yUpper(y))
393
- .attr('y2', _ => yLower(y))
394
- .attr('stroke', strokeColor)
395
- .attr('stroke-width', strokeWidth)
396
- .attr('data-series-name', series.name)
397
- .attr('class', 'spikes-lines')
398
- .on(
399
- "mouseover",
400
- (event, datumArray) =>
401
- handleMouseOverSeries(
402
- container,
403
- xAxis,
404
- series.name,
405
- datumArray,
406
- event,
407
- margin,
408
- seriesStyles,
409
- allowTooltipRef.current,
410
- mouseOverHandlerFor(`tooltip-${chartId}`)
411
- )
412
- )
413
- .on(
414
- "mouseleave",
415
- event => handleMouseLeaveSeries(
416
- series.name,
417
- event.currentTarget,
418
- seriesStyles,
419
- mouseLeaveHandlerFor(`tooltip-${chartId}`)
420
- )
421
- )
422
- .each(datum => datum.x = xAxis.scale(datum.time))
423
-
424
- // update
425
- seriesContainer
426
- .each(datum => datum.x = xAxis.scale(datum.time))
427
- .attr('x1', datum => datum.x)
428
- .attr('x2', datum => datum.x)
429
- .attr('y1', _ => yUpper(y))
430
- .attr('y2', _ => yLower(y))
431
- .attr('stroke', strokeColor)
432
- .attr('stroke-width', strokeWidth)
433
-
434
- // exit old elements
435
- seriesContainer.exit().remove()
259
+ const y1 = yUpper(y)
260
+ const y2 = yLower(y)
261
+
262
+ context2D.strokeStyle = strokeColor
263
+ context2D.lineWidth = strokeWidth
264
+
265
+ const segments: Array<[[number, number], [number, number]]> = []
266
+ for (let i = 0; i < plotData.length; i++) {
267
+ const x = xAxis.scale(plotData[i].x)
268
+ context2D.beginPath()
269
+ context2D.moveTo(x, y1)
270
+ context2D.lineTo(x, y2)
271
+ context2D.stroke()
272
+ segments.push([[x + margin.left, y1 + margin.top], [x + margin.left, y2 + margin.top]])
273
+ }
274
+
275
+ newGeometry.set(series.name, {
276
+ points: [],
277
+ segments,
278
+ hitRadius: Math.max(4, strokeWidth)
279
+ })
436
280
  })
281
+
282
+ geometryRef.current = newGeometry
283
+
284
+ context2D.restore()
437
285
  }
286
+
287
+ cc.register(`raster-plot-${chartId}`, draw, 10)
288
+ cc.requestRedraw()
438
289
  },
439
290
  [
440
- axisAssignments, chartId, container, margin,
441
- mouseLeaveHandlerFor, mouseOverHandlerFor, onPan, onZoom,
442
- panEnabled,
443
- plotDimensions,
444
- seriesFilter, seriesStyles,
445
- xAxesState, yAxesState,
446
- zoomEnabled, zoomKeyModifiersRequired,
447
- spikeMargin,
448
- hoveredSeriesRef
291
+ axisAssignments, chartId, plotDimensions, seriesFilter, seriesStyles, xAxesState, yAxesState,
292
+ spikeMargin, hoveredSeriesName, margin.left, margin.top
449
293
  ]
450
294
  )
451
295
 
452
- // need to keep the function references for use by the subscription, which forms a closure
453
- // on them. without the references, the closures become stale, and resizing during streaming
454
- // doesn't work properly
455
- const updatePlotRef = useRef<(r: Map<string, ContinuousAxisRange>, g: GSelection) => void>(noop)
456
- useEffect(
457
- () => {
458
- if (mainG !== null && container !== null) {
459
- // when the update plot function doesn't yet exist, then create the container holding the plot
460
- const clipPathId = setClipPathG(chartId, mainG, plotDimensions)
461
- if (updatePlotRef.current === noop) {
462
- mainG
463
- .selectAll<SVGGElement, TimeSeries>('g')
464
- .attr("clip-path", `url(#${clipPathId})`)
465
- .data<TimeSeries>(dataRef.current)
466
- .enter()
467
- .append('g')
468
- .attr('class', 'spikes-series')
469
- .attr('id', series => `${series.name}-${chartId}-raster`)
470
- .attr('transform', `translate(${margin.left}, ${margin.top})`)
471
-
472
- } else {
473
- mainG
474
- .selectAll<SVGGElement, TimeSeries>('g')
475
- .attr("clip-path", `url(#${clipPathId})`)
476
- }
477
- updatePlotRef.current = updatePlot
478
- }
296
+ // the time axes: their ranges, the view driver, panning and zooming, highlighting, and
297
+ // reporting the axes' intervals -- see `useStreamingTimeAxes`
298
+ useStreamingTimeAxes<TimeSeriesChartData, Datum>({
299
+ canvasContext,
300
+ dataSource,
301
+ running,
302
+ initialData,
303
+ timeOf: datum => datum.x,
304
+ axisTimesFor: timeSeriesAxisTimes(axisAssignments, xAxesState),
305
+ axisAssignments,
306
+ updatePlot,
307
+ onDataReset: () => {
308
+ dataRef.current = initialData.slice() as Array<TimeSeries>
309
+ seriesRef.current = new Map(initialData.map(series => [series.name, series as TimeSeries]))
479
310
  },
480
- [chartId, container, mainG, margin, plotDimensions, updatePlot]
481
- )
311
+ allowTooltipRef,
312
+ panEnabled,
313
+ zoomEnabled,
314
+ zoomKeyModifiersRequired,
315
+ onZoomReset,
316
+ withCadenceOf,
317
+ highlightAxesOnMouseOver,
318
+ })
482
319
 
483
- // grab a reference to the function used to update the time ranges and update that reference
484
- // if the function changes (solve for stale closures)
485
- const onUpdateTimeRef = useRef(updateAxisRanges)
320
+ // the series' axis assignments, for the chart (e.g. the tooltip looks up a spike's row's axis)
486
321
  useEffect(
487
322
  () => {
488
- onUpdateTimeRef.current = updateAxisRanges
323
+ setAxisAssignments(axisAssignments)
489
324
  },
490
- [updateAxisRanges]
325
+ [axisAssignments, setAxisAssignments]
491
326
  )
492
327
 
493
- // memoized function for subscribing to the chart-data observable
494
- const subscribe = useCallback(
328
+ // wires up a single mousemove/mouseleave listener on the shared canvas to replace the old
329
+ // per-element SVG mouseover/mouseleave handlers. Hit-tests the mouse position against the
330
+ // last-drawn spike geometry (see `geometryRef`, populated by the draw function above).
331
+ useEffect(
495
332
  () => {
496
- if (seriesObservable === undefined || mainG === null) return undefined
497
- if (withCadenceOf !== undefined) {
498
- return subscriptionTimeSeriesWithCadenceFor(
499
- seriesObservable as Observable<TimeSeriesChartData>,
500
- onSubscribe,
501
- windowingTime,
502
- axisAssignments, xAxesState,
503
- onUpdateData,
504
- dropDataAfter,
505
- updateTimingAndPlot,
506
- // as new data flows into the subscription, the subscription
507
- // updates this map directly (for performance)
508
- seriesRef.current,
509
- (axisId, end) => currentTimeRef.current.set(axisId, end),
510
- withCadenceOf
511
- )
333
+ if (!canvasContext) return
334
+
335
+ const canvas = canvasContext.canvas
336
+
337
+ const handleMove = (event: MouseEvent) => {
338
+ if (!allowTooltipRef.current) return
339
+
340
+ const [x, y] = canvasLocalPoint(event, canvas)
341
+ const hit = seriesAt(x, y, geometryRef.current)
342
+
343
+ if (hit?.name === lastHoveredRef.current && hit !== undefined) {
344
+ // still hovering the same series -- no enter/leave to fire, but the specific
345
+ // spike may have changed, so fall through and re-report below
346
+ } else if (lastHoveredRef.current !== undefined) {
347
+ handleMouseLeaveSeries(lastHoveredRef.current, mouseLeaveHandlerFor(`tooltip-${chartId}`))
348
+ }
349
+
350
+ if (hit !== undefined) {
351
+ const series = seriesRef.current.get(hit.name)
352
+ const selectedDatum = series?.data[hit.index]
353
+ const xAxis = axesFor(
354
+ hit.name,
355
+ axisAssignments,
356
+ axisId => xAxesState.axisFor(axisId).getOrUndefined(),
357
+ axisId => yAxesState.axisFor(axisId).getOrUndefined()
358
+ )[0]
359
+ if (series !== undefined && selectedDatum !== undefined && xAxis !== undefined) {
360
+ handleMouseOverSeries(
361
+ xAxis,
362
+ hit.name,
363
+ selectedDatum,
364
+ series.data,
365
+ [x, y],
366
+ margin,
367
+ mouseOverHandlerFor(`tooltip-${chartId}`)
368
+ )
369
+ }
370
+ }
371
+
372
+ lastHoveredRef.current = hit?.name
373
+ }
374
+
375
+ const handleLeaveCanvas = () => {
376
+ if (lastHoveredRef.current !== undefined) {
377
+ handleMouseLeaveSeries(lastHoveredRef.current, mouseLeaveHandlerFor(`tooltip-${chartId}`))
378
+ lastHoveredRef.current = undefined
379
+ }
380
+ }
381
+
382
+ canvas.addEventListener('mousemove', handleMove)
383
+ canvas.addEventListener('mouseleave', handleLeaveCanvas)
384
+ return () => {
385
+ canvas.removeEventListener('mousemove', handleMove)
386
+ canvas.removeEventListener('mouseleave', handleLeaveCanvas)
512
387
  }
513
- return subscriptionTimeSeriesFor(
514
- seriesObservable as Observable<TimeSeriesChartData>,
515
- onSubscribe,
516
- windowingTime,
517
- axisAssignments, xAxesState,
518
- onUpdateData,
519
- dropDataAfter,
520
- updateTimingAndPlot,
521
- // as new data flows into the subscription, the subscription
522
- // updates this map directly (for performance)
523
- seriesRef.current,
524
- (axisId, end) => currentTimeRef.current.set(axisId, end)
525
- )
526
388
  },
527
- [
528
- axisAssignments, dropDataAfter, mainG,
529
- onSubscribe, onUpdateData,
530
- seriesObservable, updateTimingAndPlot, windowingTime, xAxesState,
531
- withCadenceOf
532
- ]
389
+ [canvasContext, chartId, margin, axisAssignments, xAxesState, yAxesState, mouseOverHandlerFor, mouseLeaveHandlerFor]
533
390
  )
534
391
 
535
- const timeRangesRef = useRef<Map<string, ContinuousAxisRange>>(new Map())
392
+ // this plot needs a data source (see the `Chart`'s `dataSource` prop)
536
393
  useEffect(
537
394
  () => {
538
- if (container && mainG) {
539
- // so this gets a bit complicated. the time-ranges need to be updated whenever the time-ranges
540
- // change. for example, as data is streamed in, the times change, and then we need to update the
541
- // time-range. however, we want to keep the time-ranges to reflect their original scale so that
542
- // we can zoom properly (so the updates can't fuck with the scale). At the same time, when the
543
- // interpolation changes, then the update plot changes, and the time-ranges must maintain their
544
- // original scale as well.
545
- if (timeRangesRef.current.size === 0) {
546
- // when no time-ranges have yet been created, then create them and hold on to a mutable
547
- // reference to them
548
- timeRangesRef.current = continuousAxisRanges(xAxesState.axes as Map<string, ContinuousNumericAxis>)
549
- } else {
550
- // when the time-ranges already exist, then we want to update the time-ranges for each
551
- // existing time-range in a way that maintains the original scale.
552
- const intervals = continuousAxisIntervals(xAxesState.axes)
553
- timeRangesRef.current
554
- .forEach((range, id, rangesMap) => {
555
- const [start, end] = Optional.ofNullable(intervals.get(id))
556
- .map(interval => interval.asTuple())
557
- .getOrThrow(() => new Error(`Unable to retrieve interval for axis; axis_id: ${id}`))
558
- // .getOrElse([NaN, NaN])
559
- if (!isNaN(start) && !isNaN(end)) {
560
- // update the reference map with the new (start, end) portion of the range,
561
- // while keeping the original scale intact
562
- rangesMap.set(id, range.update(start, end))
563
- }
564
- })
565
- }
566
- updatePlot(timeRangesRef.current, mainG)
395
+ if (dataSource === undefined) {
396
+ console.error("RasterPlot requires a data source; set the enclosing Chart's `dataSource` prop")
567
397
  }
568
398
  },
569
- [chartId, color, container, mainG, plotDimensions, updatePlot, xAxesState]
399
+ [dataSource]
570
400
  )
571
401
 
572
- // subscribe/unsubscribe to the observable chart data. when the `shouldSubscribe`
573
- // is changed to `true` and we haven't subscribed yet, then subscribe. when the
574
- // `shouldSubscribe` is `false` and we had subscribed, then unsubscribe. otherwise,
575
- // do nothing.
402
+ // unregister this plot's draw function on unmount
576
403
  useEffect(
577
404
  () => {
578
- if (shouldSubscribe && subscriptionRef.current === undefined) {
579
- subscriptionRef.current = subscribe()
580
- allowTooltipRef.current = false
581
- } else if (!shouldSubscribe && subscriptionRef.current !== undefined) {
582
- subscriptionRef.current?.unsubscribe()
583
- subscriptionRef.current = undefined
584
- allowTooltipRef.current = true
405
+ return () => {
406
+ if (canvasContext) {
407
+ canvasContext.unregister(`raster-plot-${chartId}`)
408
+ }
585
409
  }
586
410
  },
587
- [shouldSubscribe, subscribe]
411
+ [canvasContext, chartId]
588
412
  )
589
413
 
590
414
  return null
591
415
  }
592
416
 
593
417
  /**
594
- * Attempts to locate the x- and y-axes for the specified series. If no axis is found for the
595
- * series name, then uses the default returned by the useChart() hook.
418
+ * Attempts to locate the x- and y-axes for the specified series. If the series has no axis
419
+ * assignment, then uses the default (first) x- and y-axes.
596
420
  * @param seriesName Name of the series for which to retrieve the axis
597
421
  * @param axisAssignments A map holding the series name and the associated x- and y-axes assigned
598
422
  * to that series. Note that the series in the axis-assignment map is merely a subset of the set
@@ -600,7 +424,8 @@ export function RasterPlot(props: Props): null {
600
424
  * @param xAxisFor The function that accepts an axis ID and returns the corresponding x-axis
601
425
  * @param yAxisFor The function that accepts an axis ID and returns the corresponding y-axis
602
426
  * @return A 2d tuple holding the linear x-axis as its first element and the category y-axis as
603
- * the second element.
427
+ * the second element (either is actually `undefined` when it isn't found, despite the type).
428
+ * @throws Error when the x-axis isn't a continuous numeric axis, or the y-axis isn't a category axis
604
429
  */
605
430
  function axesFor(
606
431
  seriesName: string,
@@ -610,79 +435,62 @@ function axesFor(
610
435
  ): [xAxis: ContinuousNumericAxis, yAxis: OrdinalStringAxis] {
611
436
  const axes = axisAssignments.get(seriesName)
612
437
  const xAxis = xAxisFor(axes?.xAxis || "")
438
+ checkAxisType("RasterPlot", "x", xAxis, AxisType.ContinuousNumeric)
613
439
  const xAxisLinear = xAxis as ContinuousNumericAxis
614
- if (xAxis && !xAxisLinear) {
615
- throw Error("Raster plot requires that x-axis be of type LinearAxis")
616
- }
617
440
  const yAxis = yAxisFor(axes?.yAxis || "")
441
+ checkAxisType("RasterPlot", "y", yAxis, AxisType.OrdinalString)
618
442
  const yAxisCategory = yAxis as OrdinalStringAxis
619
- if (yAxis && !yAxisCategory) {
620
- throw Error("Raster plot requires that y-axis be of type CategoryAxis")
621
- }
622
443
  return [xAxisLinear, yAxisCategory]
623
444
  }
624
445
 
625
446
  /**
626
- * Renders a tooltip showing the neuron, spike time, and the spike strength when the mouse hovers over a spike.
627
- * @param container The chart container
447
+ * Reports a tooltip showing the neuron, spike time, and the spike's value when the mouse hovers over a spike.
448
+ * Replaces the old version, which mutated the hovered SVG `<line>`'s stroke directly; highlighting is now
449
+ * handled by the draw function reading `hoveredSeriesName` from chart state rather than by touching an
450
+ * element here.
628
451
  * @param xAxis The x-axis
629
452
  * @param seriesName The name of the series (i.e. the neuron ID)
630
453
  * @param selectedDatum The selected datum
631
- * @param event The mouse-over series event
454
+ * @param spikes All the series' spikes that the chart holds (for the tooltip's statistics)
455
+ * @param mouseCoords The `[x, y]` position of the mouse, in canvas coordinates
632
456
  * @param margin The plot margin
633
- * @param seriesStyles The series style information (needed for (un)highlighting)
634
- * @param allowTooltip When set to `false` won't show tooltip, even if it is visible (used by pan)
635
457
  * @param mouseOverHandlerFor The handler for the mouse over (registered by the <Tooltip/>)
636
458
  */
637
459
  function handleMouseOverSeries(
638
- container: SVGSVGElement,
639
460
  xAxis: ContinuousNumericAxis,
640
461
  seriesName: string,
641
462
  selectedDatum: Datum,
642
- event: React.MouseEvent<SVGPathElement>,
463
+ spikes: Series<Datum>,
464
+ mouseCoords: [x: number, y: number],
643
465
  margin: Margin,
644
- seriesStyles: Map<string, SeriesLineStyle>,
645
- allowTooltip: boolean,
646
- mouseOverHandlerFor: ((seriesName: string, time: number, tooltipData: TooltipData<Datum, NoTooltipMetadata>, mouseCoords: [x: number, y: number]) => void) | undefined,
466
+ mouseOverHandlerFor: ((seriesName: string, time: number, tooltipData: TooltipData<Datum, RasterTooltipMetadata>, mouseCoords: [x: number, y: number]) => void) | undefined,
647
467
  ): void {
648
468
  // grab the time needed for the tooltip ID
649
- const [x, y] = d3.pointer(event, container)
469
+ const [x] = mouseCoords
650
470
  const time = Math.round(xAxis.scale.invert(x - margin.left))
651
471
 
652
- const {highlightColor, highlightWidth} = seriesStyles.get(seriesName) || defaultLineStyle()
653
-
654
- // Use d3 to select element, change color and size
655
- d3.select<SVGPathElement, Datum>(event.currentTarget)
656
- .attr('stroke', highlightColor)
657
- .attr('stroke-width', highlightWidth)
658
-
659
- if (mouseOverHandlerFor && allowTooltip) {
472
+ if (mouseOverHandlerFor) {
660
473
  // the contract for the mouse over handler is for a time-series, but here we only
661
474
  // need one point, the selected datum, and so we convert it into an array of point
662
475
  // (i.e. a time-series). The category tooltip is (and custom ones, must) be
663
- // written to expect only the selected point
664
- mouseOverHandlerFor(seriesName, time, {series: [selectedDatum], metadata: {}}, [x, y])
476
+ // written to expect only the selected point. All the series' spikes (that the chart
477
+ // holds) come along in the metadata, for the tooltip's statistics
478
+ mouseOverHandlerFor(seriesName, time, {series: [selectedDatum], metadata: {spikes}}, mouseCoords)
665
479
  }
666
480
  }
667
481
 
668
482
  /**
669
- * Unselects the time series and calls the mouse-leave-series handler registered for this series.
483
+ * Calls the mouse-leave-series handler registered for this series. Replaces the old version, which
484
+ * also reset the hovered SVG element's stroke color/width directly; that reset is now implicit --
485
+ * once `hoveredSeriesName` is cleared, the next redraw simply paints the spikes in their normal
486
+ * (non-highlighted) style.
670
487
  * @param seriesName The name of the series (i.e. the neuron ID)
671
- * @param segment The SVG line element representing the spike, over which the mouse is hovering.
672
- * @param seriesStyles The styles for the series (for (un)highlighting)
673
488
  * @param mouseLeaverHandlerFor Registered handler for the series when the mouse leaves
674
489
  */
675
490
  function handleMouseLeaveSeries(
676
491
  seriesName: string,
677
- segment: SVGPathElement,
678
- seriesStyles: Map<string, SeriesLineStyle>,
679
492
  mouseLeaverHandlerFor: ((seriesName: string) => void) | undefined,
680
493
  ): void {
681
- const {color, lineWidth} = seriesStyles.get(seriesName) || defaultLineStyle()
682
- d3.select<SVGPathElement, Datum>(segment)
683
- .attr('stroke', color)
684
- .attr('stroke-width', lineWidth)
685
-
686
494
  if (mouseLeaverHandlerFor) {
687
495
  mouseLeaverHandlerFor(seriesName)
688
496
  }