Forum > TAChart

Resizable panes again

(1/5) > >>

kapibara:
Based on the example with resizable panes we had earlier, I wanted to add the panes to the chart so they always appear below existing panes.

https://forum.lazarus.freepascal.org/index.php/topic,45989.0.html

Solution below rearranges existing axises and dividers when a new pane is added. It works until I start resizing the panes by moving the divider.

Problem is that since the order of appearance is now swapped upside down, the code you wrote in DataPointDragToolDrag needs to be rewritten.

I tried all day but didn't manage to swap it. Comes out a little wrong whatever I do.
Plus when adding a pane, it gets a few pixels too much height as seen on attached picture.

Here's the code I use for rearranging existing panes when adding new ones:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TChartPanes.ConfigureAxisTransformations(var AChartPane: TChartPane);var  i:Integer;begin  if Self.Count < 1 then  begin    aChartPane.AxisTransform.MinValue:= HALF_GAP;    aChartPane.AxisTransform.MaxValue:= 1.85;  end else  begin    { Shift all panes one step up }    { to make room for new pane on the bottom }    for i:= 0 to Count -1 do    begin      Items[i].AxisTransform.MinValue:=        Items[i].AxisTransform.MaxValue + 0.30;       Items[i].AxisTransform.MaxValue:=        Items[i].AxisTransform.MaxValue + 1.70;       If Assigned(Items[i].Divider) then        Items[i].Divider.Position:=          Items[i].AxisTransform.MaxValue + HALF_GAP;    end;     aChartPane.AxisTransform.MinValue:= HALF_GAP;    aChartPane.AxisTransform.MaxValue:= 1.85;     //Create Pane Divider and set Divider.Position    aChartPane.Divider:= TConstantLine.Create(FChart);    aChartPane.Divider.Position:=      Items[Count -1].AxisTransform.MinValue - HALF_GAP;     FChart.AddSeries(aChartPane.Divider);  end;end; 
Lots of commenting while trying to rewrite the DragToolDrag procedure. If any comments are wrong, please tell.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TChartPanes.DataPointDragToolDrag(ASender: TDataPointDragTool;  var AGraphPoint: TDoublePoint);const  MIN_SIZE = 0.5;  // Min size of a pane, avoid div by zerovar  pos, lowerPos, upperPos: Double;  ser: TConstantLine;  ex: TDoubleRect;  PaneIndex: Integer;  pane_above, pane_below: TChartPane;begin  if not (TDataPointTool(ASender).Series is TConstantLine) then exit;   ser := TConstantLine(TDataPointDragTool(ASender).Series);  ex := ser.ParentChart.GetFullExtent;   //Panes that are added later will always  //appear below panes that were added earlier.  //TChartPanes.ConfigureAxisTransformations arranges this.   //PaneIndex will always be at least 1 because the  //first pane, (PaneIndex 0) never has a divider  PaneIndex := GetPaneIndexOfDivider(ser);   //pane_above will always be 1 count less than  //pane_below because it is added before pane_below  pane_above := GetChartPane(PaneIndex -1);   //pane_below is the pane that the divider belongs to  pane_below := GetChartPane(PaneIndex);   //There is nothing to divide with only one pane.  //So there exists no dividers until more than one  //pane is created, PaneIndex will thus always be  //at least 1. Also, Count-1 will be at least 1  //because this procedure never runs until there  //are at least two panes.   //Calculates upper position of pane_below  if PaneIndex < Count-1 then    upperPos := GetChartPane(PaneIndex +1).Divider.Position              - MIN_SIZE - HALF_GAP  else    upperPos := ex.b.y - MIN_SIZE - HALF_GAP;   //Calculates lower position of pane_above  if PaneIndex = 1 then    lowerPos := ex.a.y + MIN_SIZE + HALF_GAP  else    lowerPos := GetChartPane(PaneIndex -1).Divider.Position              + MIN_SIZE + HALF_GAP;   //Ensures that the Y-axises of both pane_above and  //pane_below are within their designated chart areas  AGraphPoint.Y := EnsureRange(AGraphPoint.Y, lowerPos, upperPos);   //Adjusts axises of both panes using the values collected  //from calculations above  pane_above.AxisTransform.MaxValue := AGraphPoint.Y - HALF_GAP;  pane_below.AxisTransform.MinValue := AGraphPoint.Y + HALF_GAP;   //Adjust divider position  ser.Position := AGraphPoint.Y;end; 
Small demo attached.

wp:
Nice example.

Rather than rearranging the existing series and their transformations when a new pane is added at the bottom I thought it would be easier to introduce a PaneIndex which can grow from the center value (0) in both directions. This automatically allows to add panes above and below the existing stack without having to rearrange the Transformation's MinValue and Maxvalue. So, the first pane gets the PaneIndex 0, and when I add another pane on top of it the new pane has the PaneIndex 1 etc. When I add another pane below the center pane its Pane Index will be -1, etc. Of course, do not confuse the PaneIndex with the normal index into the panes FPList running between 0 and Count-1.

The draggable divider lines sit at the edges of the panes. The pane with PageIndex 0 has no divider. All other panes contain one divider. The panes above it (PaneIndex > 0) have their dividers at their bottom edge, the panes below it (PaneIndex < 0) have their dividers at their top edge. Panes with PaneIndex > 0 have the transformation.MinValue a HALF_GAP higher than the divider position, the Transformation.MaxValue is a HALF_GAP lower than the upper edge of the pane. Panes with PaneIndex < 0 thave the transformation MaxValue lower than the divider position by a HALF_GAP, and the MinValue is higher than the lower end of the pane by HALF_GAP.

Please have a look at the attached modified version of you sample.

kapibara:
The PaneIndex is a great idea. I actually hoped you would come up with something better than my rearranging of axises. :D

I noticed though, that left axises now overlap with a HALF_GAP or two in height.
(Axises overwrite each other slightly in the adjacent area, see pic.)
I tried to modify the code in ConfigureAxisTransformation, but had no immediate success.

I'll go over the new code now to understand how everything works.

wp:
Increase the HALF_GAP to 0.1. With such a value it looks better. Alternatively you can reactivate the line APane.Axis.Marks.AtDataOnly := true in TChartPanes.AssignAxisToPane.

To avoid the jitter of the left axis when the axis label values change due to pane resizing, you can set APane.Axis.LabelSize to a reasonably large value (like: 50) in TChartPanes.AssignAxisToPane (it depends on the length of the labels and the presence of an axis title). To avoid jumping of the axis when panes are added for the first time you should use the same value in the object inspector for the chart's LeftAxis.

kapibara:
Increasing HALF_GAP to 0.1 took care of the overlapping. Thanks!

Although, I see now, the first added pane is now initially larger than panes added later.

Also, is it possible to remove the jitter at the top of the chart when resizing a topmost pane?

Navigation

[0] Message Index

[#] Next page

Go to full version