Lazarus

Programming => General => Topic started by: munair on August 12, 2019, 05:11:44 pm

Title: [SOLVED] How to get min-max values of zoomed TAChart bottom-axis
Post by: munair on August 12, 2019, 05:11:44 pm
I have a TAChart with zoom tool attached to it. The bottom axis values are dates. When zooming into a specific part of the chart, is it possible to get the first and last date of the zoomed part so that they can be displayed in a separate label?
Title: Re: How to get min-max values of zoomed TAChart bottom-axis
Post by: munair on August 12, 2019, 10:36:35 pm
As I had to do a quick job on this one, I came up with a dirty hack, but at least it works. If anybody knows a more elegant way (e.g. accessing marks by index), please let me know.
Code: Pascal  [Select][+][-]
  1. // ..
  2. Marking: boolean;
  3. FirstMark, LastMark: double;
  4. // ...
  5. procedure TfrmMain.Chart1AfterDraw(ASender: TChart; ADrawer: IChartDrawer);
  6. begin
  7.   lbSelectedTimeValue.Caption := FormatDateTime('YYYY-MM-DD, hh:nn', FirstMark)
  8.     + ' - ' + FormatDateTime('YYYY-MM-DD, hh:nn', LastMark);
  9.   Marking := false;
  10. end;
  11.  
  12. procedure TfrmMain.Chart1AxisList1MarkToText(var AText: String; AMark: Double);
  13. begin
  14.   if Marking = false then
  15.     begin
  16.       FirstMark := AMark;
  17.       Marking := true;
  18.     end
  19.   else
  20.     LastMark := AMark;
  21. end;
Title: Re: [SOLVED] How to get min-max values of zoomed TAChart bottom-axis
Post by: wp on August 13, 2019, 12:10:23 am
You mean the first and last axis labels? Hmmm, I don't know a better solution.
Title: Re: [SOLVED] How to get min-max values of zoomed TAChart bottom-axis
Post by: munair on August 13, 2019, 06:31:35 am
Yes, first and last axis label, so that when zoomed in to a level of only days/hours, the full date range can still be displayed.

Example: https://twitter.com/ditrianum/status/1161131417604100096/photo/1 (https://twitter.com/ditrianum/status/1161131417604100096/photo/1)
Title: Re: [SOLVED] How to get min-max values of zoomed TAChart bottom-axis
Post by: wp on August 13, 2019, 10:11:48 am
Hmmm.... When you want to display information on the visible viewport, wouldn't it be better to use the "true" begin and end of the axis? The position of the axis labels is not under your full control, and depending on the label density the first label may be placed after the first data point.

In order to get the "true" zoomed axis range you can call Chart.CurrentExtent (https://wiki.lazarus.freepascal.org/TAChart_documentation#Extents) which is a rectangle structure with TDoublePoint records a and b at the left/bottom and right/top corners, respectively. There is also a LogicalExtent which does not consider Margins and data point labels; this is essentially the zoomed rectangle, but I think you need the CurrentExtent here. The begin and end of the x axis, therefore, can be determined like this:

Code: Pascal  [Select][+][-]
  1. procedure GetXAxisRange(Chart: TChart; out FirstX, LastX: double);
  2. var
  3.   ex: TDoubleRect;  // requires TAChartUtils in "uses"
  4. begin
  5.   ex := Chart.CurrentExtent;
  6.   FirstX := ex.a.x;
  7.   LastX := ex.b.x;
  8. end;

Of course, you still must convert FirstX and LastX to date/time strings as needed.

You can call this function in the OnExtentChanged event of the Chart.
Title: Re: [SOLVED] How to get min-max values of zoomed TAChart bottom-axis
Post by: munair on August 13, 2019, 11:24:06 am
Thanks wp, I'll give that a try.
Title: Re: [SOLVED] How to get min-max values of zoomed TAChart bottom-axis
Post by: munair on August 13, 2019, 11:47:29 am
YES. Works much better. The range is more accurate and when zooming/panning, it is updated down to the second. To illustrate this, the data set starts on August 1 at 20:12, which is returned by the CurrentExtent approach. My initial solution returns July 31, 0:00.
Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.Chart1ExtentChanged(ASender: TChart);
  2. begin
  3.   GetXAxisRange(ASender, FirstMark, LastMark);
  4.   lbSelectedTimeValue.Caption := FormatDateTime('YYYY-MM-DD, hh:nn', FirstMark)
  5.     + ' - ' + FormatDateTime('YYYY-MM-DD, hh:nn', LastMark);
  6. end;
TinyPortal © 2005-2018