Skip to main content

SeriesSelectionModifier3D

SeriesSelectionModifier3D adds series hover and click selection to a SciChart3DSurface. It works with 3D renderable series hit-testing and raises hoverChanged and selectionChanged events with the active series and hit-test information.

The example below uses a small 3D waterfall made from densely sampled PointLineRenderableSeries3D rows. Hovering a row highlights it, and clicking selects it. Extra points make hit-testing thin 3D lines feel less jumpy.

Use Edit in CodePen on the live example to open the same TS, HTML and CSS as an editable snippet.

const { wasmContext, sciChart3DSurface } = await SciChart3DSurface.create(divElementId, {
theme: new SciChartJsNavyTheme(),
worldDimensions: new Vector3(300, 120, 180),
cameraOptions: {
position: new Vector3(-260, 190, 230),
target: new Vector3(0, 45, 0)
}
});

sciChart3DSurface.xAxis = new NumericAxis3D(wasmContext, {
axisTitle: "Frequency",
visibleRange: new NumberRange(0, pointsPerSeries - 1),
});
sciChart3DSurface.yAxis = new NumericAxis3D(wasmContext, {
axisTitle: "Power",
visibleRange: new NumberRange(-12, 36),
});
sciChart3DSurface.zAxis = new NumericAxis3D(wasmContext, {
axisTitle: "Time",
visibleRange: new NumberRange(0, seriesCount - 1),
});

const waterfallSeries: PointLineRenderableSeries3D[] = [];
let selectedIndex: number | undefined = defaultSelectedIndex;
let hoveredIndex: number | undefined;

const updateStatus = (hitInfo?: XyzSeriesInfo3D) => {
const info = document.getElementById("selection-info");
if (!info) return;

const selected = selectedIndex === undefined ? "none" : `Row ${selectedIndex}`;
const hovered = hoveredIndex === undefined ? "none" : `Row ${hoveredIndex}`;
const point = hitInfo?.isHit ? `, point ${hitInfo.dataSeriesIndex}` : "";
info.textContent = `Selected: ${selected} | Hovered: ${hovered}${point}`;
};

const updateSeriesStyles = () => {
waterfallSeries.forEach((series, index) => {
const isSelected = index === selectedIndex;
const isHovered = index === hoveredIndex;

series.stroke = isSelected ? "#FFFFFF" : isHovered ? "#FFB36B" : "#50C7E0";
series.strokeThickness = isSelected ? 5 : isHovered ? 4 : 2;
series.opacity = isSelected ? 1 : isHovered ? 0.85 : 0.35;
});
};

for (let i = 0; i < seriesCount; i++) {
const rowData = createWaterfallRow(i);
const series = new PointLineRenderableSeries3D(wasmContext, {
id: `row-${i}`,
dataSeries: new XyzDataSeries3D(wasmContext, {
...rowData,
dataSeriesName: `Row ${i}`
}),
stroke: "#50C7E0",
strokeThickness: 2,
opacity: 0.35,
isLineStrip: true,
isAntiAliased: true
});

series.isSelected = i === defaultSelectedIndex;
waterfallSeries.push(series);
sciChart3DSurface.renderableSeries.add(series);
}

updateSeriesStyles();
updateStatus();

sciChart3DSurface.chartModifiers.add(
new MouseWheelZoomModifier3D(),
new OrbitModifier3D(),
new ResetCamera3DModifier(),
new SeriesSelectionModifier3D({
enableHover: true,
enableSelection: true,
// Thin 3D lines benefit from a larger hit-test radius.
hitTestRadius: 15,
// In a stacked waterfall, several rows can be near the pointer.
// Prefer the hit point closest to the camera.
prioritizeClosestToCamera: true,
onSelectionChanged: (args) => {
selectedIndex = parseSeriesIndex(args.selectedSeries[0]);
updateSeriesStyles();
updateStatus(args.hitTestInfo as XyzSeriesInfo3D);
},
onHoverChanged: (args) => {
hoveredIndex = parseSeriesIndex(args.hoveredSeries[0]);
updateSeriesStyles();
updateStatus(args.hitTestInfo as XyzSeriesInfo3D);
}
})
);

Key Options

OptionDescription
enableSelectionEnables click selection. Defaults to true.
enableHoverEnables hover state changes on mouse move. Defaults to false because hover requires repeated hit-tests.
hitTestRadiusPixel radius around the pointer used for hit-testing. Larger values make thin 3D lines easier to hit.
prioritizeClosestToCameraWhen multiple series are hit, choose the hit point closest to the camera. This is useful for stacked or overlapping 3D line/waterfall views.
onSelectionChangedCallback raised after selection changes. Use args.selectedSeries and args.hitTestInfo.
onHoverChangedCallback raised after hover changes. Use args.hoveredSeries and args.hitTestInfo.

Notes

  • Add the modifier to sciChart3DSurface.chartModifiers.
  • hoverChanged and selectionChanged are also available as event handlers if you prefer subscribing after construction.
  • The modifier keeps selectedSeries and hoveredSeries arrays in sync with each series' isSelected and isHovered flags.
  • For XyzDataSeries3D, cast args.hitTestInfo to XyzSeriesInfo3D when you need dataSeriesIndex, xValue, yValue or zValue.