[gelöst] TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
[gelöst] TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
Hallo,
in einem bestehendem Programm möchte ich den Range der Y-Achse beim Zoom und Panning entsprechend der Werte des dargestellten X-Bereichs der Serie anpassen.
Hätte ich zum Beispiel eine LineSeries, die hundert Werte hätte und ich hätte gezoomt nur 5 Werte (51, 55, 53, 48, 50) sichtbar, sollte der Range der Y-Achse von 48 bis 55 gehen (entsprechend auch Y gezoomt).
Ich vermute, daß die Funktionalität beim TAChart eingebaut ist, konnte sie aber weder per Internetsuche noch durch Testen herausfinden. Probiert habe ich es mit TChart.LogicalExtent. Da es jedes mal zwei mal angepasst wird, flackert es und Panning geht nicht richtig.
Nun frage ich hier, ob jemand weiß, wie es richtig gemacht wird?
Anbei das kleine Testprogramm, wo ich nicht weiterkomme.
Zweite Frage noch hinten dran. Warum funktionert es nicht, Panning bzw. Zoom abzubrechen, wenn ich Escape drücke? In meiner anderen Anwendung funktionert dies. Soweit ich sehen kann, muss man nur EscapeCancels bei den entsprechenden ChartToolSets setzen.
Windows 7, Lazarus 3.4 (rev lazarus_3_4) FPC 3.2.2 x86_64-win64-win32/win64
in einem bestehendem Programm möchte ich den Range der Y-Achse beim Zoom und Panning entsprechend der Werte des dargestellten X-Bereichs der Serie anpassen.
Hätte ich zum Beispiel eine LineSeries, die hundert Werte hätte und ich hätte gezoomt nur 5 Werte (51, 55, 53, 48, 50) sichtbar, sollte der Range der Y-Achse von 48 bis 55 gehen (entsprechend auch Y gezoomt).
Ich vermute, daß die Funktionalität beim TAChart eingebaut ist, konnte sie aber weder per Internetsuche noch durch Testen herausfinden. Probiert habe ich es mit TChart.LogicalExtent. Da es jedes mal zwei mal angepasst wird, flackert es und Panning geht nicht richtig.
Nun frage ich hier, ob jemand weiß, wie es richtig gemacht wird?
Anbei das kleine Testprogramm, wo ich nicht weiterkomme.
Zweite Frage noch hinten dran. Warum funktionert es nicht, Panning bzw. Zoom abzubrechen, wenn ich Escape drücke? In meiner anderen Anwendung funktionert dies. Soweit ich sehen kann, muss man nur EscapeCancels bei den entsprechenden ChartToolSets setzen.
Windows 7, Lazarus 3.4 (rev lazarus_3_4) FPC 3.2.2 x86_64-win64-win32/win64
- Dateianhänge
-
AutoZoom.zip
- (2.67 KiB) 139-mal heruntergeladen
Zuletzt geändert von Michl am Do 26. Dez 2024, 11:33, insgesamt 1-mal geändert.
Code: Alles auswählen
type
TLiveSelection = (lsMoney, lsChilds, lsTime);
TLive = Array[0..1] of TLiveSelection;
- fliegermichl
- Lazarusforum e. V.
- Beiträge: 1647
- Registriert: Do 9. Jun 2011, 09:42
- OS, Lazarus, FPC: Lazarus Fixes FPC Stable
- CPU-Target: 32/64Bit
- Wohnort: Echzell
Re: TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
Wenn man die ChartTools löscht und die Zuweisung Chart.LogicalExtent := LExtent; auskommentiert, scheint es so zu funktionieren wie gewünscht.
Nur den Zoom zurücksetzen (mit Escape?) hab ich auch nicht hinbekommen.
Nur den Zoom zurücksetzen (mit Escape?) hab ich auch nicht hinbekommen.
Re: TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
Ich verstehe die Anforderung nicht. Du hast einen Datensatz mit 100 Werten, x läuft zwischen 0 und 100, y zwischen 50 und ca 93 (Werte aus deinem Demo-Programm). jetzt willst du zoomen, so dass "nur 5 Werte (51, 55, 53, 48, 50) sichtbar" sind. Sind das Werte auf der x oder der y-Achse? Falls die Werte auf der x-Achse wären (wieso schreibst du sie dann in der ungeordneten Reihenfolge, in der Series sind sie doch sortiert?), soll sich dann die y-Achse so anpassen, dass sie den benötigten Bereich an y-Werten voll abdeckt? Dieselbe Frage wäre dann, wenn die gezoomten Werte auf der y-Achse wären.
Für das ESC muss der Chart fokussiert sein, sonst bekommt er den Tastendruck gar nicht durchgestellt. Am einfachsten setzst du AutoFocus auf true, dann wird der Chart automatisch fokussiert, wenn sich die Maus in den Chart hineinbewegt. Aber: Falls der Chart Bestandteil eines komplizierteren Formulars ist, insbesondere mit Eingabeelemente (TEdit) und der Fokus sitzt auf einem TEdit, dann verliert dieses Edit den Fokus mit der Mausbewegung in den Chart. Ich könnte mir vorstellen, dass das eine Menge Ärger machen kann.
Für das ESC muss der Chart fokussiert sein, sonst bekommt er den Tastendruck gar nicht durchgestellt. Am einfachsten setzst du AutoFocus auf true, dann wird der Chart automatisch fokussiert, wenn sich die Maus in den Chart hineinbewegt. Aber: Falls der Chart Bestandteil eines komplizierteren Formulars ist, insbesondere mit Eingabeelemente (TEdit) und der Fokus sitzt auf einem TEdit, dann verliert dieses Edit den Fokus mit der Mausbewegung in den Chart. Ich könnte mir vorstellen, dass das eine Menge Ärger machen kann.
Re: TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
Jaein. Prinzipiell ist das Standardverhalten fast so, wie ich es wünsche. Ich zoome ein Bereich, wo dann die X- und Y-Achse und die Werte entsprechend gezoomten Fenster darstellen. Leider ist aber ein Zoom möglich, wo Y-Werte außerhalb des Fensters liegen. Daher will ich nur in X-Richtung zoomen können und die Y-Werte sollen den maximalen Chart ausnutzen.fliegermichl hat geschrieben: Mo 23. Dez 2024, 11:53 Wenn man die ChartTools löscht und die Zuweisung Chart.LogicalExtent := LExtent; auskommentiert, scheint es so zu funktionieren wie gewünscht.
Nehme ich an, ich zomme irgendwo und fange dabei 5 Punkte der Series in X-Richtung. Die 5 sichtbaren gezoomten X-Y-Wertepaare wären dann z.B. (10, 51), (11, 55), (12, 53), (13, 48), (14, 50). Also X-Achse läuft von 10 bis 14 und die Y-Achse sollte dann von 48 bis 55 laufen.wp_xyz hat geschrieben: Mo 23. Dez 2024, 13:38 Ich verstehe die Anforderung nicht. Du hast einen Datensatz mit 100 Werten, x läuft zwischen 0 und 100, y zwischen 50 und ca 93 (Werte aus deinem Demo-Programm). jetzt willst du zoomen, so dass "nur 5 Werte (51, 55, 53, 48, 50) sichtbar" sind. Sind das Werte auf der x oder der y-Achse? Falls die Werte auf der x-Achse wären (wieso schreibst du sie dann in der ungeordneten Reihenfolge, in der Series sind sie doch sortiert?), soll sich dann die y-Achse so anpassen, dass sie den benötigten Bereich an y-Werten voll abdeckt? Dieselbe Frage wäre dann, wenn die gezoomten Werte auf der y-Achse wären.
Es soll immer nur per Mausklick und X-Verschiebung gezoomt werden können. Die z.B. fünf Werte, die dann gezoomt dargestellt werden, sollen den Chart in der Höhe (in Y-Richtung) komplett ausfüllen. In meinem kleinen Testprogramm funktionert das ja auch, allerdings nur mit der Verbiegung und dem doppelten Zeichnen. Wenn man den Code Chart.LogicalExtent := LExtent; ausklammert, hat man das Standardverhalten. Wenn man zoomt, füllt der gezoomte Bereich nicht den Chart in der Höhe voll aus, sondern wandert nur irgendwo in der Mitte ein paar Pixel nach oben oder unten.
Als Online-Beispiel geht z.B. der Chart hier https://www.onvista.de/aktien/chart/Deu ... 0005557508. Wenn der Chart gezoomt wird, füllt er die komplette Höhe aus und irgnoriert alle Werte die außerhalb liegen.
Ich denke, es ist ein so banales Feature, daß ich einfach nicht weiß wie es heißt und man es recht einfach zuschalten kann.
Danke. Das ist der Unterschied. In der eigentlichen Anwendung habe ich bei jedem ChartToolSet in OnBeforeMouseDown ein Chart.SetFocus drin. Das habe ich irgendwie ignoriert bei der Suche nach der Ursache. Ich denke, da hast du mir schon mal in der Vergangenheit geholfenwp_xyz hat geschrieben: Mo 23. Dez 2024, 13:38 Für das ESC muss der Chart fokussiert sein, sonst bekommt er den Tastendruck gar nicht durchgestellt.

