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,57 +1,61 @@
1
- import { setClipPathG } from "./plot";
1
+ import { clipToArea } from "./plot";
2
+ import { useCanvasZoomPan } from "./useCanvasZoomPan";
2
3
  import * as d3 from "d3";
3
4
  import { noop } from "../utils";
4
5
  import { useChart } from "../hooks/useChart";
5
- import { useCallback, useEffect, useMemo, useRef } from "react";
6
- import { axesForSeriesGen, ordinalAxisIntervals, ordinalAxisRanges, ordinalAxisZoomHandler, ordinalPanHandler } from "../axes/axes";
7
- import { subscriptionOrdinalXFor } from "../subscriptions/subscriptions";
8
- import { useDataObservable } from "../hooks/useDataObservable";
6
+ import { useCallback, useEffect, useEffectEvent, useMemo, useRef } from "react";
7
+ import { seriesAt, canvasLocalPoint } from "./hitTesting";
8
+ import { axesForSeriesGen, AxisType, checkAxisType, ordinalAxisIntervals, ordinalAxisRanges, ordinalAxisZoomHandler, ordinalPanHandler } from "../axes/axes";
9
+ import { ordinalViewDriverFor } from "../subscriptions/viewDrivers";
10
+ import { useDataSource, useDataSourceRunning, useInitialData, useStreamingSettings } from "../hooks/useDataSource";
11
+ import { initialOrdinalStats } from "../datasources/ordinalDataSource";
9
12
  import { usePlotDimensions } from "../hooks/usePlotDimensions";
10
- import { useInitialData } from "../hooks/useInitialData";
11
- import { copyValueStatsForSeries } from "../observables/ordinals";
12
- import { calculateOrdinalStats } from "../series/ordinalSeries";
13
- import { applyFillStylesTo, applyStrokeStylesTo, STROKE_COLOR, STROKE_OPACITY, STROKE_WIDTH } from "../styling/svgStyle";
13
+ import { applyFillStyle, applyStrokeStyle } from "../styling/canvasStyle";
14
14
  import { defaultBarSeriesStyle } from "../styling/barPlotStyle";
15
- import { AxisInterval } from "../axes/AxisInterval";
16
15
  import { Optional } from "result-fn";
