stream-charts 1.2.1 → 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 +36 -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,146 +1,128 @@
|
|
|
1
|
-
import { useCallback, useEffect,
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { useStreamingTimeAxes } from "./useStreamingTimeAxes";
|
|
3
|
+
import { useHoveredSeries } from "../hooks/useHoveredSeries";
|
|
2
4
|
import { useChart } from "../hooks/useChart";
|
|
5
|
+
import { scatterTooltipPointList, scatterTooltipPoints } from "../tooltips/tooltipUtils";
|
|
3
6
|
import * as d3 from "d3";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { clipToArea } from "./plot";
|
|
8
|
+
import { AxisType, checkAxisType, defaultLineStyle } from "../axes/axes";
|
|
9
|
+
import { seriesAt, canvasLocalPoint } from "./hitTesting";
|
|
10
|
+
import { firstIndexAtOrAfter, noop } from "../utils";
|
|
11
|
+
import { NoCurveFactory } from "./constants";
|
|
12
|
+
import { timeSeriesAxisTimes, TimeWindowBehavior } from "../subscriptions/viewDrivers";
|
|
13
|
+
import { useDataSource, useDataSourceRunning, useInitialData } from "../hooks/useDataSource";
|
|
14
|
+
import { extentWith, visibleExtent } from "../axes/autoScale";
|
|
15
|
+
import { growAutoScaledYAxes, useAutoScaleRestart } from "./autoScaleYAxes";
|
|
9
16
|
import { usePlotDimensions } from "../hooks/usePlotDimensions";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
// how close (in pixels) the mouse must be to a data point to be over that point (rather than over a
|
|
18
|
+
// line segment) -- at least this, or a little more than the markers' radius when they're larger
|
|
19
|
+
const MIN_POINT_HOVER_RADIUS = 6;
|
|
20
|
+
// the radii of the highlights on the points the tooltip shows: the hovered point, and the others
|
|
21
|
+
const TOOLTIP_POINT_RADIUS = 5;
|
|
22
|
+
const TOOLTIP_NEIGHBOR_RADIUS = 3.5;
|
|
13
23
|
/**
|
|
14
|
-
* Renders a streaming scatter plot for the series
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
24
|
+
* Renders a streaming scatter plot for the series held by the {@link StreamingDataSource} handed
|
|
25
|
+
* to the {@link Chart} (its `dataSource` prop). This component uses the {@link useChart} hook, and
|
|
26
|
+
* therefore must be a child of the {@link Chart} in order to be plugged in to the chart ecosystem
|
|
27
|
+
* (axes, tracker, tooltip).
|
|
28
|
+
*
|
|
29
|
+
* The plot never subscribes to the data stream itself: the application owns the data source (and
|
|
30
|
+
* starts/stops it), and the data source keeps ingesting even while this plot is unmounted. While
|
|
31
|
+
* the data source is running, this plot listens to its updates through a view driver that only
|
|
32
|
+
* advances the plot's own view (auto-scroll, cadence) and redraws -- created when the plot mounts
|
|
33
|
+
* (or the data source starts) and always torn down when it unmounts (or the data source stops).
|
|
34
|
+
*
|
|
35
|
+
* Internally, this no longer creates/updates SVG `<path>`/`<circle>` elements. Instead, it
|
|
36
|
+
* registers a single draw function with the chart's {@link CanvasContext} that redraws every
|
|
37
|
+
* series from scratch each time the canvas repaints. Mouse hover (for the tooltip) is handled by
|
|
38
|
+
* hit-testing the mouse position against the last-drawn series geometry (see `hitTesting.ts`) on a
|
|
39
|
+
* `mousemove` listener attached directly to the canvas, since canvas has no per-shape events.
|
|
40
|
+
*
|
|
41
|
+
* When the data source is paused, hovering over a series shows the tooltip (when there's one),
|
|
42
|
+
* and highlights the points it shows; a y-axis with `autoScale` set grows to fit the data on screen.
|
|
18
43
|
*
|
|
19
44
|
* @param props The properties associated with the scatter plot
|
|
45
|
+
* @return `null` (the plot draws onto the chart's canvas)
|
|
20
46
|
* @example
|
|
21
|
-
<ScatterPlot
|
|
22
|
-
interpolation={interpolation}
|
|
23
|
-
axisAssignments={new Map([
|
|
24
|
-
['test2', assignAxes("x-axis-2", "y-axis-2")],
|
|
25
|
-
])}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
/>
|
|
47
|
+
* <ScatterPlot
|
|
48
|
+
* interpolation={interpolation}
|
|
49
|
+
* axisAssignments={new Map([
|
|
50
|
+
* ['test2', assignAxes("x-axis-2", "y-axis-2")],
|
|
51
|
+
* ])}
|
|
52
|
+
* panEnabled={true}
|
|
53
|
+
* zoomEnabled={true}
|
|
54
|
+
* zoomKeyModifiersRequired={true}
|
|
55
|
+
* />
|
|
31
56
|
*/
|
|
32
57
|
export function ScatterPlot(props) {
|
|
33
|
-
|
|
58
|
+
var _a;
|
|
59
|
+
const { chartId, canvasContext, axes, color, seriesStyles, seriesFilter, mouse, backgroundColor, } = useChart();
|
|
60
|
+
const { hoveredSeriesName } = useHoveredSeries();
|
|
34
61
|
const { initialData } = useInitialData();
|
|
35
|
-
const { xAxesState, yAxesState,
|
|
62
|
+
const { xAxesState, yAxesState, updateAxisRanges = noop, axisRangeFor, } = axes;
|
|
36
63
|
const { mouseOverHandlerFor, mouseLeaveHandlerFor } = mouse;
|
|
37
64
|
const { plotDimensions, margin } = usePlotDimensions();
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
.map(([axisId, range]) => ([axisId, range.original.start])));
|
|
43
|
-
}, [axesRanges]);
|
|
65
|
+
// the application-owned source of the data, and whether it's running (streaming)
|
|
66
|
+
const dataSource = useDataSource();
|
|
67
|
+
const running = useDataSourceRunning(dataSource);
|
|
68
|
+
const { axisAssignments = new Map(), interpolation = d3.curveLinear, panEnabled = false, zoomEnabled = false, zoomKeyModifiersRequired = true, withCadenceOf, timeWindowBehavior = TimeWindowBehavior.SCROLL, markerRadius, hideMarkersWhileRunning = true, highlightAxesOnMouseOver = false, onZoomReset = noop, } = props;
|
|
44
69
|
// why do "dataRef" and "seriesRef" both hold on to the same underlying data? for performance.
|
|
45
70
|
//
|
|
46
71
|
// the "dataRef" and "seriesRef" both point to the same underlying data, a collection
|
|
47
|
-
// of series
|
|
48
|
-
//
|
|
72
|
+
// of series (held, and updated as new data is streamed in, by the data source). The "dataRef"
|
|
73
|
+
// array is what the draw function iterates over, and the "seriesRef" map is for looking a
|
|
74
|
+
// series up by its name.
|
|
49
75
|
//
|
|
50
76
|
// the "dataRef" object holds on to a copy of the initial data (which is an array of
|
|
51
|
-
// time-series, e.i. an array of BaseSeries<
|
|
77
|
+
// time-series, e.i. an array of BaseSeries<Datum> objects). The slice just creates a copy of
|
|
52
78
|
// the array, but the references to the BaseSeries objects are the same and still point to the same
|
|
53
79
|
// data as the "initialData" array.
|
|
54
80
|
//
|
|
55
|
-
// the "seriesRef" object is a reference to a map (series_name -> BaseSeries<
|
|
56
|
-
//
|
|
81
|
+
// the "seriesRef" object is a reference to a map (series_name -> BaseSeries<Datum>), used to find
|
|
82
|
+
// the series under the mouse (for the tooltip).
|
|
57
83
|
//
|
|
58
|
-
// the series in the "dataRef" object are the ones
|
|
59
|
-
// are updated,
|
|
84
|
+
// the series in the "dataRef" object are the ones read by the canvas draw function, and so as
|
|
85
|
+
// these are updated, the new data is picked up the next time the canvas redraws.
|
|
60
86
|
const dataRef = useRef(initialData.slice());
|
|
61
87
|
const seriesRef = useRef(new Map(initialData.map(series => [series.name, series])));
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// defined above allow the axes' times to be updated properly by avoid stale reference to these
|
|
74
|
-
// functions.
|
|
75
|
-
const updateTimingAndPlot = useCallback((ranges) => {
|
|
76
|
-
if (mainG !== null) {
|
|
77
|
-
onUpdateTimeRef.current(ranges);
|
|
78
|
-
updatePlotRef.current(ranges, mainG);
|
|
79
|
-
if (onUpdateAxesInterval) {
|
|
80
|
-
setTimeout(() => {
|
|
81
|
-
const times = new Map();
|
|
82
|
-
ranges.forEach((range, name) => times.set(name, range.current));
|
|
83
|
-
onUpdateAxesInterval(times);
|
|
84
|
-
}, 0);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}, [mainG, onUpdateAxesInterval]);
|
|
88
|
-
// todo find better way
|
|
89
|
-
// when the initial data changes, then reset the plot. note that the initial data doesn't change
|
|
90
|
-
// during the normal course of updates from the observable, only when the plot is restarted.
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
dataRef.current = initialData.slice();
|
|
93
|
-
seriesRef.current = new Map(initialData.map(series => [series.name, series]));
|
|
94
|
-
currentTimeRef.current = new Map(Array.from(xAxesState.axes.keys()).map(id => [id, 0]));
|
|
95
|
-
updateTimingAndPlot(new Map(Array.from(continuousAxisRanges(xAxesState.axes).entries())
|
|
96
|
-
.map(([id, range]) => {
|
|
97
|
-
// grab the current range, then calculate the minimum time from the initial data, and
|
|
98
|
-
// set that as the start, and then add the range to it for the end time
|
|
99
|
-
const [start, end] = range.original.asTuple();
|
|
100
|
-
const minTime = initialData
|
|
101
|
-
.filter(srs => { var _a; return ((_a = axisAssignments.get(srs.name)) === null || _a === void 0 ? void 0 : _a.xAxis) === id; })
|
|
102
|
-
.reduce((tMin, series) => Math.min(tMin, !series.isEmpty() ? series.data[0].time : tMin), Infinity);
|
|
103
|
-
const startTime = minTime === Infinity ? 0 : minTime;
|
|
104
|
-
return [id, ContinuousAxisRange.from(startTime, startTime + end - start)];
|
|
105
|
-
})));
|
|
106
|
-
},
|
|
107
|
-
// ** not happy about this **
|
|
108
|
-
// only want this effect to run when the initial data is changed, which mean all the
|
|
109
|
-
// other dependencies are recalculated anyway.
|
|
110
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
111
|
-
[initialData]);
|
|
112
|
-
/**
|
|
113
|
-
* Adjusts the time-range and updates the plot when the plot is dragged to the left or right
|
|
114
|
-
* @param deltaX The amount that the plot is dragged
|
|
115
|
-
* @param plotDimensions The dimensions of the plot
|
|
116
|
-
* @param ranges A map holding the axis ID and its associated time range
|
|
117
|
-
*/
|
|
118
|
-
const onPan = useCallback((x, plotDimensions, ranges) => panHandler(axesForSeries, margin, setAxisIntervalFor, xAxesState)(x, plotDimensions, ranges), [axesForSeries, margin, setAxisIntervalFor, xAxesState]);
|
|
119
|
-
/**
|
|
120
|
-
* Called when the user uses the scroll wheel (or scroll gesture) to zoom in or out. Zooms in/out
|
|
121
|
-
* at the location of the mouse when the scroll wheel or gesture was applied.
|
|
122
|
-
* @param transform The d3 zoom transformation information
|
|
123
|
-
* @param x The x-position of the mouse when the scroll wheel or gesture is used
|
|
124
|
-
* @param plotDimensions The dimensions of the plot
|
|
125
|
-
* @param series An array of series names
|
|
126
|
-
* @param ranges A map holding the axis ID and its associated time-range
|
|
127
|
-
*/
|
|
128
|
-
const onZoom = useCallback((transform, x, plotDimensions, ranges) => continuousAxisZoomHandler(axesForSeries, margin, setAxisIntervalFor, xAxesState)(transform, x, plotDimensions, ranges), [axesForSeries, margin, setAxisIntervalFor, xAxesState]);
|
|
88
|
+
// the last-drawn geometry for each series, in canvas coordinates, used for hit-testing mouse
|
|
89
|
+
// hover on `mousemove` (see the effect below that wires up the listener)
|
|
90
|
+
const geometryRef = useRef(new Map());
|
|
91
|
+
// the name of the series the mouse was over on the previous `mousemove`, so we know when to
|
|
92
|
+
// fire a "leave" for the old series before firing an "over" for the new one
|
|
93
|
+
const lastHoveredRef = useRef(undefined);
|
|
94
|
+
// the points the tooltip is showing (for the hovered series), which the plot highlights -- set
|
|
95
|
+
// on mouse-over while a tooltip is shown, and cleared when the mouse leaves the series
|
|
96
|
+
const tooltipPointsRef = useRef(undefined);
|
|
97
|
+
// tooltips are only shown while the data source is paused (and not while panning)
|
|
98
|
+
const allowTooltip = useRef(!((_a = dataSource === null || dataSource === void 0 ? void 0 : dataSource.running) !== null && _a !== void 0 ? _a : false));
|
|
129
99
|
const updatePlot = useCallback(
|
|
130
100
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
101
|
+
* (Re-)registers this plot's draw function with the canvas context and requests a redraw.
|
|
102
|
+
* Replaces the old version, which directly mutated SVG `<path>`/`<circle>` elements bound
|
|
103
|
+
* via d3's enter/update/exit join. Canvas has no persistent elements to join against, so
|
|
104
|
+
* the draw function just redraws every series from its current data/scale state each time
|
|
105
|
+
* it's invoked -- there's no separate "update" case to handle.
|
|
106
|
+
*
|
|
107
|
+
* Pan/zoom behavior setup lives in a separate effect (see below), not here -- this
|
|
108
|
+
* function runs on every data tick (each `windowingTime` interval), and recreating/
|
|
109
|
+
* reattaching a `d3.drag()`/`d3.zoom()` behavior that often is pure overhead with no
|
|
110
|
+
* benefit, since panEnabled/zoomEnabled/plotDimensions/margin change far less often than
|
|
111
|
+
* the data does.
|
|
112
|
+
* @param cc The canvas context to register the draw function with
|
|
134
113
|
*/
|
|
135
|
-
(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
//
|
|
114
|
+
(cc) => {
|
|
115
|
+
const draw = (context) => {
|
|
116
|
+
var _a;
|
|
117
|
+
// const __drawStart = performance.now()
|
|
118
|
+
// let __totalRetained = 0
|
|
119
|
+
// let __totalProcessed = 0
|
|
120
|
+
const { context2D } = context;
|
|
121
|
+
// create a map associating series-names with their time-series.
|
|
140
122
|
//
|
|
141
|
-
// performance-related confusion: wondering where the dataRef is updated? well it isn't
|
|
142
|
-
// directly. The dataRef holds on to an array of references to the Series. And so does the
|
|
143
|
-
// seriesRef, though
|
|
123
|
+
// performance-related confusion: wondering where the dataRef is updated? well, it isn't
|
|
124
|
+
// updated directly. The dataRef holds on to an array of references to the Series. And so does the
|
|
125
|
+
// seriesRef, though it uses a map(series_name -> series). The seriesRef is use to append
|
|
144
126
|
// data to the underlying Series, and the dataRef is used so that we can just use
|
|
145
127
|
// dataRef.current and don't have to do Array.from(seriesRef.current.values()) which
|
|
146
128
|
// creates a temporary array
|
|
@@ -148,44 +130,10 @@ export function ScatterPlot(props) {
|
|
|
148
130
|
series.name,
|
|
149
131
|
series.data
|
|
150
132
|
]));
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
d3.select(container).style("cursor", "move");
|
|
156
|
-
// during panning, we need to disable viewing the tooltip to prevent
|
|
157
|
-
// tooltips from rendering but not getting removed
|
|
158
|
-
allowTooltip.current = false;
|
|
159
|
-
})
|
|
160
|
-
.on("drag", (event) => {
|
|
161
|
-
onPan(event.dx, plotDimensions,
|
|
162
|
-
// Array.from(boundedSeries.keys()),
|
|
163
|
-
timeRanges);
|
|
164
|
-
updatePlotRef.current(timeRanges, mainGElem);
|
|
165
|
-
})
|
|
166
|
-
.on("end", () => {
|
|
167
|
-
d3.select(container).style("cursor", "auto");
|
|
168
|
-
// during panning, we disabled viewing the tooltip to prevent
|
|
169
|
-
// tooltips from rendering but not getting removed, now that panning
|
|
170
|
-
// is over, allow tooltips to render again
|
|
171
|
-
allowTooltip.current = isSubscriptionClosed();
|
|
172
|
-
});
|
|
173
|
-
svg.call(drag);
|
|
174
|
-
}
|
|
175
|
-
// set up for zooming
|
|
176
|
-
if (zoomEnabled) {
|
|
177
|
-
const zoom = d3.zoom()
|
|
178
|
-
.filter(event => !zoomKeyModifiersRequired || event.shiftKey || event.ctrlKey)
|
|
179
|
-
.scaleExtent([0, 10])
|
|
180
|
-
.translateExtent([[margin.left, margin.top], [plotDimensions.width, plotDimensions.height]])
|
|
181
|
-
.on("zoom", event => {
|
|
182
|
-
onZoom(event.transform, event.sourceEvent.offsetX - margin.left, plotDimensions, timeRanges);
|
|
183
|
-
updatePlotRef.current(timeRanges, mainGElem);
|
|
184
|
-
});
|
|
185
|
-
svg.call(zoom);
|
|
186
|
-
}
|
|
187
|
-
// define the clip-path so that the series lines don't go beyond the plot area
|
|
188
|
-
const clipPathId = setClipPathG(chartId, mainGElem, plotDimensions);
|
|
133
|
+
context2D.save();
|
|
134
|
+
clipToArea(context, plotDimensions, { x: margin.left, y: margin.top });
|
|
135
|
+
context2D.translate(margin.left, margin.top);
|
|
136
|
+
const newGeometry = new Map();
|
|
189
137
|
boundedSeries.forEach((data, name) => {
|
|
190
138
|
// grab the x and y axes assigned to the series, and if either or both
|
|
191
139
|
// axes aren't found, then give up and return
|
|
@@ -193,186 +141,295 @@ export function ScatterPlot(props) {
|
|
|
193
141
|
if (xAxisLinear === undefined || yAxisLinear === undefined)
|
|
194
142
|
return;
|
|
195
143
|
// grab the style for the series
|
|
196
|
-
const { color, lineWidth, highlightColor, highlightWidth } = seriesStyles.get(name) || defaultLineStyle();
|
|
144
|
+
const { color: seriesColor, lineWidth, highlightColor, highlightWidth } = seriesStyles.get(name) || defaultLineStyle();
|
|
197
145
|
// only show the data for which the filter matches
|
|
198
146
|
const plotData = (name.match(seriesFilter)) ? data : [];
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
147
|
+
const isHovered = hoveredSeriesName === name;
|
|
148
|
+
// skip the expensive per-point work below for retained-but-off-screen data:
|
|
149
|
+
// `plotData` can hold far more history than is ever visible (dropDataAfter is
|
|
150
|
+
// independent of, and often much larger than, the axis's current scrolling
|
|
151
|
+
// window), so iterating the *full* retained array every frame does a lot of
|
|
152
|
+
// work whose result is immediately thrown away as off-screen. Binary-search
|
|
153
|
+
// for where the visible domain begins, and only process from there on --
|
|
154
|
+
// backing up by one point so a line entering from off-screen still renders
|
|
155
|
+
// correctly across the boundary.
|
|
156
|
+
const [domainStart] = xAxisLinear.scale.domain();
|
|
157
|
+
const startIndex = Math.max(0, firstIndexAtOrAfter(plotData, domainStart, (d) => d.x) - 1);
|
|
158
|
+
const showMarkers = markerRadius != null && markerRadius >= 0 && (!running || !hideMarkersWhileRunning);
|
|
159
|
+
const markerRadiusResolved = isHovered ? markerRadius + 2 : markerRadius;
|
|
160
|
+
const segments = [];
|
|
161
|
+
let currentSegment = [];
|
|
162
|
+
const screenPoints = [];
|
|
163
|
+
context2D.fillStyle = isHovered ? highlightColor : seriesColor;
|
|
164
|
+
for (let i = startIndex; i < plotData.length; i++) {
|
|
165
|
+
const d = plotData[i];
|
|
166
|
+
const x = xAxisLinear.scale(d.x);
|
|
167
|
+
const y = yAxisLinear.scale(d.y);
|
|
168
|
+
// record geometry (outer/canvas coordinate space, margin baked in) for
|
|
169
|
+
// mousemove hit-testing, regardless of on/off-screen -- a point just past
|
|
170
|
+
// the edge should still be hoverable at the boundary
|
|
171
|
+
screenPoints.push([x + margin.left, y + margin.top]);
|
|
172
|
+
// the first point in this loop is the one deliberately backed up before
|
|
173
|
+
// the visible domain (see startIndex above); include it in the segment so
|
|
174
|
+
// the interpolated line entering from the left is smoothly clipped by the
|
|
175
|
+
// canvas's clip region as the plot scrolls, rather than the line abruptly
|
|
176
|
+
// popping into/out of existence right at the boundary
|
|
177
|
+
const isLeftEdgeContinuationPoint = i === startIndex && x < 0;
|
|
178
|
+
if (!isLeftEdgeContinuationPoint && (x < 0 || x > plotDimensions.width)) {
|
|
179
|
+
if (currentSegment.length > 0) {
|
|
180
|
+
segments.push(currentSegment);
|
|
181
|
+
currentSegment = [];
|
|
182
|
+
}
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
currentSegment.push([x, y]);
|
|
186
|
+
// point markers (one circle per datum) -- suppressed while streaming
|
|
187
|
+
// because redrawing many circles every frame is more work than a single
|
|
188
|
+
// line path
|
|
189
|
+
if (showMarkers) {
|
|
190
|
+
context2D.beginPath();
|
|
191
|
+
context2D.arc(x, y, markerRadiusResolved, 0, 2 * Math.PI);
|
|
192
|
+
context2D.fill();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (currentSegment.length > 0)
|
|
196
|
+
segments.push(currentSegment);
|
|
197
|
+
// draw the series line (interpolation is applied via a Path2D built through a
|
|
198
|
+
// d3 line generator so that custom curve factories -- e.g. curveBasis,
|
|
199
|
+
// curveStep -- keep working exactly as they did with the SVG path)
|
|
200
|
+
context2D.strokeStyle = isHovered ? highlightColor : seriesColor;
|
|
201
|
+
context2D.lineWidth = isHovered ? highlightWidth : lineWidth;
|
|
202
|
+
segments.forEach(segment => {
|
|
203
|
+
var _a;
|
|
204
|
+
const path = new Path2D((_a = d3.line().curve(interpolation)(segment)) !== null && _a !== void 0 ? _a : "");
|
|
205
|
+
context2D.stroke(path);
|
|
206
|
+
});
|
|
207
|
+
newGeometry.set(name, {
|
|
208
|
+
points: screenPoints,
|
|
209
|
+
asLine: true,
|
|
210
|
+
hitRadius: Math.max(6, (isHovered ? highlightWidth : lineWidth) + 4)
|
|
211
|
+
});
|
|
212
|
+
if (showMarkers) {
|
|
213
|
+
// markers get their own, generously-sized hit target keyed under a
|
|
214
|
+
// derived name so a marker hover can be distinguished from a line hover
|
|
215
|
+
// if the caller ever wants to (currently treated the same on mousemove)
|
|
216
|
+
newGeometry.set(`${name}-markers`, {
|
|
217
|
+
points: screenPoints,
|
|
218
|
+
hitRadius: markerRadiusResolved + 3
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
221
|
});
|
|
222
|
-
|
|
222
|
+
// highlights the points the tooltip is showing (on top of the series): the
|
|
223
|
+
// hovered point is drawn larger than its neighbors (or than a segment's ends)
|
|
224
|
+
const tooltipPoints = tooltipPointsRef.current;
|
|
225
|
+
if (tooltipPoints !== undefined && !running && tooltipPoints.seriesName.match(seriesFilter)) {
|
|
226
|
+
const [xAxisLinear, yAxisLinear] = axesFor(tooltipPoints.seriesName, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
|
|
227
|
+
if (xAxisLinear !== undefined && yAxisLinear !== undefined) {
|
|
228
|
+
const { highlightColor = color } = (_a = seriesStyles.get(tooltipPoints.seriesName)) !== null && _a !== void 0 ? _a : {};
|
|
229
|
+
const { points } = tooltipPoints;
|
|
230
|
+
scatterTooltipPointList(points).forEach(datum => {
|
|
231
|
+
const isHoveredPoint = points.kind === 'point' && datum === points.point;
|
|
232
|
+
context2D.beginPath();
|
|
233
|
+
context2D.arc(xAxisLinear.scale(datum.x), yAxisLinear.scale(datum.y), isHoveredPoint ? TOOLTIP_POINT_RADIUS : TOOLTIP_NEIGHBOR_RADIUS, 0, 2 * Math.PI);
|
|
234
|
+
context2D.fillStyle = highlightColor;
|
|
235
|
+
context2D.fill();
|
|
236
|
+
// outlined in the background color, so it stands out from the line
|
|
237
|
+
context2D.lineWidth = 1.5;
|
|
238
|
+
context2D.strokeStyle = backgroundColor;
|
|
239
|
+
context2D.stroke();
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
geometryRef.current = newGeometry;
|
|
244
|
+
context2D.restore();
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Grows the auto-scaling y-axes (see `ContinuousAxis`'s `autoScale` prop) to fit the
|
|
248
|
+
* data that's on screen: the data of the shown series (those matching the filter)
|
|
249
|
+
* within their x-axis' current window, including where their lines cross the window's
|
|
250
|
+
* edges (see `visibleExtent`). Since an axis only ever grows, the data that has
|
|
251
|
+
* scrolled off screen was already accounted for while it was on screen, so only the
|
|
252
|
+
* visible data needs checking each frame. Registered to run before the axes draw
|
|
253
|
+
* (they're at z-index 0), so the axes and the series are drawn with the grown domain
|
|
254
|
+
* in the same frame.
|
|
255
|
+
*/
|
|
256
|
+
const autoScaleYAxes = () => {
|
|
257
|
+
const withLine = interpolation !== NoCurveFactory;
|
|
258
|
+
const extents = new Map();
|
|
259
|
+
dataRef.current.forEach(series => {
|
|
260
|
+
if (!series.name.match(seriesFilter))
|
|
261
|
+
return;
|
|
262
|
+
const [xAxisLinear, yAxisLinear] = axesFor(series.name, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
|
|
263
|
+
if (xAxisLinear === undefined || (yAxisLinear === null || yAxisLinear === void 0 ? void 0 : yAxisLinear.autoScale) === undefined)
|
|
264
|
+
return;
|
|
265
|
+
const [start, end] = xAxisLinear.scale.domain();
|
|
266
|
+
const seriesExtent = visibleExtent(series.data, [start, end], yAxisLinear.scale, withLine);
|
|
267
|
+
if (seriesExtent === undefined)
|
|
268
|
+
return;
|
|
269
|
+
const extent = extents.get(yAxisLinear.axisId);
|
|
270
|
+
extents.set(yAxisLinear.axisId, extent === undefined ? seriesExtent : extentWith(extentWith(extent, seriesExtent[0]), seriesExtent[1]));
|
|
271
|
+
});
|
|
272
|
+
growAutoScaledYAxes(extents, { yAxes: yAxesState.axes, axisRangeFor, updateAxisRanges });
|
|
273
|
+
};
|
|
274
|
+
cc.register(`scatter-plot-autoscale-${chartId}`, autoScaleYAxes, -10);
|
|
275
|
+
cc.register(`scatter-plot-${chartId}`, draw, 10);
|
|
276
|
+
cc.requestRedraw();
|
|
223
277
|
}, [
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
seriesStyles, seriesFilter, interpolation,
|
|
228
|
-
mouseOverHandlerFor, mouseLeaveHandlerFor,
|
|
229
|
-
hoveredSeriesRef
|
|
278
|
+
chartId, plotDimensions, axisAssignments, xAxesState, yAxesState, seriesStyles, seriesFilter,
|
|
279
|
+
interpolation, hoveredSeriesName, markerRadius, running, hideMarkersWhileRunning, axisRangeFor,
|
|
280
|
+
updateAxisRanges, color, backgroundColor, margin.left, margin.top
|
|
230
281
|
]);
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
return subscriptionTimeSeriesFor(seriesObservable, onSubscribe, windowingTime, axisAssignments, xAxesState, onUpdateData, dropDataAfter, updateTimingAndPlot,
|
|
253
|
-
// as new data flows into the subscription, the subscription
|
|
254
|
-
// updates this map directly (for performance)
|
|
255
|
-
seriesRef.current, (axisId, end) => currentTimeRef.current.set(axisId, end), timeWindowBehavior, initialTimes);
|
|
256
|
-
}, [
|
|
257
|
-
axisAssignments, dropDataAfter, mainG,
|
|
258
|
-
onSubscribe, onUpdateData,
|
|
259
|
-
seriesObservable, updateTimingAndPlot, windowingTime, xAxesState,
|
|
282
|
+
// the time axes: their ranges, the view driver, panning and zooming, highlighting, and
|
|
283
|
+
// reporting the axes' intervals -- see `useStreamingTimeAxes`
|
|
284
|
+
useStreamingTimeAxes({
|
|
285
|
+
canvasContext,
|
|
286
|
+
dataSource,
|
|
287
|
+
running,
|
|
288
|
+
initialData,
|
|
289
|
+
timeOf: datum => datum.x,
|
|
290
|
+
axisTimesFor: timeSeriesAxisTimes(axisAssignments, xAxesState),
|
|
291
|
+
axisAssignments,
|
|
292
|
+
updatePlot,
|
|
293
|
+
onDataReset: () => {
|
|
294
|
+
dataRef.current = initialData.slice();
|
|
295
|
+
seriesRef.current = new Map(initialData.map(series => [series.name, series]));
|
|
296
|
+
},
|
|
297
|
+
allowTooltipRef: allowTooltip,
|
|
298
|
+
panEnabled,
|
|
299
|
+
zoomEnabled,
|
|
300
|
+
zoomKeyModifiersRequired,
|
|
301
|
+
onZoomReset,
|
|
260
302
|
withCadenceOf,
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
303
|
+
timeWindowBehavior,
|
|
304
|
+
highlightAxesOnMouseOver,
|
|
305
|
+
});
|
|
306
|
+
// wires up a single mousemove/mouseleave listener on the shared canvas to replace the old
|
|
307
|
+
// per-element SVG mouseover/mouseleave handlers. Hit-tests the mouse position against the
|
|
308
|
+
// last-drawn geometry (see `geometryRef`, populated by the draw function above).
|
|
264
309
|
useEffect(() => {
|
|
265
|
-
if (
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
310
|
+
if (!canvasContext)
|
|
311
|
+
return;
|
|
312
|
+
const canvas = canvasContext.canvas;
|
|
313
|
+
const handleMove = (event) => {
|
|
314
|
+
if (!allowTooltip.current)
|
|
315
|
+
return;
|
|
316
|
+
const [x, y] = canvasLocalPoint(event, canvas);
|
|
317
|
+
const hit = seriesAt(x, y, geometryRef.current);
|
|
318
|
+
// markers are recorded under a "<name>-markers" key; normalize back to the
|
|
319
|
+
// underlying series name so callers only ever see the real series name.
|
|
320
|
+
// NOTE: `hit?.name.endsWith(...)` here would be unsafe -- `?.` only protects the
|
|
321
|
+
// `.name` access, not the chained `.endsWith(...)` call, so it would throw a
|
|
322
|
+
// TypeError on every mousemove where `hit` is undefined (i.e. most of them).
|
|
323
|
+
const hitName = hit !== undefined
|
|
324
|
+
? (hit.name.endsWith('-markers') ? hit.name.slice(0, -'-markers'.length) : hit.name)
|
|
325
|
+
: undefined;
|
|
326
|
+
// only fire enter/leave transitions when the hovered series actually changes --
|
|
327
|
+
// but always recompute and re-report the tooltip content below for the *current*
|
|
328
|
+
// mouse position, even while still hovering the same series, so the tooltip keeps
|
|
329
|
+
// tracking the mouse as it moves across a series instead of freezing at wherever
|
|
330
|
+
// the hover was first detected.
|
|
331
|
+
if (hitName !== lastHoveredRef.current) {
|
|
332
|
+
if (lastHoveredRef.current !== undefined) {
|
|
333
|
+
handleMouseLeaveSeries(lastHoveredRef.current, mouseLeaveHandlerFor(`tooltip-${chartId}`));
|
|
334
|
+
}
|
|
335
|
+
lastHoveredRef.current = hitName;
|
|
276
336
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
rangesMap.set(id, range.update(start, end));
|
|
291
|
-
}
|
|
292
|
-
});
|
|
337
|
+
// the points the tooltip shows (and the plot highlights): the point under the mouse
|
|
338
|
+
// and its neighbors, or the two ends of the segment under the mouse
|
|
339
|
+
let tooltipPoints = undefined;
|
|
340
|
+
if (hitName !== undefined) {
|
|
341
|
+
const series = seriesRef.current.get(hitName);
|
|
342
|
+
const mouseOverHandler = mouseOverHandlerFor(`tooltip-${chartId}`);
|
|
343
|
+
const [xAxisLinear, yAxisLinear] = axesFor(hitName, axisAssignments, axisId => xAxesState.axisFor(axisId).getOrUndefined(), axisId => yAxesState.axisFor(axisId).getOrUndefined());
|
|
344
|
+
if (series !== undefined && xAxisLinear !== undefined && yAxisLinear !== undefined && mouseOverHandler !== undefined) {
|
|
345
|
+
const points = scatterTooltipPoints(series.data, [x - margin.left, y - margin.top], xAxisLinear.scale, yAxisLinear.scale, Math.max(MIN_POINT_HOVER_RADIUS, (markerRadius !== null && markerRadius !== void 0 ? markerRadius : 0) + 3));
|
|
346
|
+
tooltipPoints = { seriesName: hitName, points };
|
|
347
|
+
const time = Math.round(xAxisLinear.scale.invert(x - margin.left));
|
|
348
|
+
mouseOverHandler(hitName, time, { series: series.data, metadata: { points } }, [x, y]);
|
|
349
|
+
}
|
|
293
350
|
}
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
351
|
+
updateTooltipPoints(tooltipPoints);
|
|
352
|
+
};
|
|
353
|
+
// remembers the points the tooltip shows, and redraws (to highlight them) when they change
|
|
354
|
+
const updateTooltipPoints = (tooltipPoints) => {
|
|
355
|
+
const previous = tooltipPointsRef.current;
|
|
356
|
+
if (previous === undefined && tooltipPoints === undefined)
|
|
357
|
+
return;
|
|
358
|
+
if (previous !== undefined && tooltipPoints !== undefined &&
|
|
359
|
+
previous.seriesName === tooltipPoints.seriesName &&
|
|
360
|
+
previous.points.kind === tooltipPoints.points.kind) {
|
|
361
|
+
const previousList = scatterTooltipPointList(previous.points);
|
|
362
|
+
const list = scatterTooltipPointList(tooltipPoints.points);
|
|
363
|
+
if (previousList.length === list.length && previousList.every((datum, index) => datum === list[index]))
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
tooltipPointsRef.current = tooltipPoints;
|
|
367
|
+
canvasContext.requestRedraw();
|
|
368
|
+
};
|
|
369
|
+
const handleLeaveCanvas = () => {
|
|
370
|
+
if (lastHoveredRef.current !== undefined) {
|
|
371
|
+
handleMouseLeaveSeries(lastHoveredRef.current, mouseLeaveHandlerFor(`tooltip-${chartId}`));
|
|
372
|
+
lastHoveredRef.current = undefined;
|
|
373
|
+
}
|
|
374
|
+
updateTooltipPoints(undefined);
|
|
375
|
+
};
|
|
376
|
+
canvas.addEventListener('mousemove', handleMove);
|
|
377
|
+
canvas.addEventListener('mouseleave', handleLeaveCanvas);
|
|
378
|
+
return () => {
|
|
379
|
+
canvas.removeEventListener('mousemove', handleMove);
|
|
380
|
+
canvas.removeEventListener('mouseleave', handleLeaveCanvas);
|
|
381
|
+
};
|
|
382
|
+
}, [canvasContext, chartId, margin, axisAssignments, xAxesState, yAxesState, mouseOverHandlerFor, mouseLeaveHandlerFor, markerRadius]);
|
|
383
|
+
// this plot needs a data source (see the `Chart`'s `dataSource` prop)
|
|
301
384
|
useEffect(() => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
subscriptionRef.current = subscribe();
|
|
305
|
-
allowTooltip.current = false;
|
|
385
|
+
if (dataSource === undefined) {
|
|
386
|
+
console.error("ScatterPlot requires a data source; set the enclosing Chart's `dataSource` prop");
|
|
306
387
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
388
|
+
}, [dataSource]);
|
|
389
|
+
// unregister this plot's draw function (and its auto-scaling step) on unmount
|
|
390
|
+
useEffect(() => {
|
|
391
|
+
return () => {
|
|
392
|
+
if (canvasContext) {
|
|
393
|
+
canvasContext.unregister(`scatter-plot-autoscale-${chartId}`);
|
|
394
|
+
canvasContext.unregister(`scatter-plot-${chartId}`);
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}, [canvasContext, chartId]);
|
|
398
|
+
// new data, new scale: restarts the auto-scaling y-axes when the data source is replaced
|
|
399
|
+
useAutoScaleRestart(dataSource, { yAxes: yAxesState.axes, axisRangeFor, updateAxisRanges });
|
|
313
400
|
return null;
|
|
314
401
|
}
|
|
315
402
|
/**
|
|
316
|
-
* Attempts to locate the x- and y-axes for the specified series. If
|
|
317
|
-
*
|
|
403
|
+
* Attempts to locate the x- and y-axes for the specified series. If the series has no axis
|
|
404
|
+
* assignment, then uses the default (first) x- and y-axes.
|
|
318
405
|
* @param seriesName Name of the series for which to retrieve the axis
|
|
319
406
|
* @param axisAssignments A map holding the series name and the associated x- and y-axes assigned
|
|
320
407
|
* to that series. Note that the series in the axis-assignment map is merely a subset of the set
|
|
321
408
|
* of series names.
|
|
322
409
|
* @param xAxisFor The function that accepts an axis ID and returns the corresponding x-axis
|
|
323
410
|
* @param yAxisFor The function that accepts an axis ID and returns the corresponding y-axis
|
|
411
|
+
* @return The x- and y-axes (either is actually `undefined` when it isn't found, despite the type)
|
|
412
|
+
* @throws Error when either axis isn't a continuous numeric axis
|
|
324
413
|
*/
|
|
325
414
|
function axesFor(seriesName, axisAssignments, xAxisFor, yAxisFor) {
|
|
326
415
|
const axes = axisAssignments.get(seriesName);
|
|
327
416
|
const xAxis = xAxisFor((axes === null || axes === void 0 ? void 0 : axes.xAxis) || "");
|
|
328
|
-
const xAxisLinear = xAxis;
|
|
329
417
|
const yAxis = yAxisFor((axes === null || axes === void 0 ? void 0 : axes.yAxis) || "");
|
|
418
|
+
checkAxisType("ScatterPlot", "x", xAxis, AxisType.ContinuousNumeric);
|
|
419
|
+
checkAxisType("ScatterPlot", "y", yAxis, AxisType.ContinuousNumeric);
|
|
420
|
+
const xAxisLinear = xAxis;
|
|
330
421
|
const yAxisLinear = yAxis;
|
|
331
|
-
if (xAxis && !xAxisLinear) {
|
|
332
|
-
throw Error("Scatter plot requires that x-axis be of type LinearAxis");
|
|
333
|
-
}
|
|
334
|
-
if (yAxis && !yAxisLinear) {
|
|
335
|
-
throw Error("Scatter plot requires that y-axis be of type LinearAxis");
|
|
336
|
-
}
|
|
337
422
|
return [xAxisLinear, yAxisLinear];
|
|
338
423
|
}
|
|
339
424
|
/**
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
* @param series The time series
|
|
345
|
-
* @param event The mouse-over series event
|
|
346
|
-
* @param margin The plot margin
|
|
347
|
-
* @param seriesStyles The series style information (needed for (un)highlighting)
|
|
348
|
-
* @param allowTooltip When set to `false` won't show tooltip, even if it is visible (used by pan)
|
|
349
|
-
* @param mouseOverHandlerFor The handler for the mouse over (registered by the <Tooltip/>)
|
|
350
|
-
*/
|
|
351
|
-
function handleMouseOverSeries(container, xAxis, seriesName, series, event, margin, seriesStyles, allowTooltip, mouseOverHandlerFor) {
|
|
352
|
-
// grab the time needed for the tooltip ID
|
|
353
|
-
const [x, y] = d3.pointer(event, container);
|
|
354
|
-
const time = Math.round(xAxis.scale.invert(x - margin.left));
|
|
355
|
-
const { highlightColor, highlightWidth } = seriesStyles.get(seriesName) || defaultLineStyle();
|
|
356
|
-
// Use d3 to select element, change color and size
|
|
357
|
-
d3.select(event.currentTarget)
|
|
358
|
-
.attr('stroke', highlightColor)
|
|
359
|
-
.attr('stroke-width', highlightWidth);
|
|
360
|
-
if (mouseOverHandlerFor && allowTooltip) {
|
|
361
|
-
mouseOverHandlerFor(seriesName, time, { series, metadata: {} }, [x, y]);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Unselects the time series and calls the mouse-leave-series handler registered for this series.
|
|
425
|
+
* Calls the mouse-leave-series handler registered for this series. Replaces the old version, which
|
|
426
|
+
* also reset the hovered SVG element's stroke color/width directly; that reset is now implicit --
|
|
427
|
+
* once `hoveredSeriesName` is cleared, the next redraw simply paints the series in its normal
|
|
428
|
+
* (non-highlighted) style.
|
|
366
429
|
* @param seriesName The name of the series (i.e. the neuron ID)
|
|
367
|
-
* @param segment The SVG line element representing the spike, over which the mouse is hovering.
|
|
368
|
-
* @param seriesStyles The styles for the series (for (un)highlighting)
|
|
369
430
|
* @param mouseLeaverHandlerFor Registered handler for the series when the mouse leaves
|
|
370
431
|
*/
|
|
371
|
-
function handleMouseLeaveSeries(seriesName,
|
|
372
|
-
const { color, lineWidth } = seriesStyles.get(seriesName) || defaultLineStyle();
|
|
373
|
-
d3.select(segment)
|
|
374
|
-
.attr('stroke', color)
|
|
375
|
-
.attr('stroke-width', lineWidth);
|
|
432
|
+
function handleMouseLeaveSeries(seriesName, mouseLeaverHandlerFor) {
|
|
376
433
|
if (mouseLeaverHandlerFor) {
|
|
377
434
|
mouseLeaverHandlerFor(seriesName);
|
|
378
435
|
}
|