Page 1 of 1

Setting same ChartRect for two charts

Posted: Thu Aug 31, 2006 1:22 pm
by 9343323
I have two charts place one above the other on a form. I would like the ChartRect (if that is the area of the chart, which is bounded by the axes) to be identical for the two charts, so that a given x-coordinate can be at the same horisontal position on both charts. I can read the values of TChart.ChartRect.Left and TChart.ChartRect.Right, bu how can i set them and have the new settings reflected in the chart?

Best Regards and Thank You in advance,
Arne Jakobsen

Posted: Thu Aug 31, 2006 1:31 pm
by narcis
Hi Arne,

You can do something like in the code snippet below or you can use custom axes so that you don't need to use several chart. For more information on how to use custom axes please read "Tutorial 4 - Axis Control" and have a look at the features demo. Tutorials and demo can be found at TeeChart's program group.

Code: Select all

procedure TForm1.FormCreate(Sender: TObject);
var
  Chart1, Chart2, Chart3, Chart4: TChart;
begin
  Chart1 := TChart.Create( Self );
  Chart2 := TChart.Create( Self );
  Chart3 := TChart.Create( Self );
  Chart4 := TChart.Create( Self );

  Chart1.Parent := Self;
  Chart2.Parent := Self;
  Chart3.Parent := Self;
  Chart4.Parent := Self;

  Chart1.Left := 0;
  Chart2.Left := 0;
  Chart3.Left := 0;
  Chart4.Left := 0;

  Chart1.Top := 0;
  Chart2.Top := 100;
  Chart3.Top := 200;
  Chart4.Top := 300;

  Chart1.Width := 500;
  Chart2.Width := 500;
  Chart3.Width := 500;
  Chart4.Width := 500;

  Chart1.Height := 100;
  Chart2.Height := 100;
  Chart3.Height := 100;
  Chart4.Height := 100;

  Chart1.View3D := false;
  Chart2.View3D := false;
  Chart3.View3D := false;
  Chart4.View3D := false;

  Chart1.Show;
  Chart2.Show;
  Chart3.Show;
  Chart4.Show;

  Chart1.AddSeries( TLineSeries );
  Chart2.AddSeries( TLineSeries );
  Chart3.AddSeries( TLineSeries );
  Chart4.AddSeries( TLineSeries );

  Chart1[0].FillSampleValues();
  Chart2[0].FillSampleValues();
  Chart3[0].FillSampleValues();
  Chart4[0].FillSampleValues();

  Chart1.Legend.LegendStyle := lsSeries;
  Chart2.Legend.LegendStyle := lsSeries;
  Chart3.Legend.LegendStyle := lsSeries;
  Chart4.Legend.LegendStyle := lsSeries;

  Chart1.Legend.CheckBoxes := true;
  Chart2.Legend.CheckBoxes := true;
  Chart3.Legend.CheckBoxes := true;
  Chart4.Legend.CheckBoxes := true;

  Chart1.LeftAxis.Grid.Visible:=false;
  Chart2.LeftAxis.Grid.Visible:=false;
  Chart3.LeftAxis.Grid.Visible:=false;
  Chart4.LeftAxis.Grid.Visible:=false;

  Chart1.BottomAxis.Grid.Visible:=false;
  Chart2.BottomAxis.Grid.Visible:=false;
  Chart3.BottomAxis.Grid.Visible:=false;
  Chart4.BottomAxis.Grid.Visible:=false;

  Chart1.MarginUnits := muPixels;
  Chart2.MarginUnits := muPixels;
  Chart3.MarginUnits := muPixels;
  Chart4.MarginUnits := muPixels;

  Chart1.MarginLeft:=50;
  Chart2.MarginLeft:=50;
  Chart3.MarginLeft:=50;
  Chart4.MarginLeft:=50;

  Chart1.LeftAxis.LabelsSize:=30;
  Chart2.LeftAxis.LabelsSize:=30;
  Chart3.LeftAxis.LabelsSize:=30;
  Chart4.LeftAxis.LabelsSize:=30;
end;

Posted: Fri Sep 01, 2006 11:14 am
by 9343323
Thank You for yoyr reply

If I change the series a litle bit, by for instance changing:

Chart1.AddSeries( TLineSeries );
Chart2.AddSeries( TLineSeries );
Chart3.AddSeries( TLineSeries );
Chart4.AddSeries( TLineSeries );

to

ASeries := TLineSeries.Create(Chart1);
ASeries.Title := 'Loooooooooooooong name';
ASeries.ParentChart:= Chart1;
ASeries := TLineSeries.Create(Chart2);
ASeries.Title := 'short name';
ASeries.ParentChart:= Chart2;
Chart3.AddSeries( TLineSeries );
Chart4.AddSeries( TLineSeries );

