TAChartImageList lazarus / 55-TAChart ---------------------------------------------------------------------- wp · 2011-10-30 11:49 Sometimes it is necessary to have access to the legend images of a chart's series for displaying series information in listviews, treeviews etc. We already have a ChartListbox in the library, but this quite specialized. Therefore, I decided to extract the image creation code and put it into an ImageList. The image list is populated by assigning its "Chart" property accordingly. The image list can be used also for usual toolbar and menu icons, but make sure to have the chart unassigned when manually adding images. Otherwise image indices will change if additional series are added to the chart at run-time. Two demo programs are added to show this new component. Use the run- time project first - it does not require an installation into the TAChart package. The component uses features added to TAChart recently. So it requires one of the more recent svn snapshots to compile. I would be glad if this component could be added to the TAChart library. I'll need it for the next component that I am currently working on, a TChartGrid. ---------------------------------------------------------------------- Ask · 2011-10-30 16:33 First, thanks for your continued contributions. QuoteI decided to extract the image creation code and put it into an ImageList.This is sensible plan. Before applying your code I'd like to think a little about design: 1) Copying series icons as bitmaps seems a bit wasteful, I would prefer some kind of "virtual image list", where the icons are drawn directly when needed. This would also solve the problems with non-chart images, image storing and series updating. Unfortunately, it seems that TCustomImageList has no provision for such virtualization. So we are out of luck here. 2) I have minor doubts about OnPopulate event -- it is called whenever the chart broadcasts a change, so anybody handling this event cold just subscribe to the broadcast? 3) Can you describe what behavior FirstSeriesIndex/SeriesCount are aimed to achieve? For example, adding new image directly, then adding a new series will move the series images to the end of the list -- is it intended? 4) Since you are contributing a lot of code, I would appreciate if you would format it in TAChart style, in particular with spaces after, but not before the colons in variable declarations. QuoteI am currently working on, a TChartGridThis is great news, I did contemplate something in this direction. However, since this component is more complex than your previous contributions, please let's discuss the design in advance. I see several options for implementing chart-grid connection: 1) Implement TListSourceDataset and use standard DBGrid 2) Put chart data in TSdfDataset, then use TDbChartSource for chart and standard DBGrid -- this is already possible now 3) Implement ExportToGrid/ImportFromGrid methods in chatrSource and/or chart and let the user call them when needed 4) Implement TGridChartSource and use it to get chart data from the grid 5) Implement TChartSourceLink/TChartGridLink which syncronizes data between the chart and the grid 6) Implement TChartGrid as a descendant of TStringGrid 7) Implement the grid *inside* the chart. This may allow to synchronize the grid with the chart axis. Maybe you plan something else? Those methods are not mutually exclusive, but I would like to make informed choice among them. ---------------------------------------------------------------------- wp · 2011-10-30 17:39 QuoteI have minor doubts about OnPopulate event -- it is called whenever the chart broadcasts a change, so anybody handling this event cold just subscribe to the broadcast? Isn't this a problem of many event handlers, that somebody could do something stupid? BTW: I think we have that same construction in TChartListbox. QuoteCan you describe what behavior FirstSeriesIndex/SeriesCount are aimed to achieve? This provides a mechnism to protect the non-series images from deletion when the ImageList is repopulated due to broadcast. See ClearAllSeries. Quoteadding new image directly, then adding a new series That's what I tried to describe in the unit header - you just shouldn't do that... I know this is a bit cumbersome, and to my excuse I can say that the ImageList was intentionally intended to provide series images only, but then it came to my mind that it could support regular images also. QuoteMaybe you plan something else? The TChartGrid is a TDrawGrid descendant with specialized columns for the series data, no intermediate classes. The columns interface to the series data directly, no additional storage of the cell texts. So far, the grid is working fine with some minor bugs to be fixed and features to be added. QuoteI would appreciate if you would format it in TAChart style, in particular with spaces after, but not before the colons in variable declarations. I'll try to adhere to that. Anything else to consider? ---------------------------------------------------------------------- Ask · 2011-11-02 06:29 Sorry for the delay. Unfortunately, my Lazarus time is extremely limited now. I still have some plans to update it's API, especially the part about manual image adding, but I have no time now. I have committed your code with only code style changes in r33213 so as to not hold your development efforts. In addition to my previous comments, I have noticed the following: * TChartImageList.WriteData will delete series images and not add them back * heaptrc reports memory leak in TChartImageList QuoteI'll try to adhere to that. Anything else to consider?I started the documentation: http://wiki.lazarus.freepascal.org/TAChart_documentation#Coding_style ---------------------------------------------------------------------- wp · 2011-11-02 08:05 QuoteI have committed your code Thank you. QuoteTChartImageList.WriteData will delete series images and not add them back That's intended. The images are created automatically when the chart is assigned. With the inherited WriteData method every series image will be in the image list twice. ---------------------------------------------------------------------- Ask · 2011-11-02 10:09 QuoteThat's intended. The images are created automatically when the chart is assigned. With the inherited WriteData method every series image will be in the image list twice. I understand that. However, immediately after the WriteData call, the chart will be assigned, but the images will be absent. In other words, I think that "FChart := ch" assignment should be replaced by "Chart := ch". ---------------------------------------------------------------------- wp · 2011-11-02 11:18 You are right. ---------------------------------------------------------------------- wp · 2011-11-02 11:48 Coming back to your suggestions for my work on TChartGrid, let me ask a question on the design of the TAChart library. The ChartGrid, as it is being implemented now, will get its data directly from the ChartSource of the series. This means that the series must inherit from TChartSeries at least since it is the first series class that has a ChartSource; its predecessors, TCustomChartSeries and TBasicChartSeries will not work, and I will be raising an exception to prevent using them with TChartGrid. Of course, direct descendants of TCustomChartSeries and TBasicChartSeries will have access to their data in some kind as well. So if I'd want to allow these series in the TChartGrid I'd have to write some kind of interfacing class, such as a "TSeriesColumnLink" which transfers the data from the series to the grid column. But is this really necessary? As far as I can overlook the library all series inherit from TChartSeries. Will the entire library work with non-TChartSeries at all? ---------------------------------------------------------------------- Ask · 2011-11-02 11:50 Quote* TChartImageList.WriteData will delete series images and not add them back * heaptrc reports memory leak in TChartImageList Fixed both problems in r33217 ---------------------------------------------------------------------- wp · 2011-11-02 12:05 QuoteFixed both problems in r33217 Thank you - you are faster than the speed of light... ---------------------------------------------------------------------- Ask · 2011-11-02 13:41 Quoteall series inherit from TChartSeriesAt least TFuncSeries, TConstantLineSeries and TColorMapSeries do not. I am not strictly against your design, but IMHO a TChartGridLink component would have some advantages -- for example, it can potentially work with any TDrawGrid descendant. Such component may have: 1) "Direction" property, indicating either row-per-series or column- per-series 2) "SeriesLinks" property, which would be a collection of TSeriesGridLink objects 3) Some properties to specify if and how per-series legend is displayed 4) Some properties to specify what is displayed in the column/row headers 5) Some properties to synchronize grid position with chart extent TSeriesGridLink object may have: 1) SeriesIndex and GridIndex properties 2) Some properties to specify how data values are displayed   (either using series format or a separate format) 3) Some properties to specify if and how per-data item legend is displayed ---------------------------------------------------------------------- wp · 2011-11-02 15:55 Most of the properties that you mention are added to descendants of TGridColumn and TGridColumns which are available already in the most basic grid, TCustomGrid (--> TChartGridColum). Each TChartGridColumn displays data from a special data element of each series (property Kind = ckX, ckY, ckYIndex, ckText, ckMark). There is also a NumFormat property to format numbers in a special way. I see a need for a link component only with respect to data transfer. Since my design is column-based, the "Direction" property - to draw data in rows -, however, is difficult to accomplish. After fixing some remaining bugs, I'll just post my current version in the next days for you to have a look. ---------------------------------------------------------------------- wp · 2011-11-04 09:52 QuoteCopying series icons as bitmaps seems a bit wasteful, I would prefer some kind of "virtual image list", where the icons are drawn directly when needed. This would also solve the problems with non- chart images, image storing and series updating. Unfortunately, it seems that TCustomImageList has no provision for such virtualization. So we are out of luck here. Instead of using the local variable "legendItems" in the "Populate" method we could store the legend items permanently in a member FLegendItems of TChartImageList. Then we could override the DrawXXXX and GetBitmap methods of the TImageList by directly calling the drawing routines of the LegendItems, either by painting directly on the provided canvas or on that of temporary bitmaps. Also, normal icons and series icons would be separated because adding the former ones would go into the inherited ImageList while the latter ones would go into the FLegendIems. Unfortunately, the DrawXXXX methods are not virtual, but my impression is that they are not called internally. Another obstacle might be that the drawing methods use some GraphicsDrawEffects which are obained from the widgetset. So far, I don't know how to access these directly. Would that work? Also, I have the impression that this is quite some overhead which easily might eat up the memory benefits for saving a few bitmaps. ---------------------------------------------------------------------- Ask · 2011-11-04 11:44 Quotewe could override the DrawXXXX and GetBitmap methods Yes, this was my first idea too. Unfortunately, there are also GetRawImage and GetFullRawImage which are not virtual too. I think the correct design should be: keep TCustomImageList as an interface class, declare all relevant functions virtual, and introduce an additional class between TCustomImageList and TImageList. I'll ask on the mailing list, but I am afraid the compatibility reasons may prevent such a change. Quotequite some overhead which easily might eat up the memory benefits for saving a few bitmapsI am worried not so much about memory consumption, but about the fact that bitmaps will be deleted and recreated on every series update, for example on adding the data point. ---------------------------------------------------------------------- wp · 2011-11-04 14:31 Quotethe fact that bitmaps will be deleted and recreated on every series update, for example on adding the data point. Wouldn't it help if the broadcaster had information on the reason for the update? All broadcasts due to adding points can be ignored by the TChartImageList. ---------------------------------------------------------------------- Ask · 2011-11-06 19:42 QuoteWouldn't it help if the broadcaster had information on the reason for the update?Yes, it would -- as I said sometime ago, current broadcast system is very basic and has much room for improvement.