Page 1 of 1

How to place a calculated legend in a ExtraLegend

Posted: Tue Nov 01, 2022 10:14 pm
by 16586540
I use TeeChart with a Self Stacked bar chart to visualise the stratigraphy down a well. I have code to generate the legend as shown in the attached image, Stratigraphy.jpg.

However, I wish to create a split-chart with the stratigraphy on the left and a line chart on the right, I am unable to show both legends, as in StratigraphyPT.jpg. How can I place both legends on the chart. I would prefer to be able to create an ExtraLegend and then assign this to the series at the appropriate point.

I have created an ExtraLegend tool as shown below, but I don't understand how to now apply the legend code to the ExtraLegend.

Code: Select all

  if self.owner.fToggleSecondWorksheet then
  begin
    ExtraLegend := TExtraLegendTool.Create(self.owner);
    self.Owner.Chart.Tools.Add(ExtraLegend);
    ExtraLegend.Series := TUnitBarSeries(SeriesListB.Objects[iIndex]);
  end;

Re: How to place a calculated legend in a ExtraLegend

Posted: Wed Nov 02, 2022 1:02 pm
by yeray
Hello Errol,

You could override the TeeExtraLegendTool's ChartEvent to set ShowInLegend for those series you want it to consider, and reset ShowInLegend at the Chart's OnBeforeDrawChart for the main legend. Ie:
extralegend.png
extralegend.png (7.59 KiB) Viewed 4373 times

Code: Select all

uses Series, TeeExtraLegendTool;

type TMyExtraLegendTool=class(TExtraLegendTool)
  protected
    procedure ChartEvent(AEvent: TChartToolEvent); override;
end;

TLegendAccess=class(TChartLegend);

procedure TMyExtraLegendTool.ChartEvent(AEvent: TChartToolEvent);
begin
  inherited;

  if AEvent=cteAfterDraw then
  begin
    ParentChart[0].ShowInLegend:=False;
    ParentChart[1].ShowInLegend:=True;
    ParentChart[2].ShowInLegend:=True;

    if Assigned(ParentChart) and Assigned(Series) then
    begin
      Legend.Series:=Series; // call getter

      if Legend.Visible then
      begin
        TLegendAccess(Legend).CalcRect;
        Legend.DrawLegend;
      end;
    end;
  end;
end;

procedure TForm1.Chart1BeforeDrawChart(Sender: TObject);
begin
  Chart1[0].ShowInLegend:=True;
  Chart1[1].ShowInLegend:=False;
  Chart1[2].ShowInLegend:=False;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=False;
  Chart1.Gradient.Visible:=False;
  Chart1.Color:=clWhite;
  Chart1.Walls.Back.Gradient.Visible:=False;
  Chart1.Walls.Back.Color:=clWhite;

  Chart1.Axes.Bottom.EndPosition:=50;
  Chart1.Axes.Top.StartPosition:=50;

  with TBarSeries(Chart1.AddSeries(TBarSeries)) do
  begin
    MultiBar:=mbSelfStack;
    Marks.Hide;
    FillSampleValues(3);
  end;

  with TLineSeries(Chart1.AddSeries(TLineSeries)) do
  begin
    HorizAxis:=aTopAxis;
    Pointer.Show;
    Pointer.Size:=2;
    FillSampleValues(5);
  end;

  with TLineSeries(Chart1.AddSeries(TLineSeries)) do
  begin
    HorizAxis:=aTopAxis;
    Pointer.Show;
    Pointer.Size:=2;
    FillSampleValues(5);
  end;

  Chart1.Draw;

  with TMyExtraLegendTool(Chart1.Tools.Add(TMyExtraLegendTool)) do
  begin
    Series:=Chart1[1];
    Legend.LegendStyle:=lsSeries;
    Legend.Left:=Chart1.Legend.Left;
    Legend.Top:=Chart1.Legend.Top+Chart1.Legend.Height+10;
  end;
end;

Re: How to place a calculated legend in a ExtraLegend

Posted: Sun Nov 06, 2022 5:17 am
by 16586540
Hello Yeray

Thank you for your reply. I have reviewed your sample code, but I am still puzzled on how to proceed. In my code, I use a single chart and a single legend for any number of line series (see multiline.jpg with 4 series and a single combined legend). Similarly, for bar charts (multigeology.jpg).

When I make a chart with both line and bar charts, I would like to simply assign the bar chart legend (a composite legend of all rock types in the selected series) to an ExtraLegend, rather than change all my code to refer to chart[0], chart[1] etc, as would seem to be necessary if I added each series to the chart. Is this possible?

Re: How to place a calculated legend in a ExtraLegend

Posted: Mon Nov 07, 2022 2:41 pm
by yeray
Hello Errol,

If you want TBarSeries in the main series and TLineSeries in the extra legend, you can loop all the series and activate/deactivate ShowInLegend according to the series class:

Code: Select all

uses Series, TeeExtraLegendTool;

type TMyExtraLegendTool=class(TExtraLegendTool)
  protected
    procedure ChartEvent(AEvent: TChartToolEvent); override;
end;

TLegendAccess=class(TChartLegend);

procedure TMyExtraLegendTool.ChartEvent(AEvent: TChartToolEvent);
var i: Integer;
begin
  if AEvent=cteAfterDraw then
  begin
    for i:=0 to ParentChart.SeriesCount-1 do
        ParentChart[i].ShowInLegend:=ParentChart[i] is TLineSeries;

    if Assigned(ParentChart) and Assigned(Series) then
    begin
      if Legend.Visible then
      begin
        TLegendAccess(Legend).CalcRect;
        Legend.DrawLegend;
      end;
    end;
  end;
end;

procedure TForm1.Chart1BeforeDrawChart(Sender: TObject);
var i: Integer;
begin
  for i:=0 to Chart1.SeriesCount-1 do
      Chart1[i].ShowInLegend:=Chart1[i] is TBarSeries;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=False;
  Chart1.Gradient.Visible:=False;
  Chart1.Color:=clWhite;
  Chart1.Walls.Back.Gradient.Visible:=False;
  Chart1.Walls.Back.Color:=clWhite;

  Chart1.Axes.Bottom.EndPosition:=50;
  Chart1.Axes.Top.StartPosition:=50;

  Chart1.OnBeforeDrawChart:=Chart1BeforeDrawChart;

  with TBarSeries(Chart1.AddSeries(TBarSeries)) do
  begin
    MultiBar:=mbSelfStack;
    Marks.Hide;
    FillSampleValues(3);
  end;

  with TLineSeries(Chart1.AddSeries(TLineSeries)) do
  begin
    HorizAxis:=aTopAxis;
    Pointer.Show;
    Pointer.Size:=2;
    FillSampleValues(5);
  end;

  with TLineSeries(Chart1.AddSeries(TLineSeries)) do
  begin
    HorizAxis:=aTopAxis;
    Pointer.Show;
    Pointer.Size:=2;
    FillSampleValues(5);
  end;

  Chart1.Draw;

  with TMyExtraLegendTool(Chart1.Tools.Add(TMyExtraLegendTool)) do
  begin
    Series:=Chart1[1];
    Legend.LegendStyle:=lsSeries;
    Legend.Left:=Chart1.Legend.Left;
    Legend.Top:=Chart1.Legend.Top+Chart1.Legend.Height+10;
  end;
end;