MetadataProvider 3D API
SciChart Android 3D features a rich MetadataProvider API with gives the ability to change color on a point-by-point basis.
Note
Examples of using MetadataProvider API can be found in the SciChart Android Examples Suite as well as on GitHub:
To enable series coloring with MetadataProvider, you need to create a class which conforms to one of the following protocol (or possibly to all of them):
Protocol | Descriptions |
---|---|
IPointMetadataProvider3D | allows changing the fill for PointMarkers 3D. |
IStrokeMetadataProvider3D | allows painting parts of the series' stroke; |
IFillMetadataProvider3D | allows changing the fill color for IRenderableSeries3D. |
ISurfaceMeshMetadataProvider3D | allows overriding a specific cell or cells in the for SurfaceMeshRenderableSeries3D. |
ISelectableMetadataProvider3D | allows provide different colors for selected points. |
Note
The MetadataProvider API is very similar to the PaletteProvider API from SciChart 2D.
A choice depends on a RenderableSeries 3D type, which MetadataProvider 3D is designed for.
Each MetadataProvider protocol declares method(s), which provides a way to update series colors for every data points. Mentioned methods are called every time RenderableSeries 3D requires a redraw, so it expects that the colors array should be updated there correspondingly.
For the convenience, there is the MetadataProvider3DBase<T> class, which provides some basic implementation, so it's recommended to inherit from it while implementing custom MetadataProvider. There is also some predefined MetadataProviders listed below:
- DefaultSelectableMetadataProvider3D - allows provide different colors for selected points. You can find it in our examples which demonstrate selection such as - Waterfall Chart 3D and Select Scatter Point 3D Chart.
Create Custom MetadataProvider
The following code snippet demonstrates how to create a custom MetadataProvider which conforms to the - Stroke and PointMarker - metadata providers and colors them respectively to the orbitalYaw and orbitalPitch.
Note
The below code is based on the Point-Line Chart 3D example which can be found in the SciChart Android Examples Suite as well as on GitHub:
class CustomMetadataProvider extends MetadataProvider3DBase<PointLineRenderableSeries3D> implements IPointMetadataProvider3D, IStrokeMetadataProvider3D {
CustomMetadataProvider() {
super(PointLineRenderableSeries3D.class);
}
@Override
public void updateStrokeColors(IntegerValues integerValues, int i) {
updateColors(integerValues);
}
@Override
public void updatePointMetadata(IntegerValues integerValues, FloatValues floatValues, int i, float v) {
updateColors(integerValues);
final int pointsCount = renderableSeries.getCurrentRenderPassData().getPointsCount();
floatValues.setSize(pointsCount);
for (int x = 0; x < pointsCount; x++) {
floatValues.set(i, 1);
}
}
void updateColors(IntegerValues colors) {
PointLineRenderableSeries3D rSeries = renderableSeries;
XyzRenderPassData3D renderPassData = (XyzRenderPassData3D)rSeries.getCurrentRenderPassData();
double upperThreshold = rSeries.getParentSurface().getCamera().getOrbitalYaw() % 90;
double lowerThreshold = rSeries.getParentSurface().getCamera().getOrbitalPitch() % 90;
int pointsCount = renderPassData.getPointsCount();
colors.setSize(pointsCount);
final DoubleValues yValues = renderPassData.yValues;
for (int i = 0; i < pointsCount; i++) {
double value = yValues.get(i);
if (value > upperThreshold) {
colors.set(i, 0xffff0000);
} else if (value < lowerThreshold) {
colors.set(i, 0xff00ff00);
} else {
colors.set(i, 0xffffff00);
}
}
}
}
Once the MetadataProvider class is ready, its instances can be used to set it for a RenderableSeries via the metadataProvider property:
final NumericAxis3D xAxis = new NumericAxis3D();
xAxis.setGrowBy(new DoubleRange(.1, .1));
final NumericAxis3D yAxis = new NumericAxis3D();
yAxis.setGrowBy(new DoubleRange(.1, .1));
final NumericAxis3D zAxis = new NumericAxis3D();
zAxis.setGrowBy(new DoubleRange(.1, .1));
final XyzDataSeries3D<Double, Double, Double> ds = new XyzDataSeries3D<>(Double.class, Double.class, Double.class);
for (int i = 0; i < 100; i++) {
final double x = 5 * Math.sin(i);
final double y = i;
final double z = 5 * Math.cos(i);
ds.append(x, y, z);
}
final SpherePointMarker3D pointMarker = new SpherePointMarker3D();
pointMarker.setSize(5);
final ImpulseRenderableSeries3D rs = new ImpulseRenderableSeries3D();
rs.setDataSeries(ds);
rs.setStrokeThickness(convertValueToDp(2f));
rs.setPointMarker(pointMarker);
rs.setMetadataProvider(new CustomMetadataProvider());
UpdateSuspender.using(surface, () -> {
surface.setXAxis(xAxis);
surface.setYAxis(yAxis);
surface.setZAxis(zAxis);
surface.getRenderableSeries().add(rs);
surface.getChartModifiers().add(createDefaultModifiers3D());
});
Which will result with the following: