Page 1 of 1

Multiple extra legend tool to display series groups

Posted: Wed Nov 16, 2016 11:19 am
by 16579113
Hello,
I have an application with a number of lineseries in a chart plotted against multiple vertical axes (vertically stacked). Per vertical axis I would like to have a legend to show the series names linked to that axis. See the attached image example.

I can use the Legend's FirstValue and MaxnumRows properties to have the extralegends show a subset of the series, but this only works as long as the series are distributed over the Y axes in the same order is in the parent Chart's SeriesList. If for example I would like to have the 1st series on the 2nd Y axis it would not work anymore.

Solutions would be
- an event handler enabling accepting or rejecting an item in the legend
- The option to show the series in a series group
- or something showing only series attached to a particular vertical axis
I feel I need to derive a custom Legend version, but I see that this involves a lot of re-coding as many TChartLegend items are protected and few things are managed with virtual (overridable) methods.

Is there an elegant way to do this without coding?

If not: what would be the best approach to derive a custom version of the ChartLegend (to go in a Custom derivative of TExtraLegendTool)

regards, Wilfried Visser

Re: Multiple extra legend tool to display series groups

Posted: Fri Nov 18, 2016 9:10 am
by yeray
Hello,

If you only want to show the series titles (or some other text related to each series) you could use 2 TAnnotationTool(s) as in the following simple example:

Code: Select all

procedure TForm1.FormCreate(Sender: TObject);
var i, j: Integer;
begin
  Chart1.View3D:=false;
  Chart1.MarginLeft:=7;

  Chart1.CustomAxes.Add.EndPosition:=45;
  Chart1.CustomAxes.Add.StartPosition:=55;

  Chart1.Tools.Add(TAnnotationTool);
  Chart1.Tools.Add(TAnnotationTool);

  for i:=0 to 5 do
  begin
    if (i mod 3 = 0) then
      Chart1.AddSeries(TLineSeries)
    else
      with Chart1.AddSeries(TPointSeries) as TPointSeries do
      begin
        Pointer.HorizSize:=3;
        Pointer.VertSize:=3;
        Pointer.Style:=psCircle;
      end;

    Chart1[i].CustomVertAxis:=Chart1.CustomAxes[i mod 2];
    Chart1[i].FillSampleValues;
  end;

  Chart1.Draw;

  for i:=0 to Chart1.CustomAxes.Count-1 do
  begin
    with Chart1.Tools[i] as TAnnotationTool do
    begin
      Shape.CustomPosition:=True;
      Shape.Left:=Chart1.ChartRect.Left;
      Shape.Top:=Chart1.CustomAxes[i].IStartPos;
      Shape.AutoSize:=true;
      Shape.Transparency:=0;

      for j:=0 to Chart1.SeriesCount-1 do
        if (Chart1[j].CustomVertAxis = Chart1.CustomAxes[i]) then
           if (Text = '') then
              Text:='      '+SeriesTitleOrName(Chart1[j])
           else
              Text:=Text+sLineBreak+'      '+SeriesTitleOrName(Chart1[j]);
    end;
  end;
end;
If you want to also show the series symbols in the TAnnotationTool(s) then some extra code should be added to manually draw them at OnAfterDraw event. Ie:

Code: Select all

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var i, j, d: Integer;
begin
  for i:=0 to Chart1.CustomAxes.Count-1 do
  begin
    d:=9;
    with Chart1.Tools[i] as TAnnotationTool do
    begin
      for j:=0 to Chart1.SeriesCount-1 do
        if (Chart1[j].CustomVertAxis = Chart1.CustomAxes[i]) then
        begin
          Chart1[j].DrawLegend(-1,Rect(Shape.Left+6,Shape.Top+d, Shape.Left+16, Shape.Top+d+4));
          Inc(d,14);
        end;
    end;
  end;
end;

Re: Multiple extra legend tool to display series groups

Posted: Fri Nov 18, 2016 10:31 am
by 16579113
Thanks,

I more or less already have taken this route. The tip how to dray the symbol really helps !

One final question: do you alo have a suggestion how to add a checkbox in front of the symbol that can be checked/unchecked to activate/deactivate the series?

Another question: should not the TCustomLegend tool be used for this? I tried the TCustomLegend tool but it does not seem to work properly: I do not see any text I enter in the Text property appear in the TCustomLegend grid.