17
- const STREAM_CHARTS_BAR_CHART_ID = 'stream-charts-bar-chart';
18
- // elements of the bar-chart
19
- const BAR_CHART_CLASS_IDS = {
20
- currentValue: STREAM_CHARTS_BAR_CHART_ID + '-value-lines',
21
- meanValue: STREAM_CHARTS_BAR_CHART_ID + '-mean-value-lines',
22
- minMax: STREAM_CHARTS_BAR_CHART_ID + '-min-max-bars',
23
- windowedMeanValue: STREAM_CHARTS_BAR_CHART_ID + '-windowed-mean-value-lines',
24
- windowedMinMax: STREAM_CHARTS_BAR_CHART_ID + '-windowed-mean-bars'
25
- };
26
- const classIdFor = (id) => '.' + id;
27
- // constants identifying the bar-chart elements for which mouse-over/mouse-leave events are defined
28
- const TOOLTIP_PROVIDER_ID = STREAM_CHARTS_BAR_CHART_ID + '-tooltip-provider';
29
- export const BAR_CHART_TOOLTIP_PROVIDER_IDS = {
30
- currentValue: TOOLTIP_PROVIDER_ID + '-current-value',
31
- meanValue: TOOLTIP_PROVIDER_ID + '-mean-value',
32
- minMax: TOOLTIP_PROVIDER_ID + '-min-max',
33
- windowedMeanValue: TOOLTIP_PROVIDER_ID + '-windowed-min-max',
34
- windowedMinMax: TOOLTIP_PROVIDER_ID + '-windowed-mean'
16
+ import { BAR_CHART_TOOLTIP_PROVIDER_IDS } from "./constants";
17
+ import { AxisInterval } from "../axes/AxisInterval";
18
+ import { extentOf, extentWith } from "../axes/autoScale";
19
+ import { growAutoScaledYAxes, useAutoScaleRestart } from "./autoScaleYAxes";
20
+ /**
21
+ * Maps the short element-type keys used internally for hit-testing geometry (`minMax`,
22
+ * `windowedMinMax`, `meanValue`, `windowedMeanValue`, `currentValue`) to the actual provider IDs
23
+ * (`BAR_CHART_TOOLTIP_PROVIDER_IDS`) that `mouseOverHandlerFor`/`mouseLeaveHandlerFor` expect.
24
+ */
25
+ const PROVIDER_ID_FOR_ELEMENT_TYPE = {
26
+ minMax: BAR_CHART_TOOLTIP_PROVIDER_IDS.minMax,
27
+ windowedMinMax: BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMinMax,
28
+ meanValue: BAR_CHART_TOOLTIP_PROVIDER_IDS.meanValue,
29
+ windowedMeanValue: BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMeanValue,
30
+ currentValue: BAR_CHART_TOOLTIP_PROVIDER_IDS.currentValue,
35
31
  };
36
32
  /**
37
- * Renders a streaming bar plot for the series in the initial data and those sourced by the
38
- * observable specified as a property in the {@link Chart}. This component uses the {@link useChart}
33
+ * Renders a streaming bar plot for the series held by the {@link StreamingDataSource} handed to the
34
+ * {@link Chart} (its `dataSource` prop) -- along with each series' lifetime and windowed stats,
35
+ * which an {@link OrdinalDataSource} keeps. This component uses the {@link useChart}
39
36
  * hook, and therefore must be a child of the {@link Chart} to be plugged in to the
40
37
  * chart ecosystem (axes, tracker, tooltip).
41
38
  *
39
+ * Internally, this no longer creates/updates SVG `<rect>`/`<line>` elements. Instead, it registers
40
+ * a single draw function with the chart's {@link CanvasContext} that redraws every series' bars
41
+ * and lines from scratch each time the canvas repaints. Mouse hover (for the tooltip and the
42
+ * value-line/windowed-mean-line highlight) is handled by hit-testing the mouse position against
43
+ * the last-drawn geometry, keyed per `${seriesName}::${elementType}` so the five overlaid visual
44
+ * elements (min-max bar, windowed min-max bar, mean line, windowed mean line, value line) can be
45
+ * hit-tested and highlighted independently, matching the old per-element SVG mouseover behavior.
46
+ *
42
47
  * For a relatively complete example of how to use this plot component, see the
43
48
  * <a href="https://github.com/robphilipp/stream-charts-examples">`StreamingBarChart` example</a>
44
49
  *
45
50
  * @param props The properties associated with the bar plot
51
+ * @return `null` (the plot draws onto the chart's canvas)
46
52
  * @example
47
53
  * ```typescript
48
54
  * <BarPlot
49
55
  * barMargin={1}
50
- * dropDataAfter={5000}
51
56
  * panEnabled={true}
52
57
  * zoomEnabled={true}
53
58
  * zoomKeyModifiersRequired={true}
54
- * withCadenceOf={50}
55
59
  *
56
60
  * showMinMaxBars={true}
57
61
  * showValueLines={true}
@@ -62,135 +66,89 @@ export const BAR_CHART_TOOLTIP_PROVIDER_IDS = {
62
66
  * ```
63
67
  */
64
68
  export function BarPlot(props) {
65
- const { chartId, container, mainG, axes, seriesStyles, seriesFilter, mouse } = useChart();
66
- const { xAxesState, yAxesState, setAxisAssignments, setAxisIntervalFor, setOriginalAxisIntervalFor, axesRanges } = axes;
69
+ var _a;
70
+ const { chartId, canvasContext, axes, seriesStyles, seriesFilter, mouse } = useChart();
71
+ const { xAxesState, yAxesState, setAxisAssignments, setAxisIntervalFor, setOriginalAxisIntervalFor, axesRanges, axisRangeFor, updateAxisRanges, } = axes;
67
72
  const { mouseOverHandlerFor, mouseLeaveHandlerFor } = mouse;
68
73
  const { plotDimensions, margin } = usePlotDimensions();
69
- const { seriesObservable, windowingTime = 100, shouldSubscribe, onSubscribe = noop, onUpdateData, onUpdateChartTime = noop } = useDataObservable();
74
+ const { windowingTime = 100, onUpdateChartTime = noop } = useStreamingSettings();
75
+ // the application-owned source of the data, and whether it's running (streaming)
76
+ const dataSource = useDataSource();
77
+ const running = useDataSourceRunning(dataSource);
70
78
  const { initialData } = useInitialData();
71
- const { axisAssignments = new Map(), dropDataAfter = Infinity, panEnabled = false, zoomEnabled = false, zoomKeyModifiersRequired = true, showMinMaxBars = true, showWindowedMinMaxBars = true, showValueLines = true, showMeanValueLines = true, showWindowedMeanValueLines = true, barMargin = 2, barSeriesStyle = defaultBarSeriesStyle() } = props;
79
+ const { axisAssignments = new Map(), panEnabled = false, zoomEnabled = false, zoomKeyModifiersRequired = true, showMinMaxBars = true, showWindowedMinMaxBars = true, showValueLines = true, showMeanValueLines = true, showWindowedMeanValueLines = true, barMargin = 2, barSeriesStyle = defaultBarSeriesStyle(), highlightAxesOnMouseOver = false, zoomState = undefined, onZoomStateChange = noop, onZoomReset = noop, } = props;
72
80
  // why do "dataRef" and "seriesRef" both hold on to the same underlying data? for performance.
73
81
  //
74
82
  // the "dataRef" and "seriesRef" both point to the same underlying data, a collection
75
- // of series. The series in "dataRef" are bound to the DOM elements through d3. The "seriesRef" series
76
- // are the ones that are updated as new data is streamed in.
83
+ // of series (held, and updated as new data is streamed in, by the data source). The series in
84
+ // "dataRef" are read by the canvas draw function, and the "seriesRef" map is for looking a
85
+ // series up by its name.
77
86
  //
78
87
  // the "dataRef" object holds on to a copy of the initial data (which is an array of
79
88
  // time-series, e.i. an array of BaseSeries<OrdinalDatum> objects). The slice just creates a copy of
80
89
  // the array, but the references to the BaseSeries objects are the same and still point to the same
81
90
  // data as the "initialData" array.
82
91
  //
83
- // the "seriesRef" object is a reference to a map (series_name -> BaseSeries<OrdinalDatum>) which is
84
- // used to update the data in the series. When new data enters, it is appended to one or more series.
92
+ // the "seriesRef" object is a reference to a map (series_name -> BaseSeries<OrdinalDatum>), used
93
+ // to find the series under the mouse (for the tooltip).
85
94
  //
86
- // the series in the "dataRef" object are the ones bound to the DOM elements in d3, and so as these
87
- // are updated, d3 will update the DOM elements (the elements in this plot).
95
+ // the series in the "dataRef" object are the ones read by the next redraw, so as these are
96
+ // updated, the next canvas repaint picks up the new data.
88
97
  const dataRef = useRef(initialData.slice());
89
98
  const seriesRef = useRef(new Map(initialData.map(series => [series.name, series])));
90
- const statsRef = useRef(initialOrdinalStats(dataRef.current));
99
+ // the lifetime and windowed stats for each series -- kept by the data source (when it's an
100
+ // ordinal data source), so they keep accumulating while this plot is unmounted
101
+ const statsRef = useRef(statsFrom(dataSource, initialData));
91
102
  // map(axis_id -> current_time) -- maps the axis ID to the current time for that axis
92
103
  const currentTimeRef = useRef(0);
93
- const subscriptionRef = useRef(undefined);
94
- const isSubscriptionClosed = () => subscriptionRef.current === undefined || subscriptionRef.current.closed;
95
- const allowTooltipRef = useRef(isSubscriptionClosed());
96
- useEffect(() => {
97
- currentTimeRef.current = 0;
98
- }, [xAxesState]);
99
- // set the axis assignments needed if a tooltip is being used
100
- useEffect(() => {
101
- setAxisAssignments(axisAssignments);
102
- }, [axisAssignments, setAxisAssignments]);
103
- // calculates the distinct series IDs that cover all the series in the plot
104
- const axesForSeries = useMemo(() => axesForSeriesGen(initialData, axisAssignments, xAxesState), [initialData, axisAssignments, xAxesState]);
105
- // updates the timing using the onUpdateTime and updatePlot references. This and the references
106
- // defined above allow the axes' times to be updated properly by avoid stale reference to these
107
- // functions.
108
- const updateTimingAndPlot = useCallback((ranges) => {
109
- if (mainG !== null) {
110
- updatePlotRef.current(ranges, mainG);
111
- onUpdateChartTime(currentTimeRef.current);
112
- updatePlotRef.current(ranges, mainG);
113
- }
114
- }, [mainG, onUpdateChartTime]);
115
- // todo find better way
116
- // when the initial data changes, then reset the plot. note that the initial data doesn't change
117
- // during the normal course of updates from the observable, only when the plot is restarted.
118
- useEffect(() => {
119
- dataRef.current = initialData.slice();
120
- seriesRef.current = new Map(initialData.map(series => [series.name, series]));
121
- currentTimeRef.current = 0;
122
- statsRef.current = initialOrdinalStats(dataRef.current);
123
- },
124
- // ** not happy about this **
125
- // only want this effect to run when the initial data is changed, which mean all the
126
- // other dependencies are recalculated anyway.
127
- // eslint-disable-next-line react-hooks/exhaustive-deps
128
- [initialData]);
129
- /**
130
- * Adjusts the time-range and updates the plot when the plot is dragged to the left or right
131
- * @param deltaX The amount that the plot is dragged
132
- * @param plotDimensions The dimensions of the plot
133
- * @param series An array of series names
134
- * @param ranges A map holding the axis ID and its associated time range
135
- */
136
- const onPan = useCallback((x, plotDimensions, series, ranges) => ordinalPanHandler(axesForSeries, margin, setAxisIntervalFor, xAxesState)(x, plotDimensions, series, ranges), [axesForSeries, margin, setAxisIntervalFor, xAxesState]);
137
- /**
138
- * Called when the user uses the scroll wheel (or scroll gesture) to zoom in or out. Zooms in/out
139
- * at the location of the mouse when the scroll wheel or gesture was applied.
140
- * @param transform The d3 zoom transformation information
141
- * @param x The x-position of the mouse when the scroll wheel or gesture is used
142
- * @param plotDimensions The dimensions of the plot
143
- * @param series An array of series names
144
- * @param ranges A map holding the axis ID and its associated time-range
145
- */
146
- const onZoom = useCallback((transform, x, plotDimensions, ranges) => ordinalAxisZoomHandler(axesForSeries, margin, setAxisIntervalFor, setOriginalAxisIntervalFor, xAxesState)(transform, x, plotDimensions, ranges), [axesForSeries, margin, setAxisIntervalFor, setOriginalAxisIntervalFor, xAxesState]);
104
+ // tooltips are only shown while the data source is paused (and not while panning)
105
+ const allowTooltipRef = useRef(!((_a = dataSource === null || dataSource === void 0 ? void 0 : dataSource.running) !== null && _a !== void 0 ? _a : false));
106
+ // the last-drawn geometry for each `${seriesName}::${elementType}`, in canvas coordinates,
107
+ // used for hit-testing mouse hover on `mousemove` (see the effect below that wires up the
108
+ // listener)
109
+ const geometryRef = useRef(new Map());
110
+ // which specific element (series + type) the mouse was over on the previous `mousemove`, so
111
+ // we know when to fire a "leave" before firing an "over" for a different element -- unlike
112
+ // Scatter/Raster, BarPlot doesn't use the shared `hoveredSeriesName` chart state, since here
113
+ // hover is scoped to one of five element *types* per series, not the series as a whole
114
+ const lastHoveredRef = useRef(undefined);
147
115
  /**
148
- * @param ordinalRanges
149
- * @param mainGElem
116
+ * (Re-)registers this plot's draw function with the canvas context and requests a redraw.
117
+ * Replaces the old version, which directly mutated SVG `<rect>`/`<line>` elements bound via
118
+ * d3's enter/update/exit join. Canvas has no persistent elements to join against, so the draw
119
+ * function just redraws every element from current data/scale state each time it's invoked.
120
+ *
121
+ * Pan/zoom behavior setup lives in a separate effect (see below), not here -- this function
122
+ * runs on every data tick (each `windowingTime` interval), and recreating/reattaching a
123
+ * `d3.drag()`/`d3.zoom()` behavior that often is pure overhead unrelated to drawing the new
124
+ * data.
125
+ * @param cc The canvas context to register the draw function with
150
126
  */
151
- const updatePlot = useCallback((ordinalRanges, mainGElem) => {
152
- if (container) {
153
- // select the svg element bind the data to them
154
- const svg = d3.select(container);
155
- // set up panning
156
- if (panEnabled) {
157
- const drag = d3.drag()
158
- .on("start", () => {
159
- d3.select(container).style("cursor", "move");
160
- allowTooltipRef.current = false;
161
- })
162
- .on("drag", (event) => {
163
- const names = dataRef.current.map(series => series.name);
164
- onPan(event.dx, plotDimensions, names, ordinalRanges);
165
- // need to update the plot with the new time-ranges
166
- updatePlotRef.current(ordinalRanges, mainGElem);
167
- })
168
- .on("end", () => {
169
- d3.select(container).style("cursor", "auto");
170
- allowTooltipRef.current = isSubscriptionClosed();
171
- });
172
- svg.call(drag);
173
- }
174
- // set up for zooming
175
- if (zoomEnabled) {
176
- const zoom = d3.zoom()
177
- .filter((event) => !zoomKeyModifiersRequired || event.shiftKey || event.ctrlKey)
178
- .scaleExtent([1, 10])
179
- .translateExtent([[margin.left, margin.top], [plotDimensions.width, plotDimensions.height]])
180
- .on("zoom", (event) => {
181
- onZoom(event.transform, event.sourceEvent.offsetX - margin.left, plotDimensions, ordinalRanges);
182
- updatePlotRef.current(ordinalRanges, mainGElem);
183
- });
184
- svg.call(zoom);
185
- }
127
+ const updatePlot = useCallback((cc) => {
128
+ const draw = (context) => {
129
+ const { context2D } = context;
130
+ context2D.save();
131
+ clipToArea(context, plotDimensions, { x: margin.left, y: margin.top });
132
+ context2D.translate(margin.left, margin.top);
133
+ const newGeometry = new Map();
134
+ const hovered = lastHoveredRef.current;
186
135
  // enter, update, delete the bar data
187
136
  dataRef.current.forEach(series => {
188
- var _a, _b, _c;
137
+ var _a, _b, _c, _d, _e, _f;
189
138
  const [xAxis, yAxis] = axesFor(series.name, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
139
+ if (xAxis === undefined || yAxis === undefined)
140
+ return;
190
141
  // grab the series styles, or the defaults if none exist
191
- const { margin: categoryMargin = barMargin, valueLine: valueLineStyle, meanValueLine: meanValueLineStyle, windowedMeanValueLine: windowedMeanLineStyle, minMaxBar: minMaxBarStyle, windowedMinMaxBar: windowedBarStyle } = seriesStyles.get(series.name) || Object.assign(Object.assign({}, barSeriesStyle), { highlightColor: barSeriesStyle.color });
142
+ const { margin: categoryMargin = barMargin, valueLine: valueLineStyle, meanValueLine: meanValueLineStyle, windowedMeanValueLine: windowedMeanLineStyle, minMaxBar: minMaxBarStyle, windowedMinMaxBar: windowedBarStyle } = seriesStyles.get(series.name) || {
143
+ ...barSeriesStyle,
144
+ highlightColor: barSeriesStyle.color
145
+ };
192
146
  // only show the data for which the regex filter matches
193
- const plotData = series.name.match(seriesFilter) ? [series.data[series.data.length - 1]] : [];
147
+ const plotData = series.name.match(seriesFilter) && series.data.length > 0 ?
148
+ [series.data[series.data.length - 1]] :
149
+ [];
150
+ if (plotData.length === 0)
151
+ return;
194
152
  // grab the functions for determining the lower and upper bounds of the category
195
153
  const { lower, upper } = xAxisCategoryBoundsFn(xAxis.scale.bandwidth(), valueLineStyle.regular.width, categoryMargin);
196
154
  // grab the value (index) associated with the series name (this is a category axis)
@@ -198,141 +156,330 @@ export function BarPlot(props) {
198
156
  //
199
157
  // min/max bar rectangle
200
158
  const totalBar = barDimensions(minMaxBarStyle.widthFraction, lower(x), upper(x), ((_a = statsRef.current.valueStatsForSeries.get(series.name)) === null || _a === void 0 ? void 0 : _a.min.value) || 0, ((_b = statsRef.current.valueStatsForSeries.get(series.name)) === null || _b === void 0 ? void 0 : _b.max.value) || 0, yAxis);
201
- svg
202
- .select(`#${series.name}-${chartId}-bar`)
203
- .selectAll(classIdFor(BAR_CHART_CLASS_IDS.minMax))
204
- .data(plotData)
205
- .join(enter => barFor(enter.append('rect').attr('class', BAR_CHART_CLASS_IDS.minMax), totalBar, barStyleFor(showMinMaxBars, minMaxBarStyle)), update => barFor(update, totalBar, barStyleFor(showMinMaxBars, minMaxBarStyle)), exit => exit.remove())
206
- .on("mouseover", (event) => handleMouseOverBar(container, yAxis, series, statsRef.current, event, margin, seriesStyles, barSeriesStyle, allowTooltipRef.current && showMinMaxBars, mouseOverHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.minMax), BAR_CHART_TOOLTIP_PROVIDER_IDS.minMax))
207
- .on("mouseleave", event => handleMouseLeaveSeries(series.name, event.currentTarget, seriesStyles, barSeriesStyle, mouseLeaveHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.minMax), BAR_CHART_TOOLTIP_PROVIDER_IDS.minMax));
159
+ drawBar(context2D, totalBar, barStyleFor(showMinMaxBars, minMaxBarStyle));
160
+ newGeometry.set(`${series.name}::minMax`, {
161
+ points: [],
162
+ rects: [{
163
+ x: totalBar.upperX + margin.left,
164
+ y: totalBar.upperY + margin.top,
165
+ width: totalBar.width,
166
+ height: totalBar.height
167
+ }],
168
+ hitRadius: 0
169
+ });
208
170
  //
209
- // windowed-mean line when the windowed stats are defined for the series
171
+ // windowed-mean line and windowed min/max bar, when the windowed stats are defined for the series
210
172
  const seriesWindowedStats = statsRef.current.windowedValueStatsForSeries.get(series.name);
211
173
  if (seriesWindowedStats !== undefined) {
212
174
  const windowedBar = barDimensions(windowedBarStyle.widthFraction, lower(x), upper(x), seriesWindowedStats.min.value, seriesWindowedStats.max.value, yAxis);
213
- svg
214
- .select(`#${series.name}-${chartId}-bar`)
215
- .selectAll(classIdFor(BAR_CHART_CLASS_IDS.windowedMinMax))
216
- .data(plotData)
217
- .join(enter => barFor(enter.append('rect').attr('class', BAR_CHART_CLASS_IDS.windowedMinMax), windowedBar, barStyleFor(showWindowedMinMaxBars, windowedBarStyle)), update => barFor(update, windowedBar, barStyleFor(showWindowedMinMaxBars, windowedBarStyle)), exit => exit.remove())
218
- .on("mouseover", (event) => handleMouseOverBar(container, yAxis, series, statsRef.current, event, margin, seriesStyles, barSeriesStyle, allowTooltipRef.current && showWindowedMinMaxBars, mouseOverHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMinMax), BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMinMax))
219
- .on("mouseleave", event => handleMouseLeaveSeries(series.name, event.currentTarget, seriesStyles, barSeriesStyle, mouseLeaveHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMinMax), BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMinMax));
175
+ drawBar(context2D, windowedBar, barStyleFor(showWindowedMinMaxBars, windowedBarStyle));
176
+ newGeometry.set(`${series.name}::windowedMinMax`, {
177
+ points: [],
178
+ rects: [{
179
+ x: windowedBar.upperX + margin.left,
180
+ y: windowedBar.upperY + margin.top,
181
+ width: windowedBar.width,
182
+ height: windowedBar.height
183
+ }],
184
+ hitRadius: 0
185
+ });
220
186
  //
221
187
  // mean line
222
- const meanLineY = yAxis.scale(((_c = statsRef.current.valueStatsForSeries.get(series.name)) === null || _c === void 0 ? void 0 : _c.mean) || 0);
223
- svg
224
- .select(`#${series.name}-${chartId}-bar`)
225
- .selectAll(classIdFor(BAR_CHART_CLASS_IDS.meanValue))
226
- .data(showMeanValueLines ? plotData : [])
227
- .join(enter => lineFor(enter.append('line').attr('class', BAR_CHART_CLASS_IDS.meanValue), {
228
- x1: () => lower(x), y1: () => meanLineY,
229
- x2: () => upper(x), y2: () => meanLineY
230
- }, meanValueLineStyle.regular), update => lineFor(update, {
231
- x1: () => lower(x), y1: () => meanLineY,
232
- x2: () => upper(x), y2: () => meanLineY
233
- }, meanValueLineStyle.regular), exit => exit.remove())
234
- .on("mouseover", (event) => handleMouseOverBar(container, yAxis, series, statsRef.current, event, margin, seriesStyles, barSeriesStyle, allowTooltipRef.current && showMeanValueLines, mouseOverHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.meanValue), BAR_CHART_TOOLTIP_PROVIDER_IDS.meanValue))
235
- .on("mouseleave", event => handleMouseLeaveSeries(series.name, event.currentTarget, seriesStyles, barSeriesStyle, mouseLeaveHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.meanValue), BAR_CHART_TOOLTIP_PROVIDER_IDS.meanValue));
236
- const windowedMeanLineY = yAxis.scale(isNaN(seriesWindowedStats.mean) ? 0 : seriesWindowedStats.mean);
237
- svg
238
- .select(`#${series.name}-${chartId}-bar`)
239
- .selectAll(classIdFor(BAR_CHART_CLASS_IDS.windowedMeanValue))
240
- .data(showWindowedMeanValueLines ? plotData : [])
241
- .join(enter => lineFor(enter.append('line').attr('class', BAR_CHART_CLASS_IDS.windowedMeanValue), {
242
- x1: () => lower(x), y1: () => windowedMeanLineY,
243
- x2: () => upper(x), y2: () => windowedMeanLineY
244
- }, windowedMeanLineStyle.regular), update => lineFor(update, {
245
- x1: () => lower(x), y1: () => windowedMeanLineY,
246
- x2: () => upper(x), y2: () => windowedMeanLineY
247
- }, windowedMeanLineStyle.regular), exit => exit.remove())
248
- .on("mouseover", (event) => handleMouseOverBar(container, yAxis, series, statsRef.current, event, margin, seriesStyles, barSeriesStyle, allowTooltipRef.current && showWindowedMeanValueLines, mouseOverHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMeanValue), BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMeanValue))
249
- .on("mouseleave", event => handleMouseLeaveSeries(series.name, event.currentTarget, seriesStyles, barSeriesStyle, mouseLeaveHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMeanValue), BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMeanValue));
188
+ if (showMeanValueLines) {
189
+ const meanLineY = yAxis.scale(((_c = statsRef.current.valueStatsForSeries.get(series.name)) === null || _c === void 0 ? void 0 : _c.mean) || 0);
190
+ drawLine(context2D, lower(x), meanLineY, upper(x), meanLineY, meanValueLineStyle.regular);
191
+ newGeometry.set(`${series.name}::meanValue`, {
192
+ points: [],
193
+ segments: [[
194
+ [lower(x) + margin.left, meanLineY + margin.top],
195
+ [upper(x) + margin.left, meanLineY + margin.top]
196
+ ]],
197
+ hitRadius: Math.max(4, (_d = meanValueLineStyle.regular.width) !== null && _d !== void 0 ? _d : 1)
198
+ });
199
+ }
200
+ //
201
+ // windowed-mean line
202
+ if (showWindowedMeanValueLines) {
203
+ const windowedMeanLineY = yAxis.scale(isNaN(seriesWindowedStats.mean) ? 0 : seriesWindowedStats.mean);
204
+ const isHovered = (hovered === null || hovered === void 0 ? void 0 : hovered.seriesName) === series.name && hovered.elementType === 'windowedMeanValue';
205
+ const style = isHovered ? windowedMeanLineStyle.highlight : windowedMeanLineStyle.regular;
206
+ drawLine(context2D, lower(x), windowedMeanLineY, upper(x), windowedMeanLineY, style);
207
+ newGeometry.set(`${series.name}::windowedMeanValue`, {
208
+ points: [],
209
+ segments: [[
210
+ [lower(x) + margin.left, windowedMeanLineY + margin.top],
211
+ [upper(x) + margin.left, windowedMeanLineY + margin.top]
212
+ ]],
213
+ hitRadius: Math.max(4, (_e = style.width) !== null && _e !== void 0 ? _e : 1)
214
+ });
215
+ }
250
216
  }
251
217
  //
252
- // value lines
253
- svg
254
- .select(`#${series.name}-${chartId}-bar`)
255
- .selectAll(classIdFor(BAR_CHART_CLASS_IDS.currentValue))
256
- .data(showValueLines ? plotData : [])
257
- .join(enter => lineFor(enter.append('line').attr('class', BAR_CHART_CLASS_IDS.currentValue), {
258
- x1: () => lower(x), y1: datum => yAxis.scale(datum.value),
259
- x2: () => upper(x), y2: datum => yAxis.scale(datum.value)
260
- }, valueLineStyle.regular), update => lineFor(update, {
261
- x1: () => lower(x), y1: datum => yAxis.scale(datum.value),
262
- x2: () => upper(x), y2: datum => yAxis.scale(datum.value)
263
- }, valueLineStyle.regular), exit => exit.remove())
264
- .on("mouseover", (event) => handleMouseOverBar(container, yAxis, series, statsRef.current, event, margin, seriesStyles, barSeriesStyle, allowTooltipRef.current && showValueLines, mouseOverHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.currentValue), BAR_CHART_TOOLTIP_PROVIDER_IDS.currentValue))
265
- .on("mouseleave", event => handleMouseLeaveSeries(series.name, event.currentTarget, seriesStyles, barSeriesStyle, mouseLeaveHandlerFor(`tooltip-${chartId}`, BAR_CHART_TOOLTIP_PROVIDER_IDS.currentValue), BAR_CHART_TOOLTIP_PROVIDER_IDS.currentValue));
218
+ // value line
219
+ if (showValueLines) {
220
+ const datum = plotData[0];
221
+ const valueLineY = yAxis.scale(datum.value);
222
+ const isHovered = (hovered === null || hovered === void 0 ? void 0 : hovered.seriesName) === series.name && hovered.elementType === 'currentValue';
223
+ const style = isHovered ? valueLineStyle.highlight : valueLineStyle.regular;
224
+ drawLine(context2D, lower(x), valueLineY, upper(x), valueLineY, style);
225
+ newGeometry.set(`${series.name}::currentValue`, {
226
+ points: [],
227
+ segments: [[
228
+ [lower(x) + margin.left, valueLineY + margin.top],
229
+ [upper(x) + margin.left, valueLineY + margin.top]
230
+ ]],
231
+ hitRadius: Math.max(4, (_f = style.width) !== null && _f !== void 0 ? _f : 1)
232
+ });
233
+ }
266
234
  });
267
- }
235
+ geometryRef.current = newGeometry;
236
+ context2D.restore();
237
+ };
238
+ /**
239
+ * Grows the auto-scaling y-axes (see `ContinuousAxis`'s `autoScale` prop) to fit what's
240
+ * shown of the series whose categories are on screen (within the x-axis' current,
241
+ * possibly zoomed, window): the min/max bars, the windowed min/max bars, the mean and
242
+ * windowed-mean lines, and the value lines -- each only when it's shown. Registered to
243
+ * run before the axes draw (they're at z-index 0), so the axes and the bars are drawn
244
+ * with the grown domain in the same frame.
245
+ */
246
+ const autoScaleYAxes = () => {
247
+ const extents = new Map();
248
+ dataRef.current.forEach(series => {
249
+ if (!series.name.match(seriesFilter) || series.data.length === 0)
250
+ return;
251
+ const [xAxis, yAxis] = axesFor(series.name, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
252
+ if (xAxis === undefined || (yAxis === null || yAxis === void 0 ? void 0 : yAxis.autoScale) === undefined)
253
+ return;
254
+ // only the categories (at least partly) on screen
255
+ const x = xAxis.scale(series.name);
256
+ if (x === undefined || x + xAxis.scale.bandwidth() <= 0 || x >= plotDimensions.width)
257
+ return;
258
+ // what's shown of the series (mirrors the draw function above)
259
+ const values = [];
260
+ const stats = statsRef.current.valueStatsForSeries.get(series.name);
261
+ if (showMinMaxBars && stats !== undefined)
262
+ values.push(stats.min.value, stats.max.value);
263
+ const windowedStats = statsRef.current.windowedValueStatsForSeries.get(series.name);
264
+ if (windowedStats !== undefined) {
265
+ if (showWindowedMinMaxBars)
266
+ values.push(windowedStats.min.value, windowedStats.max.value);
267
+ if (showMeanValueLines && stats !== undefined)
268
+ values.push(stats.mean);
269
+ if (showWindowedMeanValueLines)
270
+ values.push(windowedStats.mean);
271
+ }
272
+ if (showValueLines)
273
+ values.push(series.data[series.data.length - 1].value);
274
+ const seriesExtent = extentOf(values, yAxis.scale);
275
+ if (seriesExtent === undefined)
276
+ return;
277
+ const extent = extents.get(yAxis.axisId);
278
+ extents.set(yAxis.axisId, extent === undefined ? seriesExtent : extentWith(extentWith(extent, seriesExtent[0]), seriesExtent[1]));
279
+ });
280
+ // (the y-axes are continuous axes, even though this plot's axes context is typed
281
+ // for its ordinal x-axes)
282
+ growAutoScaledYAxes(extents, {
283
+ yAxes: yAxesState.axes,
284
+ axisRangeFor,
285
+ updateAxisRanges: updateAxisRanges,
286
+ });
287
+ };
288
+ cc.register(`bar-plot-autoscale-${chartId}`, autoScaleYAxes, -10);
289
+ cc.register(`bar-plot-${chartId}`, draw, 10);
290
+ cc.requestRedraw();
268
291
  }, [
269
- container,
270
- panEnabled, zoomEnabled,
271
- onPan, onZoom,
272
- plotDimensions, margin, zoomKeyModifiersRequired,
273
- axisAssignments, xAxesState, yAxesState,
274
- barMargin, seriesStyles, barSeriesStyle,
275
- seriesFilter,
276
- chartId,
277
- showValueLines,
278
- showMinMaxBars,
279
- mouseOverHandlerFor, mouseLeaveHandlerFor,
280
- showMeanValueLines,
281
- showWindowedMeanValueLines,
282
- showWindowedMinMaxBars
292
+ chartId, plotDimensions, axisAssignments, xAxesState, yAxesState, barMargin, seriesStyles,
293
+ barSeriesStyle, seriesFilter, showValueLines, showMinMaxBars, showMeanValueLines,
294
+ showWindowedMeanValueLines, showWindowedMinMaxBars, axisRangeFor, updateAxisRanges,
295
+ margin.left, margin.top
283
296
  ]);
