Page 1 of 2
multiple legend
Posted: Wed Feb 18, 2009 9:35 am
by 10545622
Hi,
I would like to have 2 legends for one graph. The first one with the series name "Serie 1", "Series 2" and the second one for "Serie 3", "Series 4".
It seems that it's only possible to have all the series of a graph in a legend when we choose the lsSeries property.
Or, is it possible (and how) to have one legend but a line to separate two sets of series ?
Best regards
Posted: Wed Feb 18, 2009 11:16 am
by yeray
Hi stsl,
Yes, you could have two legends using a custom legend. Please take a look at the demo at
All features/Miscellaneous/Legend/Multiple Legends.
If you prefer to draw a line, you should draw it directly to the canvas:
Code: Select all
procedure TForm1.Chart1AfterDraw(Sender: TObject);
begin
With Chart1.Legend.ShapeBounds do
begin
With Chart1.Canvas do
begin
DoHorizLine(Left,Right,Bottom-17);
end;
end;
end;
multiple legend
Posted: Wed Feb 18, 2009 12:16 pm
by 10545622
I know that there is a multiple legend demo. But in your demo, if you use the lsSeries mode, 2 legends with all the series will be painted. In my chart, i have, for example 3 series. I would like one legend with the first serie (serie name) and the other one legend with the 2 last series.
I tried to do that :
Code: Select all
procedure TForm1.FormCreate(Sender: TObject);
begin
Series1.FillSampleValues(100);
Chart.Legend.LegendStyle := lsSeries;
Series1.ShowInLegend := False;
Series2.ShowInLegend := False;
Series3.ShowInLegend := False;
end;
procedure TForm1.ChartAfterDraw(Sender: TObject);
begin
if cbAdditionalLegend.Checked then
begin
Chart.Legend.Top := 125;
Series1.ShowInLegend := False;
Series2.ShowInLegend := True;
Series3.ShowInLegend := True;
Chart.Legend.DrawLegend;
Chart.Legend.CustomPosition := False;
end;
end;
It works but when i checked a serie (i use checkbox) the 2 legends are both painted with serie2 and serie3 intead of one legend with serie1 and the otherone with serie1 ans serie2.
[/img]
Posted: Wed Feb 18, 2009 12:31 pm
by 10545622
I made a mistake in my sample code. In the form create :
Code: Select all
Series1.ShowInLegend := True;
Series2.ShowInLegend := False;
Series3.ShowInLegend := False;
Posted: Wed Feb 18, 2009 12:37 pm
by 10545622
I found a solution of my problem. I added a OnBeforeDrawChart :
Code: Select all
procedure TForm1.ChartBeforeDrawChart(Sender: TObject);
begin
Series1.ShowInLegend := True;
Series2.ShowInLegend := False;
Series3.ShowInLegend := False;
end;
Posted: Wed Feb 18, 2009 3:16 pm
by 10545622
Now, i would like to have one legend with series and a second legend with serie groups. I modified my ChartAfterDraw procedure like this :
Code: Select all
procedure TForm1.ChartAfterDraw(Sender: TObject);
begin
if cbadditionallegend.Checked then
begin
Chart.Legend.Top := 125;
Chart.Legend.CheckBoxes:=True;
Chart.Legend.LegendStyle := lsSeriesGroups;
Chart.Legend.DrawLegend;
Chart.Legend.CustomPosition := False;
end;
end;
The two legends are properly drawn but it's now impossible to check or uncheck the series in the first legend and the groups in the second legend.
Where is my mistake ?
Best regards
Posted: Thu Feb 19, 2009 10:32 am
by yeray
Hi stsl,
Yes, I've seen the problem. It seems that, having multiple series, only the last one is clickable. I''ve added the issue to the wish list to be fixed in further releases (TV52013878).
In the meanwhile, here you have a workaround example that works for me here:
Code: Select all
const CheckBoxesSeparation = 17;
CheckBoxesSize = 12;
FirstItemTop = 56;
CheckBoxesMargin = 4;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var i:Integer;
begin
Chart1.View3D := false;
for i:=0 to Chart1.SeriesCount-1 do
Chart1[i].FillSampleValues(25);
with Chart1.SeriesGroups do
begin
Chart1.SeriesList.AddGroup('Group A');
Items[0].Add(Chart1[0]);
Items[0].Add(Chart1[1]);
Chart1.SeriesList.AddGroup('Group B');
Items[1].Add(Chart1[2]);
Items[1].Add(Chart1[3]);
end;
Chart1.Legend.CheckBoxes:=True;
end;
procedure TForm1.Chart1AfterDraw(Sender: TObject);
begin
Chart1.Legend.Top := 125;
Chart1.Legend.LegendStyle := lsSeriesGroups;
Chart1.Legend.DrawLegend;
end;
procedure TForm1.Chart1BeforeDrawChart(Sender: TObject);
begin
Chart1.Legend.CustomPosition := False;
Chart1.Legend.LegendStyle := lsSeries;
end;
procedure TForm1.Chart1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var i: Integer;
begin
for i:= 0 to Chart1.SeriesCount-1 do
if ((X > Chart1.Legend.Left + CheckBoxesMargin) and
(X < Chart1.Legend.Left + CheckBoxesMargin + CheckBoxesSize)) then
if ((Y > FirstItemTop + (i*CheckBoxesSeparation)) and
(Y < FirstItemTop + (i*CheckBoxesSeparation) + CheckBoxesSize)) then
Chart1[i].Active := not Chart1[i].Active;
end;
Posted: Thu Feb 19, 2009 2:19 pm
by 10545622
Hi,
You said that only the last one is clickable. All my legends are not clickable.
So, your sample code solved the problem for the first legend but not for the second one.
How is it possible to track the mouse position for the second legend ?
Best regards
Posted: Thu Feb 19, 2009 2:29 pm
by 10545622
and an other question :
How i can get the real values of the constantes CheckBoxesSeparation,
CheckBoxesSize, FirstItemTop and CheckBoxesMargin ?
Regards
Posted: Thu Feb 19, 2009 4:15 pm
by yeray
Hi stsl,
1) It's strange, Ive tried with extralegend tool and with more than 2 legends and always the last drawn legend is clickable.
Well, you always will be able to add another "for" to check if the click was on the checkbox. This time you could do as follows:
Code: Select all
const CheckBoxesSeparation = 17;
CheckBoxesSize = 12;
FirstItemTopLegend1 = 56;
FirstItemTopLegend2 = 131;
CheckBoxesMargin = 4;
//...
procedure TForm1.Chart1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var i, j: Integer;
begin
for i:=0 to Chart1.SeriesCount-1 do
if ((X > Chart1.Legend.Left + CheckBoxesMargin) and
(X < Chart1.Legend.Left + CheckBoxesMargin + CheckBoxesSize)) then
if ((Y > FirstItemTopLegend1 + (i*CheckBoxesSeparation)) and
(Y < FirstItemTopLegend1 + (i*CheckBoxesSeparation) + CheckBoxesSize)) then
Chart1[i].Active := not Chart1[i].Active;
for i:=0 to Chart1.SeriesGroups.Count-1 do
if ((X > Chart1.Legend.Left + CheckBoxesMargin) and
(X < Chart1.Legend.Left + CheckBoxesMargin + CheckBoxesSize)) then
if ((Y > FirstItemTopLegend2 + (i*CheckBoxesSeparation)) and
(Y < FirstItemTopLegend2 + (i*CheckBoxesSeparation) + CheckBoxesSize)) then
for j:=0 to Chart1.SeriesGroups[i].Series.Count-1 do
Chart1.SeriesGroups[i].Series[j].Active := not Chart1.SeriesGroups[i].Series[j].Active;
end;
2) I've found the constant values with a simple trick. Add the following code to your OnMouseDown or OnMouseMove event:
Code: Select all
caption := 'X: ' + floattostr(X) + ' Y: ' + floattostr(Y);
Posted: Fri Feb 20, 2009 7:39 am
by 10545622
Hi,
It tried your solution but it didn't work. Could i post (and how) a sample project to you ?
How is it possible to get the position of the legend at runtime (to fix firstItemTopLegend1 and 2) ? The user can customize the position of the legend ar runtime with the editor.
Best regards
Posted: Fri Feb 20, 2009 11:10 am
by yeray
Hi stsl,
I've made some changes to the example to be mora adaptable to different chart sizes.
Code: Select all
var
Form1: TForm1;
CheckBoxesSeparation, CheckBoxesSize, FirstItemTopLegend1, Leged2Top, CheckBoxesLeftMargin, CheckBoxesTopMargin: Integer;
implementation
uses Types;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var i:Integer;
begin
Chart1.View3D := false;
for i:=0 to Chart1.SeriesCount-1 do
Chart1[i].FillSampleValues(25);
with Chart1.SeriesGroups do
begin
Chart1.SeriesList.AddGroup('Group A');
Items[0].Add(Chart1[0]);
Items[0].Add(Chart1[1]);
Chart1.SeriesList.AddGroup('Group B');
Items[1].Add(Chart1[2]);
Items[1].Add(Chart1[3]);
end;
Chart1.Legend.CheckBoxes:=True;
CheckBoxesSeparation := 17;
CheckBoxesSize := 12;
CheckBoxesLeftMargin := 4;
CheckBoxesTopMargin := 5;
Leged2Top := 125;
end;
procedure TForm1.Chart1AfterDraw(Sender: TObject);
begin
Chart1.Legend.Top := Leged2Top;
Chart1.Legend.LegendStyle := lsSeriesGroups;
Chart1.Legend.DrawLegend;
end;
procedure TForm1.Chart1BeforeDrawChart(Sender: TObject);
begin
Chart1.Legend.CustomPosition := False;
Chart1.Legend.LegendStyle := lsSeries;
end;
procedure TForm1.Chart1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var i, j: Integer;
begin
Chart1.Canvas.Pen.Color := clRed;
for i:=0 to Chart1.SeriesCount-1 do
begin
if ((X > Chart1.Legend.Left + CheckBoxesLeftMargin) and
(X < Chart1.Legend.Left + CheckBoxesLeftMargin + CheckBoxesSize)) then
if ((Y > FirstItemTopLegend1 + (i*CheckBoxesSeparation) + CheckBoxesTopMargin) and
(Y < FirstItemTopLegend1 + (i*CheckBoxesSeparation) + CheckBoxesSize + CheckBoxesTopMargin)) then
Chart1[i].Active := not Chart1[i].Active;
// Draw rectangles to test positions
// Chart1.Canvas.Rectangle(Chart1.Legend.Left + CheckBoxesLeftMargin, FirstItemTopLegend1 + (i*CheckBoxesSeparation) + CheckBoxesTopMargin, Chart1.Legend.Left + CheckBoxesLeftMargin + CheckBoxesSize, FirstItemTopLegend1 + (i*CheckBoxesSeparation) + CheckBoxesSize + CheckBoxesTopMargin);
end;
for i:=0 to Chart1.SeriesGroups.Count-1 do
begin
if ((X > Chart1.Legend.Left + CheckBoxesLeftMargin) and
(X < Chart1.Legend.Left + CheckBoxesLeftMargin + CheckBoxesSize)) then
if ((Y > Chart1.Legend.Top + (i*CheckBoxesSeparation) + CheckBoxesTopMargin) and
(Y < Chart1.Legend.Top + (i*CheckBoxesSeparation) + CheckBoxesSize + CheckBoxesTopMargin)) then
for j:=0 to Chart1.SeriesGroups[i].Series.Count-1 do
Chart1.SeriesGroups[i].Series[j].Active := not Chart1.SeriesGroups[i].Series[j].Active;
// Draw rectangles to test positions
// Chart1.Canvas.Rectangle(Chart1.Legend.Left + CheckBoxesLeftMargin, Chart1.Legend.Top + (i*CheckBoxesSeparation) + CheckBoxesTopMargin, Chart1.Legend.Left + CheckBoxesLeftMargin + CheckBoxesSize, Chart1.Legend.Top + (i*CheckBoxesSeparation) + CheckBoxesSize + CheckBoxesTopMargin);
end;
// Show X and Y of the pixel clicked
// caption := 'X: ' + floattostr(X) + ' Y: ' + floattostr(Y);
end;
procedure TForm1.Chart1GetLegendRect(Sender: TCustomChart;
var Rect: TRect);
begin
if Rect.Top <> Leged2Top then
FirstItemTopLegend1 := Rect.Top;
end;
Yes, you can either post your files at news://
www.steema.net/steema.public.attachments newsgroup or at our
upload page.
Posted: Fri Feb 20, 2009 12:33 pm
by 10545622
Thank you for your sample.
I uploaded a file with your upload page (TChartLegend.zip). In this sample, i can check/unchek the second legend (group) but for the first legend (Series), i have to click at the right of the check box (and not on the check box) to uncheck/check the series. Click on the Gantt values button to add the grouped series and check the additionallegend check box to see the ExtraLegend tool.
In your sample, do you use an ExtraLegend tool or a multiple legend ?
It would be better if i could download your complete sample.
Best regards
Posted: Fri Feb 20, 2009 3:39 pm
by yeray
Hi stsl,
In my sample I used multiple legends, but with extralegend tool it looks more simple because you can access to legend positions when you want because it's not re-written. So we won't need OnBeforeDraw, OnAfterDraw and OnGetLegendRect events.
In your project, the legend works fine for me all the time. I mean, simply adding an extralegendtool, the normal legend remains clickable. Then we only need to find the checkboxes of the extralegend and see if the click is in its area.
The following code works for me in your project:
Code: Select all
procedure TForm1.ChartMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
i, j: Integer;
begin
for i:= 0 to Chart.SeriesGroups.Count - 1 do
begin
if (X > ExtraLegend.Legend.Left) and (X < ExtraLegend.Legend.Left + ExtraLegend.Legend.Width) then
begin
if (Y > ExtraLegend.Legend.Top + CheckBoxesMargin + (i * CheckBoxesSeparation)) and (Y < ExtraLegend.Legend.Top + CheckBoxesMargin + (i*CheckBoxesSeparation) + CheckBoxesSize) then
begin
outputdebugstring('Clic groups good');
if Chart.SeriesGroups[i].Active = gaYes then
Chart.SeriesGroups[i].Active := gaNo
else
Chart.SeriesGroups[i].Active := gaYes;
Exit;
end;
end;
end;
end;
PS: I also recommend you to change the value of CheckBoxesMargin to 5.
Posted: Fri Feb 20, 2009 3:44 pm
by 10545622
Congratulations, it works very well...
Best regards