TAChart: Series icons lazarus / 55-TAChart ---------------------------------------------------------------------- wp · 2011-06-18 19:41 @ask: Could you please add a the following public method to TBasicChartSeries? This method, DrawSeriesIcon, would enable population of an TImageList with the icon of each series. The imagelist could be used in further controls for series selection (Listbox, Listview etc.). This is my proposed code: Code: [Select]procedure TBasicChartSeries.DrawSeriesIcon(ADrawer:IChartDrawer; const ARect:TRect); var   legItems : TChartLegendItems;   i : integer; begin   legItems := TChartLegendItems.Create;   try     GetLegendItemsBasic(legItems);     for i:=0 to legItems.Count-1 do       (legItems[i] as TLegendItem).Draw(ADrawer, ARect);   finally     legItems.Free;   end; end;  For those interested, this would be the code to populate the imagelist with the series icons: Code: [Select]procedure PopulateSeriesImageList(AChart: TChart; AImageList:TImageList); var   drawer: IChartDrawer;   bmp : TBitmap;   R : TRect;   i : integer; begin   AImageList.Clear;   bmp := TBitmap.Create;   try     bmp.Width := AImageList.Width;     bmp.Height := AImageList.Height;     R := Rect(0, 0, bmp.Width, bmp.Height);     bmp.Canvas.Brush.Color := clWindow;     drawer := TCanvasDrawer.Create(bmp.Canvas);     for i:=0 to AChart.SeriesCount-1 do     begin       bmp.Canvas.FillRect(R);       AChart.Series[i].DrawSeriesIcon(drawer, R);       AImageList.Add(bmp, nil);     end;   finally     bmp.Free;   end; end; ---------------------------------------------------------------------- Ask · 2011-06-22 14:17 Sorry for delayed reply -- missed your post. The method you propose is not quite correct, since there is no guarantee that there is exactly one legend item per series. Instead, I have implemented TChart.GetLegendItems function (and TChartLegend.MeasureItem helper in case you need to estimate item size). Also, I have added combobox with legend items to the legend demo since r31335 ---------------------------------------------------------------------- wp · 2011-06-22 14:43 Thank you - this helps a lot. Quote...there is no guarantee that there is exactly one legend item per series.I'm a bit confused: how can this be? How can I create two legend entries for the same series? If I'd want to plot the same data twice my understanding was to use a datasource attached to both series. ---------------------------------------------------------------------- Ask · 2011-06-22 16:37 Quote from: wp on June 22, 2011, 04:43:21 pmHow can I create two legend entries for the same series? Currently -- by either setting Legend.Multiplicity to lmPoint or using user-drawn legend, both of which are demonstrated in legend demo. I plan to add other multiplicity values -- for example, an item per stack level in stacked series. ---------------------------------------------------------------------- wp · 2011-06-23 10:06 Thanks again. I am impressed by the complexity of TAChart. Maybe I am wrong, but there seems to be a weakness of legenditems being independent of series: how can I get the icon of a series which is inactive and therefore not displayed in the legend? One reason for wanting to do this could be using the series icons in a TCheckedListbox for quickly turning on and off of series, such as Delphi's TChartListbox. Of course, I could temporarily turn on all series, extract the icon of the hidden series and then turn the inactive series back off again. But this seems to be a bit cumbersome. Wouldn't it be better to have the LegendItems as a member of TBasicSeries? ---------------------------------------------------------------------- wp · 2011-06-24 12:12 Please ignore my previous post - after looking into the sources in more detail I found out that the LegendItems are defined by the series, just as I though it should be. But the issue with the inactive series still is still existing. Could you add a parameter "AllSeries:boolean=false" to the new method TChart.GetLegendItems in order to be able to include all series in the legend items list? Code: [Select]function TChart.GetLegendItems(AllSeries:boolean=false): TChartLegendItems; var   i: Integer; begin   Result := TChartLegendItems.Create;   try     for i := 0 to SeriesCount - 1 do       with Series[i] do         if (Active and GetShowInLegend)            or AllSeries // new         then           GetLegendItemsBasic(Result);   except     FreeAndNil(Result);     raise;   end; end; ---------------------------------------------------------------------- Ask · 2011-06-24 13:42 Heh, I have almost added this parameter first time -- then decided to wait for feedback. Turns out my plan was correct ;-) Added in r31359. I have credited you in the commit message as "Werner", since this is how you signed some of you messages. If you want different name, please let me know. ---------------------------------------------------------------------- wp · 2011-06-24 13:46 Thank you ---------------------------------------------------------------------- wp · 2011-07-04 10:09 Hi, beginning to implement a TChartListbox (a TCheckListbox descendant for turning on and off of series) I got stuck since I do not know the series to which a LegendItem belongs. Code: [Select]procedure TChartListbox.Populate; var   i : integer; begin   try     FreeAndNil(FLegendItems);     Items.BeginUpdate;     Items.Clear;     if (FChart <> nil) then begin       FLegendItems := FChart.GetLegendItems(true);       for i:=0 to FLegendItems.Count-1 do begin         Items.AddObject(FLegendItems[i].Text, FLegendItems[i]);         //Checked[i] := FLegendItems[i].Series.Visible;         // not possible, since TLegendItem forgot the series where it came from       end;     end;   finally     Items.EndUpdate;   end; end; Could you add a series field to the definition of TLegendItem? Or is there another way to get the series which belongs to a given LegendItem? ---------------------------------------------------------------------- Ask · 2011-07-04 12:01 QuoteCould you add a series field to the definition of TLegendItem? Added Owner field in r31557. It is of the base type, since otherwise a circular reference would be introduced. However, with multiple items per legend, TChartListBox would look strange. I have implemented TCustomChartSeries.GetSingleLegendItem in r31556. If you are planning to submit TChartListBox for inclusion, please consider the possibility of using it in design-time series editor. ---------------------------------------------------------------------- wp · 2011-07-05 10:32 Thank you. Now I have to assign the series to the new owner property. Is this the correct place? Code: [Select]procedure TCustomChartSeries.GetLegendItemsBasic(AItems: TChartLegendItems); var   i, oldCount: Integer; begin   oldCount := AItems.Count;   if Assigned(Legend.OnDraw) then     for i := 0 to Legend.UserItemsCount - 1 do       AItems.Add(TLegendI]"]>BlockedserDrawn.Create(i, Legend.OnDraw, Title))   else     GetLegendItems(AItems);   for i := oldCount to AItems.Count - 1 do begin     AItems[i].Owner := self;              // <---  new     Legend.InitItem(AItems[i], i - oldCount, FChart.Legend);   end; end; ---------------------------------------------------------------------- Ask · 2011-07-05 14:14 I do not quite understand. Does it not work already? Also, since you can now get a single item from series, you can write a loop over series, like you wanted at the beginning. ---------------------------------------------------------------------- wp · 2011-07-05 16:09 Thank you once more - I did not understand why you introduced the GetSingleLegendItem because you had discussed multiple legend items before. This is working now. However, there's another issue with notification - but I'll open a separate thread for that. ---------------------------------------------------------------------- wp · 2011-07-05 19:11 Going back to your answer of July 04: yes - I'd like to donate the component once it is finished. There are some issues left, though. Anyway: why should the component be used in the design-time series editor? It is just a supplementary component, e.g. like the TChartLegendPanel. ---------------------------------------------------------------------- Ask · 2011-07-06 05:00 QuoteAnyway: why should the component be used in the design-time series editor? It is not a requirement, of course, but I think it would be logical. See, for example, documentation for similar Delphi/TeeChart component: http://www.berneda.com/TeeChart6Docs/TCHARTLISTBOX.html Note that I am NOT asking you to modify series editor, just to consider it and design your API with this possibility in mind.