stream-charts 1.0.1 → 1.1.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 (271) hide show
  1. package/README.md +756 -343
  2. package/changes.md +7 -0
  3. package/dist/src/app/charts/Chart.d.ts +116 -87
  4. package/dist/src/app/charts/Chart.js +96 -101
  5. package/dist/src/app/charts/Chart.js.map +1 -1
  6. package/dist/src/app/charts/axes/AxesState.d.ts +64 -0
  7. package/dist/src/app/charts/axes/AxesState.js +97 -0
  8. package/dist/src/app/charts/axes/AxesState.js.map +1 -0
  9. package/dist/src/app/charts/axes/AxesState.test.js +30 -0
  10. package/dist/src/app/charts/axes/AxesState.test.js.map +1 -0
  11. package/dist/src/app/charts/axes/AxisInterval.d.ts +92 -0
  12. package/dist/src/app/charts/axes/AxisInterval.js +126 -0
  13. package/dist/src/app/charts/axes/AxisInterval.js.map +1 -0
  14. package/dist/src/app/charts/axes/AxisInterval.test.js +120 -0
  15. package/dist/src/app/charts/axes/AxisInterval.test.js.map +1 -0
  16. package/dist/src/app/charts/axes/BaseAxisRange.d.ts +83 -0
  17. package/dist/src/app/charts/axes/BaseAxisRange.js +58 -0
  18. package/dist/src/app/charts/axes/BaseAxisRange.js.map +1 -0
  19. package/dist/src/app/charts/axes/ContinuousAxis.d.ts +22 -0
  20. package/dist/src/app/charts/axes/ContinuousAxis.js +96 -0
  21. package/dist/src/app/charts/axes/ContinuousAxis.js.map +1 -0
  22. package/dist/src/app/charts/axes/ContinuousAxisRange.d.ts +59 -0
  23. package/dist/src/app/charts/axes/ContinuousAxisRange.js +84 -0
  24. package/dist/src/app/charts/axes/ContinuousAxisRange.js.map +1 -0
  25. package/dist/src/app/charts/axes/ContinuousAxisRange.test.js +47 -0
  26. package/dist/src/app/charts/axes/ContinuousAxisRange.test.js.map +1 -0
  27. package/dist/src/app/charts/axes/OrdinalAxis.d.ts +23 -0
  28. package/dist/src/app/charts/axes/OrdinalAxis.js +124 -0
  29. package/dist/src/app/charts/axes/OrdinalAxis.js.map +1 -0
  30. package/dist/src/app/charts/axes/OrdinalAxisRange.d.ts +69 -0
  31. package/dist/src/app/charts/axes/OrdinalAxisRange.js +100 -0
  32. package/dist/src/app/charts/axes/OrdinalAxisRange.js.map +1 -0
  33. package/dist/src/app/charts/axes/OrdinalAxisRange.test.js +48 -0
  34. package/dist/src/app/charts/axes/OrdinalAxisRange.test.js.map +1 -0
  35. package/dist/src/app/charts/axes/axes.d.ts +391 -0
  36. package/dist/src/app/charts/axes/axes.js +1046 -0
  37. package/dist/src/app/charts/axes/axes.js.map +1 -0
  38. package/dist/src/app/charts/d3types.d.ts +10 -10
  39. package/dist/src/app/charts/filters/regexFilter.d.ts +9 -0
  40. package/dist/src/app/charts/filters/regexFilter.js +18 -0
  41. package/dist/src/app/charts/filters/regexFilter.js.map +1 -0
  42. package/dist/src/app/charts/filters/regexFilter.test.d.ts +1 -0
  43. package/dist/src/app/charts/filters/regexFilter.test.js +11 -0
  44. package/dist/src/app/charts/filters/regexFilter.test.js.map +1 -0
  45. package/dist/src/app/charts/hooks/useAxes.d.ts +144 -0
  46. package/dist/src/app/charts/hooks/useAxes.js +187 -0
  47. package/dist/src/app/charts/hooks/useAxes.js.map +1 -0
  48. package/dist/src/app/charts/hooks/useChart.d.ts +30 -201
  49. package/dist/src/app/charts/hooks/useChart.js +33 -134
  50. package/dist/src/app/charts/hooks/useChart.js.map +1 -1
  51. package/dist/src/app/charts/hooks/useDataObservable.d.ts +74 -0
  52. package/dist/src/app/charts/hooks/useDataObservable.js +76 -0
  53. package/dist/src/app/charts/hooks/useDataObservable.js.map +1 -0
  54. package/dist/src/app/charts/hooks/useInitialData.d.ts +38 -0
  55. package/dist/src/app/charts/hooks/useInitialData.js +29 -0
  56. package/dist/src/app/charts/hooks/useInitialData.js.map +1 -0
  57. package/dist/src/app/charts/hooks/useMouse.d.ts +53 -0
  58. package/dist/src/app/charts/hooks/useMouse.js +65 -0
  59. package/dist/src/app/charts/hooks/useMouse.js.map +1 -0
  60. package/dist/src/app/charts/hooks/usePlotDimensions.d.ts +34 -0
  61. package/dist/src/app/charts/hooks/usePlotDimensions.js +73 -0
  62. package/dist/src/app/charts/hooks/usePlotDimensions.js.map +1 -0
  63. package/dist/src/app/charts/hooks/useTooltip.d.ts +64 -0
  64. package/dist/src/app/charts/hooks/useTooltip.js +52 -0
  65. package/dist/src/app/charts/hooks/useTooltip.js.map +1 -0
  66. package/dist/src/app/charts/observables/ChartData.d.ts +23 -0
  67. package/dist/src/app/charts/observables/ChartData.js +20 -0
  68. package/dist/src/app/charts/observables/ChartData.js.map +1 -0
  69. package/dist/src/app/charts/observables/iterates.d.ts +52 -0
  70. package/dist/src/app/charts/observables/iterates.js +121 -0
  71. package/dist/src/app/charts/observables/iterates.js.map +1 -0
  72. package/dist/src/app/charts/observables/iterates.test.d.ts +1 -0
  73. package/dist/src/app/charts/observables/iterates.test.js +180 -0
  74. package/dist/src/app/charts/observables/iterates.test.js.map +1 -0
  75. package/dist/src/app/charts/observables/ordinals.d.ts +75 -0
  76. package/dist/src/app/charts/observables/ordinals.js +141 -0
  77. package/dist/src/app/charts/observables/ordinals.js.map +1 -0
  78. package/dist/src/app/charts/observables/ordinals.test.d.ts +1 -0
  79. package/dist/src/app/charts/observables/ordinals.test.js +102 -0
  80. package/dist/src/app/charts/observables/ordinals.test.js.map +1 -0
  81. package/dist/src/app/charts/plots/BarPlot.d.ts +81 -0
  82. package/dist/src/app/charts/plots/BarPlot.js +557 -0
  83. package/dist/src/app/charts/plots/BarPlot.js.map +1 -0
  84. package/dist/src/app/charts/plots/PoincarePlot.d.ts +78 -0
  85. package/dist/src/app/charts/plots/PoincarePlot.js +504 -0
  86. package/dist/src/app/charts/plots/PoincarePlot.js.map +1 -0
  87. package/dist/src/app/charts/{RasterPlot.d.ts → plots/RasterPlot.d.ts} +1 -1
  88. package/dist/src/app/charts/{RasterPlot.js → plots/RasterPlot.js} +152 -133
  89. package/dist/src/app/charts/plots/RasterPlot.js.map +1 -0
  90. package/dist/src/app/charts/{ScatterPlot.d.ts → plots/ScatterPlot.d.ts} +10 -8
  91. package/dist/src/app/charts/plots/ScatterPlot.js +379 -0
  92. package/dist/src/app/charts/plots/ScatterPlot.js.map +1 -0
  93. package/dist/src/app/charts/{plot.d.ts → plots/plot.d.ts} +12 -14
  94. package/dist/src/app/charts/{plot.js → plots/plot.js} +19 -17
  95. package/dist/src/app/charts/plots/plot.js.map +1 -0
  96. package/dist/src/app/charts/series/baseSeries.d.ts +38 -0
  97. package/dist/src/app/charts/series/baseSeries.js +36 -0
  98. package/dist/src/app/charts/series/baseSeries.js.map +1 -0
  99. package/dist/src/app/charts/series/datumSeries.test.d.ts +1 -0
  100. package/dist/src/app/charts/series/datumSeries.test.js +50 -0
  101. package/dist/src/app/charts/series/datumSeries.test.js.map +1 -0
  102. package/dist/src/app/charts/series/iterateSeries.d.ts +42 -0
  103. package/dist/src/app/charts/series/iterateSeries.js +34 -0
  104. package/dist/src/app/charts/series/iterateSeries.js.map +1 -0
  105. package/dist/src/app/charts/series/ordinalSeries.d.ts +54 -0
  106. package/dist/src/app/charts/series/ordinalSeries.js +98 -0
  107. package/dist/src/app/charts/series/ordinalSeries.js.map +1 -0
  108. package/dist/src/app/charts/series/timeSeries.d.ts +30 -0
  109. package/dist/src/app/charts/series/timeSeries.js +19 -0
  110. package/dist/src/app/charts/series/timeSeries.js.map +1 -0
  111. package/dist/src/app/charts/{chartData.d.ts → series/timeSeriesChartData.d.ts} +11 -6
  112. package/dist/src/app/charts/series/timeSeriesChartData.js +32 -0
  113. package/dist/src/app/charts/series/timeSeriesChartData.js.map +1 -0
  114. package/dist/src/app/charts/styling/barPlotStyle.d.ts +41 -0
  115. package/dist/src/app/charts/styling/barPlotStyle.js +84 -0
  116. package/dist/src/app/charts/styling/barPlotStyle.js.map +1 -0
  117. package/dist/src/app/charts/{margins.d.ts → styling/margins.d.ts} +7 -5
  118. package/dist/src/app/charts/{margins.js → styling/margins.js} +19 -9
  119. package/dist/src/app/charts/styling/margins.js.map +1 -0
  120. package/dist/src/app/charts/styling/margins.test.d.ts +1 -0
  121. package/dist/src/app/charts/styling/margins.test.js +19 -0
  122. package/dist/src/app/charts/styling/margins.test.js.map +1 -0
  123. package/dist/src/app/charts/styling/svgStyle.d.ts +76 -0
  124. package/dist/src/app/charts/styling/svgStyle.js +84 -0
  125. package/dist/src/app/charts/styling/svgStyle.js.map +1 -0
  126. package/dist/src/app/charts/subscriptions/subscription.test.d.ts +1 -0
  127. package/dist/src/app/charts/subscriptions/subscription.test.js +395 -0
  128. package/dist/src/app/charts/subscriptions/subscription.test.js.map +1 -0
  129. package/dist/src/app/charts/subscriptions/subscriptions.d.ts +100 -0
  130. package/dist/src/app/charts/subscriptions/subscriptions.js +449 -0
  131. package/dist/src/app/charts/subscriptions/subscriptions.js.map +1 -0
  132. package/dist/src/app/charts/tooltips/BarPlotTooltipContent.d.ts +90 -0
  133. package/dist/src/app/charts/tooltips/BarPlotTooltipContent.js +302 -0
  134. package/dist/src/app/charts/tooltips/BarPlotTooltipContent.js.map +1 -0
  135. package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.d.ts +100 -0
  136. package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.js +190 -0
  137. package/dist/src/app/charts/tooltips/PoincarePlotTooltipContent.js.map +1 -0
  138. package/dist/src/app/charts/{RasterPlotTooltipContent.js → tooltips/RasterPlotTooltipContent.js} +40 -44
  139. package/dist/src/app/charts/tooltips/RasterPlotTooltipContent.js.map +1 -0
  140. package/dist/src/app/charts/tooltips/ScatterPlotTooltipContent.js +154 -0
  141. package/dist/src/app/charts/tooltips/ScatterPlotTooltipContent.js.map +1 -0
  142. package/dist/src/app/charts/{Tooltip.d.ts → tooltips/Tooltip.d.ts} +4 -2
  143. package/dist/src/app/charts/{Tooltip.js → tooltips/Tooltip.js} +23 -28
  144. package/dist/src/app/charts/tooltips/Tooltip.js.map +1 -0
  145. package/dist/src/app/charts/{tooltipUtils.d.ts → tooltips/tooltipUtils.d.ts} +11 -6
  146. package/dist/src/app/charts/{tooltipUtils.js → tooltips/tooltipUtils.js} +33 -17
  147. package/dist/src/app/charts/tooltips/tooltipUtils.js.map +1 -0
  148. package/dist/src/app/charts/{Tracker.d.ts → trackers/Tracker.d.ts} +6 -5
  149. package/dist/src/app/charts/trackers/Tracker.js +60 -0
  150. package/dist/src/app/charts/trackers/Tracker.js.map +1 -0
  151. package/dist/src/app/charts/{trackerUtils.d.ts → trackers/trackerUtils.d.ts} +13 -8
  152. package/dist/src/app/charts/trackers/trackerUtils.js +359 -0
  153. package/dist/src/app/charts/trackers/trackerUtils.js.map +1 -0
  154. package/dist/src/app/charts/utils.d.ts +22 -32
  155. package/dist/src/app/charts/utils.js +36 -37
  156. package/dist/src/app/charts/utils.js.map +1 -1
  157. package/dist/src/index.d.ts +48 -15
  158. package/dist/src/index.js +71 -15
  159. package/dist/src/index.js.map +1 -1
  160. package/package.json +30 -20
  161. package/src/app/charts/Chart.tsx +334 -0
  162. package/src/app/charts/axes/AxesState.test.ts +34 -0
  163. package/src/app/charts/axes/AxesState.ts +112 -0
  164. package/src/app/charts/axes/AxisInterval.test.ts +143 -0
  165. package/src/app/charts/axes/AxisInterval.ts +139 -0
  166. package/src/app/charts/axes/BaseAxisRange.ts +113 -0
  167. package/src/app/charts/axes/ContinuousAxis.tsx +192 -0
  168. package/src/app/charts/axes/ContinuousAxisRange.test.ts +55 -0
  169. package/src/app/charts/axes/ContinuousAxisRange.ts +96 -0
  170. package/src/app/charts/axes/OrdinalAxis.tsx +223 -0
  171. package/src/app/charts/axes/OrdinalAxisRange.test.ts +55 -0
  172. package/src/app/charts/axes/OrdinalAxisRange.ts +112 -0
  173. package/src/app/charts/axes/axes.ts +1569 -0
  174. package/src/app/charts/d3types.ts +16 -0
  175. package/src/app/charts/filters/regexFilter.test.ts +13 -0
  176. package/src/app/charts/filters/regexFilter.ts +17 -0
  177. package/src/app/charts/hooks/useAxes.tsx +341 -0
  178. package/src/app/charts/hooks/useChart.tsx +159 -0
  179. package/src/app/charts/hooks/useDataObservable.tsx +175 -0
  180. package/src/app/charts/hooks/useInitialData.tsx +65 -0
  181. package/src/app/charts/hooks/useMouse.tsx +125 -0
  182. package/src/app/charts/hooks/usePlotDimensions.tsx +120 -0
  183. package/src/app/charts/hooks/useTooltip.tsx +112 -0
  184. package/src/app/charts/observables/ChartData.ts +31 -0
  185. package/src/app/charts/observables/iterates.test.ts +201 -0
  186. package/src/app/charts/observables/iterates.ts +203 -0
  187. package/src/app/charts/observables/ordinals.test.ts +135 -0
  188. package/src/app/charts/observables/ordinals.ts +248 -0
  189. package/src/app/charts/plots/BarPlot.tsx +1088 -0
  190. package/src/app/charts/plots/PoincarePlot.tsx +832 -0
  191. package/src/app/charts/plots/RasterPlot.tsx +676 -0
  192. package/src/app/charts/plots/ScatterPlot.tsx +653 -0
  193. package/src/app/charts/plots/plot.ts +75 -0
  194. package/src/app/charts/series/baseSeries.ts +52 -0
  195. package/src/app/charts/series/datumSeries.test.ts +60 -0
  196. package/src/app/charts/series/iterateSeries.ts +56 -0
  197. package/src/app/charts/series/ordinalSeries.ts +164 -0
  198. package/src/app/charts/series/timeSeries.ts +40 -0
  199. package/src/app/charts/series/timeSeriesChartData.ts +68 -0
  200. package/src/app/charts/styling/barPlotStyle.ts +126 -0
  201. package/src/app/charts/styling/margins.test.ts +22 -0
  202. package/src/app/charts/styling/margins.ts +58 -0
  203. package/src/app/charts/styling/svgStyle.ts +118 -0
  204. package/src/app/charts/subscriptions/subscription.test.ts +499 -0
  205. package/src/app/charts/subscriptions/subscriptions.ts +635 -0
  206. package/src/app/charts/tooltips/BarPlotTooltipContent.tsx +440 -0
  207. package/src/app/charts/tooltips/PoincarePlotTooltipContent.tsx +352 -0
  208. package/src/app/charts/tooltips/RasterPlotTooltipContent.tsx +274 -0
  209. package/src/app/charts/tooltips/ScatterPlotTooltipContent.tsx +319 -0
  210. package/src/app/charts/tooltips/Tooltip.tsx +148 -0
  211. package/src/app/charts/tooltips/tooltipUtils.ts +216 -0
  212. package/src/app/charts/trackers/Tracker.tsx +129 -0
  213. package/src/app/charts/trackers/trackerUtils.ts +494 -0
  214. package/src/app/charts/utils.ts +109 -0
  215. package/dist/src/app/charts/CategoryAxis.d.ts +0 -20
  216. package/dist/src/app/charts/CategoryAxis.js +0 -112
  217. package/dist/src/app/charts/CategoryAxis.js.map +0 -1
  218. package/dist/src/app/charts/ContinuousAxis.d.ts +0 -16
  219. package/dist/src/app/charts/ContinuousAxis.js +0 -186
  220. package/dist/src/app/charts/ContinuousAxis.js.map +0 -1
  221. package/dist/src/app/charts/RasterPlot.js.map +0 -1
  222. package/dist/src/app/charts/RasterPlotTooltipContent.js.map +0 -1
  223. package/dist/src/app/charts/ScatterPlot.js +0 -351
  224. package/dist/src/app/charts/ScatterPlot.js.map +0 -1
  225. package/dist/src/app/charts/ScatterPlotTooltipContent.js +0 -163
  226. package/dist/src/app/charts/ScatterPlotTooltipContent.js.map +0 -1
  227. package/dist/src/app/charts/Tooltip.js.map +0 -1
  228. package/dist/src/app/charts/Tracker.js +0 -65
  229. package/dist/src/app/charts/Tracker.js.map +0 -1
  230. package/dist/src/app/charts/axes.d.ts +0 -132
  231. package/dist/src/app/charts/axes.js +0 -265
  232. package/dist/src/app/charts/axes.js.map +0 -1
  233. package/dist/src/app/charts/chartData.js +0 -32
  234. package/dist/src/app/charts/chartData.js.map +0 -1
  235. package/dist/src/app/charts/continuousAxisRangeFor.d.ts +0 -20
  236. package/dist/src/app/charts/continuousAxisRangeFor.js +0 -68
  237. package/dist/src/app/charts/continuousAxisRangeFor.js.map +0 -1
  238. package/dist/src/app/charts/datumSeries.d.ts +0 -59
  239. package/dist/src/app/charts/datumSeries.js +0 -55
  240. package/dist/src/app/charts/datumSeries.js.map +0 -1
  241. package/dist/src/app/charts/datumSeries.test.js +0 -50
  242. package/dist/src/app/charts/datumSeries.test.js.map +0 -1
  243. package/dist/src/app/charts/hooks/AxesState.d.ts +0 -37
  244. package/dist/src/app/charts/hooks/AxesState.js +0 -44
  245. package/dist/src/app/charts/hooks/AxesState.js.map +0 -1
  246. package/dist/src/app/charts/margins.js.map +0 -1
  247. package/dist/src/app/charts/margins.test.js +0 -14
  248. package/dist/src/app/charts/margins.test.js.map +0 -1
  249. package/dist/src/app/charts/plot.js.map +0 -1
  250. package/dist/src/app/charts/regexFilter.d.ts +0 -9
  251. package/dist/src/app/charts/regexFilter.js +0 -17
  252. package/dist/src/app/charts/regexFilter.js.map +0 -1
  253. package/dist/src/app/charts/regexFilter.test.js +0 -11
  254. package/dist/src/app/charts/regexFilter.test.js.map +0 -1
  255. package/dist/src/app/charts/subscriptions.d.ts +0 -43
  256. package/dist/src/app/charts/subscriptions.js +0 -213
  257. package/dist/src/app/charts/subscriptions.js.map +0 -1
  258. package/dist/src/app/charts/svgStyle.d.ts +0 -27
  259. package/dist/src/app/charts/svgStyle.js +0 -32
  260. package/dist/src/app/charts/svgStyle.js.map +0 -1
  261. package/dist/src/app/charts/timeRange.test.js +0 -54
  262. package/dist/src/app/charts/timeRange.test.js.map +0 -1
  263. package/dist/src/app/charts/tooltipUtils.js.map +0 -1
  264. package/dist/src/app/charts/trackerUtils.js +0 -130
  265. package/dist/src/app/charts/trackerUtils.js.map +0 -1
  266. /package/dist/src/app/charts/{datumSeries.test.d.ts → axes/AxesState.test.d.ts} +0 -0
  267. /package/dist/src/app/charts/{margins.test.d.ts → axes/AxisInterval.test.d.ts} +0 -0
  268. /package/dist/src/app/charts/{regexFilter.test.d.ts → axes/ContinuousAxisRange.test.d.ts} +0 -0
  269. /package/dist/src/app/charts/{timeRange.test.d.ts → axes/OrdinalAxisRange.test.d.ts} +0 -0
  270. /package/dist/src/app/charts/{RasterPlotTooltipContent.d.ts → tooltips/RasterPlotTooltipContent.d.ts} +0 -0
  271. /package/dist/src/app/charts/{ScatterPlotTooltipContent.d.ts → tooltips/ScatterPlotTooltipContent.d.ts} +0 -0
