stream-charts 1.0.0 → 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 +758 -345
  2. package/changes.md +10 -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} +17 -11
  146. package/dist/src/app/charts/{tooltipUtils.js → tooltips/tooltipUtils.js} +52 -25
  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,58 @@
1
+ /**
2
+ * Margin information
3
+ */
4
+ export interface Margin {
5
+ top: number
6
+ right: number
7
+ bottom: number
8
+ left: number
9
+ }
10
+
11
+ export function noMargins(): Margin {
12
+ return {top: 0, bottom: 0, left: 0, right: 0}
13
+ }
14
+
15
+ export interface Dimensions {
16
+ readonly width: number
17
+ readonly height: number
18
+ }
19
+
20
+ /**
21
+ * Given the dimensions of the plot (width, height) based on the container's width and height,
22
+ * and the plot's margins. Calculates the dimensions of the actual plot by subtracting the margins.
23
+ * @param containerWidth The overall width of the container (plot and margins)
24
+ * @param containerHeight The overall height of the container (plot and margins)
25
+ * @param plotMargins The margins around the plot (top, bottom, left, right)
26
+ * @return The dimensions of the actual plots adjusted for the margins
27
+ * from the overall dimensions
28
+ * @see containerDimensionsFrom
29
+ */
30
+ export function plotDimensionsFrom(containerWidth: number, containerHeight: number, plotMargins: Margin): Dimensions {
31
+ return {
32
+ width: containerWidth - plotMargins.left - plotMargins.right,
33
+ height: containerHeight - plotMargins.top - plotMargins.bottom
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Calculates the container's dimensions from the plot dimensions and the plot margin. The container
39
+ * dimensions are the plot dimensions plus the margins.
40
+ * @param plotDimensions The (width, height) of the plot
41
+ * @param plotMargin The margins around the plot
42
+ * @return The container dimensions.
43
+ * @see plotDimensionsFrom
44
+ */
45
+ export function containerDimensionsFrom(plotDimensions: Dimensions, plotMargin: Margin): Dimensions {
46
+ return {
47
+ width: plotDimensions.width + plotMargin.left + plotMargin.right,
48
+ height: plotDimensions.height + plotMargin.top + plotMargin.bottom
49
+ }
50
+ }
51
+
52
+ export function dimensionsEqual(dimension1: Dimensions, dimension2: Dimensions) {
53
+ return dimension1.height === dimension2.height && dimension1.width === dimension2.width
54
+ }
55
+
56
+ export function dimensionsNotEqual(dimension1: Dimensions, dimension2: Dimensions) {
57
+ return !dimensionsEqual(dimension1, dimension2)
58
+ }
@@ -0,0 +1,118 @@
1
+ import * as d3 from "d3";
2
+ import {BaseType} from "d3";
3
+
4
+ export interface SvgStyle {
5
+ height?: string | number;
6
+ width?: string | number;
7
+ outline?: string;
8
+
9
+ [propName: string]: any;
10
+ }
11
+
12
+ export const initialSvgStyle: SvgStyle = {
13
+ width: '100%',
14
+ // display: "inline-block",
15
+ // position: "floating",
16
+ top: 0,
17
+ left: 0
18
+ };
19
+
20
+ /**
21
+ * Grabs the client-width of the svg element, or 1 if the svg element hasn't yet
22
+ * been initialized. The client-width is a read-only property returns the width of
23
+ * the html element, including horizontal padding and borders, as an integer. The reason
24
+ * that we return 1 when the svg element hasn't yet been initialized, is so that the
25
+ * aspect (width / height) is 1.
26
+ * @param {SVGElement | null} svg The svg element
27
+ * @return {number} The client width of the svg
28
+ */
29
+ export function grabWidth(svg: SVGElement | null): number {
30
+ return svg !== null ? svg.clientWidth : 1;
31
+ }
32
+
33
+ /**
34
+ * Grabs the client-height of the svg element, or 1 if the svg element hasn't yet
35
+ * been initialized. The client-height is a read-only property returns the height of
36
+ * the html element, including vertical padding and borders, as an integer. The reason
37
+ * that we return 1 when the svg element hasn't yet been initialized, is so that the
38
+ * aspect (width / height) is 1.
39
+ * @param {SVGElement | null} svg The svg element
40
+ * @return {number} The client height of the svg
41
+ */
42
+ export function grabHeight(svg: SVGElement | null): number {
43
+ return svg !== null ? svg.clientHeight : 1;
44
+ }
45
+
46
+
47
+ export const STROKE_COLOR: string = "stroke"
48
+ export const STROKE_WIDTH: string = "stroke-width"
49
+ export const STROKE_OPACITY: string = "stroke-opacity"
50
+
51
+ export interface SvgStrokeStyle {
52
+ readonly color: string
53
+ readonly width: number
54
+ readonly opacity: number
55
+ }
56
+
57
+ export function updateSvgStrokeColor(current: SvgStrokeStyle, color: string) {
58
+ return {...current, color};
59
+ }
60
+
61
+ export function updateSvgStrokeWidth(current: SvgStrokeStyle, width: number) {
62
+ return {...current, width};
63
+ }
64
+
65
+ export function updateSvgStrokeOpacity(current: SvgStrokeStyle, opacity: number) {
66
+ return {...current, opacity};
67
+ }
68
+
69
+ /**
70
+ *
71
+ * @param style
72
+ * @param selection
73
+ * @template E The SVG element (e.g. SVGRectElement, SVGLineElement, etc)
74
+ * @template D The datum type
75
+ * @template The SVG G element
76
+ */
77
+ export function applyStrokeStylesTo<E extends BaseType, D, G extends BaseType = SVGGElement>(
78
+ selection: d3.Selection<E, D, G, any>,
79
+ style: Partial<SvgStrokeStyle>
80
+ ): d3.Selection<E, D, G, any> {
81
+ if (style.color !== undefined) selection.style(STROKE_COLOR, style.color)
82
+ if (style.width !== undefined) selection.style(STROKE_WIDTH, style.width)
83
+ if (style.opacity !== undefined) selection.style(STROKE_OPACITY, style.opacity)
84
+ return selection
85
+ }
86
+
87
+ const FILL_COLOR: string = "fill"
88
+ const FILL_OPACITY: string = "fill-opacity"
89
+
90
+ export interface SvgFillStyle {
91
+ readonly color: string
92
+ readonly opacity: number
93
+ }
94
+
95
+ export function updateSvgFillColor(current: SvgFillStyle, color: string): SvgFillStyle {
96
+ return {...current, color}
97
+ }
98
+
99
+ export function updateSvgFillOpacity(current: SvgFillStyle, opacity: number): SvgFillStyle {
100
+ return {...current, opacity}
101
+ }
102
+
103
+ /**
104
+ *
105
+ * @param style
106
+ * @param selection
107
+ * @template E The SVG element (e.g. SVGRectElement, SVGLineElement, etc)
108
+ * @template D The datum type
109
+ * @template The SVG G element
110
+ */
111
+ export function applyFillStylesTo<E extends BaseType, D, G extends BaseType = SVGGElement>(
112
+ selection: d3.Selection<E, D, G, any>,
113
+ style: Partial<SvgFillStyle>
114
+ ): d3.Selection<E, D, G, any> {
115
+ if (style.color !== undefined) selection.style(FILL_COLOR, style.color)
116
+ if (style.opacity !== undefined) selection.style(FILL_OPACITY, style.opacity)
117
+ return selection
118
+ }
@@ -0,0 +1,499 @@
1
+ import {filter, map, scan} from 'rxjs/operators';
2
+ import {Observable, range} from 'rxjs';
3
+ import {IterateChartData, iteratesObservable as iterateObservable} from '../observables/iterates'
4
+ import {TimeSeriesChartData} from "../series/timeSeriesChartData";
5
+ import {datumOf} from "../series/timeSeries";
6
+
7
+
8
+ type Point = {
9
+ x: number
10
+ y: number
11
+ }
12
+
13
+ const pointFrom = (x: number, y: number): Point => ({x, y})
14
+ const emptyPoint = (): Point => ({x: NaN, y: NaN})
15
+ const isEmptyPoint = (point?: Point): boolean => point === undefined || (isNaN(point.x) && isNaN(point.y))
16
+ const nonEmptyPoint = (point?: Point): boolean => !isEmptyPoint(point)
17
+
18
+ type Accumulate = {
19
+ // n-difference, which is the number of points between successive differences
20
+ n: number
21
+ // holds the previous n point (for successive-n differences)
22
+ previous: Array<Point>
23
+ // the current successive-n difference
24
+ difference?: Point
25
+ }
26
+ const initialAccumulate = (n: number = 1): Accumulate => ({n, previous: []})
27
+
28
+ /**
29
+ * Source for {@link Point} data that generates `x`-values from a range of 1 to `numPoints` and
30
+ * creates the `y`-values by applying the `valueFn` to those `x`-values.
31
+ * @param numPoints The number of points to generate
32
+ * @param valueFn The function that maps `x` to `y` (i.e. the value function is `f(x)` in `y = f(x)`)
33
+ * @return an observable of {@link Point}
34
+ */
35
+ function pointsObservable(numPoints: number = 10, valueFn: (x: number) => number): Observable<Point> {
36
+ return range(1, numPoints).pipe(map(value => pointFrom(value, valueFn(value))))
37
+ }
38
+
39
+ /**
40
+ *
41
+ * @param n The number of points back from which to calculate the `n-difference`
42
+ * @param dataObservable Observable that is the source of the underlying data
43
+ * @param useStartX Whether to use the x-value from the beginning of the interval as the x-value
44
+ * for the difference (default), or whether to use the last x-value in the interval.
45
+ */
46
+ function successiveDiffsObservable(
47
+ n: number = 1,
48
+ dataObservable: Observable<Point>,
49
+ useStartX: boolean = true
50
+ ): Observable<Point> {
51
+ return dataObservable
52
+ .pipe(
53
+ scan(({n, previous,}, current) => {
54
+ // when we have accumulated enough previous values to cover the "n-difference",
55
+ // we can calculate an actual difference
56
+ if (previous.length >= n) {
57
+ // add the new point, and take the first point from the beginning
58
+ previous.push(current)
59
+ const first: Point = previous.shift() || emptyPoint()
60
+
61
+ // calculate the n-difference, using the x-value of the initial point (default)
62
+ // or the current point (end of current time-range
63
+ const difference = pointFrom(
64
+ useStartX ? first.x : current.x,
65
+ current.y - first.y
66
+ )
67
+
68
+ return {n, previous, difference}
69
+ }
70
+
71
+ // not enough points yet, so just accumulate the current point
72
+ previous.push(current)
73
+
74
+ return {n, previous}
75
+
76
+ }, initialAccumulate(n)),
77
+ filter(accum => nonEmptyPoint(accum.difference)),
78
+ map(accum => accum.difference === undefined ? emptyPoint() : accum.difference)
79
+ )
80
+ }
81
+
82
+ describe('should be able to calculate successive differences', () => {
83
+
84
+ test('should be able to calc successive-diffs for x^2 where x is in 1..10', done => {
85
+ let results: Array<Point> = []
86
+ successiveDiffsObservable(1, pointsObservable(10, x => x * x), true).subscribe(point => results.push(point))
87
+ done()
88
+ expect(results).toHaveLength(9)
89
+ expect(results).toEqual([
90
+ {x: 1, y: 3},
91
+ {x: 2, y: 5},
92
+ {x: 3, y: 7},
93
+ {x: 4, y: 9},
94
+ {x: 5, y: 11},
95
+ {x: 6, y: 13},
96
+ {x: 7, y: 15},
97
+ {x: 8, y: 17},
98
+ {x: 9, y: 19},
99
+ ])
100
+ });
101
+
102
+ test('should be able to calc successive-diffs for x^2 where x is in 1..10 using interval end', done => {
103
+ let results: Array<Point> = []
104
+ successiveDiffsObservable(1, pointsObservable(10, x => x * x), false).subscribe(point => results.push(point))
105
+ done()
106
+ expect(results).toHaveLength(9)
107
+ expect(results).toEqual([
108
+ {x: 2, y: 3},
109
+ {x: 3, y: 5},
110
+ {x: 4, y: 7},
111
+ {x: 5, y: 9},
112
+ {x: 6, y: 11},
113
+ {x: 7, y: 13},
114
+ {x: 8, y: 15},
115
+ {x: 9, y: 17},
116
+ {x: 10, y: 19},
117
+ ])
118
+ });
119
+
120
+ test('should be able to calc 3-diffs for x^2 where x is in 1..10', done => {
121
+ let results: Array<Point> = []
122
+ successiveDiffsObservable(3, pointsObservable(10, x => x * x), true).subscribe(point => results.push(point))
123
+ done()
124
+ expect(results).toHaveLength(7)
125
+ expect(results).toEqual([
126
+ {x: 1, y: 15},
127
+ {x: 2, y: 21},
128
+ {x: 3, y: 27},
129
+ {x: 4, y: 33},
130
+ {x: 5, y: 39},
131
+ {x: 6, y: 45},
132
+ {x: 7, y: 51},
133
+ ])
134
+ });
135
+
136
+ test('should be able to calc 3-diffs for x^2 where x is in 1..10 using interval end', done => {
137
+ let results: Array<Point> = []
138
+ successiveDiffsObservable(3, pointsObservable(10, x => x * x), false).subscribe(point => results.push(point))
139
+ done()
140
+ expect(results).toHaveLength(7)
141
+ expect(results).toEqual([
142
+ {x: 4, y: 15},
143
+ {x: 5, y: 21},
144
+ {x: 6, y: 27},
145
+ {x: 7, y: 33},
146
+ {x: 8, y: 39},
147
+ {x: 9, y: 45},
148
+ {x: 10, y: 51},
149
+ ])
150
+ });
151
+ })
152
+
153
+ /**
154
+ * Observable that converts data points into iterates for poincare plots where one plots x(j+n) vs x(j)
155
+ * @param n The n-th iterate for plotting x(j+n) vs x(j)
156
+ * @param dataObservable The observable with the point data
157
+ * @return an observable of a stream of {@link Point}s
158
+ */
159
+ function iteratesObservable(n: number = 1, dataObservable: Observable<Point>): Observable<Point> {
160
+ return dataObservable
161
+ .pipe(
162
+ scan(({n, previous,}, current) => {
163
+ // when we have accumulated enough previous values to cover the "n-iterate",
164
+ // we can grab the y-value from the n-th point back
165
+ if (previous.length >= n) {
166
+ // add the new point, and take the first point from the beginning
167
+ previous.push(pointFrom(previous[previous.length - 1].y, current.y))
168
+ const first: Point = previous.shift() || emptyPoint()
169
+
170
+ // calculate the n-difference, using the x-value of the initial point (default)
171
+ // or the current point (end of current time-range
172
+ const iterate = pointFrom(first.y, current.y)
173
+
174
+ return {n, previous, difference: iterate}
175
+ }
176
+
177
+ // not enough points yet, so just accumulate the current point
178
+ previous.push(current)
179
+
180
+ return {n, previous}
181
+
182
+ }, initialAccumulate(n)),
183
+ filter(accum => nonEmptyPoint(accum.difference)),
184
+ map(accum => accum.difference === undefined ? emptyPoint() : accum.difference)
185
+ )
186
+ }
187
+
188
+ function tentFn(x: number, mu: number = 1): number {
189
+ return x < 0.5 ? mu * x : mu * (1 - x)
190
+ }
191
+
192
+ describe('should be able to calculate iterates', () => {
193
+
194
+ test('should be able to calc 1-iterates for x^2 where x is in 1..10', done => {
195
+ let results: Array<Point> = []
196
+ iteratesObservable(1, pointsObservable(10, x => 2 * x)).subscribe(point => results.push(point))
197
+ done()
198
+ expect(results).toHaveLength(9)
199
+ expect(results).toEqual([
200
+ {x: 2, y: 4},
201
+ {x: 4, y: 6},
202
+ {x: 6, y: 8},
203
+ {x: 8, y: 10},
204
+ {x: 10, y: 12},
205
+ {x: 12, y: 14},
206
+ {x: 14, y: 16},
207
+ {x: 16, y: 18},
208
+ {x: 18, y: 20}
209
+ ])
210
+ });
211
+
212
+ test('should be able to calc 3-iterates for x^2 where x is in 1..10', done => {
213
+ let results: Array<Point> = []
214
+ iteratesObservable(3, pointsObservable(10, x => 2 * x)).subscribe(point => results.push(point))
215
+ done()
216
+ expect(results).toHaveLength(7)
217
+ expect(results).toEqual([
218
+ {x: 2, y: 8},
219
+ {x: 4, y: 10},
220
+ {x: 6, y: 12},
221
+ {x: 8, y: 14},
222
+ {x: 10, y: 16},
223
+ {x: 12, y: 18},
224
+ {x: 14, y: 20}
225
+ ])
226
+ });
227
+
228
+
229
+ test('tent map should converge to (0, 0) for mu < 1', done => {
230
+ const numPoints = 100000
231
+ let lastPoint = emptyPoint()
232
+
233
+ iteratesObservable(1, range(0, numPoints).pipe(map(x => pointFrom(x, tentFn(x / numPoints, 0.15)))))
234
+ .subscribe(point => lastPoint = point)
235
+
236
+ done()
237
+ expect(lastPoint.y).toBeLessThan(1e-5)
238
+ expect(lastPoint.x).toBeLessThan(1e-5)
239
+ })
240
+ })
241
+
242
+ describe('when calculating tent-map iterates with one new data point for each event', () => {
243
+
244
+ test('should be able to calc 1-iterates for tent-map chart data, when 1 point is added at a time', done => {
245
+ const numPoints = 10
246
+ let results: Array<IterateChartData> = []
247
+ iterateObservable(
248
+ range(0, numPoints).pipe(
249
+ map(x => ({
250
+ maxTime: x,
251
+ maxTimes: new Map([['test1', x]]),
252
+ newPoints: new Map([['test1', [datumOf(x, tentFn(x / numPoints, 0.15))]]])
253
+ } as TimeSeriesChartData))
254
+ )).subscribe(point => results.push(point));
255
+ done()
256
+ expect(results).toHaveLength(9)
257
+
258
+ //
259
+ // check the first iterate datum
260
+ expect(results[0].minIterate.iterateN).toEqual(0)
261
+ expect(results[0].minIterate.iterateN_1).toEqual(0.015)
262
+ expect(results[0].maxIterate.iterateN).toEqual(0)
263
+ expect(results[0].maxIterate.iterateN_1).toEqual(0.015)
264
+
265
+ expect(results[0].minIterates.has("test1")).toBe(true)
266
+ expect(results[0].minIterates.size).toEqual(1)
267
+ expect(results[0].minIterates.get("test1")!.time).toEqual(0)
268
+ expect(results[0].minIterates.get("test1")!.iterateN).toEqual(0)
269
+ expect(results[0].minIterates.get("test1")!.iterateN_1).toEqual(0.015)
270
+
271
+ expect(results[0].maxIterates.has("test1")).toBe(true)
272
+ expect(results[0].maxIterates.size).toEqual(1)
273
+ expect(results[0].maxIterates.get("test1")!.time).toEqual(0)
274
+ expect(results[0].maxIterates.get("test1")!.iterateN).toBeCloseTo(0, 4)
275
+ expect(results[0].maxIterates.get("test1")!.iterateN_1).toBeCloseTo(0.015, 4)
276
+
277
+ // check that the accumulator "newPoints" holds the previous "newPoints" for the iterate
278
+ expect(results[0].newPoints.has("test1")).toBe(true)
279
+ expect(results[0].newPoints.get("test1")).toHaveLength(1)
280
+ expect(results[0].newPoints.get("test1")![0].time).toEqual(0)
281
+ expect(results[0].newPoints.get("test1")![0].iterateN).toEqual(0)
282
+ expect(results[0].newPoints.get("test1")![0].iterateN_1).toBeCloseTo(0.015, 4)
283
+
284
+ //
285
+ // check the last iterate datum
286
+ expect(results[8].minIterate.time).toEqual(8)
287
+ expect(results[8].minIterate.iterateN).toEqual(0)
288
+ expect(results[8].minIterate.iterateN_1).toBeCloseTo(0.015, 4)
289
+
290
+ expect(results[8].maxIterate.time).toEqual(5)
291
+ expect(results[8].maxIterate.iterateN).toBeCloseTo(0.075, 4)
292
+ expect(results[8].maxIterate.iterateN_1).toBeCloseTo(0.075, 4)
293
+
294
+ expect(results[8].minIterates.has("test1")).toBe(true)
295
+ expect(results[8].minIterates.size).toEqual(1)
296
+ expect(results[8].minIterates.get("test1")!.time).toEqual(8)
297
+ expect(results[8].minIterates.get("test1")!.iterateN).toEqual(0)
298
+ expect(results[8].minIterates.get("test1")!.iterateN_1).toBeCloseTo(0.015, 4)
299
+
300
+ expect(results[8].maxIterates.has("test1")).toBe(true)
301
+ expect(results[8].maxIterates.size).toEqual(1)
302
+ expect(results[8].maxIterates.get("test1")!.time).toEqual(5)
303
+ expect(results[8].maxIterates.get("test1")!.iterateN).toBeCloseTo(0.075, 4)
304
+ expect(results[8].maxIterates.get("test1")!.iterateN_1).toBeCloseTo(0.075, 4)
305
+
306
+ // check that the accumulator "newPoints" holds the previous "newPoints" for the iterate
307
+ expect(results[8].newPoints.has("test1")).toBe(true)
308
+ expect(results[8].newPoints.get("test1")).toHaveLength(1)
309
+ expect(results[8].newPoints.get("test1")![0].time).toEqual(8)
310
+ expect(results[8].newPoints.get("test1")![0].iterateN).toBeCloseTo(0.03, 4)
311
+ expect(results[8].newPoints.get("test1")![0].iterateN_1).toBeCloseTo(0.015, 4)
312
+ });
313
+ })
314
+
315
+ describe('when calculating tent-map 1-iterates with two new data points for each event', () => {
316
+
317
+ test('should be able to calc iterates for tent-map chart data, when 2 points are added at a time', done => {
318
+ const numPoints = 5
319
+ let results: Array<IterateChartData> = []
320
+ iterateObservable(
321
+ range(0, numPoints)
322
+ .pipe(
323
+ map(x => ({
324
+ maxTime: 2 * x,
325
+ maxTimes: new Map([['test1', 2 * x]]),
326
+ newPoints: new Map([
327
+ ['test1', [datumOf(2 * x, tentFn(2 * x / (2 * numPoints), 0.15)), datumOf(2 * x + 1, tentFn((2 * x + 1) / (2 * numPoints), 0.15))]],
328
+ ])
329
+ } as TimeSeriesChartData))
330
+ ))
331
+ .subscribe(result => results.push(result));
332
+ done()
333
+ expect(results).toHaveLength(5)
334
+ expect(results.reduce((count, result) => result.newPoints.get("test1")!.length + count, 0)).toEqual(9)
335
+
336
+ //
337
+ // check the first iterate datum
338
+ expect(results[0].minIterate.iterateN).toBeCloseTo(0, 4)
339
+ expect(results[0].minIterate.iterateN_1).toBeCloseTo(0.015, 4)
340
+ expect(results[0].maxIterate.iterateN).toBeCloseTo(0, 4)
341
+ expect(results[0].maxIterate.iterateN_1).toBeCloseTo(0.015, 4)
342
+
343
+ expect(results[0].minIterates.has("test1")).toBe(true)
344
+ expect(results[0].minIterates.size).toEqual(1)
345
+ expect(results[0].minIterates.get("test1")!.time).toBeCloseTo(0, 4)
346
+ expect(results[0].minIterates.get("test1")!.iterateN).toBeCloseTo(0, 4)
347
+ expect(results[0].minIterates.get("test1")!.iterateN_1).toBeCloseTo(0.015, 4)
348
+
349
+ expect(results[0].maxIterates.has("test1")).toBe(true)
350
+ expect(results[0].maxIterates.size).toEqual(1)
351
+ expect(results[0].maxIterates.get("test1")!.time).toEqual(0)
352
+ expect(results[0].maxIterates.get("test1")!.iterateN).toBeCloseTo(0, 4)
353
+ expect(results[0].maxIterates.get("test1")!.iterateN_1).toBeCloseTo(0.015, 4)
354
+
355
+ // check that the accumulator "newPoints" holds the previous "newPoints" for the iterate
356
+ expect(results[0].newPoints.has("test1")).toBe(true)
357
+ expect(results[0].newPoints.get("test1")).toHaveLength(1)
358
+ expect(results[0].newPoints.get("test1")![0].time).toEqual(0)
359
+ expect(results[0].newPoints.get("test1")![0].iterateN).toEqual(0)
360
+ expect(results[0].newPoints.get("test1")![0].iterateN_1).toBeCloseTo(0.015, 4)
361
+
362
+ //
363
+ // check the last iterate datum
364
+ expect(results[4].minIterate.time).toEqual(8)
365
+ expect(results[4].minIterate.iterateN).toEqual(0)
366
+ expect(results[4].minIterate.iterateN_1).toBeCloseTo(0.015, 4)
367
+
368
+ expect(results[4].maxIterate.time).toEqual(5)
369
+ expect(results[4].maxIterate.iterateN).toBeCloseTo(0.075, 4)
370
+ expect(results[4].maxIterate.iterateN_1).toBeCloseTo(0.075, 4)
371
+
372
+ expect(results[4].minIterates.size).toEqual(1)
373
+ expect(results[4].minIterates.has("test1")).toBe(true)
374
+ expect(results[4].minIterates.get("test1")!.time).toEqual(8)
375
+ expect(results[4].minIterates.get("test1")!.iterateN).toEqual(0)
376
+ expect(results[4].minIterates.get("test1")!.iterateN_1).toBeCloseTo(0.015, 4)
377
+
378
+ expect(results[4].maxIterates.size).toEqual(1)
379
+ expect(results[4].maxIterates.has("test1")).toBe(true)
380
+ expect(results[4].maxIterates.get("test1")!.time).toEqual(5)
381
+ expect(results[4].maxIterates.get("test1")!.iterateN).toBeCloseTo(0.075, 4)
382
+ expect(results[4].maxIterates.get("test1")!.iterateN_1).toBeCloseTo(0.075, 4)
383
+
384
+ // check that the accumulator "newPoints" holds the previous "newPoints" for the iterate
385
+ expect(results[4].newPoints.has("test1")).toBe(true)
386
+ expect(results[4].newPoints.get("test1")).toHaveLength(2)
387
+ expect(results[4].newPoints.get("test1")![1].time).toEqual(8)
388
+ expect(results[4].newPoints.get("test1")![1].iterateN).toBeCloseTo(0.03, 4)
389
+ expect(results[4].newPoints.get("test1")![1].iterateN_1).toBeCloseTo(0.015, 4)
390
+ });
391
+
392
+ test('should be able to calc iterates for tent-map chart data, when 2 points are added at a time, with 2 series', done => {
393
+ const numPoints = 5
394
+ let results: Array<IterateChartData> = []
395
+ iterateObservable(
396
+ range(0, numPoints)
397
+ .pipe(
398
+ map(x => ({
399
+ maxTime: 2 * x,
400
+ maxTimes: new Map([['test1', 2 * x]]),
401
+ newPoints: new Map([
402
+ ['test1', [datumOf(2 * x, tentFn(2 * x / (2 * numPoints), 0.15)), datumOf(2 * x + 1, tentFn((2 * x + 1) / (2 * numPoints), 0.15))]],
403
+ ['test2', [datumOf(2 * x, tentFn(2 * x / (2 * numPoints), 0.35)), datumOf(2 * x + 1, tentFn((2 * x + 1) / (2 * numPoints), 0.35))]],
404
+ ])
405
+ } as TimeSeriesChartData))
406
+ ))
407
+ .subscribe(result => results.push(result));
408
+ done()
409
+ expect(results).toHaveLength(5)
410
+ expect(results.reduce((count, result) => result.newPoints.get("test1")!.length + count, 0)).toEqual(9)
411
+
412
+ //
413
+ // check the first iterate datum
414
+ expect(results[0].minIterate.iterateN).toBeCloseTo(0, 4)
415
+ expect(results[0].minIterate.iterateN_1).toBeCloseTo(0.015, 4)
416
+ expect(results[0].maxIterate.iterateN).toBeCloseTo(0, 4)
417
+ expect(results[0].maxIterate.iterateN_1).toBeCloseTo(0.035, 4)
418
+
419
+ expect(results[0].minIterates.size).toEqual(2)
420
+ expect(results[0].minIterates.has("test1")).toBe(true)
421
+ expect(results[0].minIterates.get("test1")!.time).toBeCloseTo(0, 4)
422
+ expect(results[0].minIterates.get("test1")!.iterateN).toBeCloseTo(0, 4)
423
+ expect(results[0].minIterates.get("test1")!.iterateN_1).toBeCloseTo(0.015, 4)
424
+
425
+ expect(results[0].minIterates.has("test2")).toBe(true)
426
+ expect(results[0].minIterates.get("test2")!.time).toBeCloseTo(0, 4)
427
+ expect(results[0].minIterates.get("test2")!.iterateN).toBeCloseTo(0, 4)
428
+ expect(results[0].minIterates.get("test2")!.iterateN_1).toBeCloseTo(0.035, 4)
429
+
430
+ expect(results[0].maxIterates.size).toEqual(2)
431
+ expect(results[0].maxIterates.has("test1")).toBe(true)
432
+ expect(results[0].maxIterates.get("test1")!.time).toEqual(0)
433
+ expect(results[0].maxIterates.get("test1")!.iterateN).toBeCloseTo(0, 4)
434
+ expect(results[0].maxIterates.get("test1")!.iterateN_1).toBeCloseTo(0.015, 4)
435
+
436
+ expect(results[0].maxIterates.has("test2")).toBe(true)
437
+ expect(results[0].maxIterates.get("test2")!.time).toEqual(0)
438
+ expect(results[0].maxIterates.get("test2")!.iterateN).toBeCloseTo(0, 4)
439
+ expect(results[0].maxIterates.get("test2")!.iterateN_1).toBeCloseTo(0.035, 4)
440
+
441
+ // check that the accumulator "newPoints" holds the previous "newPoints" for the iterate
442
+ expect(results[0].newPoints.has("test1")).toBe(true)
443
+ expect(results[0].newPoints.get("test1")).toHaveLength(1)
444
+ expect(results[0].newPoints.get("test1")![0].time).toEqual(0)
445
+ expect(results[0].newPoints.get("test1")![0].iterateN).toEqual(0)
446
+ expect(results[0].newPoints.get("test1")![0].iterateN_1).toBeCloseTo(0.015, 4)
447
+
448
+ expect(results[0].newPoints.has("test2")).toBe(true)
449
+ expect(results[0].newPoints.get("test2")).toHaveLength(1)
450
+ expect(results[0].newPoints.get("test2")![0].time).toEqual(0)
451
+ expect(results[0].newPoints.get("test2")![0].iterateN).toEqual(0)
452
+ expect(results[0].newPoints.get("test2")![0].iterateN_1).toBeCloseTo(0.035, 4)
453
+
454
+ //
455
+ // check the last iterate datum
456
+ expect(results[4].minIterate.time).toEqual(8)
457
+ expect(results[4].minIterate.iterateN).toEqual(0)
458
+ expect(results[4].minIterate.iterateN_1).toBeCloseTo(0.015, 4)
459
+
460
+ expect(results[4].maxIterate.time).toEqual(5)
461
+ expect(results[4].maxIterate.iterateN).toBeCloseTo(0.175, 4)
462
+ expect(results[4].maxIterate.iterateN_1).toBeCloseTo(0.175, 4)
463
+
464
+ expect(results[4].minIterates.size).toEqual(2)
465
+ expect(results[4].minIterates.has("test1")).toBe(true)
466
+ expect(results[4].minIterates.get("test1")!.time).toEqual(8)
467
+ expect(results[4].minIterates.get("test1")!.iterateN).toEqual(0)
468
+ expect(results[4].minIterates.get("test1")!.iterateN_1).toBeCloseTo(0.015, 4)
469
+
470
+ expect(results[4].minIterates.has("test2")).toBe(true)
471
+ expect(results[4].minIterates.get("test2")!.time).toEqual(8)
472
+ expect(results[4].minIterates.get("test2")!.iterateN).toEqual(0)
473
+ expect(results[4].minIterates.get("test2")!.iterateN_1).toBeCloseTo(0.035, 4)
474
+
475
+ expect(results[4].maxIterates.size).toEqual(2)
476
+ expect(results[4].maxIterates.has("test1")).toBe(true)
477
+ expect(results[4].maxIterates.get("test1")!.time).toEqual(5)
478
+ expect(results[4].maxIterates.get("test1")!.iterateN).toBeCloseTo(0.075, 4)
479
+ expect(results[4].maxIterates.get("test1")!.iterateN_1).toBeCloseTo(0.075, 4)
480
+
481
+ expect(results[4].maxIterates.has("test2")).toBe(true)
482
+ expect(results[4].maxIterates.get("test2")!.time).toEqual(5)
483
+ expect(results[4].maxIterates.get("test2")!.iterateN).toBeCloseTo(0.175, 4)
484
+ expect(results[4].maxIterates.get("test2")!.iterateN_1).toBeCloseTo(0.175, 4)
485
+
486
+ // check that the accumulator "newPoints" holds the previous "newPoints" for the iterate
487
+ expect(results[4].newPoints.has("test1")).toBe(true)
488
+ expect(results[4].newPoints.get("test1")).toHaveLength(2)
489
+ expect(results[4].newPoints.get("test1")![1].time).toEqual(8)
490
+ expect(results[4].newPoints.get("test1")![1].iterateN).toBeCloseTo(0.03, 4)
491
+ expect(results[4].newPoints.get("test1")![1].iterateN_1).toBeCloseTo(0.015, 4)
492
+
493
+ expect(results[4].newPoints.has("test2")).toBe(true)
494
+ expect(results[4].newPoints.get("test2")).toHaveLength(2)
495
+ expect(results[4].newPoints.get("test2")![1].time).toEqual(8)
496
+ expect(results[4].newPoints.get("test2")![1].iterateN).toBeCloseTo(0.07, 4)
497
+ expect(results[4].newPoints.get("test2")![1].iterateN_1).toBeCloseTo(0.035, 4)
498
+ });
499
+ })