Forum > TAChart
Resizable panes again
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