Page 1 of 1

Setting custom position for chart legend

Posted: Fri Jul 21, 2017 4:21 pm
by 16466355
In a project I’m working on, I have need for the legend on a chart to be completely centered in the middle of the chart. Unfortunately, setting TChart.Legend.Left and TChartLegend.Top using the 50% strategy does not work since this centers the top left corner of the legend and not the center of the legend.

So to try to get this to work, I tried setting “Chart1.Legend.CustomPosition := True” in the OnCreate of my form. And then I used the following OnGetLegendRect procedure for Chart1.

Code: Select all

procedure TfrmMain.Chart1GetLegendRect(Sender: TCustomChart; var Rect: TRect);
begin
  Sender.Legend.Left := Trunc((Sender.Width – (Rect.Right – Rect.Left)) / 2);
  Sender.Legend.Right := Trunc((Sender.Height – (Rect.Bottom – Rect.Top)) / 2);
end;
When I step through the debugger, Left and Right are correctly being set. However, when the form actually displays, it does not reflect that, and they are both set to zero with the legend in the top left corner.

Can you please help me understand what I might be doing wrong with this method?

Alternatively, I tried the following:

Code: Select all

procedure TfrmMain.Chart1GetLegendRect(Sender: TCustomChart; var Rect: TRect);
var
  iLegendWidth, iLegendHeight: Integer;
begin
  iLegendWidth := Rect.Right – Rect.Left;
  iLegendHeight := Rect.Bottom – Rect.Top;
  Rect.Left := Trunc((Sender.Width – iLegendWidth) / 2);
  Rect.Right := Rect.Left + iLegendWidth;
  Rect.Top := Trunc((Sender.Height – iLegendHeight) / 2);
  Rect.Bottom := Rect.Top + iLegendHeight;
end;
However, that only moves the legend itself and not the items in it. I see from the documentation that I am supposed to use OnGetLegendPosition but I’m not sure how to use X, Y, and XColor to do that. Could you please help with that?

Thanks!

Re: Setting custom position for chart legend

Posted: Wed Jul 26, 2017 7:51 am
by yeray
Hello,

The second approach looks correct to me. I see the texts need an extra repaint to be correctly positioned. Ie:

Code: Select all

uses Series;

var Chart1: TChart;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1:=TChart.Create(Self);
  Chart1.Parent:=Self;

  Chart1.Align:=alClient;
  Chart1.View3D:=False;
  Chart1.Legend.CustomPosition:=True;

  for i:=0 to 9 do
    Chart1.AddSeries(TPointSeries).FillSampleValues;

  Chart1.OnGetLegendRect:=Chart1GetLegendRect;

  Chart1.Draw; 
end;

procedure TForm1.Chart1GetLegendRect(Sender: TCustomChart; var Rect: TRect);
var
  iLegendWidth, iLegendHeight: Integer;
begin
  iLegendWidth := Rect.Right - Rect.Left;
  iLegendHeight := Rect.Bottom - Rect.Top;
  Rect.Left := Trunc((Sender.Width - iLegendWidth) / 2);
  Rect.Right := Rect.Left + iLegendWidth;
  Rect.Top := Trunc((Sender.Height - iLegendHeight) / 2);
  Rect.Bottom := Rect.Top + iLegendHeight;
end;

Re: Setting custom position for chart legend

Posted: Wed Jul 26, 2017 6:54 pm
by 16466355
Hmm. Okay. Yes, I think that is correcting the problem for the display. I haven't gotten to this part yet, but one of the requirements for our program is to define a chart and directly export the chart to jpg/png/bmp/etc without having actually seen it displayed to the screen. So do you think calling the draw without displaying the chart will still do the trick in that kind of scenario, or do you think the exported image will have incorrect text placement?

Re: Setting custom position for chart legend

Posted: Mon Jul 31, 2017 11:52 am
by yeray
Hello,

You can try to force a chart repaint (actually two repaints) before exporting the chart to get the image.
However note there's a problem since v2016.19 where you can't force a repaint of a chart without a parent (#667). The workaround consists on using a temporal hidden form. Ie:

Code: Select all

uses Series;

var Chart1: TChart;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
    tmpForm: TForm;
begin
  Chart1:=TChart.Create(Self);
  //Chart1.Parent:=Self;

  Chart1.Align:=alClient;
  Chart1.View3D:=False;
  Chart1.Legend.CustomPosition:=True;

  for i:=0 to 9 do
    Chart1.AddSeries(TPointSeries).FillSampleValues;

  Chart1.OnGetLegendRect:=Chart1GetLegendRect;


  tmpForm:=TForm.Create(Self);
  tmpForm.Visible:=False;
  Chart1.Parent:=tmpForm;

  Chart1.Draw;
  Chart1.Draw;

  Image1.Picture.Bitmap:=Chart1.TeeCreateBitmap;

  Chart1.Parent:=nil;
  tmpForm.Destroy;
end;

procedure TForm1.Chart1GetLegendRect(Sender: TCustomChart; var Rect: TRect);
var
  iLegendWidth, iLegendHeight: Integer;
begin
  iLegendWidth := Rect.Right - Rect.Left;
  iLegendHeight := Rect.Bottom - Rect.Top;
  Rect.Left := Trunc((Sender.Width - iLegendWidth) / 2);
  Rect.Right := Rect.Left + iLegendWidth;
  Rect.Top := Trunc((Sender.Height - iLegendHeight) / 2);
  Rect.Bottom := Rect.Top + iLegendHeight;
end;

Re: Setting custom position for chart legend

Posted: Tue Aug 01, 2017 7:34 pm
by 16466355
Good to know! Thank you.