297
+ // new data, new scale: restarts the auto-scaling y-axes when the data source is replaced
298
+ useAutoScaleRestart(dataSource, {
299
+ yAxes: yAxesState.axes,
300
+ axisRangeFor,
301
+ updateAxisRanges: updateAxisRanges,
302
+ });
284
303
  // need to keep the function references for use by the subscription, which forms a closure
285
304
  // on them. without the references, the closures become stale, and resizing during streaming
286
305
  // doesn't work properly
287
- const updatePlotRef = useRef(noop);
306
+ const updatePlotRef = useRef(updatePlot);
288
307
  useEffect(() => {
289
- if (mainG != null && container != null) {
290
- // when the update plot function doesn't yet exist, then create the container holding the plot
291
- const clipPathId = setClipPathG(chartId, mainG, plotDimensions);
292
- if (updatePlotRef.current === noop) {
293
- mainG
294
- .selectAll('g')
295
- .attr("clip-path", `url(#${clipPathId})`)
296
- .data(dataRef.current)
297
- .enter()
298
- .append('g')
299
- .attr('class', 'spikes-series')
300
- .attr('id', series => `${series.name}-${chartId}-bar`)
301
- .attr('transform', `translate(${margin.left}, ${margin.top})`);
302
- }
303
- else {
304
- mainG
305
- .selectAll('g')
306
- .attr("clip-path", `url(#${clipPathId})`);
307
- }
308
- updatePlotRef.current = updatePlot;
308
+ updatePlotRef.current = updatePlot;
309
+ }, [updatePlot]);
310
+ useEffect(() => {
311
+ currentTimeRef.current = 0;
312
+ }, [xAxesState]);
313
+ // set the axis assignments needed if a tooltip is being used
314
+ useEffect(() => {
315
+ setAxisAssignments(axisAssignments);
316
+ }, [axisAssignments, setAxisAssignments]);
317
+ // calculates the distinct series IDs that cover all the series in the plot
318
+ const axesForSeries = useMemo(() => axesForSeriesGen(initialData, axisAssignments, xAxesState), [initialData, axisAssignments, xAxesState]);
319
+ // redraws the plot for newly arrived data and reports the chart time, using the updatePlot
320
+ // reference (to avoid a stale updatePlot). Deliberately leaves the axes' ranges
321
+ // (`ordinalRangesRef`) alone: the ordinal axes don't scroll as data arrives, so only this plot's
322
+ // own zoom, pan, and resize handling changes them -- replacing them here (as a previous version
323
+ // did, with the y-axes' ranges) left the x-axis zoom/pan handlers with nothing to act on until
324
+ // something else happened to rebuild the map.
325
+ const updateTimingAndPlot = useCallback(() => {
326
+ if (canvasContext !== null) {
327
+ // (one redraw request is enough: `onUpdateChartTime` only reports the time to the
328
+ // application, and redraw requests are coalesced into one animation frame anyway)
329
+ updatePlotRef.current(canvasContext);
330
+ onUpdateChartTime(currentTimeRef.current);
309
331
  }
310
- }, [chartId, container, mainG, margin, plotDimensions, updatePlot]);
311
- // memoized function for subscribing to the chart-data observable
312
- const subscribe = useCallback(() => {
313
- if (seriesObservable === undefined || mainG === null)
314
- return undefined;
315
- return subscriptionOrdinalXFor(seriesObservable, onSubscribe, windowingTime, axisAssignments, yAxesState, onUpdateData, dropDataAfter, updateTimingAndPlot,
316
- // as new data flows into the subscription, the subscription
317
- // updates this map directly (for performance)
318
- seriesRef.current, statsRef, (currentTime) => currentTimeRef.current = currentTime, AxisInterval.from(0, plotDimensions.width));
319
- }, [
320
- axisAssignments, dropDataAfter, mainG,
321
- onSubscribe, onUpdateData,
322
- seriesObservable, updateTimingAndPlot, windowingTime, yAxesState,
323
- plotDimensions.width
324
- ]);
332
+ }, [canvasContext, onUpdateChartTime]);
333
+ // when the initial data changes, then reset the plot. note that the initial data doesn't change
334
+ // during the normal course of updates from the data source, only when the data source is replaced.
325
335
  useEffect(() => {
326
- if (container && mainG) {
336
+ dataRef.current = initialData.slice();
337
+ seriesRef.current = new Map(initialData.map(series => [series.name, series]));
338
+ currentTimeRef.current = 0;
339
+ statsRef.current = statsFrom(dataSource, dataRef.current);
340
+ }, [initialData, dataSource]);
341
+ /**
342
+ * Adjusts the ordinal x-axes' ranges when the plot is dragged to the left or right (the caller
343
+ * redraws the plot)
344
+ * @param x The amount that the plot is dragged
345
+ * @param plotDimensions The dimensions of the plot
346
+ * @param series An array of series names
347
+ * @param ranges A map holding the axis ID and its associated range
348
+ */
349
+ const onPan = useCallback((x, plotDimensions, series, ranges) => ordinalPanHandler(axesForSeries, margin, setAxisIntervalFor, xAxesState)(x, plotDimensions, series, ranges), [axesForSeries, margin, setAxisIntervalFor, xAxesState]);
350
+ /**
351
+ * Called when the user uses the scroll wheel (or scroll gesture) to zoom in or out. Zooms in/out
352
+ * at the location of the mouse when the scroll wheel or gesture was applied.
353
+ * @param zoomFactor The *cumulative* zoom scale factor for this event -- d3-zoom's own
354
+ * `event.transform.k`, passed through unmodified. See {@link OrdinalAxisRange.scaledCumulative}
355
+ * for why the ordinal x-axis needs this cumulative factor (from which it derives the
356
+ * incremental step itself, and which it snaps back to `.original` at exactly 1).
357
+ * @param x The x-position of the mouse when the scroll wheel or gesture is used
358
+ * @param plotDimensions The dimensions of the plot
359
+ * @param ranges A map holding the axis ID and its associated range
360
+ */
361
+ const onZoom = useCallback((zoomFactor, x, plotDimensions, ranges) => ordinalAxisZoomHandler(axesForSeries, margin, setAxisIntervalFor, setOriginalAxisIntervalFor, xAxesState)(zoomFactor, x, plotDimensions, ranges), [axesForSeries, margin, setAxisIntervalFor, setOriginalAxisIntervalFor, xAxesState]);
362
+ // holds the current per-axis ordinal ranges, kept in sync by the effect below. Replaces
363
+ // threading `ordinalRanges` through as an explicit `updatePlot` parameter, so the pan/zoom
364
+ // handlers (now set up once, in a separate effect below, rather than inside `updatePlot`
365
+ // itself) can always read the current ranges without needing `updatePlot` to be recreated
366
+ // every time the ranges change.
367
+ const ordinalRangesRef = useRef(new Map());
368
+ // hands the current zoom/pan state (the ordinal x-axes' ranges, as fractions of their
369
+ // original extent, and d3-zoom's cumulative `k`) to the `onZoomStateChange` callback
370
+ const reportZoomState = useCallback((cc) => {
371
+ const ranges = {};
372
+ ordinalRangesRef.current.forEach((range, axisId) => {
373
+ const extent = range.original.measure();
374
+ if (xAxesState.axes.has(axisId) && extent > 0) {
375
+ ranges[axisId] = [
376
+ (range.current.start - range.original.start) / extent,
377
+ (range.current.end - range.original.start) / extent
378
+ ];
379
+ }
380
+ });
381
+ onZoomStateChange({ k: d3.zoomTransform(cc.canvas).k, ranges });
382
+ }, [onZoomStateChange, xAxesState.axes]);
383
+ // panning (dragging) and zooming (the mouse wheel) -- see `useCanvasZoomPan`. The ordinal zoom
384
+ // takes d3-zoom's cumulative scale (`k`), rather than the incremental factor, so that it can
385
+ // snap back to the original range exactly when fully zoomed out (see `OrdinalAxisRange.scale`)
386
+ const { setZoomScale } = useCanvasZoomPan(canvasContext, {
387
+ panEnabled,
388
+ zoomEnabled,
389
+ keyModifiersRequired: zoomKeyModifiersRequired,
390
+ scaleExtent: [1, 10],
391
+ // (an ordinal axis zooms in as d3-zoom's scale goes up, the opposite way to the other
392
+ // plots' continuous axes, so the wheel is inverted to zoom the same way as they do)
393
+ invertWheel: true,
394
+ translateExtent: [[margin.left, margin.top], [plotDimensions.width, plotDimensions.height]],
395
+ // (tooltips are suppressed while panning, so that one isn't left behind)
396
+ onPanStart: () => {
397
+ allowTooltipRef.current = false;
398
+ },
399
+ onPan: dx => {
400
+ if (canvasContext === null)
401
+ return;
402
+ onPan(dx, plotDimensions, dataRef.current.map(series => series.name), ordinalRangesRef.current);
403
+ updatePlotRef.current(canvasContext);
404
+ },
405
+ onPanEnd: () => {
406
+ var _a;
407
+ allowTooltipRef.current = !((_a = dataSource === null || dataSource === void 0 ? void 0 : dataSource.running) !== null && _a !== void 0 ? _a : false);
408
+ if (canvasContext !== null)
409
+ reportZoomState(canvasContext);
410
+ },
411
+ onZoom: ({ k, x }) => {
412
+ if (canvasContext === null)
413
+ return;
414
+ onZoom(k, x - margin.left, plotDimensions, ordinalRangesRef.current);
415
+ updatePlotRef.current(canvasContext);
416
+ reportZoomState(canvasContext);
417
+ },
418
+ onZoomReset,
419
+ // restores each axis's range to its original
420
+ resetView: () => {
421
+ ordinalRangesRef.current.forEach((range, axisId) => {
422
+ xAxesState.axisFor(axisId).ifPresent(axis => {
423
+ ordinalRangesRef.current.set(axisId, range.update(range.original.start, range.original.end));
424
+ setAxisIntervalFor(axisId, range.original);
425
+ axis.update(axis.scale.domain(), range.original, range.original, plotDimensions, margin);
426
+ });
427
+ });
428
+ if (canvasContext !== null)
429
+ updatePlotRef.current(canvasContext);
430
+ },
431
+ });
432
+ // the zoom state to restore, captured once at mount (see the `zoomState` prop); cleared once
433
+ // it has been applied (see `restoreZoomState` below), so it's only ever applied once
434
+ const pendingZoomStateRef = useRef(zoomState);
435
+ // applies the pending zoom state (if any) to the ordinal x-axes' ranges and to d3-zoom's
436
+ // transform on the canvas -- a remounted plot has a brand-new canvas, whose d3-zoom transform
437
+ // starts at identity (k = 1). Both must be restored together: the ordinal zoom math derives
438
+ // its incremental step from d3's cumulative `k` relative to the range's current/original width
439
+ // ratio, and treats `k === 1` as "snap back to fully zoomed out" (see
440
+ // `OrdinalAxisRange.scaledCumulative`), so restoring the ranges without `k` would make the
441
+ // very next wheel tick jump. Waits (leaving the state pending) until every axis in the
442
+ // snapshot exists, since the axes register themselves with the chart asynchronously.
443
+ const restoreZoomState = useCallback(() => {
444
+ const pending = pendingZoomStateRef.current;
445
+ if (pending === undefined)
446
+ return;
447
+ const axisIds = Object.keys(pending.ranges);
448
+ const ready = axisIds.every(axisId => ordinalRangesRef.current.has(axisId) && xAxesState.axisFor(axisId).getOrUndefined() !== undefined);
449
+ if (!ready || plotDimensions.width <= 0)
450
+ return;
451
+ axisIds.forEach(axisId => {
452
+ const range = ordinalRangesRef.current.get(axisId);
453
+ const axis = xAxesState.axisFor(axisId).getOrUndefined();
454
+ if (range === undefined || axis === undefined)
455
+ return;
456
+ const [startFraction, endFraction] = pending.ranges[axisId];
457
+ const { start: originalStart } = range.original;
458
+ const extent = range.original.measure();
459
+ const current = AxisInterval.from(originalStart + startFraction * extent, originalStart + endFraction * extent);
460
+ ordinalRangesRef.current.set(axisId, range.update(current.start, current.end));
461
+ setAxisIntervalFor(axisId, current);
462
+ axis.update(axis.scale.domain(), current, range.original, plotDimensions, margin);
463
+ });
464
+ // (set directly, without dispatching a "zoom" event -- see `setZoomScale`)
465
+ setZoomScale(pending.k);
466
+ pendingZoomStateRef.current = undefined;
467
+ }, [margin, plotDimensions, setAxisIntervalFor, xAxesState, setZoomScale]);
468
+ useEffect(() => {
469
+ if (canvasContext) {
327
470
  const ordinalAxesRanges = axesRanges();
328
471
  // so this gets a bit complicated. the ordinal-ranges need to be updated whenever the ordinal-ranges
329
472
  // change. for example, when the window is resized, and then we need to update the
330
473
  // ordinal-range. however, we want to keep the ordinal-ranges to reflect their original scale so that
331
474
  // we can zoom properly (so the updates can't fuck with the scale).
332
475
  if (ordinalAxesRanges.size === 0) {
333
- // when no time-ranges have yet been created, then create them and hold on to a mutable
334
- // reference to them
335
- updatePlot(ordinalAxisRanges(xAxesState.axes, AxisInterval.from(0, plotDimensions.width)), mainG);
476
+ // when no time-ranges have yet been created, then create them and populate the
477
+ // existing ref's map in place (rather than replacing it -- reassigning `.current`
478
+ // once it's already in play elsewhere, e.g. the zoom/pan handlers, isn't allowed
479
+ // by react-hooks/immutability)
480
+ ordinalRangesRef.current.clear();
481
+ ordinalAxisRanges(xAxesState.axes)
482
+ .forEach((range, id) => ordinalRangesRef.current.set(id, range));
336
483
  }
337
484
  else {
338
485
  // when the ordinal-ranges already exist, then we want to update the ordinal-ranges for each
@@ -350,64 +497,194 @@ export function BarPlot(props) {
350
497
  rangesMap.set(id, range.update(start, end));
351
498
  });
352
499
  });
353
- updatePlot(ordinalAxesRanges, mainG);
500
+ ordinalRangesRef.current.clear();
501
+ ordinalAxesRanges.forEach((range, id) => ordinalRangesRef.current.set(id, range));
354
502
  }
503
+ // restore a zoom state handed in from a previous instance (only does anything the
504
+ // first time the axes are all available -- see `restoreZoomState`)
505
+ restoreZoomState();
506
+ updatePlot(canvasContext);
355
507
  }
