Custom RenderableSeries API
If the built-in chart types in SciChart are not enough, you can create your own RenderableSeries. Custom RenderableSeries should extend BaseRenderableSeries if you want to provide some custom data, or one of predefined base classes if you want to display data from one of default IDataSeries<TX,TY> implementations.
Base class for Custom RenderableSeries | When to use |
---|---|
XyRenderableSeriesBase | If you want to use XyDataSeries<TX,TY> as data source for custom RenderableSeries |
XyyRenderableSeriesBase | If you want to use XyyDataSeries<TX,TY> as data source for custom RenderableSeries |
HlRenderableSeriesBase | If you want to use HlDataSeries<TX,TY> as data source for custom RenderableSeries |
OhlcRenderableSeriesBase | If you want to use OhlcDataSeries<TX,TY> as data source for custom RenderableSeries |
XyzRenderableSeriesBase | If you want to use XyzDataSeries<TX,TY,TZ> as data source for custom RenderableSeries |
BaseRenderableSeries | If default IDataSeries<TX,TY> implementations aren't suitable for data which should be displayed and you want to create custom DataSeries type |
Creating your Own Series
For example, let's try to create a RenderableSeries, which draws PointMarker at specified [x, y]
coordinates. Since, XyDataSeries<TX,TY> is enough to define [x, y] data we will extend XyRenderableSeriesBase:
class RoundedColumnsRenderableSeries extends FastColumnRenderableSeries {
private final FloatValues topEllipseBuffer = new FloatValues();
private final FloatValues rectsBuffer = new FloatValues();
private final FloatValues bottomEllipseBuffer = new FloatValues();
public RoundedColumnsRenderableSeries() {
super(new ColumnRenderPassData(), new ColumnHitProvider(), new NearestColumnPointProvider());
}
@Override
protected void disposeCachedData() {
super.disposeCachedData();
topEllipseBuffer.disposeItems();
rectsBuffer.disposeItems();
bottomEllipseBuffer.disposeItems();
}
@Override
protected void internalDraw(IRenderContext2D renderContext, IAssetManager2D assetManager, ISeriesRenderPassData renderPassData) {
// Don't draw transparent series
final float opacity = getOpacity();
if (opacity == 0) return;
final BrushStyle fillBrush = getFillBrushStyle();
if (fillBrush == null || !fillBrush.isVisible()) return;
final ColumnRenderPassData rpd = (ColumnRenderPassData) renderPassData;
final float diameter = rpd.columnPixelWidth;
updateDrawingBuffers(rpd, diameter, rpd.zeroLineCoord);
final IBrush2D brush = assetManager.createBrush(fillBrush);
renderContext.fillRects(rectsBuffer.getItemsArray(), 0, rectsBuffer.size(), brush);
renderContext.drawEllipses(topEllipseBuffer.getItemsArray(), 0, topEllipseBuffer.size(), diameter, diameter, brush);
renderContext.drawEllipses(bottomEllipseBuffer.getItemsArray(), 0, bottomEllipseBuffer.size(), diameter, diameter, brush);
}
private void updateDrawingBuffers(ColumnRenderPassData renderPassData, float columnPixelWidth, float zeroLine) {
final float halfWidth = columnPixelWidth / 2;
topEllipseBuffer.setSize(renderPassData.pointsCount() * 2);
rectsBuffer.setSize(renderPassData.pointsCount() * 4);
bottomEllipseBuffer.setSize(renderPassData.pointsCount() * 2);
final float[] topArray = topEllipseBuffer.getItemsArray();
final float[] rectsArray = rectsBuffer.getItemsArray();
final float[] bottomArray = bottomEllipseBuffer.getItemsArray();
final float[] xCoordsArray = renderPassData.xCoords.getItemsArray();
final float[] yCoordsArray = renderPassData.yCoords.getItemsArray();
for (int i = 0, count = renderPassData.pointsCount(); i < count; i++) {
final float x = xCoordsArray[i];
final float y = yCoordsArray[i];
topArray[i * 2] = x;
topArray[i * 2 + 1] = y - halfWidth;
rectsArray[i * 4] = x - halfWidth;
rectsArray[i * 4 + 1] = y - halfWidth;
rectsArray[i * 4 + 2] = x + halfWidth;
rectsArray[i * 4 + 3] = zeroLine + halfWidth;
bottomArray[i * 2] = x;
bottomArray[i * 2 + 1] = zeroLine + halfWidth;
}
}
}
As showed in the code above, the main method, which has to be implemented is the internalDraw
, which allows you to perform any custom drawings you want. The IRenderContext2D and IAssetManager2D are passed into it, which should be used to draw to the screen and which are the parts of the graphics context for this render pass.
The current Data to Draw - ISeriesRenderPassData protocol
The data to draw is contained in the ISeriesRenderPassData passed in to the internalDraw
method. Using the RenderPassData object you can access the data values and coordinates to draw, the xPointRange (the indices of the data to draw, inclusive), the X and Y Coordinate Calculators, that transforms data to pixel coordinates. All the above accessed through the following properties:
- yValues (other RenderPassData types might have other properties)
- yCoords (other RenderPassData types might have other properties)
- xPointRange
- getXCoordinateCalculator()
- getYCoordinateCalculator()
Depending on DataSeries type you can have a different ISeriesRenderPassData type and different ways to access the data to draw.
Series RenderPassData Type | DataSeries type used |
---|---|
XyRenderPassData | If you want to use XyDataSeries<TX,TY> as data source for custom RenderableSeries |
XyyRenderPassData | If you want to use XyyDataSeries<TX,TY> as data source for custom RenderableSeries |
XyzRenderPassData | If you want to use XyzDataSeries<TX,TY,TZ> as data source for custom RenderableSeries |
OhlcRenderPassData | If you want to use OhlcDataSeries<TX,TY> as data source for custom RenderableSeries |
HlRenderPassData | If you want to use HlDataSeries<TX,TY> as data source for custom RenderableSeries |
UniformHeatmapRenderPassData | If you want to use UniformHeatmapDataSeries<TX,TY,TZ> as data source for custom RenderableSeries |
The types above could be extended to add some additional information which is required for rendering, e.g. ColumnRenderPassData extends XyRenderPassData and adds fields for caching of column width in pixels and coordinate of zero line.
Example: RoundedColumnRenderableSeries
We have an example which shows how to create a rounded column series with this powerful API.
Note
The full Rounded Column Chart example can be found in the SciChart Android Examples Suite as well as on GitHub: