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