Recent

Author Topic: Adding text to a chart using canvas  (Read 2722 times)

mtanner

  • Full Member
  • ***
  • Posts: 226
Adding text to a chart using canvas
« on: October 24, 2015, 01:56:02 pm »
I want to add some text to a chart. For example, if the chart displays the distribution of some data, I'd like to add a small table giving the main statistics. I've done this in Delphu/TeeChart, using the chart canvas property and TextOut.

Can this be done in Lazarus/TAGraph? Does it create any platform dependencies?

wp

  • Hero Member
  • *****
  • Posts: 6336
Re: Adding text to a chart using canvas
« Reply #1 on: October 24, 2015, 04:56:44 pm »
At first: there is no pre-built component to add some text a chart. But maybe it is sufficient to show the text in the chart's title or footer?

If you want more control you can use one of the OnDrawXXXX events of the chart to perform manual drawing, see http://wiki.lazarus.freepascal.org/TAChart_Tutorial:_Background_design#The_TChart_painting_events for an explanation of the events. I'd recommend to pick the OnAfterdraw event which is called after drawing all chart elements, i.e. what you draw here will not get overpainted by other chart elements.

Yes, you could paint using the chart's canvas. But I do not recommend it because you can also paint to other canvases (printer, external files), and your manually drawn text would not appear there. It is better to use the ADrawer interface which is passed as a parameter to the event handler.

See TADrawUtils.IDrawer for the methods of the drawing backend which are similar to the canvas painting methods, except for text output which is done in a bit un-Pascal-ish way, by adding more and more methods to the TextOut methods - see example below.

Note also that drawing occurs in units of the drawer's pixels ("image coordinates"). Use the chart's GraphToImage method to convert values from "data" to "image" coordinates (This statement is simplified, correct only if transformations are not used).

Here is a simple example which displays the average value of a series in the top-left edge of a chart on a yellow background with shadow:
Code: Pascal  [Select]
  1. uses
  2.   Types, TAChartUtils, TAGeometry;
  3.  
  4. procedure TForm1.Chart1AfterDraw(ASender: TChart; ADrawer: IChartDrawer);
  5. var
  6.   i: Integer;
  7.   ave: Double;
  8.   ext: TDoubleRect;
  9.   Rext, R: TRect;
  10.   s: String;
  11. begin
  12.   // Calculate value to be displayed
  13.   ave := 0.0;
  14.   for i:=0 to Chart1LineSeries1.Count-1 do
  15.     ave := ave + Chart1LineSeries1.YValue[i];
  16.   ave := ave / Chart1Lineseries1.Count;
  17.  
  18.   // Text to be displayed - use 3 decimal places
  19.   s := 'Average value: ' + FormatFloat('0.000', ave);
  20.  
  21.   // Limits of the chart box in graph coordinates
  22.   ext := Chart1.LogicalExtent;
  23.  
  24.   // ... and in image (screen) coordinates
  25.   Rext.TopLeft := Chart1.GraphToImage(DoublePoint(ext.a.x, ext.b.y));
  26.   Rext.BottomRight := Chart1.GraphToImage(DoublePoint(ext.b.x, ext.a.y));
  27.  
  28.   // Draw text 10 pixels to the right of x axis, and 10 pixels below top edge of chart
  29.   // The text will be on a yellow background with 4-pixel wide shadow
  30.  
  31.   // Calculate rectangle boundaries for text
  32.   R.TopLeft := Point(0,0);
  33.   ADrawer.SetFont(Chart1.Title.Font);  // let's use the same font as the chart title
  34.   R.BottomRight := ADrawer.TextExtent(s);
  35.   // Move text rect 10 pixels to the right of the x axis, and 10 pixels down from top edge
  36.   OffsetRect(R, Rext.Left + 10, Rext.Top + 10);
  37.  
  38.   // Paint shadow first: move rectangle 4 more pixels to the right-bottom
  39.   OffsetRect(R, 4, 4);
  40.   ADrawer.SetBrushParams(bsSolid, clBlack);
  41.   ADrawer.FillRect(R.Left, R.Top, R.Right, R.Bottom);
  42.  
  43.   // Paint yellow background (move rect back to original position)
  44.   OffsetRect(R, -4, -4);
  45.   ADrawer.SetBrushParams(bsSolid, clYellow);
  46.   ADrawer.FillRect(R.Left, R.Top, R.Right, R.Bottom);
  47.  
  48.   // Now draw text
  49.   ADrawer.TextOut.Pos(R.Left, R.Top).Text(s).Done;  // .Done must be last command!
  50. end;

This code should not depend on platform.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

mtanner

  • Full Member
  • ***
  • Posts: 226
Re: Adding text to a chart using canvas
« Reply #2 on: October 24, 2015, 05:06:49 pm »
Thanks WP, I shall work on that.

In Delphi/TeeChart you can just use the OnAfterDraw event to add text, and it doesn't seem to give any problems with printing.

I looked at the documentatyion and when I got to the IDrawer stuff I decided to leave the problem for a while - lots of other more pressing TAGraph things to figure out. I considered using Foot, but that isn't really how I want the graphs to look.