| Contents page
Previous | Next
Tutorial 13 - Custom drawing on the Chart Panel
TeeChart offers extensive custom drawing facilities via the TCanvas3D component. With Canvas you may add shapes, lines and text anywhere on the Chart Panel and define their colours, pen and brush styles.
When using TeeChart's Canvas methods remember that drawing order is important. Drawing a Line on the Chart then adding Series data points will cause the Line to be overdrawn. You could put the Line in the Series BeforeDrawValues event for the Line to appear above the Chart grid and below the Series. You could place the Line code in the OnAfterDraw event for the Line to appear above the Series.
Event order, 4 principle Chart draw events
- OnBeforeDrawChart event
- OnBeforeDrawAxes event
- OnBeforeDrawSeries event
- OnAfterDraw event
Let's add a Canvas Line:
//Draw a Line diagonally from top left to bottom right //in the Chart Area of a 2D Chart With Chart1, ChartRect do begin //Move the pointer to the top left Chart point Canvas.MoveTo(Left,Top); //Draw the Line Canvas.LineTo(Right,Bottom); end;
3D Orthogonal Chart
On an Orthogonal 3D Chart the Axis positions are offset from the Chart area due to 3D orthogonal displacement. We can move the Line accordingly:
//Draw a Line diagonally from top left to bottom right //in the Chart Area of a 3D Chart With Chart1, ChartRect do begin //Move the pointer to the top left Chart point Canvas.MoveTo(Left Width3D,Top - Height3D); //Draw the Line adjustment for 3D displacement Canvas.LineTo(Right Width3D,Bottom - Height3D); end;
3D Nativemode or OpenGL Chart
To draw the same line on a Native 3D Chart or OpenGL Chart (This will also work on a 2D and 3D Orthogonal Chart):
//Draw a Line diagonally from top left to bottom right //in the Chart Area of a 3D Nativemode or OpenGL Chart With Chart1,Canvas do begin Pen.Color := clBlue; Pen.Width := 1; Pen.Style := psDot; //Pen must be 1 to use Pen.Style Brush.Style := bsClear; //transparency //Then draw the Line MoveTo3D(ChartRect.Left,ChartRect.Top,0); LineTo3D(ChartRect.Right,ChartRect.Bottom,Width3D); end;
MoveTo3D and LineTo3D methods recognise the displacement made to the ChartRect as a result of Elevation and Rotation applied with 'Full' 3D.
Canvas Pen and Brush
The Line above is drawn using the Pen and Brush defined for the last object drawn before the Line is drawn. That may or may not be the Pen you want. You can change the Pen accordingly:
//Define Pen and Brush before drawing the Line With Chart1,Canvas,ChartRect do begin Pen.Color := clBlue; Pen.Width := 1; Pen.Style := psDot; //Pen must be 1 to use Pen.Style Brush.Style := bsClear; //transparency //Then draw the Line MoveTo(Left Width3D,Top - Height3D); LineTo(Right Width3D,Bottom - Height3D); end;
Adding 2D Shapes
Add 2D Canvas Shapes in a similar manner to Canvas Lines. The following example adds a Rectangle in the centre of the Chart Area:
3D orthogonal Charts support only 2D shapes.
With Chart1, Canvas do begin //prepare Pen and Brush Pen.Color := clBlue; Pen.Width := 1; Pen.Style := psDot; Brush.Color := clWhite; Brush.Style := bsSolid; //You can draw a Rectangle on any Chart (2D or 3D) Rectangle(100,100,200,200); end;
On a 3D Chart you can move the Rectangle in a Z plane too. See the RectangleWithZ method. This example for an orthogonal or Nativemode/OpenGL Chart places the Rectangle on the Left Wall but displaces it halfway towards the rear of the Chart (towards the Back Wall).
With Chart1,Canvas,ChartRect do begin //prepare Pen and Brush Pen.Color := clBlue; Pen.Width := 1; Pen.Style := psDot; Brush.Color := clWhite; Brush.Style := bsSolid; //Draw Rectangle with Z displacement RectangleWithZ(Rect(Left, Top, Left ((Right-Left) div 2), Top ((Bottom-top) div 2)), Width3D div 2); end;
Adding 3D Shapes
You may add 3D shapes to 3D Charts. This example draws a Cube in the top, left quadrant of the Chart rectangle. The depth covers the area from the front of the Walls to the Back Wall. See the Cube method.
With Chart1,Canvas,ChartRect do begin //prepare Pen and Brush Pen.Color := clBlue; Pen.Width := 1; Pen.Style := psDot; Brush.Color := clWhite; Brush.Style := bsSolid; Cube(Left, Left ((Right-Left) div 2), Top, Top ((Bottom-Top) div 2), 0, Width3D, True); end;
2D Text location
Add Text to a Rectangle:
procedure TForm1.Button1Click(Sender: TObject); var rectLeft,rectTop,rectRight,rectBottom:Integer; begin With Chart1, Canvas, ChartRect do begin rectLeft:= Left; rectTop:= Top; rectRight:= Left (Right - Left) div 2; rectBottom:= Top (Bottom - Top) div 2; //prepare Pen and Brush Pen.Color := clBlue; Pen.Width := 1; Pen.Style := psDot; Brush.Color := clWhite; Brush.Style := bsSolid; //Draw the Rectangle Rectangle(rectLeft,rectTop,rectRight,rectBottom); //Modify Font Font.Color := clRed; //add the Text start at the midpoint of the Rectangle TextOut(rectLeft (rectRight - rectLeft) div 2, rectTop (rectBottom-rectTop) div 2, 'Hello'); end; end;
3D Text location
You can place Text in a differing 3D plane by using the TextOut3D method.
With Chart1, Canvas, ChartRect do begin Brush.Style := bsClear; TextOut3D(Left, Top, Width3D div 2, 'Hello'); end;
This example takes the 3rd and 10th values of a Series, plots a Line between them and tells us the value of the first and Last point of the new Line and the difference between them:
'First add some data to the empty Chart procedure TForm1.BitBtn1Click(Sender: TObject); begin Series1.FillSampleValues(20); end;
//You could put this code in the OnAfterDraw event procedure TForm1.Chart1AfterDraw(Sender: TObject); begin With Chart1 do Begin If SeriesCount > 0 Then begin If Series1.Count > 10 Then begin //Add some Shapes Canvas.Pen.Color := clBlue; Canvas.Pen.Width := 1; Canvas.Pen.Style := psDot; Canvas.Brush.Style := bsClear; Canvas.MoveTo (Axes.Bottom.CalcXPosValue(Series1.XValues), Axes.Left.CalcYPosValue(Series1.YValues)); Canvas.LineTo (Axes.Bottom.CalcXPosValue(Series1.XValues), Axes.Left.CalcYPosValue(Series1.YValues)); Canvas.Brush.Style := bsSolid; Canvas.TextOut(Axes.Bottom.CalcXPosValue(Series1.XValues), Axes.Left.CalcYPosValue(Series1.YValues), 'Point value: ' FloatToStr(Series1.YValues)); Canvas.TextOut(Axes.Bottom.CalcXPosValue(Series1.XValues), Axes.Left.CalcYPosValue(Series1.YValues), 'Point value: ' FloatToStr(Series1.YValues)); Canvas.TextOut(Axes.Bottom.CalcXPosValue(Series1.XValues), Axes.Left.CalcYPosValue(Series1.YValues) Canvas.TextHeight('Any letter'), 'Change is: ' FloatToStr(Series1.YValues - Series1.YValues)); end; end; end; end;
Advanced custom drawing
Almost all TeeChart units use now the TeCanvas unit. This unit is a low-level unit that provides all drawing functions encapsulated in the new TCanvas3D component.
If you do special customized drawing using the TeeChart Canvas property, you should add this unit to your Forms "Uses" clause. It is safe to use it as it has no dependencies other than the normal Delphi units.
This Canvas-derived class incorporates support for 3D rotation, zoom, scroll and 3D primitives. It has all methods virtual and abstract, so it means you can not use it directly. You should use a derived class which implements all methods and properties.
Using this Canvas, the Chart components can now support "plug-in" Canvases. That is, you can change at design-time or run-time the "Chart1.Canvas" property, and all drawing will be redirected to the new Canvas:
Chart1.Canvas := TGLCanvas.Create ; //<-- switches display to OpenGL
TeeChart includes these new virtual Canvases:
- TGLCanvas ( for OpenGL rendering )
Implementing a new virtual Canvas, though not trivial, should be quite easy to do. You can even create, for example, a TVRMLCanvas, which will generate an ascii file containing VRML (Virtual Reality) graphic instructions. ( Or another to save to DXF, 3DS, etc ).
These Canvases apply to the base class TCustomChart, so they work for TChart, TDBChart, TQRChart or any other derived Chart class.
Note: OpenGL DLL's are only for 32bit Windows, hence too, the GLCanvas.
This is the implementation of the virtual TCanvas3D class used internally. It is a wrapper around a standard Delphi TCanvas class. It has many direct calls to Windows GDI to speed up drawing. It adds the TCanvas3D features like rotation, zoom, etc. It works with all Delphi and C Builder versions. TGLCanvas class:
This class resides in a separate unit / package to make applications independant of OpenGL's DLLs. It works only for 32bit Delphi (and C Builder ). When using the TGLCanvas for a Chart include 'Uses TeeGLEditor' and the Chart Editor will add another page at runtime to change GL characteristics such as Light location and colour. For OpenGL to be available at designtime, add the TTeeOpenGL component to the Form, associate it with the Chart and set Active:=True. There is a new non-visual component ( TTeeOpenGL ), that allows you to "connect" an existing Chart to it at design or run-time, and immediately see the Chart rendered using OpenGL 3D libraries. This component allows you to also define OpenGL specific properties, like Lighting attributes. Comparison between TTeeCanvas3D and TGLCanvas:
- The OpenGL canvas supports lighting ( lights , light colors, positions, etc ) while the TeeCanvas draws 3D sides with darker colors to simulate lighting.
- The OpenGL canvas does not support metafile creation, so for printing a big and fat TBitmap should be created and sent to the printer Canvas, which means it works only with printers with good memory and sane drivers. Metafiles cannot be created, copied to clipboard, saved or printed.
- The OpenGL canvas needs the OpenGL DLLs ( available in Windows NT and later and alternative libraries from www.sgi.com. Depending on your CPU and video hardware, the OpenGL Dlls from Silicon Graphics may be faster than the ones from Microsoft.
- The OpenGL canvas supports different Font Sizes and Colors, but it does not support more than one Font style. All characters of a Font are converted to drawing instructions. This takes up quite a lot of memory and CPU speed.
© 1998-2019 Steema Software SL. All rights reserved.