@@ -0,0 +1,635 @@
1
+ import {bufferTime, map, mergeAll, mergeWith} from "rxjs/operators";
2
+ import {continuousAxisRanges, ContinuousNumericAxis, ordinalAxisRanges, OrdinalStringAxis} from "../axes/axes";
3
+ import {Datum, TimeSeries} from "../series/timeSeries";
4
+ import {interval, Observable, Subscription} from "rxjs";
5
+ import {TimeSeriesChartData} from "../series/timeSeriesChartData";
6
+ import {AxesAssignment} from "../plots/plot";
7
+ import {AxesState} from "../axes/AxesState";
8
+ import {BaseSeries, emptySeries} from "../series/baseSeries";
9
+ import {IterateChartData} from "../observables/iterates";
10
+ import {IterateDatum, IterateSeries} from "../series/iterateSeries";
11
+ import {
12
+ copyOrdinalDatumExtremum,
13
+ copyOrdinalValueStats,
14
+ copyValueStatsForSeries,
15
+ defaultOrdinalValueStats,
16
+ initialMaxValueDatum,
17
+ initialMinValueDatum,
18
+ OrdinalChartData,
19
+ OrdinalStats,
20
+ OrdinalValueStats
21
+ } from "../observables/ordinals";
22
+ import {ChartData} from "../observables/ChartData";
23
+ import {OrdinalDatum} from "../series/ordinalSeries";
24
+ import {RefObject} from "react";
25
+ import {AxisInterval} from "../axes/AxisInterval";
26
+ import {Optional} from "result-fn";
27
+ import {OrdinalAxisRange} from "../axes/OrdinalAxisRange";
28
+ import {ContinuousAxisRange} from "../axes/ContinuousAxisRange";
29
+
30
+ export enum TimeWindowBehavior { SCROLL, SQUEEZE }
31
+
32
+ /**
33
+ * Creates a subscription to the series observable with the data stream. This is common code
34
+ * shared by the plots.
35
+ * @param seriesObservable The series observable holding the stream of chart data
36
+ * @param onSubscribe Callback for when the observable is subscribed to
37
+ * @param windowingTime Basically the update time when data is collected and then rendered
38
+ * @param axisAssignments The assignment of the series to their x- and y-axes
39
+ * @param xAxesState The current state of the x-axis
40
+ * @param onUpdateData Callback for when data is updated
41
+ * @param dropDataAfter Limits the amount of data stored. Any data older than this value (ms) will
42
+ * be dropped on the next update
43
+ * @param updateTimingAndPlot The callback function to update the plot and timing
44
+ * @param seriesMap The series-name and the associated series
45
+ * @param setCurrentTime Callback to update the current time based on the streamed data
46
+ * @param timeWindowBehavior Whether to scroll the time axis or squeeze it
47
+ * @param initialTimes The initial times for each axis, a map(axis_id -> initial_time)
48
+ * @return A subscription to the observable (for cancelling and the likes)
49
+ */
50
+ export function subscriptionTimeSeriesFor(
51
+ seriesObservable: Observable<TimeSeriesChartData>,
52
+ onSubscribe: (subscription: Subscription) => void,
53
+ windowingTime: number,
54
+ axisAssignments: Map<string, AxesAssignment>,
55
+ xAxesState: AxesState<ContinuousNumericAxis>,
56
+ onUpdateData: ((seriesName: string, data: Array<Datum>) => void) | undefined,
57
+ dropDataAfter: number,
58
+ updateTimingAndPlot: (ranges: Map<string, ContinuousAxisRange>) => void,
59
+ seriesMap: Map<string, TimeSeries>,
60
+ setCurrentTime: (axisId: string, end: number) => void,
61
+ timeWindowBehavior: TimeWindowBehavior = TimeWindowBehavior.SCROLL,
62
+ initialTimes: Map<string, number> = new Map<string, number>(),
63
+ ): Subscription {
64
+ const subscription = seriesObservable
65
+ .pipe(bufferTime(windowingTime))
66
+ .subscribe(dataList => {
67
+ dataList.forEach(data => {
68
+ // grab the time-windows for the x-axes
69
+ const timesWindows = continuousAxisRanges(xAxesState.axes as Map<string, ContinuousNumericAxis>);
70
+
71
+ //
72
+ // calculate the max times for each x-axis, which is the max time over all the
73
+ // series assigned to an x-axis
74
+
75
+ // get the series associated with each axis (Map<axis_id, [series_names]>)
76
+ const axesSeries = associatedSeriesForXAxes(data, axisAssignments, xAxesState)
77
+
78
+ // add each new point to it's corresponding series, the new points
79
+ // is a map(series_name -> new_point[])
80
+ data.newPoints.forEach((newData, name) => {
81
+ // grab the current series associated with the new data
82
+ const series = seriesMap.get(name) || emptySeries(name)
83
+
84
+ // update the handler with the new data point
85
+ if (onUpdateData) onUpdateData(name, newData)
86
+
87
+ // add the new data to the series
88
+ series.data.push(...newData)
89
+
90
+ // calculate the current time for the series' assigned x-axis (which may end up
91
+ // just being the default) based on the max time for the series, and the overall
92
+ // max time
93
+ const axisId = axisAssignments.get(name)?.xAxis || xAxesState.axisDefaultId().getOrElse("");
94
+ const currentAxisTime = axesSeries.get(axisId)
95
+ ?.reduce(
96
+ (tMax, seriesName) => Math.max(data.maxTimes.get(seriesName) || data.maxTime, tMax),
97
+ -Infinity
98
+ ) || data.maxTime
99
+
100
+ if (currentAxisTime !== undefined) {
101
+ // drop data that is older than the max time-window
102
+ while (currentAxisTime - series.data[0].time > dropDataAfter) {
103
+ series.data.shift()
104
+ }
105
+
106
+ // update the time range for the x-axis, and if the time range
107
+ // needs to be updated, then recalculate the time range for the
108
+ // axis, update the time windows, and call the setCurrentTime
109
+ // callback to update the current time for the caller
110
+ const range = timesWindows.get(axisId)
111
+ const [startTime, endTime] = Optional.ofNullable(range?.current)
112
+ .map(interval => interval.asTuple())
113
+ .getOrElse([0, 0])
114
+ if (range !== undefined && endTime < currentAxisTime) {
115
+ const timeWindow = endTime - startTime
116
+ const timeRange = ContinuousAxisRange.from(
117
+ // 0,
118
+ timeWindowBehavior === TimeWindowBehavior.SQUEEZE && initialTimes.get(axisId) !== undefined ?
119
+ initialTimes.get(axisId)! :
120
+ Math.max(0, currentAxisTime - timeWindow),
121
+ Math.max(currentAxisTime, timeWindow)
122
+ )
123
+ timesWindows.set(axisId, timeRange)
124
+ setCurrentTime(axisId, endTime) // callback
125
+ }
126
+ }
127
+ })
128
+
129
+ // update the data
130
+ updateTimingAndPlot(timesWindows) // callback
131
+ })
132
+ })
133
+
134
+ // provide the subscription to the caller
135
+ onSubscribe(subscription) // callback
136
+
137
+ return subscription
138
+ }
139
+
140
+ /**
141
+ * **Function has side effects on the Series (for performance).**
142
+ *
143
+ * Creates a subscription to the series observable with the data stream. The common code is
144
+ * shared by the plots.
145
+ * @param seriesObservable The series observable holding the stream of chart data
146
+ * @param onSubscribe Callback for when the observable is subscribed to
147
+ * @param windowingTime Basically the update time when data is collected and then rendered
148
+ * @param axisAssignments The assignment of the series to their x- and y-axes
149
+ * @param xAxesState The current state of the x-axis
150
+ * @param onUpdateData Callback for when data is updated
151
+ * @param dropDataAfter Limits the amount of data stored. Any data older than this value (ms) will
152
+ * be dropped on the next update
153
+ * @param updateTimingAndPlot The callback function to update the plot and timing
154
+ * @param seriesMap The series-name and the associated series
155
+ * @param setCurrentTime Callback to update the current time based on the streamed data
156
+ * @param cadencePeriod The number of milliseconds between time updates
157
+ * @return A subscription to the observable (for cancelling and the likes)
158
+ */
159
+ export function subscriptionTimeSeriesWithCadenceFor(
160
+ seriesObservable: Observable<TimeSeriesChartData>,
161
+ onSubscribe: (subscription: Subscription) => void,
162
+ windowingTime: number,
163
+ axisAssignments: Map<string, AxesAssignment>,
164
+ xAxesState: AxesState<ContinuousNumericAxis>,
165
+ onUpdateData: ((seriesName: string, data: Array<Datum>) => void) | undefined,
166
+ dropDataAfter: number,
167
+ updateTimingAndPlot: (ranges: Map<string, ContinuousAxisRange>) => void,
168
+ seriesMap: Map<string, TimeSeries>,
169
+ setCurrentTime: (axisId: string, end: number) => void,
170
+ cadencePeriod: number
171
+ ): Subscription {
172
+ const maxTime = Array.from(seriesMap.entries())
173
+ .reduce(
174
+ (tMax, [, series]) => Math.max(tMax, series.last().map(datum => datum.time).getOrElse(tMax)),
175
+ -Infinity
176
+ )
177
+ const cadence = interval(cadencePeriod)
178
+ .pipe(
179
+ map(value => ({
180
+ currentTime: value * cadencePeriod,
181
+ maxTime: value * cadencePeriod,
182
+ maxTimes: new Map(),
183
+ newPoints: new Map()
184
+ } as TimeSeriesChartData)
185
+ )
186
+ )
187
+
188
+ const subscription = seriesObservable
189
+ .pipe(
190
+ mergeWith(cadence),
191
+ bufferTime(windowingTime),
192
+ mergeAll(),
193
+ )
194
+ .subscribe(data => {
195
+ // grab the time-windows for the x-axes
196
+ const timesWindows = continuousAxisRanges(xAxesState.axes as Map<string, ContinuousNumericAxis>)
197
+
198
+ if (data.currentTime !== undefined) {
199
+ xAxesState.axisIds().forEach(axisId => {
200
+ const range = timesWindows.get(axisId)
201
+ if (range !== undefined && data.currentTime !== undefined) {
202
+ const [startTime, endTime] = range.current.asTuple()
203
+ const timeWindow = endTime - startTime
204
+ // const timeWindow = measureOf(range.current)
205
+ const timeRange = ContinuousAxisRange.from(
206
+ Math.max(0, Math.max(endTime, data.currentTime + maxTime) - timeWindow),
207
+ Math.max(Math.max(endTime, data.currentTime + maxTime), timeWindow)
208
+ )
209
+ timesWindows.set(axisId, timeRange)
210
+ setCurrentTime(axisId, data.currentTime + maxTime)
211
+ }
212
+ })
213
+ }
214
+
215
+ if (data.newPoints.size === 0) {
216
+ updateTimingAndPlot(timesWindows)
217
+ return
218
+ }
219
+
220
+ // determine which series belong to each x-axis
221
+ const axesSeries = associatedSeriesForXAxes(data, axisAssignments, xAxesState)
222
+
223
+ // add each new point to it's corresponding series, the new points
224
+ // is a map(series_name -> new_point[])
225
+ data.newPoints.forEach((newData, name) => {
226
+ // grab the current series associated with the new data
227
+ const series = seriesMap.get(name) || emptySeries(name);
228
+
229
+ // update the handler with the new data point
230
+ if (onUpdateData) onUpdateData(name, newData);
231
+
232
+ // add the new data to the series
233
+ series.data.push(...newData);
234
+
235
+ // drop data when specified
236
+ const axisId = axisAssignments.get(name)?.xAxis || xAxesState.axisDefaultId().getOrElse("")
237
+ const currentAxisTime = axesSeries.get(axisId)
238
+ ?.reduce(
239
+ (tMax, seriesName) => Math.max(data.maxTimes.get(seriesName) || data.maxTime, tMax),
240
+ -Infinity
241
+ ) || data.maxTime
242
+ if (currentAxisTime !== undefined) {
243
+ // drop data that is older than the max time-window
244
+ while (currentAxisTime - series.data[0].time > dropDataAfter) {
245
+ series.data.shift()
246
+ }
247
+ }
248
+ })
249
+
250
+ // update the data
251
+ updateTimingAndPlot(timesWindows)
252
+ })
253
+
254
+ // provide the subscription to the caller
255
+ onSubscribe(subscription)
256
+
257
+ return subscription
258
+ }
259
+
260
+ /**
261
+ * Creates a subscription to the series observable with the data stream. The common code is
262
+ * shared by the plots.
263
+ * @param seriesObservable The series observable holding the stream of chart data
264
+ * @param onSubscribe Callback for when the observable is subscribed to
265
+ * @param windowingTime Basically the update time when data is collected and then rendered
266
+ * @param xAxesState The current state of the x-axis
267
+ * @param yAxesState The current state of the y-axis
268
+ * @param onUpdateData Callback for when data is updated
269
+ * @param dropDataAfter Limits the amount of data stored. Any data older than this value (ms) will
270
+ * be dropped on the next update
271
+ * @param updateRangesAndPlot The callback function to update the plot
272
+ * @param seriesMap The series-name and the associated series
273
+ * @param updateCurrentTime Callback to update the current time based on the streamed data
274
+ * @return A subscription to the observable (for cancelling and the likes)
275
+ */
276
+ export function subscriptionIteratesFor(
277
+ seriesObservable: Observable<IterateChartData>,
278
+ onSubscribe: (subscription: Subscription) => void,
279
+ windowingTime: number,
280
+ xAxesState: AxesState<ContinuousNumericAxis>,
281
+ yAxesState: AxesState<ContinuousNumericAxis>,
282
+ onUpdateData: ((seriesName: string, data: Array<IterateDatum>) => void) | undefined,
283
+ dropDataAfter: number,
284
+ updateRangesAndPlot: () => void,
285
+ seriesMap: Map<string, IterateSeries>,
286
+ updateCurrentTime: (time: number) => void
287
+ ): Subscription {
288
+ // maintains the x and y-axis ranges based on the original domain of the axes
289
+ const xAxesRanges = new Map<string, ContinuousAxisRange>(Array.from(xAxesState.axes.entries())
290
+ .map(([id, axis]) => {
291
+ const [start, end] = (axis as ContinuousNumericAxis).scale.domain()
292
+ return [id, ContinuousAxisRange.from(start, end)]
293
+ }))
294
+ const yAxesRanges = new Map<string, ContinuousAxisRange>(Array.from(yAxesState.axes.entries())
295
+ .map(([id, axis]) => {
296
+ const [start, end] = (axis as ContinuousNumericAxis).scale.domain()
297
+ return [id, ContinuousAxisRange.from(start, end)]
298
+ }))
299
+
300
+ /**
301
+ * Updates the original axis range with new domain values, while maintaining the original
302
+ * domain values.
303
+ * @param originals The original axis ranges
304
+ * @param axes The current axes
305
+ */
306
+ function updateRange(originals: Map<string, ContinuousAxisRange>, axes: Map<string, ContinuousNumericAxis>): void {
307
+ axes.forEach((axis, id) => {
308
+ const [start, end] = axis.scale.domain()
309
+ const original: ContinuousAxisRange = originals.get(id) || ContinuousAxisRange.from(start, end)
310
+ originals.set(id, original.update(start, end))
311
+ })
312
+ }
313
+
314
+ const subscription = seriesObservable
315
+ .pipe(bufferTime(windowingTime))
316
+ .subscribe(dataList => {
317
+ dataList.forEach(data => {
318
+ // calculate the bounds for each of the x- and y-axes
319
+ updateRange(xAxesRanges, xAxesState.axes as Map<string, ContinuousNumericAxis>)
320
+ updateRange(yAxesRanges, yAxesState.axes as Map<string, ContinuousNumericAxis>)
321
+
322
+ // add each new point to its corresponding series, the newPoints object
323
+ // is a map(series_name -> new_point[])
324
+ data.newPoints.forEach((newData, seriesName) => {
325
+ // grab the current series associated with the new data
326
+ const series = seriesMap.get(seriesName) || emptySeries(seriesName)
327
+
328
+ // update the handler with the new data points
329
+ if (onUpdateData) onUpdateData(seriesName, newData)
330
+
331
+ // add the new data to the series
332
+ series.data.push(...newData)
333
+
334
+ // calculate and update the current time, which will be that max time of the
335
+ // f[n+1](x) values (y-axis)
336
+ const currentTime = Array.from(data.newPoints.values())
337
+ .reduce((maxTime, currentSeries) => {
338
+ const seriesMaxTime = currentSeries.length > 0 ? currentSeries[currentSeries.length-1].time : 0
339
+ if (seriesMaxTime > maxTime) {
340
+ return seriesMaxTime
341
+ }
342
+ return maxTime
343
+ }, 0)
344
+
345
+ updateCurrentTime(currentTime)
346
+
347
+ // drop data that is older than the max time-window
348
+ while (currentTime - series.data[0].time > dropDataAfter) {
349
+ series.data.shift()
350
+ }
351
+
352
+ })
353
+
354
+ // update the data
355
+ const xRange = xAxesRanges.get(xAxesState.axisDefaultId().getOrElse(""))
356
+ const yRange = yAxesRanges.get(yAxesState.axisDefaultId().getOrElse(""))
357
+ if (xRange !== undefined && yRange !== undefined) {
358
+ updateRangesAndPlot()
359
+ }
360
+ })
361
+ })
362
+
363
+ // provide the subscription to the caller
364
+ onSubscribe(subscription)
365
+
366
+ return subscription
367
+ }
368
+
369
+ export interface WindowedOrdinalStats extends OrdinalStats {
370
+ /**
371
+ * A map associating each series to stats about that series (e.g. map(series_name -> stats))
372
+ */
373
+ windowedValueStatsForSeries: Map<string, OrdinalValueStats>
374
+ }
375
+
376
+ /**
377
+ * Creates a subscription to the series observable with the data stream. The common code is
378
+ * shared by the plots.
379
+ * @param seriesObservable The series observable holding the stream of chart data
380
+ * @param onSubscribe Callback for when the observable is subscribed to
381
+ * @param windowingTime Basically the update time when data is collected and then rendered
382
+ * @param axisAssignments The assignment of the series to their x- and y-axes
383
+ * @param yAxesState The current state of the x-axis
384
+ * @param onUpdateData Callback for when data is updated
385
+ * @param dropDataAfter Limits the amount of data stored. Any data older than this value (ms) will
386
+ * be dropped on the next update
387
+ * @param updateTimingAndPlot The callback function to update the plot and timing
388
+ * @param seriesMap The series-name and the associated series
389
+ * @param ordinalStatsRef The statistics about the data in the chart and about each series
390
+ * @param setCurrentTime Callback to update the current time based on the streamed data
391
+ * @param originalRange The original range of the axes
392
+ * @return A subscription to the observable (for cancelling and the likes)
393
+ */
394
+ export function subscriptionOrdinalXFor(
395
+ seriesObservable: Observable<OrdinalChartData>,
396
+ onSubscribe: (subscription: Subscription) => void,
397
+ windowingTime: number,
398
+ axisAssignments: Map<string, AxesAssignment>,
399
+ yAxesState: AxesState<OrdinalStringAxis>,
400
+ onUpdateData: ((seriesName: string, data: Array<OrdinalDatum>) => void) | undefined,
401
+ dropDataAfter: number,
402
+ updateTimingAndPlot: (ranges: Map<string, OrdinalAxisRange>) => void,
403
+ seriesMap: Map<string, BaseSeries<OrdinalDatum>>,
404
+ ordinalStatsRef: RefObject<WindowedOrdinalStats>,
405
+ setCurrentTime: (currentTime: number) => void,
406
+ originalRange: AxisInterval,
407
+ ): Subscription {
408
+
409
+ /**
410
+ * First of two functions to calculate the current ordinal stats for the current time window. This
411
+ * function updates the windowed stats for the new data.
412
+ * @param newData The new data for that series
413
+ * @param windowedStats The current windowed ordinal value status
414
+ * @return The windowed ordinal value stats updated for the new data
415
+ */
416
+ function updatedWindowedValueStatsForNewData(newData: Array<OrdinalDatum>, windowedStats: OrdinalValueStats): OrdinalValueStats {
417
+ const updatedStats = copyOrdinalValueStats(windowedStats)
418
+ updatedStats.count += newData.length
419
+ const newSum = newData.reduce((total, datum) => total + datum.value, 0)
420
+ updatedStats.sum += newSum
421
+ updatedStats.sumSquared += newSum * newSum
422
+ updatedStats.mean = (updatedStats.count > 0) ? updatedStats.sum / updatedStats.count : NaN
423
+ updatedStats.min = newData.reduce((min, datum) => datum.value < min.value ? datum : min, updatedStats.min)
424
+ updatedStats.max = newData.reduce((max, datum) => datum.value > max.value ? datum : max, updatedStats.max)
425
+ return updatedStats
426
+ }
427
+
428
+ /**
429
+ * Second of two functions to calculate the current ordinal stats for the current time window. This
430
+ * function updates the windowed stats by for the dropped data
431
+ * @param droppedData An array of datum that was dropped from the time window
432
+ * @param windowedStats The current windowed ordinal value stats
433
+ * @param series An array of series holding all the current data in the time-window
434
+ * @return The windowed ordinal value stats updated for the dropped data
435
+ */
436
+ function updateWindowedValueStatsForDroppedData(
437
+ droppedData: Array<OrdinalDatum>,
438
+ windowedStats: OrdinalValueStats,
439
+ series: BaseSeries<OrdinalDatum>
440
+ ): OrdinalValueStats {
441
+ const updatedStats = copyOrdinalValueStats(windowedStats)
442
+ // calculate the windowed stats based on the dropped data
443
+ updatedStats.count -= droppedData.length
444
+ const droppedSum = droppedData.reduce((total, datum) => total + datum.value, 0)
445
+ updatedStats.sum -= droppedSum
446
+ updatedStats.sumSquared -= droppedSum * droppedSum
447
+ updatedStats.mean = (updatedStats.count > 0) ? updatedStats.sum / updatedStats.count : NaN
448
+ updatedStats.min = series.data.reduce((min, datum) => datum.value < min.value ? datum : min, initialMinValueDatum())
449
+ updatedStats.max = series.data.reduce((max, datum) => datum.value > max.value ? datum : max, initialMaxValueDatum())
450
+ return updatedStats
451
+ }
452
+
453
+ //
454
+ // beginning of the subscription function
455
+ //
456
+ const subscription = seriesObservable
457
+ .pipe(bufferTime(windowingTime))
458
+ .subscribe(dataList => {
459
+ dataList.forEach((data: OrdinalChartData) => {
460
+ // grab the axis ranges for the y-axes
461
+ const yAxisRanges = ordinalAxisRanges(
462
+ yAxesState.axes as Map<string, OrdinalStringAxis>,
463
+ originalRange
464
+ );
465
+
466
+ //
467
+ // calculate the max times for each x-axis, which is the max time over all the
468
+ // series assigned to an x-axis
469
+
470
+ // get the series associated with each y-axis (Map<axis_id, [series_names]>)
471
+ const axesSeries = associatedSeriesForYAxes(data, axisAssignments, yAxesState)
472
+
473
+ // add each new point to it's corresponding series, the new points
474
+ // is a map(series_name -> new_point[])
475
+ data.newPoints.forEach((newData, name) => {
476
+ // grab the current series associated with the new data
477
+ const series = seriesMap.get(name) || emptySeries(name)
478
+
479
+ // update the handler with the new data point
480
+ if (onUpdateData) onUpdateData(name, newData)
481
+
482
+ // add the new data to the series
483
+ series.data.push(...newData)
484
+
485
+ // grab the stats
486
+ ordinalStatsRef.current.minDatum = copyOrdinalDatumExtremum(data.stats.minDatum)
487
+ ordinalStatsRef.current.maxDatum = copyOrdinalDatumExtremum(data.stats.maxDatum)
488
+ ordinalStatsRef.current.valueStatsForSeries = copyValueStatsForSeries(data.stats.valueStatsForSeries)
489
+
490
+ // set up for the windowed-stats
491
+ const lifetimeValueStats = data.stats.valueStatsForSeries.get(name) || defaultOrdinalValueStats()
492
+ if (!ordinalStatsRef.current.windowedValueStatsForSeries.has(name)) {
493
+ ordinalStatsRef.current.windowedValueStatsForSeries.set(name, copyOrdinalValueStats(lifetimeValueStats))
494
+ // ordinalStatsRef.current.windowedValueStatsForSeries.set(name, defaultOrdinalValueStats())
495
+ }
496
+
497
+ // update the windowed-stats for the new points (later will deal with datum
498
+ // that were dropped)
499
+ const updatedStats = ordinalStatsRef.current.windowedValueStatsForSeries.get(name)!
500
+ const windowedValueStats = updatedWindowedValueStatsForNewData(newData, updatedStats)
501
+ ordinalStatsRef.current.windowedValueStatsForSeries.set(name, windowedValueStats)
502
+
503
+ // calculate the current value for the series' assigned y-axis (which may end up
504
+ // just being the default) based on the max time for the series, and the overall
505
+ // max time
506
+ const axisId = axisAssignments.get(name)?.yAxis || yAxesState.axisDefaultId().getOrElse("");
507
+ const currentTime = axesSeries.get(axisId)
508
+ ?.reduce(
509
+ (tMax, _) => Math.max(data.stats.maxDatum.time.time, tMax),
510
+ -Infinity
511
+ ) || NaN
512
+ setCurrentTime(currentTime)
513
+
514
+ if (currentTime !== undefined) {
515
+ // drop data that is older than the max time-window, holding on to the dropped ones
516
+ let droppedData: Array<OrdinalDatum> = []
517
+ while (currentTime - series.data[0].time > dropDataAfter) {
518
+ const dropped = series.data.shift()
519
+ if (dropped !== undefined) {
520
+ droppedData.push(dropped)
521
+ }
522
+ }
523
+
524
+ // calculate the windowed stats based on the dropped data
525
+ if (droppedData.length > 0) {
526
+ ordinalStatsRef.current.windowedValueStatsForSeries.set(
527
+ name,
528
+ updateWindowedValueStatsForDroppedData(droppedData, windowedValueStats, series)
529
+ )
530
+ }
531
+
532
+ // // update the time range for the x-axis, and if the time range
533
+ // // needs to be updated, then recalculate the time range for the
534
+ // // axis, update the time windows, and call the setCurrentTime
535
+ // // callback to update the current time for the caller
536
+ // const range = yAxisRanges.get(axisId)
537
+ // if (range !== undefined && range.end < currentAxisTime) {
538
+ // const timeWindow = range.end - range.start
539
+ // const timeRange = continuousAxisRangeFor(
540
+ // // 0,
541
+ // timeWindowBehavior === TimeWindowBehavior.SQUEEZE && initialTimes.get(axisId) !== undefined ?
542
+ // initialTimes.get(axisId)! :
543
+ // Math.max(0, currentAxisTime - timeWindow),
544
+ // Math.max(currentAxisTime, timeWindow)
545
+ // )
546
+ // yAxisRanges.set(axisId, timeRange)
547
+ // setCurrentTime(axisId, timeRange.end) // callback
548
+ // }
549
+ }
550
+ })
551
+
552
+ // // grab the stats
553
+ // ordinalStatsRef.current.minDatum = copyOrdinalDatumExtremum(data.stats.minDatum)
554
+ // ordinalStatsRef.current.maxDatum = copyOrdinalDatumExtremum(data.stats.maxDatum)
555
+ // ordinalStatsRef.current.valueStatsForSeries = copyValueStatsForSeries(data.stats.valueStatsForSeries)
556
+
557
+ // update the data
558
+ updateTimingAndPlot(yAxisRanges) // callback
559
+ })
560
+ })
561
+
562
+ // provide the subscription to the caller
563
+ onSubscribe(subscription) // callback
564
+
565
+ return subscription
566
+ }
567
+
568
+ /**
569
+ * Determines which series are assigned to which x-axes, and returns a map holding the
570
+ * x-axis names and their associated list of series
571
+ * @param data The chart data
572
+ * @param axisAssignments A map holding the series names and its associated x-axis and y-axis names
573
+ * @param xAxesState Holds information about the axis and how it is displayed
574
+ * @return A map holding the x-axis names the names of the series associated with the axis.
575
+ */
576
+ function associatedSeriesForXAxes(
577
+ data: TimeSeriesChartData,
578
+ axisAssignments: Map<string, AxesAssignment>,
579
+ xAxesState: AxesState<ContinuousNumericAxis>
580
+ ): Map<string, Array<string>> {
581
+ return associatedSeriesFor(
582
+ assignment => assignment?.xAxis || xAxesState.axisDefaultId().getOrElse(""),
583
+ data,
584
+ axisAssignments
585
+ )
586
+ }
587
+
588
+ /**
589
+ * Determines which series are assigned to which y-axes, and returns a map holding the
590
+ * x-axis names and their associated list of series
591
+ * @param data The chart data
592
+ * @param axisAssignments A map holding the series names and its associated x-axis and y-axis names
593
+ * @param yAxesState Holds information about the axis and how it is displayed
594
+ * @return A map holding the y-axis names the names of the series associated with the axis.
595
+ */
596
+ function associatedSeriesForYAxes(
597
+ data: ChartData,
598
+ axisAssignments: Map<string, AxesAssignment>,
599
+ yAxesState: AxesState<OrdinalStringAxis>
600
+ ): Map<string, Array<string>> {
601
+ return associatedSeriesFor(
602
+ assignment => assignment?.yAxis || yAxesState.axisDefaultId().getOrElse(""),
603
+ data,
604
+ axisAssignments
605
+ )
606
+ }
607
+
608
+ /**
609
+ * Determines which series are assigned to which axes, and returns a map holding the
610
+ * axis names and their associated list of series. The extractor function returns the axis ID
611
+ * for the series and is responsible for return the x-axis ID or the y-axis ID depending
612
+ * on the context of the call.
613
+ * @param axisIdExtractor A function that accepts the {@link AxesAssignment} and returns the axis ID
614
+ * @param data The chart data
615
+ * @param axisAssignments A map holding the series names and its associated x-axis and y-axis names
616
+ * @return A map holding the axis names the names of the series associated with the axis.
617
+ */
618
+ function associatedSeriesFor(
619
+ axisIdExtractor: (assignment?: AxesAssignment) => string,
620
+ data: ChartData,
621
+ axisAssignments: Map<string, AxesAssignment>
622
+ ): Map<string, Array<string>> {
623
+ return Array
624
+ .from(data.seriesNames)
625
+ .reduce(
626
+ (assignedSeries, seriesName) => {
627
+ const id = axisIdExtractor(axisAssignments.get(seriesName))
628
+ const series = assignedSeries.get(id) || []
629
+ series.push(seriesName)
630
+ assignedSeries.set(id, series)
631
+ return assignedSeries
632
+ },
633
+ new Map<string, Array<string>>()
634
+ )
635
+ }