356
- }, [axesRanges, container, mainG, plotDimensions.width, updatePlot, xAxesState.axes]);
357
- // subscribe/unsubscribe to the observable chart data. when the `shouldSubscribe`
358
- // is changed to `true` and we haven't subscribed yet, then subscribe. when the
359
- // `shouldSubscribe` is `false` and we had subscribed, then unsubscribe. otherwise,
360
- // do nothing.
508
+ }, [axesRanges, canvasContext, plotDimensions.width, updatePlot, xAxesState.axes, restoreZoomState]);
509
+ // wires up a single mousemove/mouseleave listener on the shared canvas to replace the old
510
+ // per-element SVG mouseover/mouseleave handlers. Hit-tests the mouse position against the
511
+ // last-drawn geometry (see `geometryRef`, populated by the draw function above), keyed per
512
+ // `${seriesName}::${elementType}` so the five overlaid elements resolve independently.
361
513
  useEffect(() => {
362
- var _a;
363
- if (shouldSubscribe && subscriptionRef.current === undefined) {
364
- subscriptionRef.current = subscribe();
365
- allowTooltipRef.current = false;
366
- }
367
- else if (!shouldSubscribe && subscriptionRef.current !== undefined) {
368
- (_a = subscriptionRef.current) === null || _a === void 0 ? void 0 : _a.unsubscribe();
369
- subscriptionRef.current = undefined;
514
+ if (!canvasContext)
515
+ return;
516
+ const canvas = canvasContext.canvas;
517
+ // highlights (or un-highlights) the x- and y-axes a series is plotted against --
518
+ // keyed on the series name alone (not the specific hovered element type), so moving
519
+ // the mouse between a series' own bar/lines doesn't flicker the highlight off and on.
520
+ // Unlike Scatter/Outlier, bar series styles don't carry a single flat highlight
521
+ // color/width (they're nested per element type), so this uses the axis' own default
522
+ // highlight styling rather than trying to match a specific element's highlight style.
523
+ const highlightAxesFor = (seriesName, isHighlighted) => {
524
+ if (!highlightAxesOnMouseOver)
525
+ return;
526
+ const [xAxis, yAxis] = axesFor(seriesName, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
527
+ xAxis === null || xAxis === void 0 ? void 0 : xAxis.setHighlighted(isHighlighted);
528
+ yAxis === null || yAxis === void 0 ? void 0 : yAxis.setHighlighted(isHighlighted);
529
+ };
530
+ const handleMove = (event) => {
531
+ const [x, y] = canvasLocalPoint(event, canvas);
532
+ const hit = seriesAt(x, y, geometryRef.current);
533
+ // geometry keys are "${seriesName}::${elementType}"; split back apart
534
+ const [hitSeriesName, hitElementType] = hit !== undefined ? hit.name.split('::') : [undefined, undefined];
535
+ const previous = lastHoveredRef.current;
536
+ const sameAsBefore = previous !== undefined && hitSeriesName === previous.seriesName && hitElementType === previous.elementType;
537
+ if ((previous === null || previous === void 0 ? void 0 : previous.seriesName) !== hitSeriesName) {
538
+ if (previous !== undefined)
539
+ highlightAxesFor(previous.seriesName, false);
540
+ if (hitSeriesName !== undefined)
541
+ highlightAxesFor(hitSeriesName, true);
542
+ }
543
+ if (!sameAsBefore) {
544
+ if (previous !== undefined) {
545
+ handleMouseLeaveSeries(previous.seriesName, mouseLeaveHandlerFor(`tooltip-${chartId}`, PROVIDER_ID_FOR_ELEMENT_TYPE[previous.elementType]));
546
+ }
547
+ if (hitSeriesName !== undefined && hitElementType !== undefined) {
548
+ const series = seriesRef.current.get(hitSeriesName);
549
+ const yAxis = axesFor(hitSeriesName, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined())[1];
550
+ const showingByType = {
551
+ minMax: showMinMaxBars,
552
+ windowedMinMax: showWindowedMinMaxBars,
553
+ meanValue: showMeanValueLines,
554
+ windowedMeanValue: showWindowedMeanValueLines,
555
+ currentValue: showValueLines,
556
+ };
557
+ if (series !== undefined && yAxis !== undefined && allowTooltipRef.current && showingByType[hitElementType]) {
558
+ handleMouseOverBar(yAxis, series, statsRef.current, [x, y], margin, mouseOverHandlerFor(`tooltip-${chartId}`, PROVIDER_ID_FOR_ELEMENT_TYPE[hitElementType]));
559
+ }
560
+ }
561
+ lastHoveredRef.current = hitSeriesName !== undefined && hitElementType !== undefined ?
562
+ { seriesName: hitSeriesName, elementType: hitElementType } :
563
+ undefined;
564
+ // the value-line and windowed-mean-line highlight depends on hover state, so
565
+ // request a redraw when it changes
566
+ canvasContext.requestRedraw();
567
+ }
568
+ };
569
+ const handleLeaveCanvas = () => {
570
+ const previous = lastHoveredRef.current;
571
+ if (previous !== undefined) {
572
+ handleMouseLeaveSeries(previous.seriesName, mouseLeaveHandlerFor(`tooltip-${chartId}`, PROVIDER_ID_FOR_ELEMENT_TYPE[previous.elementType]));
573
+ highlightAxesFor(previous.seriesName, false);
574
+ lastHoveredRef.current = undefined;
575
+ canvasContext.requestRedraw();
576
+ }
577
+ };
578
+ canvas.addEventListener('mousemove', handleMove);
579
+ canvas.addEventListener('mouseleave', handleLeaveCanvas);
580
+ return () => {
581
+ canvas.removeEventListener('mousemove', handleMove);
582
+ canvas.removeEventListener('mouseleave', handleLeaveCanvas);
583
+ };
584
+ }, [
585
+ canvasContext, chartId, margin, axisAssignments, xAxesState, yAxesState,
586
+ mouseOverHandlerFor, mouseLeaveHandlerFor,
587
+ showMinMaxBars, showWindowedMinMaxBars, showMeanValueLines, showWindowedMeanValueLines, showValueLines,
588
+ highlightAxesOnMouseOver
589
+ ]);
590
+ // the latest `updateTimingAndPlot`, for the view driver to call -- the driver is created once
591
+ // per run (see below), so it must not capture a stale one (e.g. bound to an older canvas)
592
+ const updateTimingAndPlotRef = useRef(updateTimingAndPlot);
593
+ useEffect(() => {
594
+ updateTimingAndPlotRef.current = updateTimingAndPlot;
595
+ }, [updateTimingAndPlot]);
596
+ // creates the view driver that keeps this plot's view in step with the data source, using the
597
+ // current settings -- see `useStreamingTimeAxes`'s identical effect event
598
+ const createViewDriver = useEffectEvent((source) => ordinalViewDriverFor(source, windowingTime, () => updateTimingAndPlotRef.current(), currentTime => currentTimeRef.current = currentTime));
599
+ // while the data source is running (and this plot has a canvas), drive the view from the
600
+ // data source's updates -- see `useStreamingTimeAxes`'s identical effect. The driver belongs to this plot
601
+ // instance alone and is always torn down with it.
602
+ useEffect(() => {
603
+ if (dataSource === undefined || !running || canvasContext === null)
604
+ return;
605
+ allowTooltipRef.current = false;
606
+ const driver = createViewDriver(dataSource);
607
+ return () => {
608
+ driver.unsubscribe();
370
609
  allowTooltipRef.current = true;
610
+ };
611
+ }, [dataSource, running, canvasContext]);
612
+ // this plot needs a data source (see the `Chart`'s `dataSource` prop)
613
+ useEffect(() => {
614
+ if (dataSource === undefined) {
615
+ console.error("BarPlot requires a data source; set the enclosing Chart's `dataSource` prop");
371
616
  }
372
- }, [shouldSubscribe, subscribe]);
617
+ }, [dataSource]);
618
+ // unregister this plot's draw function on unmount
619
+ useEffect(() => {
620
+ return () => {
621
+ if (canvasContext) {
622
+ canvasContext.unregister(`bar-plot-autoscale-${chartId}`);
623
+ canvasContext.unregister(`bar-plot-${chartId}`);
624
+ }
625
+ };
626
+ }, [canvasContext, chartId]);
373
627
  return null;
