semiotic 2.0.2 → 3.0.0-beta.1
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/CLAUDE.md +530 -0
- package/README.md +190 -37
- package/ai/cli.js +48 -0
- package/ai/dist/ai/componentRegistry.js +45 -0
- package/ai/dist/ai/mcp-server.js +99 -0
- package/ai/dist/ai/renderHOCToSVG.js +77 -0
- package/ai/dist/src/components/Annotation.js +358 -0
- package/ai/dist/src/components/AnnotationLayer/AnnotationLayer.js +369 -0
- package/ai/dist/src/components/Axis/Axis.js +373 -0
- package/ai/dist/src/components/Axis/axisTitle.js +14 -0
- package/ai/dist/src/components/Axis/index.js +7 -0
- package/ai/dist/src/components/Axis/summaryGraphic.js +37 -0
- package/ai/dist/src/components/Brush.js +84 -0
- package/ai/dist/src/components/DividedLine.js +65 -0
- package/ai/dist/src/components/FacetController.js +259 -0
- package/ai/dist/src/components/Frame.js +139 -0
- package/ai/dist/src/components/InteractionLayer.js +328 -0
- package/ai/dist/src/components/Legend.js +140 -0
- package/ai/dist/src/components/MiniMap.js +75 -0
- package/ai/dist/src/components/MinimapXYFrame.js +99 -0
- package/ai/dist/src/components/NetworkFrame.js +335 -0
- package/ai/dist/src/components/OrdinalFrame.js +437 -0
- package/ai/dist/src/components/ResponsiveFrame.js +68 -0
- package/ai/dist/src/components/ResponsiveMinimapXYFrame.js +11 -0
- package/ai/dist/src/components/ResponsiveNetworkFrame.js +11 -0
- package/ai/dist/src/components/ResponsiveOrdinalFrame.js +11 -0
- package/ai/dist/src/components/ResponsiveXYFrame.js +10 -0
- package/ai/dist/src/components/SparkFrame.js +113 -0
- package/ai/dist/src/components/SparkNetworkFrame.js +11 -0
- package/ai/dist/src/components/SparkOrdinalFrame.js +11 -0
- package/ai/dist/src/components/SparkXYFrame.js +11 -0
- package/ai/dist/src/components/Tooltip/Tooltip.js +304 -0
- package/ai/dist/src/components/TooltipPositioner/index.js +132 -0
- package/ai/dist/src/components/VisualizationLayer.js +395 -0
- package/ai/dist/src/components/XYFrame.js +524 -0
- package/ai/dist/src/components/annotationLayerBehavior/annotationHandling.js +73 -0
- package/ai/dist/src/components/annotationLayerBehavior/d3labeler.js +254 -0
- package/ai/dist/src/components/annotationRules/baseRules.js +150 -0
- package/ai/dist/src/components/annotationRules/networkframeRules.js +198 -0
- package/ai/dist/src/components/annotationRules/orframeRules.js +695 -0
- package/ai/dist/src/components/annotationRules/xyframeRules.js +299 -0
- package/ai/dist/src/components/batchWork.js +35 -0
- package/ai/dist/src/components/charts/index.js +96 -0
- package/ai/dist/src/components/charts/network/ChordDiagram.js +245 -0
- package/ai/dist/src/components/charts/network/CirclePack.js +177 -0
- package/ai/dist/src/components/charts/network/ForceDirectedGraph.js +248 -0
- package/ai/dist/src/components/charts/network/SankeyDiagram.js +305 -0
- package/ai/dist/src/components/charts/network/TreeDiagram.js +268 -0
- package/ai/dist/src/components/charts/network/Treemap.js +177 -0
- package/ai/dist/src/components/charts/ordinal/BarChart.js +191 -0
- package/ai/dist/src/components/charts/ordinal/BoxPlot.js +235 -0
- package/ai/dist/src/components/charts/ordinal/DonutChart.js +178 -0
- package/ai/dist/src/components/charts/ordinal/DotPlot.js +194 -0
- package/ai/dist/src/components/charts/ordinal/GroupedBarChart.js +194 -0
- package/ai/dist/src/components/charts/ordinal/PieChart.js +155 -0
- package/ai/dist/src/components/charts/ordinal/StackedBarChart.js +213 -0
- package/ai/dist/src/components/charts/ordinal/SwarmPlot.js +219 -0
- package/ai/dist/src/components/charts/realtime/RealtimeBarChart.js +91 -0
- package/ai/dist/src/components/charts/realtime/RealtimeLineChart.js +73 -0
- package/ai/dist/src/components/charts/realtime/RealtimeSwarmChart.js +85 -0
- package/ai/dist/src/components/charts/realtime/RealtimeWaterfallChart.js +86 -0
- package/ai/dist/src/components/charts/shared/ChartError.js +72 -0
- package/ai/dist/src/components/charts/shared/colorUtils.js +138 -0
- package/ai/dist/src/components/charts/shared/formatUtils.js +176 -0
- package/ai/dist/src/components/charts/shared/hooks.js +49 -0
- package/ai/dist/src/components/charts/shared/legendUtils.js +57 -0
- package/ai/dist/src/components/charts/shared/types.js +2 -0
- package/ai/dist/src/components/charts/shared/validateChartData.js +82 -0
- package/ai/dist/src/components/charts/shared/validateProps.js +640 -0
- package/ai/dist/src/components/charts/xy/AreaChart.js +220 -0
- package/ai/dist/src/components/charts/xy/BubbleChart.js +222 -0
- package/ai/dist/src/components/charts/xy/Heatmap.js +230 -0
- package/ai/dist/src/components/charts/xy/LineChart.js +302 -0
- package/ai/dist/src/components/charts/xy/Scatterplot.js +136 -0
- package/ai/dist/src/components/charts/xy/StackedAreaChart.js +220 -0
- package/ai/dist/src/components/constants/coordinateNames.js +11 -0
- package/ai/dist/src/components/constants/frame_props.js +251 -0
- package/ai/dist/src/components/constants/jsx.js +71 -0
- package/ai/dist/src/components/data/dataFunctions.js +473 -0
- package/ai/dist/src/components/data/multiAccessorUtils.js +14 -0
- package/ai/dist/src/components/data/networkPipelineCache.js +43 -0
- package/ai/dist/src/components/data/ordinalPipelineCache.js +53 -0
- package/ai/dist/src/components/data/unflowedFunctions.js +5 -0
- package/ai/dist/src/components/data/xyPipelineCache.js +49 -0
- package/ai/dist/src/components/generic_utilities/functions.js +5 -0
- package/ai/dist/src/components/index.js +145 -0
- package/ai/dist/src/components/interactionLayerBehavior/InteractionCanvas.js +128 -0
- package/ai/dist/src/components/processing/InteractionItems.js +223 -0
- package/ai/dist/src/components/processing/hierarchyUtils.js +104 -0
- package/ai/dist/src/components/processing/layouts/chordLayout.js +58 -0
- package/ai/dist/src/components/processing/layouts/forceLayout.js +142 -0
- package/ai/dist/src/components/processing/layouts/hierarchyLayout.js +31 -0
- package/ai/dist/src/components/processing/layouts/index.js +32 -0
- package/ai/dist/src/components/processing/layouts/sankeyLayout.js +96 -0
- package/ai/dist/src/components/processing/layouts/simpleLayouts.js +34 -0
- package/ai/dist/src/components/processing/layouts/types.js +2 -0
- package/ai/dist/src/components/processing/network.js +771 -0
- package/ai/dist/src/components/processing/networkDefaults.js +39 -0
- package/ai/dist/src/components/processing/networkLayoutHelpers.js +98 -0
- package/ai/dist/src/components/processing/ordinal.js +889 -0
- package/ai/dist/src/components/processing/ordinalConstants.js +23 -0
- package/ai/dist/src/components/processing/ordinalOverlays.js +88 -0
- package/ai/dist/src/components/processing/ordinalRenderPipeline.js +196 -0
- package/ai/dist/src/components/processing/xyDrawing.js +484 -0
- package/ai/dist/src/components/realtime/BinAccumulator.js +36 -0
- package/ai/dist/src/components/realtime/IncrementalExtent.js +55 -0
- package/ai/dist/src/components/realtime/RealtimeFrame.js +710 -0
- package/ai/dist/src/components/realtime/RingBuffer.js +104 -0
- package/ai/dist/src/components/realtime/renderers/barRenderer.js +133 -0
- package/ai/dist/src/components/realtime/renderers/candlestickRenderer.js +7 -0
- package/ai/dist/src/components/realtime/renderers/lineRenderer.js +164 -0
- package/ai/dist/src/components/realtime/renderers/swarmRenderer.js +91 -0
- package/ai/dist/src/components/realtime/renderers/types.js +2 -0
- package/ai/dist/src/components/realtime/renderers/waterfallRenderer.js +163 -0
- package/ai/dist/src/components/realtime/types.js +2 -0
- package/ai/dist/src/components/semiotic-ai.js +66 -0
- package/ai/dist/src/components/semiotic-network.js +30 -0
- package/ai/dist/src/components/semiotic-ordinal.js +28 -0
- package/ai/dist/src/components/semiotic-realtime.js +37 -0
- package/ai/dist/src/components/semiotic-server.js +8 -0
- package/ai/dist/src/components/semiotic-xy.js +41 -0
- package/ai/dist/src/components/semiotic.js +101 -0
- package/ai/dist/src/components/server/renderToStaticSVG.js +392 -0
- package/ai/dist/src/components/store/TooltipStore.js +13 -0
- package/ai/dist/src/components/store/createStore.js +77 -0
- package/ai/dist/src/components/svg/SvgHelper.js +308 -0
- package/ai/dist/src/components/svg/areaDrawing.js +312 -0
- package/ai/dist/src/components/svg/boxplotRenderer.js +441 -0
- package/ai/dist/src/components/svg/bucketizedRenderer.js +677 -0
- package/ai/dist/src/components/svg/ckbinsRenderer.js +92 -0
- package/ai/dist/src/components/svg/ckmeans.js +238 -0
- package/ai/dist/src/components/svg/contourLayout.js +73 -0
- package/ai/dist/src/components/svg/contourRenderer.js +53 -0
- package/ai/dist/src/components/svg/edgeGenerators.js +181 -0
- package/ai/dist/src/components/svg/frameFunctions.js +579 -0
- package/ai/dist/src/components/svg/graphAlgorithms.js +138 -0
- package/ai/dist/src/components/svg/hexbinLayout.js +163 -0
- package/ai/dist/src/components/svg/lineDrawing.js +427 -0
- package/ai/dist/src/components/svg/networkDrawing.js +207 -0
- package/ai/dist/src/components/svg/nodeGenerators.js +131 -0
- package/ai/dist/src/components/svg/pieceDrawing.js +110 -0
- package/ai/dist/src/components/svg/pieceLayouts.js +588 -0
- package/ai/dist/src/components/svg/sankeyLinks.js +143 -0
- package/ai/dist/src/components/svg/summaryAxis.js +48 -0
- package/ai/dist/src/components/svg/summaryLayouts.js +202 -0
- package/ai/dist/src/components/svg/swarmLayout.js +128 -0
- package/ai/dist/src/components/types/annotationTypes.js +2 -0
- package/ai/dist/src/components/types/canvasTypes.js +2 -0
- package/ai/dist/src/components/types/generalTypes.js +2 -0
- package/ai/dist/src/components/types/interactionTypes.js +2 -0
- package/ai/dist/src/components/types/legendTypes.js +2 -0
- package/ai/dist/src/components/types/networkTypes.js +2 -0
- package/ai/dist/src/components/types/ordinalTypes.js +2 -0
- package/ai/dist/src/components/types/xyTypes.js +2 -0
- package/ai/dist/src/components/useBoundingRect.js +24 -0
- package/ai/dist/src/components/useDerivedStateFromProps.js +25 -0
- package/ai/dist/src/components/useLegacyUnmountCallback.js +21 -0
- package/ai/dist/src/components/visualizationLayerBehavior/axis.js +249 -0
- package/ai/dist/src/components/visualizationLayerBehavior/general.js +435 -0
- package/ai/dist/src/setupTests.js +4 -0
- package/ai/examples.md +394 -0
- package/ai/schema.json +1178 -0
- package/ai/system-prompt.md +38 -0
- package/dist/Annotation.d.ts +3 -0
- package/dist/AnnotationLayer/AnnotationLayer.d.ts +25 -0
- package/dist/Axis/Axis.d.ts +7 -0
- package/dist/Axis/axisTitle.d.ts +10 -0
- package/dist/Axis/index.d.ts +2 -0
- package/dist/Axis/summaryGraphic.d.ts +17 -0
- package/dist/Brush.d.ts +12 -0
- package/dist/DividedLine.d.ts +16 -0
- package/dist/FacetController.d.ts +12 -0
- package/dist/Frame.d.ts +2 -0
- package/dist/InteractionLayer.d.ts +3 -0
- package/dist/Legend.d.ts +3 -0
- package/dist/MiniMap.d.ts +14 -0
- package/dist/MinimapXYFrame.d.ts +10 -0
- package/dist/NetworkFrame.d.ts +8 -0
- package/dist/OrdinalFrame.d.ts +8 -0
- package/dist/ResponsiveFrame.d.ts +22 -0
- package/dist/ResponsiveMinimapXYFrame.d.ts +3 -0
- package/dist/ResponsiveNetworkFrame.d.ts +3 -0
- package/dist/ResponsiveOrdinalFrame.d.ts +3 -0
- package/dist/ResponsiveXYFrame.d.ts +3 -0
- package/dist/SparkFrame.d.ts +14 -0
- package/dist/SparkNetworkFrame.d.ts +5 -0
- package/dist/SparkOrdinalFrame.d.ts +5 -0
- package/dist/SparkXYFrame.d.ts +5 -0
- package/dist/Tooltip/Tooltip.d.ts +141 -0
- package/dist/TooltipPositioner/index.d.ts +7 -0
- package/dist/VisualizationLayer.d.ts +33 -0
- package/dist/XYFrame.d.ts +8 -0
- package/dist/annotationLayerBehavior/annotationHandling.d.ts +19 -0
- package/dist/annotationLayerBehavior/d3labeler.d.ts +9 -0
- package/dist/annotationRules/baseRules.d.ts +25 -0
- package/dist/annotationRules/networkframeRules.d.ts +48 -0
- package/dist/annotationRules/orframeRules.d.ts +103 -0
- package/dist/annotationRules/xyframeRules.d.ts +117 -0
- package/dist/batchWork.d.ts +6 -0
- package/dist/charts/index.d.ts +62 -0
- package/dist/charts/network/ChordDiagram.d.ts +181 -0
- package/dist/charts/network/CirclePack.d.ts +103 -0
- package/dist/charts/network/ForceDirectedGraph.d.ts +192 -0
- package/dist/charts/network/SankeyDiagram.d.ts +195 -0
- package/dist/charts/network/TreeDiagram.d.ts +200 -0
- package/dist/charts/network/Treemap.d.ts +98 -0
- package/dist/charts/ordinal/BarChart.d.ts +119 -0
- package/dist/charts/ordinal/BoxPlot.d.ts +125 -0
- package/dist/charts/ordinal/DonutChart.d.ts +95 -0
- package/dist/charts/ordinal/DotPlot.d.ts +128 -0
- package/dist/charts/ordinal/GroupedBarChart.d.ts +113 -0
- package/dist/charts/ordinal/PieChart.d.ts +83 -0
- package/dist/charts/ordinal/StackedBarChart.d.ts +119 -0
- package/dist/charts/ordinal/SwarmPlot.d.ts +137 -0
- package/dist/charts/realtime/RealtimeBarChart.d.ts +102 -0
- package/dist/charts/realtime/RealtimeLineChart.d.ts +78 -0
- package/dist/charts/realtime/RealtimeSwarmChart.d.ts +88 -0
- package/dist/charts/realtime/RealtimeWaterfallChart.d.ts +85 -0
- package/dist/charts/shared/ChartError.d.ts +19 -0
- package/dist/charts/shared/colorUtils.d.ts +62 -0
- package/dist/charts/shared/formatUtils.d.ts +82 -0
- package/dist/charts/shared/hooks.d.ts +20 -0
- package/dist/charts/shared/legendUtils.d.ts +32 -0
- package/dist/charts/shared/types.d.ts +58 -0
- package/dist/charts/shared/validateChartData.d.ts +41 -0
- package/dist/charts/shared/validateProps.d.ts +18 -0
- package/dist/charts/xy/AreaChart.d.ts +127 -0
- package/dist/charts/xy/BubbleChart.d.ts +157 -0
- package/dist/charts/xy/Heatmap.d.ts +153 -0
- package/dist/charts/xy/LineChart.d.ts +193 -0
- package/dist/charts/xy/Scatterplot.d.ts +50 -0
- package/dist/charts/xy/StackedAreaChart.d.ts +131 -0
- package/dist/constants/coordinateNames.d.ts +8 -0
- package/dist/constants/frame_props.d.ts +13 -0
- package/dist/constants/jsx.d.ts +19 -0
- package/dist/data/dataFunctions.d.ts +45 -0
- package/dist/data/multiAccessorUtils.d.ts +1 -0
- package/dist/data/networkPipelineCache.d.ts +27 -0
- package/dist/data/ordinalPipelineCache.d.ts +33 -0
- package/dist/data/unflowedFunctions.d.ts +1 -0
- package/dist/data/xyPipelineCache.d.ts +35 -0
- package/dist/generic_utilities/functions.d.ts +1 -0
- package/dist/index.d.ts +133 -0
- package/dist/interactionLayerBehavior/InteractionCanvas.d.ts +20 -0
- package/dist/network.js +8520 -0
- package/dist/network.js.map +1 -0
- package/dist/network.min.js +1 -0
- package/dist/network.module.js +8484 -0
- package/dist/network.module.js.map +1 -0
- package/dist/network.module.min.js +1 -0
- package/dist/ordinal.js +9276 -0
- package/dist/ordinal.js.map +1 -0
- package/dist/ordinal.min.js +1 -0
- package/dist/ordinal.module.js +9242 -0
- package/dist/ordinal.module.js.map +1 -0
- package/dist/ordinal.module.min.js +1 -0
- package/dist/processing/InteractionItems.d.ts +13 -0
- package/dist/processing/hierarchyUtils.d.ts +16 -0
- package/dist/processing/layouts/chordLayout.d.ts +2 -0
- package/dist/processing/layouts/forceLayout.d.ts +3 -0
- package/dist/processing/layouts/hierarchyLayout.d.ts +10 -0
- package/dist/processing/layouts/index.d.ts +8 -0
- package/dist/processing/layouts/sankeyLayout.d.ts +8 -0
- package/dist/processing/layouts/simpleLayouts.d.ts +7 -0
- package/dist/processing/layouts/types.d.ts +17 -0
- package/dist/processing/network.d.ts +111 -0
- package/dist/processing/networkDefaults.d.ts +36 -0
- package/dist/processing/networkLayoutHelpers.d.ts +54 -0
- package/dist/processing/ordinal.d.ts +102 -0
- package/dist/processing/ordinalConstants.d.ts +33 -0
- package/dist/processing/ordinalOverlays.d.ts +33 -0
- package/dist/processing/ordinalRenderPipeline.d.ts +148 -0
- package/dist/processing/xyDrawing.d.ts +140 -0
- package/dist/realtime/BinAccumulator.d.ts +8 -0
- package/dist/realtime/IncrementalExtent.d.ts +13 -0
- package/dist/realtime/RealtimeFrame.d.ts +4 -0
- package/dist/realtime/RingBuffer.d.ts +19 -0
- package/dist/realtime/renderers/barRenderer.d.ts +2 -0
- package/dist/realtime/renderers/candlestickRenderer.d.ts +2 -0
- package/dist/realtime/renderers/lineRenderer.d.ts +2 -0
- package/dist/realtime/renderers/swarmRenderer.d.ts +2 -0
- package/dist/realtime/renderers/types.d.ts +9 -0
- package/dist/realtime/renderers/waterfallRenderer.d.ts +3 -0
- package/dist/realtime/types.d.ts +113 -0
- package/dist/realtime.js +1598 -0
- package/dist/realtime.js.map +1 -0
- package/dist/realtime.min.js +1 -0
- package/dist/realtime.module.js +1566 -0
- package/dist/realtime.module.js.map +1 -0
- package/dist/realtime.module.min.js +1 -0
- package/dist/semiotic-ai.d.ts +28 -0
- package/dist/semiotic-ai.js +18722 -0
- package/dist/semiotic-ai.js.map +1 -0
- package/dist/semiotic-ai.min.js +1 -0
- package/dist/semiotic-ai.module.js +18668 -0
- package/dist/semiotic-ai.module.js.map +1 -0
- package/dist/semiotic-ai.module.min.js +1 -0
- package/dist/semiotic-network.d.ts +19 -0
- package/dist/semiotic-ordinal.d.ts +18 -0
- package/dist/semiotic-realtime.d.ts +23 -0
- package/dist/semiotic-server.d.ts +1 -0
- package/dist/semiotic-xy.d.ts +24 -0
- package/dist/semiotic.d.ts +51 -0
- package/dist/semiotic.js +18723 -12996
- package/dist/semiotic.js.map +1 -0
- package/dist/semiotic.min.js +1 -0
- package/dist/semiotic.module.js +18666 -12965
- package/dist/semiotic.module.js.map +1 -0
- package/dist/semiotic.module.min.js +1 -0
- package/dist/server/renderToStaticSVG.d.ts +9 -0
- package/dist/server.js +8360 -0
- package/dist/server.js.map +1 -0
- package/dist/server.min.js +1 -0
- package/dist/server.module.js +8331 -0
- package/dist/server.module.js.map +1 -0
- package/dist/server.module.min.js +1 -0
- package/dist/store/TooltipStore.d.ts +2 -0
- package/dist/store/createStore.d.ts +1 -0
- package/dist/svg/SvgHelper.d.ts +33 -0
- package/dist/svg/areaDrawing.d.ts +21 -0
- package/dist/svg/boxplotRenderer.d.ts +15 -0
- package/dist/svg/bucketizedRenderer.d.ts +16 -0
- package/dist/svg/ckbinsRenderer.d.ts +20 -0
- package/dist/svg/ckmeans.d.ts +69 -0
- package/dist/svg/contourLayout.d.ts +6 -0
- package/dist/svg/contourRenderer.d.ts +12 -0
- package/dist/svg/edgeGenerators.d.ts +51 -0
- package/dist/svg/frameFunctions.d.ts +108 -0
- package/dist/svg/graphAlgorithms.d.ts +14 -0
- package/dist/svg/hexbinLayout.d.ts +7 -0
- package/dist/svg/lineDrawing.d.ts +99 -0
- package/dist/svg/networkDrawing.d.ts +16 -0
- package/dist/svg/nodeGenerators.d.ts +58 -0
- package/dist/svg/pieceDrawing.d.ts +12 -0
- package/dist/svg/pieceLayouts.d.ts +53 -0
- package/dist/svg/sankeyLinks.d.ts +3 -0
- package/dist/svg/summaryAxis.d.ts +6 -0
- package/dist/svg/summaryLayouts.d.ts +53 -0
- package/dist/svg/swarmLayout.d.ts +13 -0
- package/dist/types/annotationTypes.d.ts +135 -0
- package/dist/types/canvasTypes.d.ts +9 -0
- package/dist/types/generalTypes.d.ts +238 -0
- package/dist/types/interactionTypes.d.ts +72 -0
- package/dist/types/legendTypes.d.ts +20 -0
- package/dist/types/networkTypes.d.ts +175 -0
- package/dist/types/ordinalTypes.d.ts +112 -0
- package/dist/types/xyTypes.d.ts +115 -0
- package/dist/useBoundingRect.d.ts +2 -0
- package/dist/useDerivedStateFromProps.d.ts +1 -0
- package/dist/useLegacyUnmountCallback.d.ts +2 -0
- package/dist/visualizationLayerBehavior/axis.d.ts +36 -0
- package/dist/visualizationLayerBehavior/general.d.ts +80 -0
- package/dist/xy.js +7944 -0
- package/dist/xy.js.map +1 -0
- package/dist/xy.min.js +1 -0
- package/dist/xy.module.js +7903 -0
- package/dist/xy.module.js.map +1 -0
- package/dist/xy.module.min.js +1 -0
- package/package.json +116 -65
package/dist/realtime.js
ADDED
|
@@ -0,0 +1,1598 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const React = require('react');
|
|
5
|
+
const d3Scale = require('d3-scale');
|
|
6
|
+
|
|
7
|
+
function _interopNamespace(e) {
|
|
8
|
+
if (e && e.__esModule) return e;
|
|
9
|
+
const n = Object.create(null);
|
|
10
|
+
if (e) {
|
|
11
|
+
for (const k in e) {
|
|
12
|
+
if (k !== 'default') {
|
|
13
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return e[k]; }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
26
|
+
|
|
27
|
+
class RingBuffer {
|
|
28
|
+
constructor(_capacity) {
|
|
29
|
+
this._capacity = _capacity;
|
|
30
|
+
this.head = 0;
|
|
31
|
+
this._size = 0;
|
|
32
|
+
if (_capacity < 1) {
|
|
33
|
+
throw new Error("RingBuffer capacity must be at least 1");
|
|
34
|
+
}
|
|
35
|
+
this.buffer = new Array(_capacity);
|
|
36
|
+
}
|
|
37
|
+
push(value) {
|
|
38
|
+
let evicted;
|
|
39
|
+
if (this._size === this._capacity) {
|
|
40
|
+
// Buffer is full — the slot at head is the oldest item
|
|
41
|
+
evicted = this.buffer[this.head];
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
this._size++;
|
|
45
|
+
}
|
|
46
|
+
this.buffer[this.head] = value;
|
|
47
|
+
this.head = (this.head + 1) % this._capacity;
|
|
48
|
+
return evicted;
|
|
49
|
+
}
|
|
50
|
+
pushMany(values) {
|
|
51
|
+
const evicted = [];
|
|
52
|
+
for (const v of values) {
|
|
53
|
+
const e = this.push(v);
|
|
54
|
+
if (e !== undefined) {
|
|
55
|
+
evicted.push(e);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return evicted;
|
|
59
|
+
}
|
|
60
|
+
get(index) {
|
|
61
|
+
if (index < 0 || index >= this._size)
|
|
62
|
+
return undefined;
|
|
63
|
+
const realIndex = (this.head - this._size + index + this._capacity) % this._capacity;
|
|
64
|
+
return this.buffer[realIndex];
|
|
65
|
+
}
|
|
66
|
+
peek() {
|
|
67
|
+
if (this._size === 0)
|
|
68
|
+
return undefined;
|
|
69
|
+
return this.buffer[(this.head - 1 + this._capacity) % this._capacity];
|
|
70
|
+
}
|
|
71
|
+
peekOldest() {
|
|
72
|
+
if (this._size === 0)
|
|
73
|
+
return undefined;
|
|
74
|
+
return this.buffer[(this.head - this._size + this._capacity) % this._capacity];
|
|
75
|
+
}
|
|
76
|
+
[Symbol.iterator]() {
|
|
77
|
+
let i = 0;
|
|
78
|
+
const self = this;
|
|
79
|
+
return {
|
|
80
|
+
next() {
|
|
81
|
+
if (i >= self._size)
|
|
82
|
+
return { done: true, value: undefined };
|
|
83
|
+
return { done: false, value: self.get(i++) };
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
toArray() {
|
|
88
|
+
const result = [];
|
|
89
|
+
for (const item of this) {
|
|
90
|
+
result.push(item);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
resize(newCapacity) {
|
|
95
|
+
if (newCapacity < 1) {
|
|
96
|
+
throw new Error("RingBuffer capacity must be at least 1");
|
|
97
|
+
}
|
|
98
|
+
const items = this.toArray();
|
|
99
|
+
const evicted = [];
|
|
100
|
+
while (items.length > newCapacity) {
|
|
101
|
+
evicted.push(items.shift());
|
|
102
|
+
}
|
|
103
|
+
this._capacity = newCapacity;
|
|
104
|
+
this.buffer = new Array(newCapacity);
|
|
105
|
+
this.head = 0;
|
|
106
|
+
this._size = 0;
|
|
107
|
+
for (const item of items) {
|
|
108
|
+
this.push(item);
|
|
109
|
+
}
|
|
110
|
+
return evicted;
|
|
111
|
+
}
|
|
112
|
+
clear() {
|
|
113
|
+
this.buffer = new Array(this._capacity);
|
|
114
|
+
this.head = 0;
|
|
115
|
+
this._size = 0;
|
|
116
|
+
}
|
|
117
|
+
get size() {
|
|
118
|
+
return this._size;
|
|
119
|
+
}
|
|
120
|
+
get capacity() {
|
|
121
|
+
return this._capacity;
|
|
122
|
+
}
|
|
123
|
+
get full() {
|
|
124
|
+
return this._size === this._capacity;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
class IncrementalExtent {
|
|
129
|
+
constructor() {
|
|
130
|
+
this._min = Infinity;
|
|
131
|
+
this._max = -Infinity;
|
|
132
|
+
this._dirty = false;
|
|
133
|
+
}
|
|
134
|
+
push(value) {
|
|
135
|
+
if (Number.isNaN(value))
|
|
136
|
+
return;
|
|
137
|
+
if (value < this._min)
|
|
138
|
+
this._min = value;
|
|
139
|
+
if (value > this._max)
|
|
140
|
+
this._max = value;
|
|
141
|
+
}
|
|
142
|
+
evict(value) {
|
|
143
|
+
if (value === this._min || value === this._max) {
|
|
144
|
+
this._dirty = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
recalculate(values, accessor) {
|
|
148
|
+
this._min = Infinity;
|
|
149
|
+
this._max = -Infinity;
|
|
150
|
+
for (const v of values) {
|
|
151
|
+
const n = accessor ? accessor(v) : v;
|
|
152
|
+
if (Number.isNaN(n))
|
|
153
|
+
continue;
|
|
154
|
+
if (n < this._min)
|
|
155
|
+
this._min = n;
|
|
156
|
+
if (n > this._max)
|
|
157
|
+
this._max = n;
|
|
158
|
+
}
|
|
159
|
+
this._dirty = false;
|
|
160
|
+
}
|
|
161
|
+
clear() {
|
|
162
|
+
this._min = Infinity;
|
|
163
|
+
this._max = -Infinity;
|
|
164
|
+
this._dirty = false;
|
|
165
|
+
}
|
|
166
|
+
get extent() {
|
|
167
|
+
return [this._min, this._max];
|
|
168
|
+
}
|
|
169
|
+
get min() {
|
|
170
|
+
return this._min;
|
|
171
|
+
}
|
|
172
|
+
get max() {
|
|
173
|
+
return this._max;
|
|
174
|
+
}
|
|
175
|
+
get dirty() {
|
|
176
|
+
return this._dirty;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function resolveColor$1(value, thresholds, baseColor) {
|
|
181
|
+
let color = baseColor;
|
|
182
|
+
for (const t of thresholds) {
|
|
183
|
+
if (t.thresholdType === "lesser") {
|
|
184
|
+
if (value < t.value)
|
|
185
|
+
color = t.color;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
if (value > t.value)
|
|
189
|
+
color = t.color;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return color;
|
|
193
|
+
}
|
|
194
|
+
const lineRenderer = (ctx, data, scales, layout, style, accessors, annotations) => {
|
|
195
|
+
const { time: timeScale, value: valueScale } = scales;
|
|
196
|
+
const { timeAxis } = layout;
|
|
197
|
+
const { time: getTime, value: getValue } = accessors;
|
|
198
|
+
const baseColor = style.stroke || "#007bff";
|
|
199
|
+
// Extract color thresholds from annotations
|
|
200
|
+
const colorThresholds = annotations
|
|
201
|
+
? annotations
|
|
202
|
+
.filter((a) => a.type === "threshold" && a.color)
|
|
203
|
+
.map((a) => ({
|
|
204
|
+
value: a.value,
|
|
205
|
+
color: a.color,
|
|
206
|
+
thresholdType: (a.thresholdType || "greater")
|
|
207
|
+
}))
|
|
208
|
+
: null;
|
|
209
|
+
const hasColorThresholds = colorThresholds && colorThresholds.length > 0;
|
|
210
|
+
// Fast path: no color thresholds — single-path draw, zero overhead
|
|
211
|
+
if (!hasColorThresholds) {
|
|
212
|
+
ctx.beginPath();
|
|
213
|
+
ctx.strokeStyle = baseColor;
|
|
214
|
+
ctx.lineWidth = style.strokeWidth || 2;
|
|
215
|
+
if (style.strokeDasharray) {
|
|
216
|
+
ctx.setLineDash(style.strokeDasharray.split(/[\s,]+/).map(Number));
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
ctx.setLineDash([]);
|
|
220
|
+
}
|
|
221
|
+
let started = false;
|
|
222
|
+
for (const d of data) {
|
|
223
|
+
const t = getTime(d);
|
|
224
|
+
const v = getValue(d);
|
|
225
|
+
if (t == null || v == null || Number.isNaN(t) || Number.isNaN(v)) {
|
|
226
|
+
started = false;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const tPixel = timeScale(t);
|
|
230
|
+
const vPixel = valueScale(v);
|
|
231
|
+
const x = timeAxis === "x" ? tPixel : vPixel;
|
|
232
|
+
const y = timeAxis === "x" ? vPixel : tPixel;
|
|
233
|
+
if (!started) {
|
|
234
|
+
ctx.moveTo(x, y);
|
|
235
|
+
started = true;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
ctx.lineTo(x, y);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
ctx.stroke();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
// Threshold mode: segment-based drawing
|
|
245
|
+
ctx.lineWidth = style.strokeWidth || 2;
|
|
246
|
+
if (style.strokeDasharray) {
|
|
247
|
+
ctx.setLineDash(style.strokeDasharray.split(/[\s,]+/).map(Number));
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
ctx.setLineDash([]);
|
|
251
|
+
}
|
|
252
|
+
let prevX = null;
|
|
253
|
+
let prevY = null;
|
|
254
|
+
let prevValue = null;
|
|
255
|
+
let prevColor = null;
|
|
256
|
+
let pathStarted = false;
|
|
257
|
+
function toPixel(t, v) {
|
|
258
|
+
const tPixel = timeScale(t);
|
|
259
|
+
const vPixel = valueScale(v);
|
|
260
|
+
return timeAxis === "x" ? [tPixel, vPixel] : [vPixel, tPixel];
|
|
261
|
+
}
|
|
262
|
+
function startSegment(color, x, y) {
|
|
263
|
+
ctx.beginPath();
|
|
264
|
+
ctx.strokeStyle = color;
|
|
265
|
+
ctx.moveTo(x, y);
|
|
266
|
+
pathStarted = true;
|
|
267
|
+
}
|
|
268
|
+
function endSegment() {
|
|
269
|
+
if (pathStarted) {
|
|
270
|
+
ctx.stroke();
|
|
271
|
+
pathStarted = false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
for (const d of data) {
|
|
275
|
+
const t = getTime(d);
|
|
276
|
+
const v = getValue(d);
|
|
277
|
+
if (t == null || v == null || Number.isNaN(t) || Number.isNaN(v)) {
|
|
278
|
+
endSegment();
|
|
279
|
+
prevX = null;
|
|
280
|
+
prevY = null;
|
|
281
|
+
prevValue = null;
|
|
282
|
+
prevColor = null;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const [x, y] = toPixel(t, v);
|
|
286
|
+
const currColor = resolveColor$1(v, colorThresholds, baseColor);
|
|
287
|
+
if (prevX === null || prevColor === null || prevValue === null) {
|
|
288
|
+
// First valid point
|
|
289
|
+
startSegment(currColor, x, y);
|
|
290
|
+
prevX = x;
|
|
291
|
+
prevY = y;
|
|
292
|
+
prevValue = v;
|
|
293
|
+
prevColor = currColor;
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (currColor === prevColor) {
|
|
297
|
+
ctx.lineTo(x, y);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
// Find all thresholds crossed between prevValue and v, sorted by interpolation t
|
|
301
|
+
const crossings = [];
|
|
302
|
+
for (const threshold of colorThresholds) {
|
|
303
|
+
const tv = threshold.value;
|
|
304
|
+
// Check if the threshold value lies between prevValue and v
|
|
305
|
+
if ((prevValue <= tv && v >= tv) || (prevValue >= tv && v <= tv)) {
|
|
306
|
+
// Don't add crossing at exact endpoints
|
|
307
|
+
if (prevValue !== tv && v !== tv) {
|
|
308
|
+
const interpT = (tv - prevValue) / (v - prevValue);
|
|
309
|
+
crossings.push({ t: interpT, color: "" }); // color resolved after sorting
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Sort crossings by interpolation parameter
|
|
314
|
+
crossings.sort((a, b) => a.t - b.t);
|
|
315
|
+
for (const crossing of crossings) {
|
|
316
|
+
const midX = prevX + (x - prevX) * crossing.t;
|
|
317
|
+
const midY = prevY + (y - prevY) * crossing.t;
|
|
318
|
+
// Nudge slightly past the crossing to determine the color on the other side
|
|
319
|
+
const nudgedValue = prevValue + (v - prevValue) * Math.min(crossing.t + 0.0001, 1);
|
|
320
|
+
const nextColor = resolveColor$1(nudgedValue, colorThresholds, baseColor);
|
|
321
|
+
ctx.lineTo(midX, midY);
|
|
322
|
+
endSegment();
|
|
323
|
+
startSegment(nextColor, midX, midY);
|
|
324
|
+
}
|
|
325
|
+
ctx.lineTo(x, y);
|
|
326
|
+
}
|
|
327
|
+
prevX = x;
|
|
328
|
+
prevY = y;
|
|
329
|
+
prevValue = v;
|
|
330
|
+
prevColor = currColor;
|
|
331
|
+
}
|
|
332
|
+
endSegment();
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const DEFAULT_PALETTE$1 = [
|
|
336
|
+
"#007bff", "#28a745", "#dc3545", "#fd7e14", "#6f42c1",
|
|
337
|
+
"#20c997", "#e83e8c", "#17a2b8", "#6610f2", "#ffc107"
|
|
338
|
+
];
|
|
339
|
+
function resolveColor(value, thresholds, baseColor) {
|
|
340
|
+
let color = baseColor;
|
|
341
|
+
for (const t of thresholds) {
|
|
342
|
+
if (t.thresholdType === "lesser") {
|
|
343
|
+
if (value < t.value)
|
|
344
|
+
color = t.color;
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
if (value > t.value)
|
|
348
|
+
color = t.color;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return color;
|
|
352
|
+
}
|
|
353
|
+
const swarmRenderer = (ctx, data, scales, layout, style, accessors, annotations, options) => {
|
|
354
|
+
var _a, _b, _c, _d, _e;
|
|
355
|
+
const { time: timeScale, value: valueScale } = scales;
|
|
356
|
+
const { timeAxis } = layout;
|
|
357
|
+
const { time: getTime, value: getValue, category: getCategory } = accessors;
|
|
358
|
+
const ss = options === null || options === void 0 ? void 0 : options.swarmStyle;
|
|
359
|
+
const barColors = options === null || options === void 0 ? void 0 : options.barColors;
|
|
360
|
+
const radius = (_a = ss === null || ss === void 0 ? void 0 : ss.radius) !== null && _a !== void 0 ? _a : 3;
|
|
361
|
+
const defaultFill = (_c = (_b = ss === null || ss === void 0 ? void 0 : ss.fill) !== null && _b !== void 0 ? _b : style.stroke) !== null && _c !== void 0 ? _c : "#007bff";
|
|
362
|
+
const opacity = (_d = ss === null || ss === void 0 ? void 0 : ss.opacity) !== null && _d !== void 0 ? _d : 0.7;
|
|
363
|
+
const hasStroke = (ss === null || ss === void 0 ? void 0 : ss.stroke) != null;
|
|
364
|
+
// Extract color thresholds from annotations
|
|
365
|
+
const colorThresholds = annotations
|
|
366
|
+
? annotations
|
|
367
|
+
.filter((a) => a.type === "threshold" && a.color)
|
|
368
|
+
.map((a) => ({
|
|
369
|
+
value: a.value,
|
|
370
|
+
color: a.color,
|
|
371
|
+
thresholdType: (a.thresholdType || "greater")
|
|
372
|
+
}))
|
|
373
|
+
: null;
|
|
374
|
+
const hasColorThresholds = colorThresholds && colorThresholds.length > 0;
|
|
375
|
+
ctx.globalAlpha = opacity;
|
|
376
|
+
let paletteIndex = 0;
|
|
377
|
+
const categoryColorCache = {};
|
|
378
|
+
for (const d of data) {
|
|
379
|
+
const t = getTime(d);
|
|
380
|
+
const v = getValue(d);
|
|
381
|
+
if (v == null || Number.isNaN(v))
|
|
382
|
+
continue;
|
|
383
|
+
let x, y;
|
|
384
|
+
if (timeAxis === "x") {
|
|
385
|
+
x = timeScale(t);
|
|
386
|
+
y = valueScale(v);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
x = valueScale(v);
|
|
390
|
+
y = timeScale(t);
|
|
391
|
+
}
|
|
392
|
+
// Determine fill color
|
|
393
|
+
let fill = defaultFill;
|
|
394
|
+
if (getCategory) {
|
|
395
|
+
const cat = getCategory(d);
|
|
396
|
+
if (barColors && barColors[cat]) {
|
|
397
|
+
fill = barColors[cat];
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
if (!(cat in categoryColorCache)) {
|
|
401
|
+
categoryColorCache[cat] = DEFAULT_PALETTE$1[paletteIndex % DEFAULT_PALETTE$1.length];
|
|
402
|
+
paletteIndex++;
|
|
403
|
+
}
|
|
404
|
+
fill = categoryColorCache[cat];
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Threshold coloring overrides category/default fill
|
|
408
|
+
if (hasColorThresholds) {
|
|
409
|
+
fill = resolveColor(v, colorThresholds, fill);
|
|
410
|
+
}
|
|
411
|
+
ctx.fillStyle = fill;
|
|
412
|
+
ctx.beginPath();
|
|
413
|
+
ctx.arc(x, y, radius, 0, Math.PI * 2);
|
|
414
|
+
ctx.fill();
|
|
415
|
+
if (hasStroke) {
|
|
416
|
+
ctx.strokeStyle = ss.stroke;
|
|
417
|
+
ctx.lineWidth = (_e = ss === null || ss === void 0 ? void 0 : ss.strokeWidth) !== null && _e !== void 0 ? _e : 1;
|
|
418
|
+
ctx.stroke();
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
ctx.globalAlpha = 1;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const candlestickRenderer = () => {
|
|
425
|
+
throw new Error("candlestickRenderer: Not yet implemented");
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
const DEFAULT_POSITIVE_COLOR = "#28a745";
|
|
429
|
+
const DEFAULT_NEGATIVE_COLOR = "#dc3545";
|
|
430
|
+
function computeWaterfallExtent(data, getValue) {
|
|
431
|
+
let min = 0;
|
|
432
|
+
let max = 0;
|
|
433
|
+
let cumulative = 0;
|
|
434
|
+
for (const d of data) {
|
|
435
|
+
const v = getValue(d);
|
|
436
|
+
if (v == null || Number.isNaN(v))
|
|
437
|
+
continue;
|
|
438
|
+
cumulative += v;
|
|
439
|
+
if (cumulative < min)
|
|
440
|
+
min = cumulative;
|
|
441
|
+
if (cumulative > max)
|
|
442
|
+
max = cumulative;
|
|
443
|
+
}
|
|
444
|
+
return [min, max];
|
|
445
|
+
}
|
|
446
|
+
const waterfallRenderer = (ctx, data, scales, layout, style, accessors, annotations, options) => {
|
|
447
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
448
|
+
const { time: timeScale, value: valueScale } = scales;
|
|
449
|
+
const { timeAxis, width, height } = layout;
|
|
450
|
+
const { time: getTime, value: getValue } = accessors;
|
|
451
|
+
const ws = options === null || options === void 0 ? void 0 : options.waterfallStyle;
|
|
452
|
+
const positiveColor = (_a = ws === null || ws === void 0 ? void 0 : ws.positiveColor) !== null && _a !== void 0 ? _a : DEFAULT_POSITIVE_COLOR;
|
|
453
|
+
const negativeColor = (_b = ws === null || ws === void 0 ? void 0 : ws.negativeColor) !== null && _b !== void 0 ? _b : DEFAULT_NEGATIVE_COLOR;
|
|
454
|
+
const gap = (_c = ws === null || ws === void 0 ? void 0 : ws.gap) !== null && _c !== void 0 ? _c : 1;
|
|
455
|
+
const connectorStroke = ws === null || ws === void 0 ? void 0 : ws.connectorStroke;
|
|
456
|
+
const connectorWidth = (_d = ws === null || ws === void 0 ? void 0 : ws.connectorWidth) !== null && _d !== void 0 ? _d : 1;
|
|
457
|
+
const hasStroke = (ws === null || ws === void 0 ? void 0 : ws.stroke) != null;
|
|
458
|
+
if (hasStroke) {
|
|
459
|
+
ctx.strokeStyle = ws.stroke;
|
|
460
|
+
ctx.lineWidth = (_e = ws === null || ws === void 0 ? void 0 : ws.strokeWidth) !== null && _e !== void 0 ? _e : 1;
|
|
461
|
+
}
|
|
462
|
+
// Collect into array for random access (skip NaN/null values)
|
|
463
|
+
const arr = [];
|
|
464
|
+
for (const d of data) {
|
|
465
|
+
const v = getValue(d);
|
|
466
|
+
if (v == null || Number.isNaN(v))
|
|
467
|
+
continue;
|
|
468
|
+
arr.push(d);
|
|
469
|
+
}
|
|
470
|
+
if (arr.length === 0)
|
|
471
|
+
return;
|
|
472
|
+
let baseline = 0;
|
|
473
|
+
// Track the end edge of the previous bar and its cumulative value for connectors
|
|
474
|
+
let prevEdge = null;
|
|
475
|
+
let prevCumulative = null;
|
|
476
|
+
for (let i = 0; i < arr.length; i++) {
|
|
477
|
+
const d = arr[i];
|
|
478
|
+
const t = getTime(d);
|
|
479
|
+
const delta = getValue(d);
|
|
480
|
+
const cumEnd = baseline + delta;
|
|
481
|
+
// Compute bar width from time gap to next point
|
|
482
|
+
let barWidthTime;
|
|
483
|
+
if (i < arr.length - 1) {
|
|
484
|
+
barWidthTime = getTime(arr[i + 1]) - t;
|
|
485
|
+
}
|
|
486
|
+
else if (i > 0) {
|
|
487
|
+
barWidthTime = t - getTime(arr[i - 1]);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
// Single point fallback: use 0 to trigger pixel fallback
|
|
491
|
+
barWidthTime = 0;
|
|
492
|
+
}
|
|
493
|
+
ctx.fillStyle = delta >= 0 ? positiveColor : negativeColor;
|
|
494
|
+
if (timeAxis === "x") {
|
|
495
|
+
let rawX0, rawX1;
|
|
496
|
+
if (barWidthTime !== 0) {
|
|
497
|
+
rawX0 = timeScale(t);
|
|
498
|
+
rawX1 = timeScale(t + barWidthTime);
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
rawX0 = timeScale(t);
|
|
502
|
+
rawX1 = rawX0 + width / 10;
|
|
503
|
+
}
|
|
504
|
+
const x0 = Math.min(rawX0, rawX1) + gap / 2;
|
|
505
|
+
const x1 = Math.max(rawX0, rawX1) - gap / 2;
|
|
506
|
+
const barWidth = x1 - x0;
|
|
507
|
+
if (barWidth <= 0) {
|
|
508
|
+
baseline = cumEnd;
|
|
509
|
+
prevEdge = x1;
|
|
510
|
+
prevCumulative = cumEnd;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
const yBaseline = valueScale(baseline);
|
|
514
|
+
const yTop = valueScale(cumEnd);
|
|
515
|
+
const rectY = Math.min(yBaseline, yTop);
|
|
516
|
+
const rectH = Math.abs(yBaseline - yTop);
|
|
517
|
+
// Connector line at the baseline level from previous bar's right edge to this bar's left edge
|
|
518
|
+
if (connectorStroke && prevEdge != null && prevCumulative != null) {
|
|
519
|
+
ctx.save();
|
|
520
|
+
ctx.strokeStyle = connectorStroke;
|
|
521
|
+
ctx.lineWidth = connectorWidth;
|
|
522
|
+
const connY = valueScale(prevCumulative);
|
|
523
|
+
ctx.beginPath();
|
|
524
|
+
ctx.moveTo(prevEdge, connY);
|
|
525
|
+
ctx.lineTo(x0, connY);
|
|
526
|
+
ctx.stroke();
|
|
527
|
+
ctx.restore();
|
|
528
|
+
if (hasStroke) {
|
|
529
|
+
ctx.strokeStyle = ws.stroke;
|
|
530
|
+
ctx.lineWidth = (_f = ws === null || ws === void 0 ? void 0 : ws.strokeWidth) !== null && _f !== void 0 ? _f : 1;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
ctx.fillRect(x0, rectY, barWidth, rectH);
|
|
534
|
+
if (hasStroke)
|
|
535
|
+
ctx.strokeRect(x0, rectY, barWidth, rectH);
|
|
536
|
+
prevEdge = x1;
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
// timeAxis === "y": horizontal bars
|
|
540
|
+
let rawY0, rawY1;
|
|
541
|
+
if (barWidthTime !== 0) {
|
|
542
|
+
rawY0 = timeScale(t);
|
|
543
|
+
rawY1 = timeScale(t + barWidthTime);
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
rawY0 = timeScale(t);
|
|
547
|
+
rawY1 = rawY0 + height / 10;
|
|
548
|
+
}
|
|
549
|
+
const y0 = Math.min(rawY0, rawY1) + gap / 2;
|
|
550
|
+
const y1 = Math.max(rawY0, rawY1) - gap / 2;
|
|
551
|
+
const barHeight = y1 - y0;
|
|
552
|
+
if (barHeight <= 0) {
|
|
553
|
+
baseline = cumEnd;
|
|
554
|
+
prevEdge = y1;
|
|
555
|
+
prevCumulative = cumEnd;
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
const xBaseline = valueScale(baseline);
|
|
559
|
+
const xEnd = valueScale(cumEnd);
|
|
560
|
+
const rectX = Math.min(xBaseline, xEnd);
|
|
561
|
+
const rectW = Math.abs(xEnd - xBaseline);
|
|
562
|
+
// Connector line at the baseline level from previous bar's bottom edge to this bar's top edge
|
|
563
|
+
if (connectorStroke && prevEdge != null && prevCumulative != null) {
|
|
564
|
+
ctx.save();
|
|
565
|
+
ctx.strokeStyle = connectorStroke;
|
|
566
|
+
ctx.lineWidth = connectorWidth;
|
|
567
|
+
const connX = valueScale(prevCumulative);
|
|
568
|
+
ctx.beginPath();
|
|
569
|
+
ctx.moveTo(connX, prevEdge);
|
|
570
|
+
ctx.lineTo(connX, y0);
|
|
571
|
+
ctx.stroke();
|
|
572
|
+
ctx.restore();
|
|
573
|
+
if (hasStroke) {
|
|
574
|
+
ctx.strokeStyle = ws.stroke;
|
|
575
|
+
ctx.lineWidth = (_g = ws === null || ws === void 0 ? void 0 : ws.strokeWidth) !== null && _g !== void 0 ? _g : 1;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
ctx.fillRect(rectX, y0, rectW, barHeight);
|
|
579
|
+
if (hasStroke)
|
|
580
|
+
ctx.strokeRect(rectX, y0, rectW, barHeight);
|
|
581
|
+
prevEdge = y1;
|
|
582
|
+
}
|
|
583
|
+
baseline = cumEnd;
|
|
584
|
+
prevCumulative = cumEnd;
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
function computeBins(data, getTime, getValue, binSize, getCategory) {
|
|
589
|
+
const bins = new Map();
|
|
590
|
+
for (const d of data) {
|
|
591
|
+
const t = getTime(d);
|
|
592
|
+
const v = getValue(d);
|
|
593
|
+
if (t == null || v == null || Number.isNaN(t) || Number.isNaN(v))
|
|
594
|
+
continue;
|
|
595
|
+
const binStart = Math.floor(t / binSize) * binSize;
|
|
596
|
+
let bin = bins.get(binStart);
|
|
597
|
+
if (!bin) {
|
|
598
|
+
bin = { start: binStart, end: binStart + binSize, total: 0, categories: new Map() };
|
|
599
|
+
bins.set(binStart, bin);
|
|
600
|
+
}
|
|
601
|
+
bin.total += v;
|
|
602
|
+
if (getCategory) {
|
|
603
|
+
const cat = getCategory(d);
|
|
604
|
+
bin.categories.set(cat, (bin.categories.get(cat) || 0) + v);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return bins;
|
|
608
|
+
}
|
|
609
|
+
function computeBinExtent(data, getTime, getValue, binSize, getCategory) {
|
|
610
|
+
const bins = computeBins(data, getTime, getValue, binSize, getCategory);
|
|
611
|
+
if (bins.size === 0)
|
|
612
|
+
return [0, 0];
|
|
613
|
+
let maxTotal = 0;
|
|
614
|
+
for (const bin of bins.values()) {
|
|
615
|
+
if (bin.total > maxTotal)
|
|
616
|
+
maxTotal = bin.total;
|
|
617
|
+
}
|
|
618
|
+
return [0, maxTotal];
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const DEFAULT_PALETTE = [
|
|
622
|
+
"#4e79a7", "#f28e2b", "#e15759", "#76b7b2",
|
|
623
|
+
"#59a14f", "#edc948", "#b07aa1", "#ff9da7",
|
|
624
|
+
"#9c755f", "#bab0ac"
|
|
625
|
+
];
|
|
626
|
+
const barRenderer = (ctx, data, scales, layout, style, accessors, annotations, options) => {
|
|
627
|
+
var _a, _b;
|
|
628
|
+
const binSize = options === null || options === void 0 ? void 0 : options.binSize;
|
|
629
|
+
if (!binSize)
|
|
630
|
+
return;
|
|
631
|
+
const { time: timeScale, value: valueScale } = scales;
|
|
632
|
+
const { timeAxis } = layout;
|
|
633
|
+
const { time: getTime, value: getValue, category: getCategory } = accessors;
|
|
634
|
+
const barColors = options === null || options === void 0 ? void 0 : options.barColors;
|
|
635
|
+
const barStyle = options === null || options === void 0 ? void 0 : options.barStyle;
|
|
636
|
+
const bins = computeBins(data, getTime, getValue, binSize, getCategory);
|
|
637
|
+
if (bins.size === 0)
|
|
638
|
+
return;
|
|
639
|
+
const [domainMin, domainMax] = timeScale.domain();
|
|
640
|
+
const gap = (_a = barStyle === null || barStyle === void 0 ? void 0 : barStyle.gap) !== null && _a !== void 0 ? _a : 1;
|
|
641
|
+
const hasCategories = getCategory != null;
|
|
642
|
+
// Determine category order: barColors keys first, then alphabetical for unlisted
|
|
643
|
+
let categoryOrder = null;
|
|
644
|
+
if (hasCategories) {
|
|
645
|
+
const allCategories = new Set();
|
|
646
|
+
for (const bin of bins.values()) {
|
|
647
|
+
for (const cat of bin.categories.keys()) {
|
|
648
|
+
allCategories.add(cat);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
const colorKeys = barColors ? Object.keys(barColors) : [];
|
|
652
|
+
const listed = new Set(colorKeys);
|
|
653
|
+
const unlisted = Array.from(allCategories).filter(c => !listed.has(c)).sort();
|
|
654
|
+
categoryOrder = [...colorKeys.filter(k => allCategories.has(k)), ...unlisted];
|
|
655
|
+
}
|
|
656
|
+
// Bar stroke settings
|
|
657
|
+
const hasBarStroke = (barStyle === null || barStyle === void 0 ? void 0 : barStyle.stroke) != null;
|
|
658
|
+
if (hasBarStroke) {
|
|
659
|
+
ctx.strokeStyle = barStyle.stroke;
|
|
660
|
+
ctx.lineWidth = (_b = barStyle === null || barStyle === void 0 ? void 0 : barStyle.strokeWidth) !== null && _b !== void 0 ? _b : 1;
|
|
661
|
+
}
|
|
662
|
+
for (const bin of bins.values()) {
|
|
663
|
+
if (timeAxis === "x") {
|
|
664
|
+
const clampedStart = Math.max(bin.start, domainMin);
|
|
665
|
+
const clampedEnd = Math.min(bin.end, domainMax);
|
|
666
|
+
if (clampedStart >= clampedEnd)
|
|
667
|
+
continue;
|
|
668
|
+
const rawX0 = timeScale(clampedStart);
|
|
669
|
+
const rawX1 = timeScale(clampedEnd);
|
|
670
|
+
const x0 = Math.min(rawX0, rawX1) + gap / 2;
|
|
671
|
+
const x1 = Math.max(rawX0, rawX1) - gap / 2;
|
|
672
|
+
const barWidth = x1 - x0;
|
|
673
|
+
if (barWidth <= 0)
|
|
674
|
+
continue;
|
|
675
|
+
if (hasCategories && categoryOrder) {
|
|
676
|
+
let cumulativeBase = 0;
|
|
677
|
+
let paletteIdx = 0;
|
|
678
|
+
for (const cat of categoryOrder) {
|
|
679
|
+
const catVal = bin.categories.get(cat) || 0;
|
|
680
|
+
if (catVal === 0)
|
|
681
|
+
continue;
|
|
682
|
+
const yBottom = valueScale(cumulativeBase);
|
|
683
|
+
const yTop = valueScale(cumulativeBase + catVal);
|
|
684
|
+
const rectY = Math.min(yBottom, yTop);
|
|
685
|
+
const rectH = Math.abs(yBottom - yTop);
|
|
686
|
+
ctx.fillStyle = (barColors && barColors[cat]) || DEFAULT_PALETTE[paletteIdx % DEFAULT_PALETTE.length];
|
|
687
|
+
ctx.fillRect(x0, rectY, barWidth, rectH);
|
|
688
|
+
if (hasBarStroke)
|
|
689
|
+
ctx.strokeRect(x0, rectY, barWidth, rectH);
|
|
690
|
+
cumulativeBase += catVal;
|
|
691
|
+
paletteIdx++;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
const yZero = valueScale(0);
|
|
696
|
+
const yTop = valueScale(bin.total);
|
|
697
|
+
const rectY = Math.min(yZero, yTop);
|
|
698
|
+
const rectH = Math.abs(yZero - yTop);
|
|
699
|
+
ctx.fillStyle = (barStyle === null || barStyle === void 0 ? void 0 : barStyle.fill) || style.stroke || "#007bff";
|
|
700
|
+
ctx.fillRect(x0, rectY, barWidth, rectH);
|
|
701
|
+
if (hasBarStroke)
|
|
702
|
+
ctx.strokeRect(x0, rectY, barWidth, rectH);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
// timeAxis === "y": horizontal bars
|
|
707
|
+
const clampedStart = Math.max(bin.start, domainMin);
|
|
708
|
+
const clampedEnd = Math.min(bin.end, domainMax);
|
|
709
|
+
if (clampedStart >= clampedEnd)
|
|
710
|
+
continue;
|
|
711
|
+
const rawY0 = timeScale(clampedStart);
|
|
712
|
+
const rawY1 = timeScale(clampedEnd);
|
|
713
|
+
const y0 = Math.min(rawY0, rawY1) + gap / 2;
|
|
714
|
+
const y1 = Math.max(rawY0, rawY1) - gap / 2;
|
|
715
|
+
const barHeight = y1 - y0;
|
|
716
|
+
if (barHeight <= 0)
|
|
717
|
+
continue;
|
|
718
|
+
if (hasCategories && categoryOrder) {
|
|
719
|
+
let cumulativeBase = 0;
|
|
720
|
+
let paletteIdx = 0;
|
|
721
|
+
for (const cat of categoryOrder) {
|
|
722
|
+
const catVal = bin.categories.get(cat) || 0;
|
|
723
|
+
if (catVal === 0)
|
|
724
|
+
continue;
|
|
725
|
+
const xLeft = valueScale(cumulativeBase);
|
|
726
|
+
const xRight = valueScale(cumulativeBase + catVal);
|
|
727
|
+
const rectX = Math.min(xLeft, xRight);
|
|
728
|
+
const rectW = Math.abs(xRight - xLeft);
|
|
729
|
+
ctx.fillStyle = (barColors && barColors[cat]) || DEFAULT_PALETTE[paletteIdx % DEFAULT_PALETTE.length];
|
|
730
|
+
ctx.fillRect(rectX, y0, rectW, barHeight);
|
|
731
|
+
if (hasBarStroke)
|
|
732
|
+
ctx.strokeRect(rectX, y0, rectW, barHeight);
|
|
733
|
+
cumulativeBase += catVal;
|
|
734
|
+
paletteIdx++;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
const xZero = valueScale(0);
|
|
739
|
+
const xEnd = valueScale(bin.total);
|
|
740
|
+
const rectX = Math.min(xZero, xEnd);
|
|
741
|
+
const rectW = Math.abs(xEnd - xZero);
|
|
742
|
+
ctx.fillStyle = (barStyle === null || barStyle === void 0 ? void 0 : barStyle.fill) || style.stroke || "#007bff";
|
|
743
|
+
ctx.fillRect(rectX, y0, rectW, barHeight);
|
|
744
|
+
if (hasBarStroke)
|
|
745
|
+
ctx.strokeRect(rectX, y0, rectW, barHeight);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
const RENDERERS = {
|
|
752
|
+
line: lineRenderer,
|
|
753
|
+
swarm: swarmRenderer,
|
|
754
|
+
candlestick: candlestickRenderer,
|
|
755
|
+
waterfall: waterfallRenderer,
|
|
756
|
+
bar: barRenderer
|
|
757
|
+
};
|
|
758
|
+
const DEFAULT_MARGIN = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
759
|
+
const DEFAULT_LINE_STYLE = {};
|
|
760
|
+
function resolveAccessor(accessor, fallback) {
|
|
761
|
+
if (typeof accessor === "function")
|
|
762
|
+
return (d) => +accessor(d);
|
|
763
|
+
const key = accessor || fallback;
|
|
764
|
+
return (d) => +d[key];
|
|
765
|
+
}
|
|
766
|
+
function getTimeAxis(arrowOfTime) {
|
|
767
|
+
return arrowOfTime === "up" || arrowOfTime === "down" ? "y" : "x";
|
|
768
|
+
}
|
|
769
|
+
function buildScales(arrowOfTime, timeExtent, valueExtent, width, height) {
|
|
770
|
+
const timeAxis = getTimeAxis(arrowOfTime);
|
|
771
|
+
let timeRange;
|
|
772
|
+
let valueRange;
|
|
773
|
+
if (timeAxis === "x") {
|
|
774
|
+
timeRange = arrowOfTime === "right" ? [0, width] : [width, 0];
|
|
775
|
+
valueRange = [height, 0];
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
timeRange = arrowOfTime === "down" ? [0, height] : [height, 0];
|
|
779
|
+
valueRange = [0, width];
|
|
780
|
+
}
|
|
781
|
+
return {
|
|
782
|
+
time: d3Scale.scaleLinear().domain(timeExtent).range(timeRange),
|
|
783
|
+
value: d3Scale.scaleLinear().domain(valueExtent).range(valueRange)
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
function defaultTickFormat(v) {
|
|
787
|
+
return String(Math.round(v * 100) / 100);
|
|
788
|
+
}
|
|
789
|
+
const LIGHT_THEME = {
|
|
790
|
+
axisStroke: "#ccc",
|
|
791
|
+
tickText: "#666",
|
|
792
|
+
crosshair: "rgba(0, 0, 0, 0.25)",
|
|
793
|
+
hoverFill: "rgba(255, 255, 255, 0.3)",
|
|
794
|
+
hoverStroke: "rgba(0, 0, 0, 0.4)",
|
|
795
|
+
pointRing: "white"
|
|
796
|
+
};
|
|
797
|
+
/** Read CSS custom properties from an element to build theme-aware colors */
|
|
798
|
+
function resolveThemeColors(el) {
|
|
799
|
+
if (!el)
|
|
800
|
+
return LIGHT_THEME;
|
|
801
|
+
const style = getComputedStyle(el);
|
|
802
|
+
const textSecondary = style.getPropertyValue("--text-secondary").trim();
|
|
803
|
+
const textPrimary = style.getPropertyValue("--text-primary").trim();
|
|
804
|
+
const surface3 = style.getPropertyValue("--surface-3").trim();
|
|
805
|
+
const surface0 = style.getPropertyValue("--surface-0").trim();
|
|
806
|
+
// If no CSS custom properties are found, fall back to light defaults
|
|
807
|
+
if (!textSecondary && !textPrimary)
|
|
808
|
+
return LIGHT_THEME;
|
|
809
|
+
return {
|
|
810
|
+
axisStroke: surface3 || LIGHT_THEME.axisStroke,
|
|
811
|
+
tickText: textSecondary || LIGHT_THEME.tickText,
|
|
812
|
+
crosshair: textSecondary ? `${textSecondary}66` : LIGHT_THEME.crosshair,
|
|
813
|
+
hoverFill: surface0 ? `${surface0}4D` : LIGHT_THEME.hoverFill,
|
|
814
|
+
hoverStroke: textSecondary ? `${textSecondary}99` : LIGHT_THEME.hoverStroke,
|
|
815
|
+
pointRing: surface0 || LIGHT_THEME.pointRing
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
function drawAxes(ctx, arrowOfTime, timeScale, valueScale, width, height, tickFormatTime, tickFormatValue, theme) {
|
|
819
|
+
const timeAxis = getTimeAxis(arrowOfTime);
|
|
820
|
+
const fmtValue = tickFormatValue || defaultTickFormat;
|
|
821
|
+
const colors = theme || LIGHT_THEME;
|
|
822
|
+
ctx.strokeStyle = colors.axisStroke;
|
|
823
|
+
ctx.lineWidth = 1;
|
|
824
|
+
ctx.fillStyle = colors.tickText;
|
|
825
|
+
ctx.font = "10px sans-serif";
|
|
826
|
+
ctx.textAlign = "center";
|
|
827
|
+
ctx.textBaseline = "top";
|
|
828
|
+
if (timeAxis === "x") {
|
|
829
|
+
ctx.beginPath();
|
|
830
|
+
ctx.moveTo(0, height);
|
|
831
|
+
ctx.lineTo(width, height);
|
|
832
|
+
ctx.stroke();
|
|
833
|
+
ctx.beginPath();
|
|
834
|
+
ctx.moveTo(0, 0);
|
|
835
|
+
ctx.lineTo(0, height);
|
|
836
|
+
ctx.stroke();
|
|
837
|
+
const timeTicks = timeScale.ticks(5);
|
|
838
|
+
ctx.textAlign = "center";
|
|
839
|
+
ctx.textBaseline = "top";
|
|
840
|
+
for (const tick of timeTicks) {
|
|
841
|
+
const x = timeScale(tick);
|
|
842
|
+
ctx.beginPath();
|
|
843
|
+
ctx.moveTo(x, height);
|
|
844
|
+
ctx.lineTo(x, height + 5);
|
|
845
|
+
ctx.stroke();
|
|
846
|
+
if (tickFormatTime) {
|
|
847
|
+
ctx.fillText(tickFormatTime(tick), x, height + 7);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
ctx.textAlign = "right";
|
|
851
|
+
ctx.textBaseline = "middle";
|
|
852
|
+
const valueTicks = valueScale.ticks(5);
|
|
853
|
+
for (const tick of valueTicks) {
|
|
854
|
+
const y = valueScale(tick);
|
|
855
|
+
ctx.beginPath();
|
|
856
|
+
ctx.moveTo(-5, y);
|
|
857
|
+
ctx.lineTo(0, y);
|
|
858
|
+
ctx.stroke();
|
|
859
|
+
ctx.fillText(fmtValue(tick), -8, y);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
ctx.beginPath();
|
|
864
|
+
ctx.moveTo(0, 0);
|
|
865
|
+
ctx.lineTo(0, height);
|
|
866
|
+
ctx.stroke();
|
|
867
|
+
ctx.beginPath();
|
|
868
|
+
ctx.moveTo(0, timeAxis === "y" && arrowOfTime === "down" ? 0 : height);
|
|
869
|
+
ctx.lineTo(width, timeAxis === "y" && arrowOfTime === "down" ? 0 : height);
|
|
870
|
+
ctx.stroke();
|
|
871
|
+
ctx.textAlign = "center";
|
|
872
|
+
ctx.textBaseline = "top";
|
|
873
|
+
const valueTicks = valueScale.ticks(5);
|
|
874
|
+
for (const tick of valueTicks) {
|
|
875
|
+
const x = valueScale(tick);
|
|
876
|
+
ctx.beginPath();
|
|
877
|
+
ctx.moveTo(x, height);
|
|
878
|
+
ctx.lineTo(x, height + 5);
|
|
879
|
+
ctx.stroke();
|
|
880
|
+
ctx.fillText(fmtValue(tick), x, height + 7);
|
|
881
|
+
}
|
|
882
|
+
ctx.textAlign = "right";
|
|
883
|
+
ctx.textBaseline = "middle";
|
|
884
|
+
const timeTicks = timeScale.ticks(5);
|
|
885
|
+
for (const tick of timeTicks) {
|
|
886
|
+
const y = timeScale(tick);
|
|
887
|
+
ctx.beginPath();
|
|
888
|
+
ctx.moveTo(-5, y);
|
|
889
|
+
ctx.lineTo(0, y);
|
|
890
|
+
ctx.stroke();
|
|
891
|
+
if (tickFormatTime) {
|
|
892
|
+
ctx.fillText(tickFormatTime(tick), -8, y);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
// Binary search: find the index of the nearest point by time value
|
|
898
|
+
function findNearestIndex(buf, targetTime, getTime) {
|
|
899
|
+
if (buf.size === 0)
|
|
900
|
+
return -1;
|
|
901
|
+
let lo = 0;
|
|
902
|
+
let hi = buf.size - 1;
|
|
903
|
+
while (lo < hi) {
|
|
904
|
+
const mid = (lo + hi) >> 1;
|
|
905
|
+
const t = getTime(buf.get(mid));
|
|
906
|
+
if (t < targetTime)
|
|
907
|
+
lo = mid + 1;
|
|
908
|
+
else
|
|
909
|
+
hi = mid;
|
|
910
|
+
}
|
|
911
|
+
// lo is first point with time >= targetTime; check if lo-1 is closer
|
|
912
|
+
if (lo > 0) {
|
|
913
|
+
const tLo = getTime(buf.get(lo));
|
|
914
|
+
const tPrev = getTime(buf.get(lo - 1));
|
|
915
|
+
if (Math.abs(tPrev - targetTime) <= Math.abs(tLo - targetTime)) {
|
|
916
|
+
return lo - 1;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return lo;
|
|
920
|
+
}
|
|
921
|
+
function drawCrosshair(ctx, hover, width, height, config, pointColor, theme) {
|
|
922
|
+
const showCrosshair = config.crosshair !== false;
|
|
923
|
+
if (!showCrosshair)
|
|
924
|
+
return;
|
|
925
|
+
const colors = theme || LIGHT_THEME;
|
|
926
|
+
ctx.save();
|
|
927
|
+
const crossStyle = typeof config.crosshair === "object" ? config.crosshair : {};
|
|
928
|
+
ctx.strokeStyle = crossStyle.stroke || colors.crosshair;
|
|
929
|
+
ctx.lineWidth = crossStyle.strokeWidth || 1;
|
|
930
|
+
if (crossStyle.strokeDasharray) {
|
|
931
|
+
ctx.setLineDash(crossStyle.strokeDasharray.split(/[\s,]+/).map(Number));
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
ctx.setLineDash([4, 4]);
|
|
935
|
+
}
|
|
936
|
+
// Vertical guide
|
|
937
|
+
ctx.beginPath();
|
|
938
|
+
ctx.moveTo(hover.x, 0);
|
|
939
|
+
ctx.lineTo(hover.x, height);
|
|
940
|
+
ctx.stroke();
|
|
941
|
+
// Horizontal guide
|
|
942
|
+
ctx.beginPath();
|
|
943
|
+
ctx.moveTo(0, hover.y);
|
|
944
|
+
ctx.lineTo(width, hover.y);
|
|
945
|
+
ctx.stroke();
|
|
946
|
+
ctx.restore();
|
|
947
|
+
// Point indicator
|
|
948
|
+
ctx.beginPath();
|
|
949
|
+
ctx.arc(hover.x, hover.y, 4, 0, Math.PI * 2);
|
|
950
|
+
ctx.fillStyle = pointColor;
|
|
951
|
+
ctx.fill();
|
|
952
|
+
ctx.strokeStyle = colors.pointRing;
|
|
953
|
+
ctx.lineWidth = 2;
|
|
954
|
+
ctx.stroke();
|
|
955
|
+
}
|
|
956
|
+
const defaultTooltipStyle = {
|
|
957
|
+
background: "rgba(0, 0, 0, 0.85)",
|
|
958
|
+
color: "white",
|
|
959
|
+
padding: "6px 10px",
|
|
960
|
+
borderRadius: 4,
|
|
961
|
+
fontSize: 12,
|
|
962
|
+
lineHeight: 1.5,
|
|
963
|
+
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
|
|
964
|
+
pointerEvents: "none",
|
|
965
|
+
whiteSpace: "nowrap"
|
|
966
|
+
};
|
|
967
|
+
function DefaultTooltip({ hover, formatTime }) {
|
|
968
|
+
const fmtValue = (v) => Number.isInteger(v) ? String(v) : v.toFixed(2);
|
|
969
|
+
const fmtTime = formatTime || fmtValue;
|
|
970
|
+
const colorMap = hover.data.barColors;
|
|
971
|
+
const hoveredCat = hover.data.hoveredCategory;
|
|
972
|
+
const hoveredCatVal = hover.data.hoveredCategoryValue;
|
|
973
|
+
return (React__namespace.createElement("div", { className: "semiotic-tooltip", style: defaultTooltipStyle },
|
|
974
|
+
hoveredCat != null && hoveredCatVal != null ? (React__namespace.createElement(React__namespace.Fragment, null,
|
|
975
|
+
React__namespace.createElement("div", { style: { display: "flex", alignItems: "center", gap: 5, fontWeight: 600, marginBottom: 2 } },
|
|
976
|
+
colorMap && colorMap[hoveredCat] && (React__namespace.createElement("span", { style: { width: 8, height: 8, borderRadius: "50%", background: colorMap[hoveredCat], flexShrink: 0 } })),
|
|
977
|
+
React__namespace.createElement("span", null, hoveredCat),
|
|
978
|
+
React__namespace.createElement("span", { style: { marginLeft: "auto" } }, fmtValue(hoveredCatVal))),
|
|
979
|
+
React__namespace.createElement("div", { style: { opacity: 0.6, fontSize: 11 } },
|
|
980
|
+
"total ",
|
|
981
|
+
fmtValue(hover.value)))) : (React__namespace.createElement("div", { style: { fontWeight: 600, marginBottom: 2 } }, fmtValue(hover.value))),
|
|
982
|
+
React__namespace.createElement("div", { style: { opacity: 0.7, fontSize: 11 } }, fmtTime(hover.time))));
|
|
983
|
+
}
|
|
984
|
+
const RealtimeFrame = React.forwardRef(function RealtimeFrame(props, ref) {
|
|
985
|
+
const { chartType = "line", arrowOfTime = "right", windowMode = "sliding", windowSize = 200, data, timeAccessor, valueAccessor, timeExtent: fixedTimeExtent, valueExtent: fixedValueExtent, extentPadding = 0.1, size = [500, 300], margin: marginProp, className, lineStyle = DEFAULT_LINE_STYLE, annotations, svgAnnotationRules, hoverAnnotation, tooltipContent, customHoverBehavior, showAxes = true, background, categoryAccessor, binSize, barColors, barStyle, waterfallStyle, swarmStyle, tickFormatTime, tickFormatValue } = props;
|
|
986
|
+
const margin = Object.assign(Object.assign({}, DEFAULT_MARGIN), marginProp);
|
|
987
|
+
const adjustedWidth = size[0] - margin.left - margin.right;
|
|
988
|
+
const adjustedHeight = size[1] - margin.top - margin.bottom;
|
|
989
|
+
// Memoize accessors so they don't change every render.
|
|
990
|
+
// Without this, the data effect re-runs on every render
|
|
991
|
+
// (new function reference), which triggers cascading re-renders.
|
|
992
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
993
|
+
const getTime = React.useMemo(() => resolveAccessor(timeAccessor, "time"), [timeAccessor]);
|
|
994
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
995
|
+
const getValue = React.useMemo(() => resolveAccessor(valueAccessor, "value"), [valueAccessor]);
|
|
996
|
+
const getCategory = React.useMemo(() => categoryAccessor
|
|
997
|
+
? (typeof categoryAccessor === "function" ? categoryAccessor : (d) => d[categoryAccessor])
|
|
998
|
+
: undefined, [categoryAccessor]);
|
|
999
|
+
const bufferRef = React.useRef(new RingBuffer(windowSize));
|
|
1000
|
+
const timeExtentRef = React.useRef(new IncrementalExtent());
|
|
1001
|
+
const valueExtentRef = React.useRef(new IncrementalExtent());
|
|
1002
|
+
const canvasRef = React.useRef(null);
|
|
1003
|
+
const rafRef = React.useRef(0);
|
|
1004
|
+
const dirtyRef = React.useRef(false);
|
|
1005
|
+
const scalesRef = React.useRef(null);
|
|
1006
|
+
const [annotationFrame, setAnnotationFrame] = React.useState(0);
|
|
1007
|
+
const growingCapRef = React.useRef(windowSize);
|
|
1008
|
+
// Hover state: ref for canvas (sync), React state for tooltip (async)
|
|
1009
|
+
const hoverRef = React.useRef(null);
|
|
1010
|
+
const [hoverPoint, setHoverPoint] = React.useState(null);
|
|
1011
|
+
// Store the render function in a ref so scheduleRender is stable
|
|
1012
|
+
// and never goes stale. The ref is updated every React render
|
|
1013
|
+
// (below the hooks) so it always captures fresh props/closures.
|
|
1014
|
+
const renderFnRef = React.useRef(() => { });
|
|
1015
|
+
// Stable scheduleRender — never recreated, so no stale closure chain
|
|
1016
|
+
const scheduleRender = React.useCallback(() => {
|
|
1017
|
+
if (rafRef.current)
|
|
1018
|
+
return;
|
|
1019
|
+
rafRef.current = requestAnimationFrame(() => renderFnRef.current());
|
|
1020
|
+
}, []);
|
|
1021
|
+
const pushPoint = React.useCallback((point) => {
|
|
1022
|
+
const buf = bufferRef.current;
|
|
1023
|
+
const t = getTime(point);
|
|
1024
|
+
const v = getValue(point);
|
|
1025
|
+
if (windowMode === "growing" && buf.full) {
|
|
1026
|
+
growingCapRef.current *= 2;
|
|
1027
|
+
buf.resize(growingCapRef.current);
|
|
1028
|
+
}
|
|
1029
|
+
const evicted = buf.push(point);
|
|
1030
|
+
timeExtentRef.current.push(t);
|
|
1031
|
+
valueExtentRef.current.push(v);
|
|
1032
|
+
if (evicted != null) {
|
|
1033
|
+
timeExtentRef.current.evict(getTime(evicted));
|
|
1034
|
+
valueExtentRef.current.evict(getValue(evicted));
|
|
1035
|
+
}
|
|
1036
|
+
dirtyRef.current = true;
|
|
1037
|
+
scheduleRender();
|
|
1038
|
+
}, [windowMode, getTime, getValue, scheduleRender]);
|
|
1039
|
+
const pushManyPoints = React.useCallback((points) => {
|
|
1040
|
+
for (const p of points) {
|
|
1041
|
+
pushPoint(p);
|
|
1042
|
+
}
|
|
1043
|
+
}, [pushPoint]);
|
|
1044
|
+
const clearAll = React.useCallback(() => {
|
|
1045
|
+
bufferRef.current.clear();
|
|
1046
|
+
timeExtentRef.current.clear();
|
|
1047
|
+
valueExtentRef.current.clear();
|
|
1048
|
+
dirtyRef.current = true;
|
|
1049
|
+
scheduleRender();
|
|
1050
|
+
}, [scheduleRender]);
|
|
1051
|
+
React.useImperativeHandle(ref, () => ({
|
|
1052
|
+
push: pushPoint,
|
|
1053
|
+
pushMany: pushManyPoints,
|
|
1054
|
+
clear: clearAll,
|
|
1055
|
+
getData: () => bufferRef.current.toArray()
|
|
1056
|
+
}), [pushPoint, pushManyPoints, clearAll]);
|
|
1057
|
+
// Controlled data prop
|
|
1058
|
+
React.useEffect(() => {
|
|
1059
|
+
if (!data)
|
|
1060
|
+
return;
|
|
1061
|
+
bufferRef.current.clear();
|
|
1062
|
+
timeExtentRef.current.clear();
|
|
1063
|
+
valueExtentRef.current.clear();
|
|
1064
|
+
for (const d of data) {
|
|
1065
|
+
bufferRef.current.push(d);
|
|
1066
|
+
timeExtentRef.current.push(getTime(d));
|
|
1067
|
+
valueExtentRef.current.push(getValue(d));
|
|
1068
|
+
}
|
|
1069
|
+
dirtyRef.current = true;
|
|
1070
|
+
scheduleRender();
|
|
1071
|
+
}, [data, getTime, getValue, scheduleRender]);
|
|
1072
|
+
// Hover mouse handler — stored in ref so it always captures fresh closures
|
|
1073
|
+
const hoverHandlerRef = React.useRef(() => { });
|
|
1074
|
+
const hoverLeaveRef = React.useRef(() => { });
|
|
1075
|
+
hoverHandlerRef.current = (e) => {
|
|
1076
|
+
if (!hoverAnnotation)
|
|
1077
|
+
return;
|
|
1078
|
+
const canvas = canvasRef.current;
|
|
1079
|
+
if (!canvas)
|
|
1080
|
+
return;
|
|
1081
|
+
const rect = canvas.getBoundingClientRect();
|
|
1082
|
+
// Mouse position in chart coordinates (canvas is full-size, ctx translated by margin)
|
|
1083
|
+
const chartX = e.clientX - rect.left - margin.left;
|
|
1084
|
+
const chartY = e.clientY - rect.top - margin.top;
|
|
1085
|
+
// Outside chart area → clear hover
|
|
1086
|
+
if (chartX < 0 || chartX > adjustedWidth || chartY < 0 || chartY > adjustedHeight) {
|
|
1087
|
+
if (hoverRef.current) {
|
|
1088
|
+
hoverRef.current = null;
|
|
1089
|
+
setHoverPoint(null);
|
|
1090
|
+
if (customHoverBehavior)
|
|
1091
|
+
customHoverBehavior(null);
|
|
1092
|
+
scheduleRender();
|
|
1093
|
+
}
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
const scales = scalesRef.current;
|
|
1097
|
+
if (!scales)
|
|
1098
|
+
return;
|
|
1099
|
+
const buf = bufferRef.current;
|
|
1100
|
+
if (buf.size === 0)
|
|
1101
|
+
return;
|
|
1102
|
+
const timeAxis = getTimeAxis(arrowOfTime);
|
|
1103
|
+
const timePixel = timeAxis === "x" ? chartX : chartY;
|
|
1104
|
+
const targetTime = scales.time.invert(timePixel);
|
|
1105
|
+
let hover;
|
|
1106
|
+
if (chartType === "bar" && binSize) {
|
|
1107
|
+
// Snap to the bin the cursor is in
|
|
1108
|
+
const bins = computeBins(buf, getTime, getValue, binSize, getCategory);
|
|
1109
|
+
const binStart = Math.floor(targetTime / binSize) * binSize;
|
|
1110
|
+
const bin = bins.get(binStart);
|
|
1111
|
+
if (!bin)
|
|
1112
|
+
return;
|
|
1113
|
+
const [domainMin, domainMax] = scales.time.domain();
|
|
1114
|
+
const clampedStart = Math.max(bin.start, domainMin);
|
|
1115
|
+
const clampedEnd = Math.min(bin.end, domainMax);
|
|
1116
|
+
const midTime = clampedStart + (clampedEnd - clampedStart) / 2;
|
|
1117
|
+
const tPixel = scales.time(midTime);
|
|
1118
|
+
const vPixel = scales.value(bin.total);
|
|
1119
|
+
const x = timeAxis === "x" ? tPixel : vPixel;
|
|
1120
|
+
const y = timeAxis === "x" ? vPixel : tPixel;
|
|
1121
|
+
// Hit-test which category segment the cursor is in
|
|
1122
|
+
let hoveredCategory;
|
|
1123
|
+
let hoveredCategoryValue;
|
|
1124
|
+
if (getCategory && bin.categories.size > 0) {
|
|
1125
|
+
const colorKeys = barColors ? Object.keys(barColors) : [];
|
|
1126
|
+
const listed = new Set(colorKeys);
|
|
1127
|
+
const unlisted = Array.from(bin.categories.keys()).filter(c => !listed.has(c)).sort();
|
|
1128
|
+
const catOrder = [...colorKeys.filter(k => bin.categories.has(k)), ...unlisted];
|
|
1129
|
+
const valuePixel = timeAxis === "x" ? chartY : chartX;
|
|
1130
|
+
let cumBase = 0;
|
|
1131
|
+
for (const cat of catOrder) {
|
|
1132
|
+
const catVal = bin.categories.get(cat) || 0;
|
|
1133
|
+
if (catVal === 0)
|
|
1134
|
+
continue;
|
|
1135
|
+
const edgeA = scales.value(cumBase);
|
|
1136
|
+
const edgeB = scales.value(cumBase + catVal);
|
|
1137
|
+
const lo = Math.min(edgeA, edgeB);
|
|
1138
|
+
const hi = Math.max(edgeA, edgeB);
|
|
1139
|
+
if (valuePixel >= lo && valuePixel <= hi) {
|
|
1140
|
+
hoveredCategory = cat;
|
|
1141
|
+
hoveredCategoryValue = catVal;
|
|
1142
|
+
break;
|
|
1143
|
+
}
|
|
1144
|
+
cumBase += catVal;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
hover = {
|
|
1148
|
+
data: {
|
|
1149
|
+
binStart: bin.start, binEnd: bin.end, total: bin.total,
|
|
1150
|
+
categories: Object.fromEntries(bin.categories),
|
|
1151
|
+
barColors: barColors || {},
|
|
1152
|
+
hoveredCategory,
|
|
1153
|
+
hoveredCategoryValue
|
|
1154
|
+
},
|
|
1155
|
+
time: midTime,
|
|
1156
|
+
value: bin.total,
|
|
1157
|
+
x,
|
|
1158
|
+
y
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
const idx = findNearestIndex(buf, targetTime, getTime);
|
|
1163
|
+
if (idx < 0)
|
|
1164
|
+
return;
|
|
1165
|
+
const d = buf.get(idx);
|
|
1166
|
+
const t = getTime(d);
|
|
1167
|
+
const v = getValue(d);
|
|
1168
|
+
const tPixel = scales.time(t);
|
|
1169
|
+
const vPixel = scales.value(v);
|
|
1170
|
+
const x = timeAxis === "x" ? tPixel : vPixel;
|
|
1171
|
+
const y = timeAxis === "x" ? vPixel : tPixel;
|
|
1172
|
+
hover = { data: d, time: t, value: v, x, y };
|
|
1173
|
+
}
|
|
1174
|
+
hoverRef.current = hover;
|
|
1175
|
+
setHoverPoint(hover);
|
|
1176
|
+
if (customHoverBehavior)
|
|
1177
|
+
customHoverBehavior(hover);
|
|
1178
|
+
scheduleRender();
|
|
1179
|
+
};
|
|
1180
|
+
hoverLeaveRef.current = () => {
|
|
1181
|
+
if (hoverRef.current) {
|
|
1182
|
+
hoverRef.current = null;
|
|
1183
|
+
setHoverPoint(null);
|
|
1184
|
+
if (customHoverBehavior)
|
|
1185
|
+
customHoverBehavior(null);
|
|
1186
|
+
scheduleRender();
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
// Stable event handlers that delegate to refs
|
|
1190
|
+
const onMouseMove = React.useCallback((e) => hoverHandlerRef.current(e), []);
|
|
1191
|
+
const onMouseLeave = React.useCallback(() => hoverLeaveRef.current(), []);
|
|
1192
|
+
// Update the render function ref on every React render.
|
|
1193
|
+
// This captures the latest props (arrowOfTime, chartType, lineStyle,
|
|
1194
|
+
// annotations, etc.) without needing useCallback dependency chains.
|
|
1195
|
+
// The rAF loop calls this via renderFnRef, so it always sees fresh values.
|
|
1196
|
+
renderFnRef.current = () => {
|
|
1197
|
+
var _a;
|
|
1198
|
+
rafRef.current = 0;
|
|
1199
|
+
const canvas = canvasRef.current;
|
|
1200
|
+
if (!canvas)
|
|
1201
|
+
return;
|
|
1202
|
+
const ctx = canvas.getContext("2d");
|
|
1203
|
+
if (!ctx)
|
|
1204
|
+
return;
|
|
1205
|
+
const buf = bufferRef.current;
|
|
1206
|
+
const tExtent = timeExtentRef.current;
|
|
1207
|
+
const vExtent = valueExtentRef.current;
|
|
1208
|
+
if (tExtent.dirty) {
|
|
1209
|
+
tExtent.recalculate(buf, getTime);
|
|
1210
|
+
}
|
|
1211
|
+
if (vExtent.dirty) {
|
|
1212
|
+
vExtent.recalculate(buf, getValue);
|
|
1213
|
+
}
|
|
1214
|
+
let tDomain = fixedTimeExtent || tExtent.extent;
|
|
1215
|
+
let vDomain = fixedValueExtent || vExtent.extent;
|
|
1216
|
+
if (chartType === "bar" && binSize && !fixedValueExtent && buf.size > 0) {
|
|
1217
|
+
const [, maxTotal] = computeBinExtent(buf, getTime, getValue, binSize, getCategory);
|
|
1218
|
+
vDomain = [0, maxTotal + maxTotal * extentPadding];
|
|
1219
|
+
}
|
|
1220
|
+
else if (chartType === "waterfall" && !fixedValueExtent && buf.size > 0) {
|
|
1221
|
+
const [minCum, maxCum] = computeWaterfallExtent(buf, getValue);
|
|
1222
|
+
const range = maxCum - minCum;
|
|
1223
|
+
const pad = range > 0 ? range * extentPadding : 1;
|
|
1224
|
+
vDomain = [
|
|
1225
|
+
Math.min(0, minCum - Math.abs(pad)),
|
|
1226
|
+
Math.max(0, maxCum + Math.abs(pad))
|
|
1227
|
+
];
|
|
1228
|
+
}
|
|
1229
|
+
else if (!fixedValueExtent && vDomain[0] !== Infinity) {
|
|
1230
|
+
const range = vDomain[1] - vDomain[0];
|
|
1231
|
+
const pad = range > 0 ? range * extentPadding : 1;
|
|
1232
|
+
vDomain = [vDomain[0] - pad, vDomain[1] + pad];
|
|
1233
|
+
}
|
|
1234
|
+
if (tDomain[0] === Infinity || tDomain[1] === -Infinity) {
|
|
1235
|
+
tDomain = [0, 1];
|
|
1236
|
+
}
|
|
1237
|
+
if (vDomain[0] === Infinity || vDomain[1] === -Infinity) {
|
|
1238
|
+
vDomain = [0, 1];
|
|
1239
|
+
}
|
|
1240
|
+
const scales = buildScales(arrowOfTime, tDomain, vDomain, adjustedWidth, adjustedHeight);
|
|
1241
|
+
scalesRef.current = scales;
|
|
1242
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1243
|
+
canvas.width = size[0] * dpr;
|
|
1244
|
+
canvas.height = size[1] * dpr;
|
|
1245
|
+
canvas.style.width = `${size[0]}px`;
|
|
1246
|
+
canvas.style.height = `${size[1]}px`;
|
|
1247
|
+
ctx.scale(dpr, dpr);
|
|
1248
|
+
ctx.translate(margin.left, margin.top);
|
|
1249
|
+
ctx.clearRect(-margin.left, -margin.top, size[0], size[1]);
|
|
1250
|
+
// Resolve theme colors from CSS custom properties for theme-aware rendering
|
|
1251
|
+
const theme = resolveThemeColors(canvas);
|
|
1252
|
+
if (background) {
|
|
1253
|
+
ctx.fillStyle = background;
|
|
1254
|
+
ctx.fillRect(0, 0, adjustedWidth, adjustedHeight);
|
|
1255
|
+
}
|
|
1256
|
+
if (showAxes) {
|
|
1257
|
+
ctx.save();
|
|
1258
|
+
drawAxes(ctx, arrowOfTime, scales.time, scales.value, adjustedWidth, adjustedHeight, tickFormatTime, tickFormatValue, theme);
|
|
1259
|
+
ctx.restore();
|
|
1260
|
+
}
|
|
1261
|
+
const renderer = RENDERERS[chartType];
|
|
1262
|
+
if (renderer) {
|
|
1263
|
+
const layout = {
|
|
1264
|
+
width: adjustedWidth,
|
|
1265
|
+
height: adjustedHeight,
|
|
1266
|
+
timeAxis: getTimeAxis(arrowOfTime)
|
|
1267
|
+
};
|
|
1268
|
+
renderer(ctx, buf, scales, layout, lineStyle, { time: getTime, value: getValue, category: getCategory }, annotations, chartType === "bar" ? { binSize, barColors, barStyle }
|
|
1269
|
+
: chartType === "waterfall" ? { waterfallStyle }
|
|
1270
|
+
: chartType === "swarm" ? { swarmStyle, barColors }
|
|
1271
|
+
: undefined);
|
|
1272
|
+
}
|
|
1273
|
+
// Draw bar highlight on hovered bin/segment
|
|
1274
|
+
if (hoverAnnotation && hoverRef.current && chartType === "bar" && binSize) {
|
|
1275
|
+
const hd = hoverRef.current.data;
|
|
1276
|
+
if (hd.binStart != null) {
|
|
1277
|
+
const gap = (_a = barStyle === null || barStyle === void 0 ? void 0 : barStyle.gap) !== null && _a !== void 0 ? _a : 1;
|
|
1278
|
+
const tAxis = getTimeAxis(arrowOfTime);
|
|
1279
|
+
// Determine which segment to highlight
|
|
1280
|
+
const segBase = hd.hoveredCategory != null
|
|
1281
|
+
? (() => {
|
|
1282
|
+
// Walk categories to find the cumulative base of the hovered segment
|
|
1283
|
+
const cats = hd.categories || {};
|
|
1284
|
+
const colorKeys = barColors ? Object.keys(barColors) : [];
|
|
1285
|
+
const listed = new Set(colorKeys);
|
|
1286
|
+
const unlisted = Object.keys(cats).filter((c) => !listed.has(c)).sort();
|
|
1287
|
+
const catOrder = [...colorKeys.filter((k) => k in cats), ...unlisted];
|
|
1288
|
+
let base = 0;
|
|
1289
|
+
for (const cat of catOrder) {
|
|
1290
|
+
if (cat === hd.hoveredCategory)
|
|
1291
|
+
return base;
|
|
1292
|
+
base += cats[cat] || 0;
|
|
1293
|
+
}
|
|
1294
|
+
return base;
|
|
1295
|
+
})()
|
|
1296
|
+
: 0;
|
|
1297
|
+
const segTop = hd.hoveredCategory != null
|
|
1298
|
+
? segBase + (hd.hoveredCategoryValue || 0)
|
|
1299
|
+
: hd.total;
|
|
1300
|
+
const [domainMin, domainMax] = scales.time.domain();
|
|
1301
|
+
const clampedBinStart = Math.max(hd.binStart, domainMin);
|
|
1302
|
+
const clampedBinEnd = Math.min(hd.binEnd, domainMax);
|
|
1303
|
+
if (tAxis === "x") {
|
|
1304
|
+
const rawX0 = scales.time(clampedBinStart);
|
|
1305
|
+
const rawX1 = scales.time(clampedBinEnd);
|
|
1306
|
+
const x0 = Math.min(rawX0, rawX1) + gap / 2;
|
|
1307
|
+
const x1 = Math.max(rawX0, rawX1) - gap / 2;
|
|
1308
|
+
const yBot = scales.value(segBase);
|
|
1309
|
+
const yTop = scales.value(segTop);
|
|
1310
|
+
const ry = Math.min(yBot, yTop);
|
|
1311
|
+
const rh = Math.abs(yBot - yTop);
|
|
1312
|
+
ctx.fillStyle = theme.hoverFill;
|
|
1313
|
+
ctx.fillRect(x0, ry, x1 - x0, rh);
|
|
1314
|
+
ctx.strokeStyle = theme.hoverStroke;
|
|
1315
|
+
ctx.lineWidth = 1;
|
|
1316
|
+
ctx.setLineDash([]);
|
|
1317
|
+
ctx.strokeRect(x0, ry, x1 - x0, rh);
|
|
1318
|
+
}
|
|
1319
|
+
else {
|
|
1320
|
+
const rawY0 = scales.time(clampedBinStart);
|
|
1321
|
+
const rawY1 = scales.time(clampedBinEnd);
|
|
1322
|
+
const y0 = Math.min(rawY0, rawY1) + gap / 2;
|
|
1323
|
+
const y1 = Math.max(rawY0, rawY1) - gap / 2;
|
|
1324
|
+
const xLeft = scales.value(segBase);
|
|
1325
|
+
const xRight = scales.value(segTop);
|
|
1326
|
+
const rx = Math.min(xLeft, xRight);
|
|
1327
|
+
const rw = Math.abs(xRight - xLeft);
|
|
1328
|
+
ctx.fillStyle = theme.hoverFill;
|
|
1329
|
+
ctx.fillRect(rx, y0, rw, y1 - y0);
|
|
1330
|
+
ctx.strokeStyle = theme.hoverStroke;
|
|
1331
|
+
ctx.lineWidth = 1;
|
|
1332
|
+
ctx.setLineDash([]);
|
|
1333
|
+
ctx.strokeRect(rx, y0, rw, y1 - y0);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
// Draw crosshair after chart data so it renders on top
|
|
1338
|
+
if (hoverAnnotation && hoverRef.current) {
|
|
1339
|
+
const config = typeof hoverAnnotation === "object" ? hoverAnnotation : {};
|
|
1340
|
+
drawCrosshair(ctx, hoverRef.current, adjustedWidth, adjustedHeight, config, lineStyle.stroke || "#007bff", theme);
|
|
1341
|
+
}
|
|
1342
|
+
const wasDirty = dirtyRef.current;
|
|
1343
|
+
dirtyRef.current = false;
|
|
1344
|
+
// Trigger React re-render so SVG annotations recompute positions
|
|
1345
|
+
// using the scales we just stored in scalesRef.
|
|
1346
|
+
// Only do this when data actually changed (wasDirty) to avoid
|
|
1347
|
+
// setAnnotationFrame → re-render → effect → scheduleRender → loop.
|
|
1348
|
+
if (wasDirty && annotations && annotations.length > 0 && svgAnnotationRules) {
|
|
1349
|
+
setAnnotationFrame(f => f + 1);
|
|
1350
|
+
}
|
|
1351
|
+
};
|
|
1352
|
+
// Initial render and cleanup
|
|
1353
|
+
React.useEffect(() => {
|
|
1354
|
+
scheduleRender();
|
|
1355
|
+
return () => {
|
|
1356
|
+
if (rafRef.current) {
|
|
1357
|
+
cancelAnimationFrame(rafRef.current);
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
}, [scheduleRender]);
|
|
1361
|
+
// Re-render canvas when visual props change
|
|
1362
|
+
React.useEffect(() => {
|
|
1363
|
+
dirtyRef.current = true;
|
|
1364
|
+
scheduleRender();
|
|
1365
|
+
}, [arrowOfTime, chartType, adjustedWidth, adjustedHeight, showAxes, background, lineStyle, scheduleRender]);
|
|
1366
|
+
// Compute annotation elements during React render using latest scales
|
|
1367
|
+
const renderedAnnotations = React__namespace.useMemo(() => {
|
|
1368
|
+
if (!annotations || annotations.length === 0 || !svgAnnotationRules) {
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
const scales = scalesRef.current;
|
|
1372
|
+
const timeAxis = getTimeAxis(arrowOfTime);
|
|
1373
|
+
return annotations
|
|
1374
|
+
.map((annotation, i) => svgAnnotationRules(annotation, i, {
|
|
1375
|
+
scales,
|
|
1376
|
+
timeAxis,
|
|
1377
|
+
width: adjustedWidth,
|
|
1378
|
+
height: adjustedHeight
|
|
1379
|
+
}))
|
|
1380
|
+
.filter(Boolean);
|
|
1381
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1382
|
+
}, [annotations, svgAnnotationRules, arrowOfTime, adjustedWidth, adjustedHeight, annotationFrame]);
|
|
1383
|
+
const hasAnnotations = renderedAnnotations && renderedAnnotations.length > 0;
|
|
1384
|
+
// Tooltip positioning: anchor at the hovered point, flip if near edges
|
|
1385
|
+
const tooltipElement = hoverAnnotation && hoverPoint ? (React__namespace.createElement("div", { className: "realtime-frame-tooltip", style: {
|
|
1386
|
+
position: "absolute",
|
|
1387
|
+
left: margin.left + hoverPoint.x,
|
|
1388
|
+
top: margin.top + hoverPoint.y,
|
|
1389
|
+
transform: `translate(${hoverPoint.x > adjustedWidth * 0.7 ? "calc(-100% - 12px)" : "12px"}, ${hoverPoint.y < adjustedHeight * 0.3 ? "4px" : "calc(-100% - 4px)"})`,
|
|
1390
|
+
pointerEvents: "none",
|
|
1391
|
+
zIndex: 1
|
|
1392
|
+
} }, tooltipContent
|
|
1393
|
+
? tooltipContent(hoverPoint)
|
|
1394
|
+
: React__namespace.createElement(DefaultTooltip, { hover: hoverPoint, formatTime: tickFormatTime }))) : null;
|
|
1395
|
+
return (React__namespace.createElement("div", { className: `realtime-frame${className ? ` ${className}` : ""}`, style: {
|
|
1396
|
+
position: "relative",
|
|
1397
|
+
width: size[0],
|
|
1398
|
+
height: size[1]
|
|
1399
|
+
}, onMouseMove: hoverAnnotation ? onMouseMove : undefined, onMouseLeave: hoverAnnotation ? onMouseLeave : undefined },
|
|
1400
|
+
React__namespace.createElement("canvas", { ref: canvasRef, style: {
|
|
1401
|
+
position: "absolute",
|
|
1402
|
+
left: 0,
|
|
1403
|
+
top: 0
|
|
1404
|
+
} }),
|
|
1405
|
+
hasAnnotations && (React__namespace.createElement("svg", { width: size[0], height: size[1], style: {
|
|
1406
|
+
position: "absolute",
|
|
1407
|
+
top: 0,
|
|
1408
|
+
left: 0,
|
|
1409
|
+
pointerEvents: "none"
|
|
1410
|
+
} },
|
|
1411
|
+
React__namespace.createElement("g", { transform: `translate(${margin.left},${margin.top})` }, renderedAnnotations))),
|
|
1412
|
+
tooltipElement));
|
|
1413
|
+
});
|
|
1414
|
+
|
|
1415
|
+
/**
|
|
1416
|
+
* RealtimeLineChart - Simplified wrapper for streaming line charts.
|
|
1417
|
+
*
|
|
1418
|
+
* Wraps RealtimeFrame with `chartType="line"` and exposes stroke/strokeWidth
|
|
1419
|
+
* as top-level props instead of requiring a `lineStyle` object.
|
|
1420
|
+
*
|
|
1421
|
+
* @example
|
|
1422
|
+
* ```tsx
|
|
1423
|
+
* const ref = useRef<RealtimeFrameHandle>(null)
|
|
1424
|
+
*
|
|
1425
|
+
* <RealtimeLineChart
|
|
1426
|
+
* ref={ref}
|
|
1427
|
+
* stroke="#007bff"
|
|
1428
|
+
* strokeWidth={2}
|
|
1429
|
+
* windowSize={200}
|
|
1430
|
+
* enableHover
|
|
1431
|
+
* />
|
|
1432
|
+
* ```
|
|
1433
|
+
*/
|
|
1434
|
+
const RealtimeLineChart = React.forwardRef(function RealtimeLineChart(props, ref) {
|
|
1435
|
+
const { size = [500, 300], margin, className, arrowOfTime = "right", windowMode = "sliding", windowSize = 200, data, timeAccessor, valueAccessor, timeExtent, valueExtent, extentPadding, stroke = "#007bff", strokeWidth = 2, strokeDasharray, showAxes = true, background, enableHover, tooltipContent, onHover, annotations, svgAnnotationRules, tickFormatTime, tickFormatValue } = props;
|
|
1436
|
+
const frameRef = React.useRef(null);
|
|
1437
|
+
React.useImperativeHandle(ref, () => ({
|
|
1438
|
+
push: (point) => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.push(point); },
|
|
1439
|
+
pushMany: (points) => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.pushMany(points); },
|
|
1440
|
+
clear: () => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.clear(); },
|
|
1441
|
+
getData: () => { var _a, _b; return (_b = (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.getData()) !== null && _b !== void 0 ? _b : []; }
|
|
1442
|
+
}));
|
|
1443
|
+
const lineStyle = { stroke, strokeWidth, strokeDasharray };
|
|
1444
|
+
return (React__namespace.createElement(RealtimeFrame, { ref: frameRef, chartType: "line", size: size, margin: margin, className: className, arrowOfTime: arrowOfTime, windowMode: windowMode, windowSize: windowSize, data: data, timeAccessor: timeAccessor, valueAccessor: valueAccessor, timeExtent: timeExtent, valueExtent: valueExtent, extentPadding: extentPadding, lineStyle: lineStyle, showAxes: showAxes, background: background, hoverAnnotation: enableHover, tooltipContent: tooltipContent, customHoverBehavior: onHover, annotations: annotations, svgAnnotationRules: svgAnnotationRules, tickFormatTime: tickFormatTime, tickFormatValue: tickFormatValue }));
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1447
|
+
/**
|
|
1448
|
+
* RealtimeBarChart - Simplified wrapper for streaming temporal histograms.
|
|
1449
|
+
*
|
|
1450
|
+
* Wraps RealtimeFrame with `chartType="bar"` and exposes bar styling as
|
|
1451
|
+
* top-level props. Supports both simple and stacked (categorical) modes.
|
|
1452
|
+
*
|
|
1453
|
+
* Edge bins that only partially fall within the visible time window are
|
|
1454
|
+
* rendered at proportionally narrower widths (Datadog-style).
|
|
1455
|
+
*
|
|
1456
|
+
* @example
|
|
1457
|
+
* ```tsx
|
|
1458
|
+
* // Simple histogram
|
|
1459
|
+
* <RealtimeBarChart
|
|
1460
|
+
* ref={ref}
|
|
1461
|
+
* binSize={20}
|
|
1462
|
+
* fill="#007bff"
|
|
1463
|
+
* enableHover
|
|
1464
|
+
* />
|
|
1465
|
+
*
|
|
1466
|
+
* // Stacked by category
|
|
1467
|
+
* <RealtimeBarChart
|
|
1468
|
+
* ref={ref}
|
|
1469
|
+
* binSize={25}
|
|
1470
|
+
* categoryAccessor="category"
|
|
1471
|
+
* colors={{ errors: "#dc3545", warnings: "#fd7e14", info: "#007bff" }}
|
|
1472
|
+
* enableHover
|
|
1473
|
+
* />
|
|
1474
|
+
* ```
|
|
1475
|
+
*/
|
|
1476
|
+
const RealtimeBarChart = React.forwardRef(function RealtimeBarChart(props, ref) {
|
|
1477
|
+
const { binSize, size = [500, 300], margin, className, arrowOfTime = "right", windowMode = "sliding", windowSize = 200, data, timeAccessor, valueAccessor, timeExtent, valueExtent, extentPadding, categoryAccessor, colors, fill, stroke, strokeWidth, gap, showAxes = true, background, enableHover, tooltipContent, onHover, annotations, svgAnnotationRules, tickFormatTime, tickFormatValue } = props;
|
|
1478
|
+
const frameRef = React.useRef(null);
|
|
1479
|
+
React.useImperativeHandle(ref, () => ({
|
|
1480
|
+
push: (point) => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.push(point); },
|
|
1481
|
+
pushMany: (points) => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.pushMany(points); },
|
|
1482
|
+
clear: () => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.clear(); },
|
|
1483
|
+
getData: () => { var _a, _b; return (_b = (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.getData()) !== null && _b !== void 0 ? _b : []; }
|
|
1484
|
+
}));
|
|
1485
|
+
const barStyle = {};
|
|
1486
|
+
if (fill != null)
|
|
1487
|
+
barStyle.fill = fill;
|
|
1488
|
+
if (stroke != null)
|
|
1489
|
+
barStyle.stroke = stroke;
|
|
1490
|
+
if (strokeWidth != null)
|
|
1491
|
+
barStyle.strokeWidth = strokeWidth;
|
|
1492
|
+
if (gap != null)
|
|
1493
|
+
barStyle.gap = gap;
|
|
1494
|
+
return (React__namespace.createElement(RealtimeFrame, { ref: frameRef, chartType: "bar", size: size, margin: margin, className: className, arrowOfTime: arrowOfTime, windowMode: windowMode, windowSize: windowSize, data: data, timeAccessor: timeAccessor, valueAccessor: valueAccessor, timeExtent: timeExtent, valueExtent: valueExtent, extentPadding: extentPadding, binSize: binSize, categoryAccessor: categoryAccessor, barColors: colors, barStyle: barStyle, showAxes: showAxes, background: background, hoverAnnotation: enableHover, tooltipContent: tooltipContent, customHoverBehavior: onHover, annotations: annotations, svgAnnotationRules: svgAnnotationRules, tickFormatTime: tickFormatTime, tickFormatValue: tickFormatValue }));
|
|
1495
|
+
});
|
|
1496
|
+
|
|
1497
|
+
/**
|
|
1498
|
+
* RealtimeSwarmChart - Simplified wrapper for streaming dot/swarm charts.
|
|
1499
|
+
*
|
|
1500
|
+
* Wraps RealtimeFrame with `chartType="swarm"` and exposes dot styling as
|
|
1501
|
+
* top-level props. Each data point renders as an individual dot at its
|
|
1502
|
+
* (time, value) coordinates.
|
|
1503
|
+
*
|
|
1504
|
+
* Supports threshold coloring via annotations to recolor dots that cross
|
|
1505
|
+
* value boundaries.
|
|
1506
|
+
*
|
|
1507
|
+
* @example
|
|
1508
|
+
* ```tsx
|
|
1509
|
+
* <RealtimeSwarmChart
|
|
1510
|
+
* ref={ref}
|
|
1511
|
+
* radius={4}
|
|
1512
|
+
* opacity={0.8}
|
|
1513
|
+
* categoryAccessor="sensor"
|
|
1514
|
+
* colors={{ sensor1: "#007bff", sensor2: "#28a745" }}
|
|
1515
|
+
* />
|
|
1516
|
+
* ```
|
|
1517
|
+
*/
|
|
1518
|
+
const RealtimeSwarmChart = React.forwardRef(function RealtimeSwarmChart(props, ref) {
|
|
1519
|
+
const { size = [500, 300], margin, className, arrowOfTime = "right", windowMode = "sliding", windowSize = 200, data, timeAccessor, valueAccessor, timeExtent, valueExtent, extentPadding, categoryAccessor, colors, radius, fill, opacity, stroke, strokeWidth, showAxes = true, background, enableHover, tooltipContent, onHover, annotations, svgAnnotationRules, tickFormatTime, tickFormatValue } = props;
|
|
1520
|
+
const frameRef = React.useRef(null);
|
|
1521
|
+
React.useImperativeHandle(ref, () => ({
|
|
1522
|
+
push: (point) => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.push(point); },
|
|
1523
|
+
pushMany: (points) => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.pushMany(points); },
|
|
1524
|
+
clear: () => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.clear(); },
|
|
1525
|
+
getData: () => { var _a, _b; return (_b = (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.getData()) !== null && _b !== void 0 ? _b : []; }
|
|
1526
|
+
}));
|
|
1527
|
+
const swarmStyle = {};
|
|
1528
|
+
if (radius != null)
|
|
1529
|
+
swarmStyle.radius = radius;
|
|
1530
|
+
if (fill != null)
|
|
1531
|
+
swarmStyle.fill = fill;
|
|
1532
|
+
if (opacity != null)
|
|
1533
|
+
swarmStyle.opacity = opacity;
|
|
1534
|
+
if (stroke != null)
|
|
1535
|
+
swarmStyle.stroke = stroke;
|
|
1536
|
+
if (strokeWidth != null)
|
|
1537
|
+
swarmStyle.strokeWidth = strokeWidth;
|
|
1538
|
+
return (React__namespace.createElement(RealtimeFrame, { ref: frameRef, chartType: "swarm", size: size, margin: margin, className: className, arrowOfTime: arrowOfTime, windowMode: windowMode, windowSize: windowSize, data: data, timeAccessor: timeAccessor, valueAccessor: valueAccessor, timeExtent: timeExtent, valueExtent: valueExtent, extentPadding: extentPadding, categoryAccessor: categoryAccessor, barColors: colors, swarmStyle: swarmStyle, showAxes: showAxes, background: background, hoverAnnotation: enableHover, tooltipContent: tooltipContent, customHoverBehavior: onHover, annotations: annotations, svgAnnotationRules: svgAnnotationRules, tickFormatTime: tickFormatTime, tickFormatValue: tickFormatValue }));
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1541
|
+
/**
|
|
1542
|
+
* RealtimeWaterfallChart - Simplified wrapper for streaming waterfall charts.
|
|
1543
|
+
*
|
|
1544
|
+
* Wraps RealtimeFrame with `chartType="waterfall"` and exposes waterfall styling
|
|
1545
|
+
* as top-level props. Visualizes cumulative deltas as connected bars rising and
|
|
1546
|
+
* falling from a running baseline.
|
|
1547
|
+
*
|
|
1548
|
+
* @example
|
|
1549
|
+
* ```tsx
|
|
1550
|
+
* <RealtimeWaterfallChart
|
|
1551
|
+
* ref={ref}
|
|
1552
|
+
* positiveColor="#28a745"
|
|
1553
|
+
* negativeColor="#dc3545"
|
|
1554
|
+
* connectorStroke="#999"
|
|
1555
|
+
* windowSize={300}
|
|
1556
|
+
* />
|
|
1557
|
+
* ```
|
|
1558
|
+
*/
|
|
1559
|
+
const RealtimeWaterfallChart = React.forwardRef(function RealtimeWaterfallChart(props, ref) {
|
|
1560
|
+
const { size = [500, 300], margin, className, arrowOfTime = "right", windowMode = "sliding", windowSize = 200, data, timeAccessor, valueAccessor, timeExtent, valueExtent, extentPadding, positiveColor, negativeColor, connectorStroke, connectorWidth, gap, stroke, strokeWidth, showAxes = true, background, enableHover, tooltipContent, onHover, annotations, svgAnnotationRules, tickFormatTime, tickFormatValue } = props;
|
|
1561
|
+
const frameRef = React.useRef(null);
|
|
1562
|
+
React.useImperativeHandle(ref, () => ({
|
|
1563
|
+
push: (point) => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.push(point); },
|
|
1564
|
+
pushMany: (points) => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.pushMany(points); },
|
|
1565
|
+
clear: () => { var _a; return (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.clear(); },
|
|
1566
|
+
getData: () => { var _a, _b; return (_b = (_a = frameRef.current) === null || _a === void 0 ? void 0 : _a.getData()) !== null && _b !== void 0 ? _b : []; }
|
|
1567
|
+
}));
|
|
1568
|
+
const waterfallStyle = {};
|
|
1569
|
+
if (positiveColor != null)
|
|
1570
|
+
waterfallStyle.positiveColor = positiveColor;
|
|
1571
|
+
if (negativeColor != null)
|
|
1572
|
+
waterfallStyle.negativeColor = negativeColor;
|
|
1573
|
+
if (connectorStroke != null)
|
|
1574
|
+
waterfallStyle.connectorStroke = connectorStroke;
|
|
1575
|
+
if (connectorWidth != null)
|
|
1576
|
+
waterfallStyle.connectorWidth = connectorWidth;
|
|
1577
|
+
if (gap != null)
|
|
1578
|
+
waterfallStyle.gap = gap;
|
|
1579
|
+
if (stroke != null)
|
|
1580
|
+
waterfallStyle.stroke = stroke;
|
|
1581
|
+
if (strokeWidth != null)
|
|
1582
|
+
waterfallStyle.strokeWidth = strokeWidth;
|
|
1583
|
+
return (React__namespace.createElement(RealtimeFrame, { ref: frameRef, chartType: "waterfall", size: size, margin: margin, className: className, arrowOfTime: arrowOfTime, windowMode: windowMode, windowSize: windowSize, data: data, timeAccessor: timeAccessor, valueAccessor: valueAccessor, timeExtent: timeExtent, valueExtent: valueExtent, extentPadding: extentPadding, waterfallStyle: waterfallStyle, showAxes: showAxes, background: background, hoverAnnotation: enableHover, tooltipContent: tooltipContent, customHoverBehavior: onHover, annotations: annotations, svgAnnotationRules: svgAnnotationRules, tickFormatTime: tickFormatTime, tickFormatValue: tickFormatValue }));
|
|
1584
|
+
});
|
|
1585
|
+
|
|
1586
|
+
exports.IncrementalExtent = IncrementalExtent;
|
|
1587
|
+
exports.RealtimeBarChart = RealtimeBarChart;
|
|
1588
|
+
exports.RealtimeFrame = RealtimeFrame;
|
|
1589
|
+
exports.RealtimeLineChart = RealtimeLineChart;
|
|
1590
|
+
exports.RealtimeSwarmChart = RealtimeSwarmChart;
|
|
1591
|
+
exports.RealtimeWaterfallChart = RealtimeWaterfallChart;
|
|
1592
|
+
exports.RingBuffer = RingBuffer;
|
|
1593
|
+
exports.barRenderer = barRenderer;
|
|
1594
|
+
exports.candlestickRenderer = candlestickRenderer;
|
|
1595
|
+
exports.lineRenderer = lineRenderer;
|
|
1596
|
+
exports.swarmRenderer = swarmRenderer;
|
|
1597
|
+
exports.waterfallRenderer = waterfallRenderer;
|
|
1598
|
+
//# sourceMappingURL=realtime.js.map
|