Code: Alles auswählen
type
TLiveSelection = (lsMoney, lsChilds, lsTime);
TLive = Array[0..1] of TLiveSelection;
Re: TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
Nein, das ist keineswegs banal. Denn jede Änderung des Extent löst wieder ein OnExtentChanged-Event aus, und das ganze wird sehr schnell unübersichtlich. Eigentlich müsste man in die MouseUp-Behandlung des Tools reingehen, da hat man das aktuell aktive Auswahl-Rechteck für den neuen Zoom-Bereich als "SelectionRect" zur Verfügung und könnte angepasst werden, bevor der LogicalExtent geändert wird. Aber hier wird nirgendwo ein Event ausgelöst, so dass man eigenen Code einhängen könnte.Michl hat geschrieben: Mo 23. Dez 2024, 20:36 Ich denke, es ist ein so banales Feature, daß ich einfach nicht weiß wie es heißt und man es recht einfach zuschalten kann.
Ich habe nun in Laz/Main ein neues Event
Code: Alles auswählen
OnCalculateNewExtent(ATool: TChartTool; var ANewExtent: TDoubleRect)
Code: Alles auswählen
procedure TForm1.ChartToolsetZoomDragTool1CalculateNewExtent(ATool: TChartTool;
var ANewExtent: TDoubleRect);
var
newExt: TDoubleRect;
ymin, ymax: Double;
ser: TBasicPointSeries;
i: Integer;
begin
ResetRange(newExt.a.X, newExt.b.X);
ResetRange(newExt.a.Y, newExt.b.Y);
for i := 0 to ATool.Chart.SeriesCount-1 do
if (ATool.Chart.Series[i] is TBasicPointSeries) then
begin
ResetRange(ymin, ymax);
ser := TBasicPointSeries(ATool.Chart.Series[i]);
if ser.IsRotated then
begin
ser.FindYRange(ANewExtent.a.Y, ANewExtent.b.Y, ymin, ymax);
UpdateMinMax(ymin, newExt.a.X, newExt.b.X);
UpdateMinmax(ymax, newExt.a.X, newExt.b.X);
end else
begin
ser.FindYRange(ANewExtent.a.X, ANewExtent.b.X, ymin, ymax);
UpdateMinMax(ymin, newExt.a.Y, newExt.b.Y);
UpdateMinMax(ymax, newExt.a.Y, newExt.b.Y);
end;
end;
if newExt.a.X <> Infinity then ANewExtent.a.X := newExt.a.X;
if newExt.a.Y <> Infinity then ANewExtent.a.Y := newExt.a.Y;
if newExt.b.X <> -Infinity then ANewExtent.b.X := newExt.b.X;
if newExt.b.Y <> -Infinity then ANewExtent.b.Y := newExt.b.Y;
end;
Bin noch nicht ganz sicher, evtl sollte man diesen Code auch gleich mit ins Tool packen und einen neuen Wert für RatioLimit einführen, zrlStretched (wie zrlFixedY, nur halt mit angepasster Y-Scala, bzw. bei vertauschen Achsen wie zrlFixedX mit angepasster X-Scala).
Re: TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
Oha, danke für die Arbeit und das zu Weihnachten! Ich dachte wirklich, das ist von Hause aus implementiert, sofort abrufbar und ich einfach nicht mit den richtigen Begriffen suchfähig bin.
Also ja, ich wäre dafür dieses Feature von Hause aus zur Verfügung zu stellen und ein neuen Wert für RatioLimit einzufügen, wie zrlStretchedY (oder zrlStretchedX)!!
Ich habe Lazarus mal auf den letzten Stand gebracht und mein Projekt entsprechend verändert. Vielen Dank, es funktioniert! Ich habe den Code von meinem vorherigen Testprojekt genommen, da ich nicht weiß, was bei dem von dir geposteteten Code ResetRange macht.
Ein letzten Weihnachtswunsch hätte ich noch. Kannst du das gleiche Event noch beim ChartToolsetPanDragTool einfügen, damit ich auch beim Panning das selbe Verhalten erzielen kann?
Weiß nicht, ob es noch bei anderen ChartTools sinnvoll wäre.
Also ja, ich wäre dafür dieses Feature von Hause aus zur Verfügung zu stellen und ein neuen Wert für RatioLimit einzufügen, wie zrlStretchedY (oder zrlStretchedX)!!
Ich habe Lazarus mal auf den letzten Stand gebracht und mein Projekt entsprechend verändert. Vielen Dank, es funktioniert! Ich habe den Code von meinem vorherigen Testprojekt genommen, da ich nicht weiß, was bei dem von dir geposteteten Code ResetRange macht.
Ein letzten Weihnachtswunsch hätte ich noch. Kannst du das gleiche Event noch beim ChartToolsetPanDragTool einfügen, damit ich auch beim Panning das selbe Verhalten erzielen kann?
Weiß nicht, ob es noch bei anderen ChartTools sinnvoll wäre.
Zuletzt geändert von Michl am Do 26. Dez 2024, 11:21, insgesamt 1-mal geändert.
Code: Alles auswählen
type
TLiveSelection = (lsMoney, lsChilds, lsTime);
TLive = Array[0..1] of TLiveSelection;
Re: TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
Das hatte ich angefangen, aber dann wieder aufgegeben, weil es einen Rattenschwanz von Fallunterscheidungen hinter sich her zieht:Michl hat geschrieben: Di 24. Dez 2024, 14:43 Also ja, ich wäre dafür dieses Feature von Hause aus zur Verfügung zu stellen und ein neuen Wert für RatioLimit einzufügen, wie zrlStretchedY (oder zrlStretchedX)!!
- Wenn mehrere Series im Chart sind, bezieht sich das Stretch meistens auf alle Series, aber vielleicht einmal auch nur auf eine oder zwei Series. Welche?
- Vielleicht will der User die Achse nur bei "schönen" Labels beginnen und enden lassen.
- Ganz unübersichtlich wird es, wenn der Chart mit AutoScaleAxisTransformations in mehrere "Tafeln" eingeteilt ist.
Da stelle ich lieber nur das OnCalculateNewExtent-Event bereit und überlasse dem User die Verantwortung, das Verhalten nach seinen Anforderungen im Event-Handler selbst zu implementieren. Wahrscheinlich überarbeite ich aber dein Beispiel und füge es noch zu den TAChart-Demos [EDIT: erledigt, im Ordner tachart/demo/tools_calculate_new_extent].
Oh, das hatte ich beim Copy&Paste übersehen:Michl hat geschrieben: Di 24. Dez 2024, 14:43 da ich nicht weiß, was bei dem von dir geposteteten Code ResetRange macht.
Code: Alles auswählen
procedure ResetRange(out min, max: Double);
begin
min := Infinity;
max := -Infinity;
end;
OnCalculateNewExtent gibt es nun bei allen Zoom/Drag-Tools. Man kann denselben Event-Handler bei all diesen Tools verwenden.Michl hat geschrieben: Di 24. Dez 2024, 14:43 Kannst du das gleiche Event noch beim ChartToolsetPanDragTool einfügen, damit ich auch beim Panning das selbe Verhalten erzielen kann?
Re: TAChart Zoom Y-Achse entsprechend sichtbarer Werte X-Achse
Super. Funktioniert prima.
In meinem Testprojekt ist nur noch das Einhängen in die Eventhandler OnCalculateNewExtent nötig:
Vielen Dank! Für mich passt das so.
In meinem Testprojekt ist nur noch das Einhängen in die Eventhandler OnCalculateNewExtent nötig:
Code: Alles auswählen
procedure TForm1.ChartToolsetCalculateNewExtent(ATool: TChartTool; var ANewExtent: TDoubleRect);
var
LSeries: TLineSeries;
YMin, YMax: Double;
begin
LSeries := TLineSeries(Chart.Series[0]);
YMin := 1000;
YMax := -1000;
LSeries.FindYRange(ANewExtent.a.X, ANewExtent.b.X, YMin, YMax);
ANewExtent.a.Y := YMin;
ANewExtent.b.Y := YMax;
end;
- Dateianhänge
-
AutoZoomNeu.zip
- (2.45 KiB) 124-mal heruntergeladen
Code: Alles auswählen
type
TLiveSelection = (lsMoney, lsChilds, lsTime);
TLive = Array[0..1] of TLiveSelection;