Interactive Waterfall (Spectral) Chart
The Interactive Waterfall Chart is a scientific visualization that stacks multiple spectral line series in a 3D-like perspective. Each series represents a slice of data at a point in time or frequency, creating the appearance of a waterfall of spectra. Hover and click interactions let users select and compare individual slices.
The JavaScript Interactive Waterfall Chart Example can be found in the SciChart.JS Examples Suite on GitHub, or in the live demo at scichart.com/demo.
How the Waterfall Effect Works
SciChart.js has no single "waterfall series" type. The depth-stacking effect is achieved by:
- Creating one
FastLineRenderableSeriesper slice, each bound to its own X and Y axis. - Setting
overrideOffseton each axis to shift it by a fixed pixel amount, nudging every successive series further back in the visual stack. - Hiding all axes except the frontmost one, so the chart reads cleanly while still using multiple coordinate systems internally.
// Demonstrates how to create a Spectral Waterfall Chart using SciChart.js.
// The waterfall effect is achieved by giving each series its own X and Y axis
// and using overrideOffset to shift each axis so the series appear stacked in depth.
const {
SciChartSurface,
NumericAxis,
FastLineRenderableSeries,
XyDataSeries,
EAxisAlignment,
EXyDirection,
NumberRange,
MouseWheelZoomModifier,
ZoomExtentsModifier,
ZoomPanModifier,
SeriesSelectionModifier,
SciChartJsNavyTheme,
} = SciChart;
// or, for npm: import { SciChartSurface, ... } from "scichart"
const { sciChartSurface, wasmContext } = await SciChartSurface.create(divElementId, {
theme: new SciChartJsNavyTheme(),
disableAspect: true,
});
const seriesCount = 30;
const spectraSize = 200;
for (let i = 0; i < seriesCount; i++) {
// Each series gets its own Y axis, offset upward to create the depth effect.
// overrideOffset shifts the axis position, stacking series behind one another.
const yAxis = new NumericAxis(wasmContext, {
id: `Y${i}`,
axisAlignment: EAxisAlignment.Left,
visibleRange: new NumberRange(-50, 60),
isVisible: i === seriesCount - 1, // only the last (frontmost) axis is visible
overrideOffset: 3 * -i, // each axis is offset 3px upward
});
sciChartSurface.yAxes.add(yAxis);
// Each series also gets its own X axis, offset to the right for the depth effect.
const xAxis = new NumericAxis(wasmContext, {
id: `X${i}`,
axisAlignment: EAxisAlignment.Bottom,
growBy: new NumberRange(0, 0.2),
isVisible: i === seriesCount - 1, // only the last (frontmost) axis is visible
overrideOffset: 2 * i, // each axis is offset 2px to the right
});
sciChartSurface.xAxes.add(xAxis);
const { xValues, yValues } = generateSpectralData(i, spectraSize);
sciChartSurface.renderableSeries.add(
new FastLineRenderableSeries(wasmContext, {
id: `S${i}`,
xAxisId: `X${i}`,
yAxisId: `Y${i}`,
stroke: "#64BAE4",
strokeThickness: 1,
dataSeries: new XyDataSeries(wasmContext, {
xValues,
yValues,
dataSeriesName: `Spectra ${i}`,
}),
})
);
}
// Selection modifier highlights hovered / clicked series
sciChartSurface.chartModifiers.add(
new SeriesSelectionModifier({
enableHover: true,
enableSelection: true,
onHoverChanged: (args) => {
args.allSeries.forEach((s) => {
s.stroke = s.isHovered || s.isSelected ? "#FFBE93" : "#64BAE4";
s.strokeThickness = s.isHovered || s.isSelected ? 3 : 1;
});
},
onSelectionChanged: (args) => {
args.allSeries.forEach((s) => {
s.stroke = s.isSelected ? "White" : s.isHovered ? "#FFBE93" : "#64BAE4";
s.strokeThickness = s.isSelected || s.isHovered ? 3 : 1;
});
},
}),
new ZoomPanModifier({ enableZoom: true, xyDirection: EXyDirection.XDirection }),
new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
new ZoomExtentsModifier({ xyDirection: EXyDirection.XDirection })
);
In the code above:
overrideOffset: 3 * -ion each Y axis shifts it 3 px upward per slice, moving each series higher than the previous one.overrideOffset: 2 * ion each X axis shifts it 2 px to the right per slice, adding the horizontal perspective tilt.isVisible: i === seriesCount - 1shows only the frontmost axis so tick marks and labels appear only once.SeriesSelectionModifierwithenableHoverandenableSelectionhighlights individual slices on hover and click.- Zoom and pan are restricted to the X direction so the depth offset is never accidentally distorted.
The overrideOffset Property
overrideOffset lets you bypass SciChart's automatic axis layout and position an axis at an exact pixel offset from its default location. This is what makes the 3D stacking possible: by incrementing the offset for each successive axis, you physically move each layer back in the chart.
For a deeper explanation of overrideOffset and how it interacts with SciChart's layout system, see Axis Offset and overrideOffset.
Series Selection and Highlighting
Attach a SeriesSelectionModifier to enable hover and click highlighting across all series:
new SeriesSelectionModifier({
enableHover: true,
enableSelection: true,
onHoverChanged: (args) => {
args.allSeries.forEach((s) => {
s.stroke = s.isHovered || s.isSelected ? "#FFBE93" : "#64BAE4";
s.strokeThickness = s.isHovered || s.isSelected ? 3 : 1;
});
},
onSelectionChanged: (args) => {
args.allSeries.forEach((s) => {
s.stroke = s.isSelected ? "White" : s.isHovered ? "#FFBE93" : "#64BAE4";
s.strokeThickness = s.isSelected || s.isHovered ? 3 : 1;
});
},
})
The full SciChart.JS Examples interactive version extends this further with a draggable cross-section annotation and two linked detail charts — see the source on GitHub for the complete implementation.
See Also
- The Waterfall Chart Type — financial waterfall charts built with Rectangle Series
- Axis Offset and overrideOffset — the key property enabling the depth-stacking effect
- SeriesSelectionModifier — adding hover and click selection to series
- Multi-Axis Charts — working with multiple axes