374
628
  }
629
+ /**
630
+ * The bar style, made fully transparent when the bar isn't shown
631
+ * @param isVisible Whether the bar is shown
632
+ * @param style The bar's style
633
+ * @return The style (with its fill and stroke opacities 0 when the bar isn't shown)
634
+ */
375
635
  function barStyleFor(isVisible, style) {
376
- return Object.assign(Object.assign({}, style), { fill: updateOpacityFor(isVisible, style.fill), stroke: updateOpacityFor(isVisible, style.stroke) });
636
+ return {
637
+ ...style,
638
+ fill: updateOpacityFor(isVisible, style.fill),
639
+ stroke: updateOpacityFor(isVisible, style.stroke)
640
+ };
377
641
  }
642
+ /**
643
+ * The fill or stroke style, made fully transparent when its element isn't shown
644
+ * @param isVisible Whether the element is shown
645
+ * @param style The fill or stroke style
646
+ * @return The style (with an opacity of 0 when the element isn't shown)
647
+ */
378
648
  function updateOpacityFor(isVisible, style) {
379
- return Object.assign(Object.assign({}, style), { opacity: isVisible ? style.opacity : 0 });
649
+ return {
650
+ ...style,
651
+ opacity: isVisible ? style.opacity : 0
652
+ };
380
653
  }
