mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-18 03:39:21 +02:00
TAChart: Add axis transformations and ability to bind series to axises.
This implements most of the issue #13832, although the interface is very crude yet. git-svn-id: trunk@23217 -
This commit is contained in:
parent
388cebcf91
commit
53892fe909
@ -69,6 +69,44 @@ type
|
|||||||
property Style default psDot;
|
property Style default psDot;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TChartAxisTransformation }
|
||||||
|
|
||||||
|
TChartAxisTransformation = class (TPersistent)
|
||||||
|
private
|
||||||
|
FOnChanged: TNotifyEvent;
|
||||||
|
procedure SetOnChanged(const AValue: TNotifyEvent);
|
||||||
|
protected
|
||||||
|
procedure Changed;
|
||||||
|
public
|
||||||
|
function AxisToGraph(AX: Double): Double; virtual;
|
||||||
|
function GraphToAxis(AX: Double): Double; virtual;
|
||||||
|
|
||||||
|
property OnChanged: TNotifyEvent read FOnChanged write SetOnChanged;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TChartAxisLogLinearTransformation }
|
||||||
|
|
||||||
|
TChartAxisLogLinearTransformation = class (TChartAxisTransformation)
|
||||||
|
private
|
||||||
|
FLogarithmic: Boolean;
|
||||||
|
FOffset: Double;
|
||||||
|
FScale: Double;
|
||||||
|
procedure SetLogarithmic(AValue: Boolean);
|
||||||
|
procedure SetOffset(AValue: Double);
|
||||||
|
procedure SetScale(AValue: Double);
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
public
|
||||||
|
procedure Assign(Source: TPersistent); override;
|
||||||
|
|
||||||
|
function AxisToGraph(AX: Double): Double; override;
|
||||||
|
function GraphToAxis(AX: Double): Double; override;
|
||||||
|
published
|
||||||
|
property Logarithmic: Boolean read FLogarithmic write SetLogarithmic default false;
|
||||||
|
property Offset: Double read FOffset write SetOffset;
|
||||||
|
property Scale: Double read FScale write SetScale;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TChartAxis }
|
{ TChartAxis }
|
||||||
|
|
||||||
TChartAxis = class(TCollectionItem)
|
TChartAxis = class(TCollectionItem)
|
||||||
@ -86,6 +124,7 @@ type
|
|||||||
FTickColor: TColor;
|
FTickColor: TColor;
|
||||||
FTickLength: Integer;
|
FTickLength: Integer;
|
||||||
FTitle: TChartAxisTitle;
|
FTitle: TChartAxisTitle;
|
||||||
|
FTransformation: TChartAxisLogLinearTransformation;
|
||||||
FVisible: Boolean;
|
FVisible: Boolean;
|
||||||
|
|
||||||
procedure SetAlignment(AValue: TChartAxisAlignment);
|
procedure SetAlignment(AValue: TChartAxisAlignment);
|
||||||
@ -97,6 +136,7 @@ type
|
|||||||
procedure SetTickColor(AValue: TColor);
|
procedure SetTickColor(AValue: TColor);
|
||||||
procedure SetTickLength(AValue: Integer);
|
procedure SetTickLength(AValue: Integer);
|
||||||
procedure SetTitle(AValue: TChartAxisTitle);
|
procedure SetTitle(AValue: TChartAxisTitle);
|
||||||
|
procedure SetTransformation(AValue: TChartAxisLogLinearTransformation);
|
||||||
procedure SetVisible(const AValue: Boolean);
|
procedure SetVisible(const AValue: Boolean);
|
||||||
|
|
||||||
procedure StyleChanged(ASender: TObject);
|
procedure StyleChanged(ASender: TObject);
|
||||||
@ -130,6 +170,8 @@ type
|
|||||||
property TickLength: Integer
|
property TickLength: Integer
|
||||||
read FTickLength write SetTickLength default DEF_TICK_LENGTH;
|
read FTickLength write SetTickLength default DEF_TICK_LENGTH;
|
||||||
property Title: TChartAxisTitle read FTitle write SetTitle;
|
property Title: TChartAxisTitle read FTitle write SetTitle;
|
||||||
|
property Transformation: TChartAxisLogLinearTransformation
|
||||||
|
read FTransformation write SetTransformation;
|
||||||
property Visible: Boolean read FVisible write SetVisible default true;
|
property Visible: Boolean read FVisible write SetVisible default true;
|
||||||
published
|
published
|
||||||
property OnMarkToText: TChartAxisMarkToTextEvent
|
property OnMarkToText: TChartAxisMarkToTextEvent
|
||||||
@ -245,11 +287,14 @@ begin
|
|||||||
FTickColor := clBlack;
|
FTickColor := clBlack;
|
||||||
FTickLength := DEF_TICK_LENGTH;
|
FTickLength := DEF_TICK_LENGTH;
|
||||||
FTitle := TChartAxisTitle.Create(ACollection.Owner as TCustomChart);
|
FTitle := TChartAxisTitle.Create(ACollection.Owner as TCustomChart);
|
||||||
|
FTransformation := TChartAxisLogLinearTransformation.Create;
|
||||||
|
FTransformation.OnChanged := @StyleChanged;
|
||||||
FVisible := true;
|
FVisible := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TChartAxis.Destroy;
|
destructor TChartAxis.Destroy;
|
||||||
begin
|
begin
|
||||||
|
FTransformation.Free;
|
||||||
FTitle.Free;
|
FTitle.Free;
|
||||||
FGrid.Free;
|
FGrid.Free;
|
||||||
inherited;
|
inherited;
|
||||||
@ -265,7 +310,7 @@ procedure TChartAxis.Draw(
|
|||||||
sz: TSize;
|
sz: TSize;
|
||||||
markText: String;
|
markText: String;
|
||||||
begin
|
begin
|
||||||
x := ATransf.XGraphToImage((AMark - Offset) / Scale);
|
x := ATransf.XGraphToImage(Transformation.AxisToGraph(AMark));
|
||||||
|
|
||||||
if Grid.Visible then begin
|
if Grid.Visible then begin
|
||||||
ACanvas.Pen.Assign(Grid);
|
ACanvas.Pen.Assign(Grid);
|
||||||
@ -297,7 +342,7 @@ procedure TChartAxis.Draw(
|
|||||||
markText: String;
|
markText: String;
|
||||||
sz: TSize;
|
sz: TSize;
|
||||||
begin
|
begin
|
||||||
y := ATransf.YGraphToImage((AMark - Offset) / Scale);
|
y := ATransf.YGraphToImage(Transformation.AxisToGraph(AMark));
|
||||||
|
|
||||||
if Grid.Visible then begin
|
if Grid.Visible then begin
|
||||||
ACanvas.Pen.Assign(Grid);
|
ACanvas.Pen.Assign(Grid);
|
||||||
@ -394,8 +439,8 @@ end;
|
|||||||
|
|
||||||
function TChartAxis.GetMarks(AMin, AMax: Double): TDoubleDynArray;
|
function TChartAxis.GetMarks(AMin, AMax: Double): TDoubleDynArray;
|
||||||
begin
|
begin
|
||||||
AMin := AMin * Scale + Offset;
|
AMin := Transformation.GraphToAxis(AMin);
|
||||||
AMax := AMax * Scale + Offset;
|
AMax := Transformation.GraphToAxis(AMax);
|
||||||
if AMin > AMax then
|
if AMin > AMax then
|
||||||
Exchange(AMin, AMax);
|
Exchange(AMin, AMax);
|
||||||
Result := GetIntervals(AMin, AMax, Inverted);
|
Result := GetIntervals(AMin, AMax, Inverted);
|
||||||
@ -550,6 +595,14 @@ begin
|
|||||||
StyleChanged(Self);
|
StyleChanged(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TChartAxis.SetTransformation(
|
||||||
|
AValue: TChartAxisLogLinearTransformation);
|
||||||
|
begin
|
||||||
|
if FTransformation = AValue then exit;
|
||||||
|
FTransformation.Assign(AValue);
|
||||||
|
StyleChanged(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TChartAxis.SetVisible(const AValue: Boolean);
|
procedure TChartAxis.SetVisible(const AValue: Boolean);
|
||||||
begin
|
begin
|
||||||
if FVisible = AValue then exit;
|
if FVisible = AValue then exit;
|
||||||
@ -610,5 +663,87 @@ begin
|
|||||||
a.FAlignment := AXIS_INDEX[AIndex];
|
a.FAlignment := AXIS_INDEX[AIndex];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TChartAxisTransformation }
|
||||||
|
|
||||||
|
function TChartAxisTransformation.AxisToGraph(AX: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := AX;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TChartAxisTransformation.Changed;
|
||||||
|
begin
|
||||||
|
if Assigned(FOnChanged) then
|
||||||
|
FOnChanged(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TChartAxisTransformation.GraphToAxis(AX: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := AX;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TChartAxisTransformation.SetOnChanged(const AValue: TNotifyEvent);
|
||||||
|
begin
|
||||||
|
if TMethod(FOnChanged) = TMethod(AValue) then exit;
|
||||||
|
FOnChanged := AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TChartAxisLogLinearTransformation }
|
||||||
|
|
||||||
|
procedure TChartAxisLogLinearTransformation.Assign(Source: TPersistent);
|
||||||
|
begin
|
||||||
|
if Source is TChartAxisLogLinearTransformation then
|
||||||
|
with Source as TChartAxisLogLinearTransformation do begin
|
||||||
|
Self.Logarithmic := Logarithmic;
|
||||||
|
Self.Offset := Offset;
|
||||||
|
Self.Scale := Scale;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TChartAxisLogLinearTransformation.AxisToGraph(AX: Double): Double;
|
||||||
|
begin
|
||||||
|
if not Logarithmic then
|
||||||
|
Result := AX
|
||||||
|
else if AX > 0 then
|
||||||
|
Result := Ln(AX)
|
||||||
|
else
|
||||||
|
Result := NegInfinity;
|
||||||
|
Result := Result * Scale + Offset;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TChartAxisLogLinearTransformation.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FScale := 1.0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TChartAxisLogLinearTransformation.GraphToAxis(AX: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := (AX - Offset) / Scale;
|
||||||
|
if Logarithmic then
|
||||||
|
Result := Exp(AX);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TChartAxisLogLinearTransformation.SetLogarithmic(AValue: Boolean);
|
||||||
|
begin
|
||||||
|
if FLogarithmic = AValue then exit;
|
||||||
|
FLogarithmic := AValue;
|
||||||
|
Changed;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TChartAxisLogLinearTransformation.SetOffset(AValue: Double);
|
||||||
|
begin
|
||||||
|
if FOffset = AValue then exit;
|
||||||
|
FOffset := AValue;
|
||||||
|
Changed;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TChartAxisLogLinearTransformation.SetScale(AValue: Double);
|
||||||
|
begin
|
||||||
|
if FScale = AValue then exit;
|
||||||
|
FScale := AValue;
|
||||||
|
if FScale = 0 then FScale := 1.0;
|
||||||
|
Changed;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -26,10 +26,19 @@ uses
|
|||||||
Classes, Graphics, SysUtils,
|
Classes, Graphics, SysUtils,
|
||||||
TAChartUtils, TAGraph, TASources, TATypes;
|
TAChartUtils, TAGraph, TASources, TATypes;
|
||||||
|
|
||||||
|
const
|
||||||
|
DEF_AXIS_INDEX = -1;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ TCustomChartSeries }
|
{ TCustomChartSeries }
|
||||||
|
|
||||||
TCustomChartSeries = class(TBasicChartSeries)
|
TCustomChartSeries = class(TBasicChartSeries)
|
||||||
|
private
|
||||||
|
FAxisIndexX: Integer;
|
||||||
|
FAxisIndexY: Integer;
|
||||||
|
procedure SetAxisIndexX(AValue: Integer);
|
||||||
|
procedure SetAxisIndexY(AValue: Integer);
|
||||||
|
|
||||||
protected
|
protected
|
||||||
procedure SetActive(AValue: Boolean); override;
|
procedure SetActive(AValue: Boolean); override;
|
||||||
procedure SetDepth(AValue: TChartDistance); override;
|
procedure SetDepth(AValue: TChartDistance); override;
|
||||||
@ -37,8 +46,17 @@ type
|
|||||||
procedure SetZPosition(AValue: TChartDistance); override;
|
procedure SetZPosition(AValue: TChartDistance); override;
|
||||||
procedure StyleChanged(Sender: TObject);
|
procedure StyleChanged(Sender: TObject);
|
||||||
procedure UpdateParentChart;
|
procedure UpdateParentChart;
|
||||||
|
|
||||||
|
protected
|
||||||
|
function AxisToGraphX(AX: Double): Double; override;
|
||||||
|
function AxisToGraphY(AY: Double): Double; override;
|
||||||
|
function GraphToAxisX(AX: Double): Double; override;
|
||||||
|
function GraphToAxisY(AY: Double): Double; override;
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(AOwner: TComponent); override;
|
constructor Create(AOwner: TComponent); override;
|
||||||
|
property AxisIndexX: Integer read FAxisIndexX write SetAxisIndexX default DEF_AXIS_INDEX;
|
||||||
|
property AxisIndexY: Integer read FAxisIndexY write SetAxisIndexY default DEF_AXIS_INDEX;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TChartGetMarkEvent = procedure (
|
TChartGetMarkEvent = procedure (
|
||||||
@ -114,6 +132,21 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
Math, TAChartAxis;
|
||||||
|
|
||||||
|
var
|
||||||
|
VIdentityTransformation: TChartAxisTransformation;
|
||||||
|
|
||||||
|
function TransformationByAxis(
|
||||||
|
AChart: TChart; AAxisIndex: Integer): TChartAxisTransformation;
|
||||||
|
begin
|
||||||
|
if InRange(AAxisIndex, 0, AChart.AxisList.Count - 1) then
|
||||||
|
Result := AChart.AxisList[AAxisIndex].Transformation
|
||||||
|
else
|
||||||
|
Result := VIdentityTransformation;
|
||||||
|
end;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
{ TChartSeriesListener }
|
{ TChartSeriesListener }
|
||||||
@ -147,11 +180,33 @@ end;
|
|||||||
|
|
||||||
{ TCustomChartSeries }
|
{ TCustomChartSeries }
|
||||||
|
|
||||||
|
function TCustomChartSeries.AxisToGraphX(AX: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := TransformationByAxis(FChart, AxisIndexX).AxisToGraph(AX)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCustomChartSeries.AxisToGraphY(AY: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := TransformationByAxis(FChart, AxisIndexY).AxisToGraph(AY)
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TCustomChartSeries.Create(AOwner: TComponent);
|
constructor TCustomChartSeries.Create(AOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
inherited Create(AOwner);
|
inherited Create(AOwner);
|
||||||
FActive := true;
|
FActive := true;
|
||||||
FShowInLegend := true;
|
FShowInLegend := true;
|
||||||
|
FAxisIndexX := DEF_AXIS_INDEX;
|
||||||
|
FAxisIndexY := DEF_AXIS_INDEX;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCustomChartSeries.GraphToAxisX(AX: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := TransformationByAxis(FChart, AxisIndexX).GraphToAxis(AX)
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCustomChartSeries.GraphToAxisY(AY: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := TransformationByAxis(FChart, AxisIndexY).GraphToAxis(AY)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCustomChartSeries.SetActive(AValue: Boolean);
|
procedure TCustomChartSeries.SetActive(AValue: Boolean);
|
||||||
@ -161,6 +216,20 @@ begin
|
|||||||
UpdateParentChart;
|
UpdateParentChart;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomChartSeries.SetAxisIndexX(AValue: Integer);
|
||||||
|
begin
|
||||||
|
if FAxisIndexX = AValue then exit;
|
||||||
|
FAxisIndexX := AValue;
|
||||||
|
UpdateParentChart;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCustomChartSeries.SetAxisIndexY(AValue: Integer);
|
||||||
|
begin
|
||||||
|
if FAxisIndexY = AValue then exit;
|
||||||
|
FAxisIndexY := AValue;
|
||||||
|
UpdateParentChart;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCustomChartSeries.SetDepth(AValue: TChartDistance);
|
procedure TCustomChartSeries.SetDepth(AValue: TChartDistance);
|
||||||
begin
|
begin
|
||||||
if FDepth = AValue then exit;
|
if FDepth = AValue then exit;
|
||||||
@ -453,5 +522,8 @@ begin
|
|||||||
ListSource.SetYValue(AIndex, AValue);
|
ListSource.SetYValue(AIndex, AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
VIdentityTransformation := TChartAxisTransformation.Create;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -84,6 +84,8 @@ type
|
|||||||
procedure Draw(ACanvas: TCanvas); override;
|
procedure Draw(ACanvas: TCanvas); override;
|
||||||
function Extent: TDoubleRect; override;
|
function Extent: TDoubleRect; override;
|
||||||
published
|
published
|
||||||
|
property AxisIndexX;
|
||||||
|
property AxisIndexY;
|
||||||
property BarBrush: TBrush read FBarBrush write SetBarBrush;
|
property BarBrush: TBrush read FBarBrush write SetBarBrush;
|
||||||
property BarPen: TPen read FBarPen write SetBarPen;
|
property BarPen: TPen read FBarPen write SetBarPen;
|
||||||
property BarWidthPercent: Integer
|
property BarWidthPercent: Integer
|
||||||
@ -136,6 +138,8 @@ type
|
|||||||
|
|
||||||
procedure Draw(ACanvas: TCanvas); override;
|
procedure Draw(ACanvas: TCanvas); override;
|
||||||
published
|
published
|
||||||
|
property AxisIndexX;
|
||||||
|
property AxisIndexY;
|
||||||
property AreaBrush: TBrush read FAreaBrush write SetAreaBrush;
|
property AreaBrush: TBrush read FAreaBrush write SetAreaBrush;
|
||||||
property AreaLinesPen: TPen read FAreaLinesPen write FAreaLinesPen;
|
property AreaLinesPen: TPen read FAreaLinesPen write FAreaLinesPen;
|
||||||
property Depth;
|
property Depth;
|
||||||
@ -184,6 +188,8 @@ type
|
|||||||
procedure BeginUpdate;
|
procedure BeginUpdate;
|
||||||
procedure EndUpdate;
|
procedure EndUpdate;
|
||||||
published
|
published
|
||||||
|
property AxisIndexX;
|
||||||
|
property AxisIndexY;
|
||||||
property Depth;
|
property Depth;
|
||||||
property LinePen: TPen read FLinePen write SetLinePen;
|
property LinePen: TPen read FLinePen write SetLinePen;
|
||||||
property LineType: TLineType
|
property LineType: TLineType
|
||||||
|
Loading…
Reference in New Issue
Block a user