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.
- TS
- HTML
- CSS
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);
}
})
);
<div class="wrapper">
<div id="scichart-root"></div>
<div class="chart-overlay">
<div class="title">SeriesSelectionModifier3D</div>
<div class="subtitle">Hover a waterfall row, click to select it</div>
<div id="selection-info">Selected: Row 3</div>
</div>
</div>
body {
margin: 0;
font-family: Arial, sans-serif;
}
.wrapper {
position: relative;
width: 100%;
height: 100vh;
}
#scichart-root {
width: 100%;
height: 100%;
}
.chart-overlay {
position: absolute;
left: 14px;
top: 12px;
pointer-events: none;
color: #ffffff;
background: #07111fcc;
border: 1px solid #50c7e055;
border-radius: 4px;
padding: 10px 12px;
min-width: 210px;
}
.title {
font-size: 15px;
font-weight: 700;
}
.subtitle,
#selection-info {
margin-top: 4px;
font-size: 12px;
color: #d7ebff;
}
Key Options
| Option | Description |
|---|---|
enableSelection | Enables click selection. Defaults to true. |
enableHover | Enables hover state changes on mouse move. Defaults to false because hover requires repeated hit-tests. |
hitTestRadius | Pixel radius around the pointer used for hit-testing. Larger values make thin 3D lines easier to hit. |
prioritizeClosestToCamera | When multiple series are hit, choose the hit point closest to the camera. This is useful for stacked or overlapping 3D line/waterfall views. |
onSelectionChanged | Callback raised after selection changes. Use args.selectedSeries and args.hitTestInfo. |
onHoverChanged | Callback raised after hover changes. Use args.hoveredSeries and args.hitTestInfo. |
Notes
- Add the modifier to
sciChart3DSurface.chartModifiers. hoverChangedandselectionChangedare also available as event handlers if you prefer subscribing after construction.- The modifier keeps
selectedSeriesandhoveredSeriesarrays in sync with each series'isSelectedandisHoveredflags. - For
XyzDataSeries3D, castargs.hitTestInfotoXyzSeriesInfo3Dwhen you needdataSeriesIndex,xValue,yValueorzValue.