regards and thanks again,
Wilfried Visser, VisserTek

Re: Multiple extra legend tool to display series groups

Posted: Mon Nov 21, 2016 1:12 pm
by yeray
Hello,
wvisser wrote:do you alo have a suggestion how to add a checkbox in front of the symbol that can be checked/unchecked to activate/deactivate the series?
You can draw it manually using DrawCheckBox function and use Chart's OnClick event to activate/deactivate the according series. Ie:

Code: Select all

uses TeeTools, Series;

procedure TForm1.Chart1Click(Sender: TObject);
var i, j, n, line: Integer;
    annot: TAnnotationTool;
begin
  for i:=0 to Chart1.Tools.Count-1 do
  begin
    annot:=Chart1.Tools[i] as TAnnotationTool;
    if annot.Clicked(Chart1.GetCursorPos.X, Chart1.GetCursorPos.Y) then
    begin
      line:=(abs(Chart1.GetCursorPos.Y-(annot.Shape.Top+3)) div (abs(annot.Shape.Font.Height)+3))+1;

      n:=0;
      for j:=0 to Chart1.SeriesCount-1 do
        if (Chart1[j].CustomVertAxis = Chart1.CustomAxes[i]) then
        begin
          Inc(n);
          if (n=line) then
          begin
            Chart1[j].Active:=not Chart1[j].Active;
            exit;
          end;
        end;
      exit;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i, j: Integer;
begin
  Chart1.View3D:=false;
  Chart1.MarginLeft:=7;

  Chart1.CustomAxes.Add.EndPosition:=45;
  Chart1.CustomAxes.Add.StartPosition:=55;

  Chart1.Tools.Add(TAnnotationTool);
  Chart1.Tools.Add(TAnnotationTool);

  for i:=0 to 5 do
  begin
    if (i mod 3 = 0) then
      Chart1.AddSeries(TLineSeries)
    else
      with Chart1.AddSeries(TPointSeries) as TPointSeries do
      begin
        Pointer.HorizSize:=3;
        Pointer.VertSize:=3;
        Pointer.Style:=psCircle;
      end;

    Chart1[i].CustomVertAxis:=Chart1.CustomAxes[i mod 2];
    Chart1[i].FillSampleValues;
  end;

  Chart1.Draw;

  for i:=0 to Chart1.CustomAxes.Count-1 do
  begin
    with Chart1.Tools[i] as TAnnotationTool do
    begin
      Shape.CustomPosition:=True;
      Shape.Left:=Chart1.ChartRect.Left;
      Shape.Top:=Chart1.CustomAxes[i].IStartPos;
      Shape.AutoSize:=true;
      Shape.Transparency:=0;

      for j:=0 to Chart1.SeriesCount-1 do
        if (Chart1[j].CustomVertAxis = Chart1.CustomAxes[i]) then
           if (Text = '') then
              Text:='          '+SeriesTitleOrName(Chart1[j])
           else
              Text:=Text+sLineBreak+'          '+SeriesTitleOrName(Chart1[j]);
    end;
  end;
end;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var i, j, d, tmpX: Integer;
begin
  for i:=0 to Chart1.CustomAxes.Count-1 do
  begin
    d:=9;
    with Chart1.Tools[i] as TAnnotationTool do
    begin
      tmpX:=Shape.Left+20;

      for j:=0 to Chart1.SeriesCount-1 do
        if (Chart1[j].CustomVertAxis = Chart1.CustomAxes[i]) then
        begin
          Chart1[j].DrawLegend(-1,Rect(tmpX,Shape.Top+d, tmpX+10, Shape.Top+d+4));
          Chart1.Canvas.DrawCheckBox(Shape.Left+4, Shape.Top+d-5, Chart1[j].Active, clNone);
          Inc(d,14);
        end;
    end;
  end;
end;
wvisser wrote:should not the TCustomLegend tool be used for this? I tried the TCustomLegend tool but it does not seem to work properly: I do not see any text I enter in the Text property appear in the TCustomLegend grid.
That could be a different approach. Take a look at the examples under "What's New ?\Welcome!\New Chart Tools\Custom Legend Tool" in the New Features demo program shipped with the installation to see it in action, with code.