Recent

Author Topic: TChartAxis.LabelSize  (Read 1897 times)

piola

  • Full Member
  • ***
  • Posts: 118
  • Lazarus 2.2, 64bit on Windows 8.1 x64
TChartAxis.LabelSize
« on: July 29, 2019, 09:31:01 pm »
Dear all,

I have two (or more) charts that I want to be displayed above each other (stacked). By default, the frames have different widths, depending on the length of axis labels. I found the "axisalign" demo and the LabelSize property which basically solves this problem.

However, there is a new issue now: The documentation says:

Quote
if different from 0 - overrides the automatic calculation of the space needed by the axis marks

Unfortunately I found nothing about how to get the value that would be used for LabelSize=0. For the perfect layout, I would need the maximum of the individual chart's automatic LabelSize. How can I determine that?

Kind regards

piola

  • Full Member
  • ***
  • Posts: 118
  • Lazarus 2.2, 64bit on Windows 8.1 x64
Re: TChartAxis.LabelSize
« Reply #1 on: August 13, 2019, 09:19:56 pm »
I hope I have resolved the problem with the following code:

Code: [Select]
TYPE
  TChartAxisHelper = CLASS HELPER FOR TChartAxis
    PRIVATE FUNCTION GetAutoLabelSize: Integer;
    PUBLIC PROPERTY AutoLabelSize: Integer READ GetAutoLabelSize;
  END;

FUNCTION TChartAxisHelper.GetAutoLabelSize: Integer;

  VAR
    sz: Integer;
    v: Boolean;
    d: IChartDrawer = NIL;
    mv: TChartValueTextArray = NIL;
    i: Integer;

  BEGIN
    v := Self.IsVertical;
    d := TChart(Self.GetChart).Drawer;
    SetLength (mv, Self.ValueCount);
    FOR i := 0 TO (Self.ValueCount-1) DO mv[i] := Self.Value[i];
    sz := Self.Marks.Measure (d, NOT v, Self.TickLength, mv);
    Result := Round (sz / d.Scale(1));
  END;

It would however be helpful if the default LabelSize value could be queried in an upcoming version of TAChart.

wp

  • Hero Member
  • *****
  • Posts: 11855
Re: TChartAxis.LabelSize
« Reply #2 on: August 13, 2019, 11:41:51 pm »
Thank you. Nice code! I used the basic idea in a function TChartAxis.MeasureLabelSize (--> r61690). However, I removed the d.Scale(1) because you normally would pass the function result directly to the LabelSize property which is in "image" units (not "device" units which are obtained by dividing by d.Scale(1)).

Moreover, I added a new property "AlignSides" (a set of calLeft, calRight, calBottom, calTop) to the TChartExtentLink. You can add several charts to its "LinkedCharts" property. When, for example, calLeft is added to "AlignSides" then the MeasureLabelSize function is called for the left axes of the linked charts; the maximum value is calculated and applied to the "LabelSize" properties of these axes. This way all left sides of the linked charts are automatically aligned (of course, it is assumed that the charts themselves have the same width and their left sides are aligned). Turn off "Enabled" if you do not want to sync an axis range. For simplicity I considered only the case that there is only a single axis per side; a second left axis would be ignored; I think the algorithm can be extended if needed.
« Last Edit: August 14, 2019, 11:00:30 am by wp »

piola

  • Full Member
  • ***
  • Posts: 118
  • Lazarus 2.2, 64bit on Windows 8.1 x64
Re: TChartAxis.LabelSize
« Reply #3 on: August 15, 2019, 09:52:20 pm »
I removed the d.Scale(1) because you normally would pass the function result directly to the LabelSize property which is in "image" units (not "device" units which are obtained by dividing by d.Scale(1)).

Yes, I was not sure about this point. The code for assigning LabelSize contains this:

Code: [Select]
if FLabelSize = 0 then
    // Default distance (= length of marks)
    sz := Marks.Measure(d, not v, TickLength, FMarkValues)
  else
    // User-defined distance
    sz := d.Scale(FLabelSize);

So my reading was that when assigning a value it will get scaled whereas the computed value seems to already be scaled. And as I have to explicitly assign LabelSize to all charts affected, I thought that I have to avoid duplicate scaling.

wp

  • Hero Member
  • *****
  • Posts: 11855
Re: TChartAxis.LabelSize
« Reply #4 on: August 15, 2019, 11:54:06 pm »
I think your original code was correct, and I updated the commit. Marks.Measure is normally called during the painting process where all image coordinates are scaled to device coordinates, and thus returns device coordinates. But the new function MeasureLabelSize is called outside the painting process and must return image coordinates - therefore you were correct to apply an inverse scaling operation.

piola

  • Full Member
  • ***
  • Posts: 118
  • Lazarus 2.2, 64bit on Windows 8.1 x64
Re: TChartAxis.LabelSize
« Reply #5 on: August 17, 2019, 12:29:59 pm »
Thank you for the extension of TChartExtentLink which I am currently testing now. This is a very useful feature.

I have one small suggestion: Now that one can use the ChartExtentLink also to only align charts, maybe there should be an additional mode "elmNone". This way all axes would be independent, but charts could still be aligned next to or above each other.

wp

  • Hero Member
  • *****
  • Posts: 11855
Re: TChartAxis.LabelSize
« Reply #6 on: August 17, 2019, 12:39:05 pm »
maybe there should be an additional mode "elmNone". This way all axes would be independent, but charts could still be aligned next to or above each other.
Isn't this the same as setting "Enabled" to false? I do reckognize that the component usage is a bit diffuse now...

piola

  • Full Member
  • ***
  • Posts: 118
  • Lazarus 2.2, 64bit on Windows 8.1 x64
Re: TChartAxis.LabelSize
« Reply #7 on: August 18, 2019, 03:13:33 am »
Isn't this the same as setting "Enabled" to false? I do reckognize that the component usage is a bit diffuse now...

Ah, ok, I missed that, thank you.

While using your new "AlignSides" implementation, I have found some minor issues:

a) procedure TChartExtentLink.AddChart(AChart: TChart);

The last line should be "DoAlignSides".

Reason: When using the chart extent link programmatically, aligning sides doesn't work when setting "AlignSides" first, and adding charts afterwards.

b) procedure TChartExtentLink.SyncWith(AChart: TChart);

The last line should be "DoAlignSides".

Reason: When changing the extent, labels of one or more of the affected charts could become larger or smaller. For example, an axis may be scaled from 0 to 5 first, then changed from 0 to 100. The last label "100" takes more space than "5".

wp

  • Hero Member
  • *****
  • Posts: 11855
Re: TChartAxis.LabelSize
« Reply #8 on: August 18, 2019, 10:59:51 am »
Done.

 

TinyPortal © 2005-2018