381
654
  /**
382
- * Sets the attributes for the bar based on the d3 selection
383
- * @param selection The d3 selection (rect SVG element)
384
- * @param dimensions The bar dimensions
655
+ * Draws a bar (rectangle) onto the canvas context. Replaces the old `barFor`, which set SVG
656
+ * `<rect>` attributes via a d3 selection.
657
+ * @param context The canvas 2D context
658
+ * @param dimensions The bar's dimensions
385
659
  * @param style The bar style holding the fill and stroke styles
386
- * @return The updated SVG selection (rect SVG element)
387
660
  */
388
- function barFor(selection, dimensions, style) {
389
- selection
390
- .attr('x', () => dimensions.upperX)
391
- .attr('y', () => dimensions.upperY)
392
- .attr('width', () => dimensions.width)
393
- .attr('height', () => dimensions.height);
394
- return applyStrokeStylesTo(applyFillStylesTo(selection, style.fill), style.stroke);
661
+ function drawBar(context, dimensions, style) {
662
+ var _a;
663
+ if (dimensions.width <= 0 || dimensions.height <= 0)
664
+ return;
665
+ applyFillStyle(context, style.fill);
666
+ context.fillRect(dimensions.upperX, dimensions.upperY, dimensions.width, dimensions.height);
667
+ if (((_a = style.stroke.width) !== null && _a !== void 0 ? _a : 0) > 0) {
668
+ applyStrokeStyle(context, style.stroke);
669
+ context.strokeRect(dimensions.upperX, dimensions.upperY, dimensions.width, dimensions.height);
670
+ }
395
671
  }
396
672
  /**
397
- * Creates the line segment for values and means
398
- * @param selection The d3 selection (rect SVG element)
399
- * @param pathSegment The object containing functions for extracting the (x1, y1) and (x2, y2)
400
- * points for the path segment
673
+ * Draws a horizontal line segment (used for the value/mean/windowed-mean lines) onto the canvas
674
+ * context. Replaces the old `lineFor`, which set SVG `<line>` attributes via a d3 selection.
675
+ * @param context The canvas 2D context
676
+ * @param x1 The line's start x-coordinate
677
+ * @param y1 The line's start y-coordinate
678
+ * @param x2 The line's end x-coordinate
679
+ * @param y2 The line's end y-coordinate
401
680
  * @param strokeStyle The stroke style
402
- * @return The updated SVG selection (rect SVG element)
403
681
  */
404
- function lineFor(selection, pathSegment, strokeStyle) {
405
- selection
406
- .attr('x1', datum => pathSegment.x1(datum))
407
- .attr('y1', datum => pathSegment.y1(datum))
408
- .attr('x2', datum => pathSegment.x2(datum))
409
- .attr('y2', datum => pathSegment.y2(datum));
410
- return applyStrokeStylesTo(selection, strokeStyle);
682
+ function drawLine(context, x1, y1, x2, y2, strokeStyle) {
683
+ applyStrokeStyle(context, strokeStyle);
684
+ context.beginPath();
685
+ context.moveTo(x1, y1);
686
+ context.lineTo(x2, y2);
687
+ context.stroke();
411
688
  }
412
689
  /**
413
690
  * Calculates the upper (x, y) coordinates of the bar, and the width and height of the bar
@@ -434,48 +711,48 @@ function barDimensions(widthFraction, lowerX, upperX, min, max, axis) {
434
711
  };
435
712
  }
436
713
  /**
437
- * Calculates the ordinal stats for each of the ordinal series (generally, initial data) and
438
- * returns a {@link WindowedOrdinalStats} object
439
- * @param series The array of ordinal series
440
- * @return A {@link WindowedOrdinalStats} object with the stats for each of the series
714
+ * @param dataSource The chart's data source
715
+ * @param series The series to calculate the stats for when the data source doesn't keep them
716
+ * @return The data source's (live) stats when it keeps them (i.e. an ordinal data source);
717
+ * otherwise, the stats calculated from the specified series
441
718
  */
442
- function initialOrdinalStats(series) {
443
- const ordinalStats = calculateOrdinalStats(series);
444
- return Object.assign(Object.assign({}, ordinalStats), { windowedValueStatsForSeries: copyValueStatsForSeries(ordinalStats.valueStatsForSeries) });
719
+ function statsFrom(dataSource, series) {
720
+ return dataSource !== null && typeof dataSource === 'object' && 'stats' in dataSource ?
721
+ dataSource.stats :
722
+ initialOrdinalStats(series);
445
723
  }
446
724
  /**
447
- * Attempts to locate the x- and y-axes for the specified series. If no axis is found for the
448
- * series name, then uses the default returned by the useChart() hook.
725
+ * Attempts to locate the x- and y-axes for the specified series. If the series has no axis
726
+ * assignment, then uses the default (first) x- and y-axes.
449
727
  * @param seriesName Name of the series for which to retrieve the axis
450
728
  * @param axisAssignments A map holding the series name and the associated x- and y-axes assigned
451
729
  * to that series. Note that the series in the axis-assignment map is merely a subset of the set
452
730
  * of series names.
453
731
  * @param xAxisFor The function that accepts an axis ID and returns the corresponding x-axis
454
732
  * @param yAxisFor The function that accepts an axis ID and returns the corresponding y-axis
455
- * @return A 2d tuple holding the linear x-axis as its first element and the category y-axis as
456
- * the second element.
733
+ * @return A 2d tuple holding the category x-axis as its first element and the linear y-axis as
734
+ * the second element (either is actually `undefined` when it isn't found, despite the type).
735
+ * @throws Error when the x-axis isn't a category axis, or the y-axis isn't a continuous numeric axis
457
736
  */
458
737
  function axesFor(seriesName, axisAssignments, xAxisFor, yAxisFor) {
459
738
  const axes = axisAssignments.get(seriesName);
460
739
  const xAxis = xAxisFor((axes === null || axes === void 0 ? void 0 : axes.xAxis) || "");
740
+ checkAxisType("BarPlot", "x", xAxis, AxisType.OrdinalString);
461
741
  const xAxisCategory = xAxis;
462
- if (xAxis && !xAxisCategory) {
463
- throw Error("Bar plot requires that x-axis be of type CategoryAxis");
464
- }
465
742
  const yAxis = yAxisFor((axes === null || axes === void 0 ? void 0 : axes.yAxis) || "");
743
+ checkAxisType("BarPlot", "y", yAxis, AxisType.ContinuousNumeric);
466
744
  const yAxisContinuous = yAxis;
467
- if (yAxis && !yAxisContinuous) {
468
- throw Error("Bar plot requires that y-axis be of type ContinuousNumericAxis");
469
- }
470
745
  return [xAxisCategory, yAxisContinuous];
471
746
  }
472
747
  /**
473
- * Calculates the upper and lower coordinate for the category
474
- * @param categorySize The size of the category (i.e. plot_height / num_series)
748
+ * Calculates the lower (left) and upper (right) x-coordinates of a category's lines, inside its
749
+ * margins
750
+ * @param categorySize The size of the category (i.e. plot_width / num_series)
475
751
  * @param lineWidth The width of the series line
476
- * @param margin The margin applied to the top and bottom of the spike line (vertical spacing)
477
- * @return An object with two functions, that when handed a y-coordinate, return the location
478
- * for the start (yUpper) or end (yLower) of the spikes line.
752
+ * @param margin The margin applied to the left and right of the category's lines (horizontal spacing)
753
+ * @return An object with two functions, that when handed the category's (left) x-coordinate,
754
+ * return the location of the start (lower) or end (upper) of its lines (when the category is no
755
+ * wider than the margin, the lines are just the line width long)
479
756
  */
480
757
  function xAxisCategoryBoundsFn(categorySize, lineWidth, margin) {
481
758
  if (categorySize <= margin)
@@ -489,68 +766,38 @@ function xAxisCategoryBoundsFn(categorySize, lineWidth, margin) {
489
766
  };
490
767
  }
491
768
  /**
492
- * Renders a tooltip showing for the bar in the bar chart (see {@link BarPlotTooltipContent})
493
- * @param container The chart container
769
+ * Reports a tooltip for the hovered element of a series in the bar chart (see {@link BarPlotTooltipContent}).
770
+ * Replaces the old version, which also mutated the hovered SVG element's stroke directly for the
771
+ * two element types that support a highlight (`currentValue`, `windowedMeanValue`); that highlight
772
+ * is now handled by the draw function checking the hover state (see `updatePlot`'s `draw`) rather
773
+ * than by touching an element here.
494
774
  * @param yAxis The y-axis
495
775
  * @param selectedSeries The selected series
496
776
  * @param seriesStats The statistics about the current series
497
- * @param event The mouse-over series event holding the line element
777
+ * @param mouseCoords The `[x, y]` position of the mouse, in canvas coordinates
498
778
  * @param margin The plot margin
499
- * @param barStyles The series style information (needed for (un)highlighting)
500
- * @param defaultBarSeriesStyle The default bar series style that is used if no style is found for the series
501
- * @param allowTooltip When set to `false` won't show tooltip, even if it is visible (used by pan)
502
779
  * @param mouseOverHandlerFor The handler for the mouse over (registered by the <Tooltip/>)
503
- * @param tooltipProvider The ID of the tooltip provider
504
780
  */
505
- function handleMouseOverBar(container, yAxis, selectedSeries, seriesStats, event, margin, barStyles, defaultBarSeriesStyle, allowTooltip, mouseOverHandlerFor, tooltipProvider) {
506
- // grab the time needed for the tooltip ID
507
- const [x, y] = d3.pointer(event, container);
781
+ function handleMouseOverBar(yAxis, selectedSeries, seriesStats, mouseCoords, margin, mouseOverHandlerFor) {
782
+ const [, y] = mouseCoords;
508
783
  const value = yAxis.scale.invert(y - margin.top);
509
784
  const { name: categoryName, data: selectedData } = selectedSeries;
510
- const barSeriesStyle = barStyles.get(categoryName) || defaultBarSeriesStyle;
511
- const lineStyle = lineStyleFor(tooltipProvider, barSeriesStyle);
512
- if (lineStyle !== undefined) {
513
- d3.select(event.currentTarget)
514
- .style(STROKE_COLOR, lineStyle.highlight.color)
515
- .style(STROKE_WIDTH, lineStyle.highlight.width)
516
- .style(STROKE_OPACITY, lineStyle.highlight.opacity);
517
- }
518
- if (mouseOverHandlerFor && allowTooltip) {
785
+ if (mouseOverHandlerFor) {
519
786
  // the contract for the mouse over handler is for a series
520
- mouseOverHandlerFor(categoryName, value, { series: selectedData, metadata: seriesStats }, [x, y]);
787
+ mouseOverHandlerFor(categoryName, value, { series: selectedData, metadata: seriesStats }, mouseCoords);
521
788
  }
522
789
  }
523
790
  /**
524
- * Unselects the time series and calls the mouse-leave-series handler registered for this series.
791
+ * Calls the mouse-leave-series handler registered for this series. Replaces the old version, which
792
+ * also reset the hovered SVG element's stroke color/width directly; that reset is now implicit --
793
+ * once the hover state no longer matches this element, the next redraw simply paints it in its
794
+ * normal (non-highlighted) style.
525
795
  * @param seriesName The name of the series (i.e. the neuron ID)
526
- * @param segment The SVG line element representing the spike, over which the mouse is hovering.
527
- * @param seriesStyles The styles for the series (for (un)highlighting)
528
- * @param defaultBarSeriesStyle The default bar series style that is used if no style is found for the series
529
796
  * @param mouseLeaverHandlerFor Registered handler for the series when the mouse leaves
530
- * @param tooltipProvider The tooltip provider ID for the mouse-over event
531
797
  */
532
- function handleMouseLeaveSeries(seriesName, segment, seriesStyles, defaultBarSeriesStyle, mouseLeaverHandlerFor, tooltipProvider) {
533
- const barSeriesStyle = seriesStyles.get(seriesName) || defaultBarSeriesStyle;
534
- const lineStyle = lineStyleFor(tooltipProvider, barSeriesStyle);
535
- if (lineStyle !== undefined) {
536
- d3.select(segment)
537
- .style(STROKE_COLOR, lineStyle.regular.color)
538
- .style(STROKE_WIDTH, lineStyle.regular.width)
539
- .style(STROKE_OPACITY, lineStyle.regular.opacity);
540
- }
798
+ function handleMouseLeaveSeries(seriesName, mouseLeaverHandlerFor) {
541
799
  if (mouseLeaverHandlerFor) {
542
800
  mouseLeaverHandlerFor(seriesName);
543
801
  }
544
802
  }
545
- function lineStyleFor(tooltipProvider, barSeriesStyle) {
546
- const { valueLine, windowedMeanValueLine } = barSeriesStyle;
547
- switch (tooltipProvider) {
548
- case BAR_CHART_TOOLTIP_PROVIDER_IDS.currentValue:
549
- return valueLine;
550
- case BAR_CHART_TOOLTIP_PROVIDER_IDS.windowedMeanValue:
551
- return windowedMeanValueLine;
552
- default:
553
- return undefined;
554
- }
555
- }
556
803
  //# sourceMappingURL=BarPlot.js.map