Then I am in trouble again, because the chart makes room for the legend by resizing the plot area. Can I do anything to syncronize the sizes of the plot areas in two charts? Something like:

ALeftMargin := max(Chart1.MarginLeft, Chart2.MarginLeft);
Chart1.MarginLeft := ALeftMargin;
Chart2.MarginLeft := ALeftMargin;

ARightMargin := max(Chart1.MarginRight, Chart2.MarginRight);
Chart1.MarginRight := ARightMargin;
Chart2.MarginRight := ARightMargin;

Except that it should work for the plot areas.


Best Regards and Thank You in advance
Arne Jakobsen

Posted: Mon Sep 04, 2006 11:07 am
by narcis
Hi Arne,

Then you can try doing something like this:

Code: Select all

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TeEngine, Series, ExtCtrls, TeeProcs, Chart, StdCtrls;

type
  TForm1 = class(TForm)
    Chart1: TChart;
    Chart2: TChart;
    Series1: TLineSeries;
    Series2: TLineSeries;
    Series3: TLineSeries;
    procedure Chart1AfterDraw(Sender: TObject);
    procedure Chart2AfterDraw(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure UpdateChartMargins;
    function MaxLegendTextSize: Integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses Math;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
begin
  UpdateChartMargins;
end;

procedure TForm1.Chart2AfterDraw(Sender: TObject);
begin
  UpdateChartMargins;
end;

procedure TForm1.UpdateChartMargins;
var
  ALeftMargin, ARightMargin: Integer;
begin
  ALeftMargin := max(Chart1.MarginLeft, Chart2.MarginLeft);
  Chart1.MarginLeft := ALeftMargin;
  Chart2.MarginLeft := ALeftMargin;

  ARightMargin:=MaxLegendTextSize*Chart1.Legend.Font.Size;

  Chart1.MarginRight:=ARightMargin;
  Chart2.MarginRight:=ARightMargin;

  Chart1.Legend.CustomPosition:=true;
  Chart1.Legend.Left := Chart1.Width - ARightMargin + 10;
  Chart1.Legend.Top := 50;

  Chart2.Legend.CustomPosition:=true;
  Chart2.Legend.Left := Chart1.Legend.Left;
  Chart2.Legend.Top := Chart1.Legend.Top;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Chart1.MarginUnits:=muPixels;
  Chart2.MarginUnits:=muPixels;

  Chart1.Legend.ResizeChart:=false;
  Chart2.Legend.ResizeChart:=false;

  Chart1.Draw;
  Chart2.Draw;
end;

function TForm1.MaxLegendTextSize: Integer;
var i,max,tmp: Integer;
begin

  max:=0;
  for i:=0 to Chart1.Legend.Items.Count - 1 do
  begin
    tmp:=StrLen(PChar(string(Chart1.Legend.Item[i].Text)));
    if tmp>max then max:=tmp;
  end;

  for i:=0 to Chart2.Legend.Items.Count - 1 do
  begin
    tmp:=StrLen(PChar(string(Chart2.Legend.Item[i].Text)));
    if tmp>max then max:=tmp;
  end;

  result:=max;
end;

end.

Posted: Tue Sep 05, 2006 12:54 pm
by 9333098
How about directly assigning values to chart1.ChartRect.Left, etc. and make the two charts the same. This fixes the inner axis bounding region, so if axis label size changes with data value, the position of the inner region will remain fixed.

Posted: Wed Sep 06, 2006 12:47 pm
by 9343323
I ended up doing something like the following:

Chart1.MarginUnits := muPixels;
Chart2.MarginUnits := muPixels;

if (Chart1.ChartRect.Left > Chart2.ChartRect.Left) then begin
Chart2.MarginLeft := Chart2.MarginLeft +
Chart1.ChartRect.Left - Chart2.ChartRect.Left;
end else if (Chart2.ChartRect.Left > Chart1.ChartRect.Left) then begin
Chart1.MarginLeft := Chart1.MarginLeft +
Chart2.ChartRect.Left - Chart1.ChartRect.Left;
end;

if (Chart1.ChartRect.Right > Chart2.ChartRect.Right) then begin
Chart1.MarginRight := Chart1.MarginRight +
Chart1.ChartRect.Right - Chart2.ChartRect.Right;
end else if (Chart2.ChartRect.Right > Chart1.ChartRect.Right) then begin
Chart2.MarginRight := Chart2.MarginRight +
Chart2.ChartRect.Right - Chart1.ChartRect.Right;
end;

Thank you for your assistance,
Arne Jakobsen