The secret to SciChart’s speed is a bespoke, immediate-mode raster drawing engine. This means that all drawing in SciChart is done ‘immediately’ to the screen, and is cleared and redrawn each time the chart is updated.
Now in SciChart you can take advantage of our immediate-mode drawing API, to create custom RenderableSeries, custom Point-Markers, Draw on top of the chart, or even create your own immediate-mode drawing applications.
The IRenderContext2D Interface
All the drawing to the separate layer is achieved with the IRenderContext2D interface. All drawing is done to the RenderSurface, using either a Canvas API, or OpenGL depending on your RenderSurface.
Using this interface, you can:
- draw lines of variable stroke width
- draw a rectangle
- draw an ellipse shape
- fill an area with a brush
- fill a rectangle area
- draw some text to the render surface
- draw sprite
- set clip rect which prevents drawing outside specified bounds
- rotate, scale and translate RenderContext
Believe it or not, you can achieve a lot with just those!
The IAssetManager2D interface
The second part RenderContext API is IAssetManager2D interface which is responsible for creation and storing of RenderSurface specific resources from Style classes.
Using this interface, you can
- create pens to draw stroke with
- create brushes to fill rects, ellipses with
- create textures from Bitmap
- store and get some heavy resources which should be reused during drawing (e.g. textures, sprites )
Example of using RenderContext API
For example we'll create a simple example of IRenderSurfaceRenderer which can be set as renderer for RenderSurface:
Custom RenderSurface Renderer |
Copy Code
|
---|---|
private class TestRenderSurfaceRenderer implements IRenderSurfaceRenderer{ private final RectF sprite2Rect = new RectF(0,0, 0.5f, 0.5f); private final RectF sprite3Rect = new RectF(0.25f,0.25f, 0.75f, 0.75f); private final BrushStyle solidStyle; private final BrushStyle linearGradient; private final BrushStyle radialGradient; private final TextureBrushStyle textureStyle; private final PenStyle simpleLine; private final PenStyle aaLine; private final PenStyle texturedLine; private final PenStyle texturedAaLine; private final PenStyle dashedSimpleLine; private final PenStyle dashedAaLine; private final PenStyle dashedTexturedLine; private final PenStyle dashedTexturedAaLine; private final PenStyle thickSimpleLine; private final PenStyle thickAaLine; private final PenStyle thickTexturedLine; private final PenStyle thickTexturedAaLine; private final PenStyle dashedThickSimpleLine; private final PenStyle dashedThickAaLine; private final PenStyle dashedThickTexturedLine; private final PenStyle dashedThickTexturedAaLine; private final FontStyle fontStyle; private final FontStyle customFontStyle; private final Bitmap texture; private final float[] xAxisArrow = {0,0, 50, 0, 30, -10, 50, 0, 30, 10, 50, 0}; private final float[] yAxisArrow = {0,0, 0, 50, -10, 30, 0, 50, 10, 30, 0, 50}; private float degrees, dx, dy, opacity; public TestRenderSurfaceRenderer(Bitmap texture) { solidStyle = new SolidBrushStyle(ColorUtil.argb(0xEE, 0xFF, 0xC9, 0xA8)); linearGradient = new LinearGradientBrushStyle(0, 0, 1, 1, ColorUtil.argb(0xEE, 0xFF, 0xC9, 0xA8), ColorUtil.argb(0xEE, 0x13, 0x24, 0xA5)); radialGradient = new RadialGradientBrushStyle(0.5f, 0.5f, 0.5f, 0.5f, ColorUtil.argb(0xEE, 0xFF, 0xC9, 0xA8), ColorUtil.argb(0xEE, 0x13, 0x24, 0xA5)); textureStyle = new TextureBrushStyle(texture); fontStyle = new FontStyleBuilder(getActivity()).withTextSize(32).withTextColor(ColorUtil.Red).build(); customFontStyle = new FontStyleBuilder(getActivity()).withTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD_ITALIC)).withTextSize(23).withTextColor(ColorUtil.Yellow).build(); simpleLine = new SolidPenStyleBuilder(getActivity()).withColor(ColorUtil.Red).withAntiAliasing(false).withThickness(1f).build(); aaLine = new SolidPenStyleBuilder(getActivity()).withColor(ColorUtil.Green).withAntiAliasing(true).withThickness(1f).build(); texturedLine = new TexturePenStyleBuilder(getActivity()).withTextureBrush(textureStyle).withAntiAliasing(false).withThickness(1f).build(); texturedAaLine = new TexturePenStyleBuilder(getActivity()).withTextureBrush(textureStyle).withAntiAliasing(true).withThickness(1f).build(); dashedSimpleLine = new SolidPenStyleBuilder(getActivity()).withColor(ColorUtil.Blue).withAntiAliasing(false).withThickness(1f).withStrokeDashArray(new float[]{5, 10, 5, 10}).build(); dashedAaLine = new SolidPenStyleBuilder(getActivity()).withColor(ColorUtil.Magenta).withAntiAliasing(true).withThickness(1f).withStrokeDashArray(new float[]{10, 5, 10, 5}).build(); dashedTexturedLine = new TexturePenStyleBuilder(getActivity()).withTextureBrush(textureStyle).withAntiAliasing(false).withStrokeDashArray(new float[]{5, 10, 5, 10}).withThickness(1f).build(); dashedTexturedAaLine = new TexturePenStyleBuilder(getActivity()).withTextureBrush(textureStyle).withAntiAliasing(true).withStrokeDashArray(new float[]{10, 5, 10, 5}).withThickness(1f).build(); thickSimpleLine = new SolidPenStyleBuilder(getActivity()).withColor(ColorUtil.Red).withAntiAliasing(false).withThickness(10f).build(); thickAaLine = new SolidPenStyleBuilder(getActivity()).withColor(ColorUtil.Green).withAntiAliasing(true).withThickness(10f).build(); thickTexturedLine = new TexturePenStyleBuilder(getActivity()).withTextureBrush(textureStyle).withAntiAliasing(false).withThickness(10f).build(); thickTexturedAaLine = new TexturePenStyleBuilder(getActivity()).withTextureBrush(textureStyle).withAntiAliasing(true).withThickness(10f).build(); dashedThickSimpleLine = new SolidPenStyleBuilder(getActivity()).withColor(ColorUtil.Blue).withAntiAliasing(false).withThickness(20f).withStrokeDashArray(new float[]{5, 10, 5, 10}).build(); dashedThickAaLine = new SolidPenStyleBuilder(getActivity()).withColor(ColorUtil.Magenta).withAntiAliasing(true).withThickness(20f).withStrokeDashArray(new float[]{0, 20, 10, 5}).build(); dashedThickTexturedLine = new TexturePenStyleBuilder(getActivity()).withTextureBrush(textureStyle).withAntiAliasing(false).withThickness(20f).withStrokeDashArray(new float[]{5, 10, 5, 10}).build(); dashedThickTexturedAaLine = new TexturePenStyleBuilder(getActivity()).withTextureBrush(textureStyle).withAntiAliasing(true).withThickness(20).withStrokeDashArray(new float[]{0, 20, 10, 5}).build(); this.texture = texture; } @Override public void onSurfaceAttached(IRenderSurface surface) { } @Override public void onSurfaceDetached(IRenderSurface surface) { } @Override public void onSurfaceSizeChanged(int width, int height, int oldWidth, int oldHeight) { } public void setTransform(float degrees, float dx, float dy, float opacity){ this.degrees = degrees; this.dx = dx - translateX.getMax() / 2; this.dy = dy - translateY.getMax() / 2; this.opacity = opacity; } @Override public void onDraw(IRenderContext2D renderContext, IAssetManager2D assetManager) { renderContext.translate(dx, dy); renderContext.rotate(degrees); final IBrush2D solidBrushPerScreen = assetManager.createBrush(solidStyle, TextureMappingMode.PerScreen, opacity); final IBrush2D radialGradientBrushPerScreen = assetManager.createBrush(radialGradient, TextureMappingMode.PerScreen, opacity); final IBrush2D linearGradientBrushPerScreen = assetManager.createBrush(linearGradient, TextureMappingMode.PerScreen, opacity); final IBrush2D textureBrushPerScreen = assetManager.createBrush(textureStyle, TextureMappingMode.PerScreen, opacity); final IBrush2D solidBrushPerPrimitive = assetManager.createBrush(solidStyle, TextureMappingMode.PerPrimitive, opacity); final IBrush2D radialGradientBrushPerPrimitive = assetManager.createBrush(radialGradient, TextureMappingMode.PerPrimitive, opacity); final IBrush2D linearGradientBrushPerPrimitive = assetManager.createBrush(linearGradient, TextureMappingMode.PerPrimitive, opacity); final IBrush2D textureBrushPerPrimitive = assetManager.createBrush(textureStyle, TextureMappingMode.PerPrimitive, opacity); final IPen2D simpleLine = assetManager.createPen(this.simpleLine, opacity); final IPen2D aaLine = assetManager.createPen(this.aaLine, opacity); final IPen2D dashedSimpleLine = assetManager.createPen(this.dashedSimpleLine, opacity); final IPen2D dashedAaLine = assetManager.createPen(this.dashedAaLine, opacity); final IPen2D thickSimpleLine = assetManager.createPen(this.thickSimpleLine, opacity); final IPen2D thickAaLine = assetManager.createPen(this.thickAaLine, opacity); final IPen2D dashedThickSimpleLine = assetManager.createPen(this.dashedThickSimpleLine, opacity); final IPen2D dashedThickAaLine = assetManager.createPen(this.dashedThickAaLine, opacity); final IPen2D texturedLine = assetManager.createPen(this.texturedLine, opacity); final IPen2D texturedAaLine = assetManager.createPen(this.texturedAaLine, opacity); final IPen2D dashedTexturedLine = assetManager.createPen(this.dashedTexturedLine, opacity); final IPen2D dashedTexturedAaLine = assetManager.createPen(this.dashedTexturedAaLine, opacity); final IPen2D thickTexturedLine = assetManager.createPen(this.thickTexturedLine, opacity); final IPen2D thickTexturedAaLine = assetManager.createPen(this.thickTexturedAaLine, opacity); final IPen2D dashedThickTexturedLine = assetManager.createPen(this.dashedThickTexturedLine, opacity); final IPen2D dashedThickTexturedAaLine = assetManager.createPen(this.dashedThickTexturedAaLine, opacity); final IFont font = assetManager.createFont(this.fontStyle); final IFont customFont = assetManager.createFont(this.customFontStyle); final ITexture2D sprite1 = assetManager.createTexture(texture); final ITexture2D sprite2 = assetManager.createTexture(texture, sprite2Rect); final ITexture2D sprite3 = assetManager.createTexture(texture, sprite3Rect); renderContext.drawLines(xAxisArrow, 0, xAxisArrow.length, simpleLine); renderContext.drawLines(yAxisArrow, 0, yAxisArrow.length, aaLine); renderContext.save(); renderContext.translate(10, 10); renderContext.drawLine(0, 0, 80, 80, simpleLine); renderContext.drawLine(100, 0, 180, 80, aaLine); renderContext.drawLine(200, 0, 280, 80, dashedSimpleLine); renderContext.drawLine(300, 0, 380, 80, dashedAaLine); renderContext.drawLine(0, 100, 80, 180, thickSimpleLine); renderContext.drawLine(100, 100, 180, 180, thickAaLine); renderContext.drawLine(200, 100, 280, 180, dashedThickSimpleLine); renderContext.drawLine(300, 100, 380, 180, dashedThickAaLine); renderContext.translate(0, 200); renderContext.drawLine(0, 0, 80, 80, texturedLine); renderContext.drawLine(100, 0, 180, 80, texturedAaLine); renderContext.drawLine(200, 0, 280, 80, dashedTexturedLine); renderContext.drawLine(300, 0, 380, 80, dashedTexturedAaLine); renderContext.drawLine(0, 100, 80, 180, thickTexturedLine); renderContext.drawLine(100, 100, 180, 180, thickTexturedAaLine); renderContext.drawLine(200, 100, 280, 180, dashedThickTexturedLine); renderContext.drawLine(300, 100, 380, 180, dashedThickTexturedAaLine); renderContext.translate(0, 200); renderContext.drawRect(0, 0, 80, 80, simpleLine); renderContext.drawRect(100, 0, 180, 80, aaLine); renderContext.drawRect(200, 0, 280, 80, dashedSimpleLine); renderContext.drawRect(300, 0, 380, 80, dashedAaLine); renderContext.drawRect(0, 100, 80, 180, thickSimpleLine); renderContext.drawRect(100, 100, 180, 180, thickAaLine); renderContext.drawRect(200, 100, 280, 180, dashedThickSimpleLine); renderContext.drawRect(300, 100, 380, 180, dashedThickAaLine); renderContext.translate(0, 200); renderContext.fillRect(0, 0, 80, 80, solidBrushPerScreen); renderContext.fillRect(100, 0, 180, 80, linearGradientBrushPerScreen); renderContext.fillRect(200, 0, 280, 80, radialGradientBrushPerScreen); renderContext.fillRect(300, 0, 380, 80, textureBrushPerScreen); renderContext.fillRect(0, 100, 80, 180, solidBrushPerPrimitive); renderContext.fillRect(100, 100, 180, 180, linearGradientBrushPerPrimitive); renderContext.fillRect(200, 100, 280, 180, radialGradientBrushPerPrimitive); renderContext.fillRect(300, 100, 380, 180, textureBrushPerPrimitive); renderContext.translate(0, 200); renderContext.drawEllipse(50, 50, 80, 80, simpleLine, solidBrushPerScreen); renderContext.drawEllipse(150, 50, 80, 80, aaLine, linearGradientBrushPerScreen); renderContext.drawEllipse(250, 50, 80, 80, dashedSimpleLine, radialGradientBrushPerScreen); renderContext.drawEllipse(350, 50, 80, 80, dashedAaLine, textureBrushPerScreen); renderContext.drawEllipse(50, 150, 80, 80, thickSimpleLine, solidBrushPerPrimitive); renderContext.drawEllipse(150, 150, 80, 80, thickAaLine, linearGradientBrushPerPrimitive); renderContext.drawEllipse(250, 150, 80, 80, dashedThickSimpleLine, radialGradientBrushPerPrimitive); renderContext.drawEllipse(350, 150, 80, 80, dashedThickAaLine, textureBrushPerPrimitive); renderContext.restore(); renderContext.save(); renderContext.translate(500, 0); renderContext.drawText(font, 0, 0, fontStyle.textColor, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); renderContext.drawText(font, 0, 50, fontStyle.textColor, "abcdefghijklmnopqrstuvwxyz"); renderContext.drawText(font, 0, 100, fontStyle.textColor, "1234567890~!@#$%^&*()-+=/|\\'\""); renderContext.drawText(customFont, 0, 150, customFontStyle.textColor, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); renderContext.drawText(customFont, 0, 200, customFontStyle.textColor, "abcdefghijklmnopqrstuvwxyz"); renderContext.drawText(customFont, 0, 250, customFontStyle.textColor, "1234567890~!@#$%^&*()-+=/|\\'\""); renderContext.translate(0, 300); renderContext.drawSprite(sprite1, 0, 0, opacity); renderContext.translate(0, sprite1.getHeight() + 10); renderContext.drawSprite(sprite2, 0, 0, opacity); renderContext.translate(0, sprite2.getHeight() + 10); renderContext.drawSprite(sprite3, 0, 0, opacity); renderContext.translate(0, sprite3.getHeight() + 10); sprite1.dispose(); sprite2.dispose(); sprite3.dispose(); } } |