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:
ask 2009-12-21 16:23:56 +00:00
parent 388cebcf91
commit 53892fe909
3 changed files with 217 additions and 4 deletions

View File

@ -69,6 +69,44 @@ type
property Style default psDot;
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 = class(TCollectionItem)
@ -86,6 +124,7 @@ type
FTickColor: TColor;
FTickLength: Integer;
FTitle: TChartAxisTitle;
FTransformation: TChartAxisLogLinearTransformation;
FVisible: Boolean;
procedure SetAlignment(AValue: TChartAxisAlignment);
@ -97,6 +136,7 @@ type
procedure SetTickColor(AValue: TColor);
procedure SetTickLength(AValue: Integer);
procedure SetTitle(AValue: TChartAxisTitle);
procedure SetTransformation(AValue: TChartAxisLogLinearTransformation);
procedure SetVisible(const AValue: Boolean);
procedure StyleChanged(ASender: TObject);
@ -130,6 +170,8 @@ type
property TickLength: Integer
read FTickLength write SetTickLength default DEF_TICK_LENGTH;
property Title: TChartAxisTitle read FTitle write SetTitle;
property Transformation: TChartAxisLogLinearTransformation
read FTransformation write SetTransformation;
property Visible: Boolean read FVisible write SetVisible default true;
published
property OnMarkToText: TChartAxisMarkToTextEvent
@ -245,11 +287,14 @@ begin
FTickColor := clBlack;
FTickLength := DEF_TICK_LENGTH;
FTitle := TChartAxisTitle.Create(ACollection.Owner as TCustomChart);
FTransformation := TChartAxisLogLinearTransformation.Create;
FTransformation.OnChanged := @StyleChanged;
FVisible := true;
end;
destructor TChartAxis.Destroy;
begin
FTransformation.Free;
FTitle.Free;
FGrid.Free;
inherited;
@ -265,7 +310,7 @@ procedure TChartAxis.Draw(
sz: TSize;
markText: String;
begin
x := ATransf.XGraphToImage((AMark - Offset) / Scale);
x := ATransf.XGraphToImage(Transformation.AxisToGraph(AMark));
if Grid.Visible then begin
ACanvas.Pen.Assign(Grid);
@ -297,7 +342,7 @@ procedure TChartAxis.Draw(
markText: String;
sz: TSize;
begin
y := ATransf.YGraphToImage((AMark - Offset) / Scale);
y := ATransf.YGraphToImage(Transformation.AxisToGraph(AMark));
if Grid.Visible then begin
ACanvas.Pen.Assign(Grid);
@ -394,8 +439,8 @@ end;
function TChartAxis.GetMarks(AMin, AMax: Double): TDoubleDynArray;
begin
AMin := AMin * Scale + Offset;
AMax := AMax * Scale + Offset;
AMin := Transformation.GraphToAxis(AMin);
AMax := Transformation.GraphToAxis(AMax);
if AMin > AMax then
Exchange(AMin, AMax);
Result := GetIntervals(AMin, AMax, Inverted);
@ -550,6 +595,14 @@ begin
StyleChanged(Self);
end;
procedure TChartAxis.SetTransformation(
AValue: TChartAxisLogLinearTransformation);
begin
if FTransformation = AValue then exit;
FTransformation.Assign(AValue);
StyleChanged(Self);
end;
procedure TChartAxis.SetVisible(const AValue: Boolean);
begin
if FVisible = AValue then exit;
@ -610,5 +663,87 @@ begin
a.FAlignment := AXIS_INDEX[AIndex];
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.

View File

@ -26,10 +26,19 @@ uses
Classes, Graphics, SysUtils,
TAChartUtils, TAGraph, TASources, TATypes;
const
DEF_AXIS_INDEX = -1;
type
{ TCustomChartSeries }
TCustomChartSeries = class(TBasicChartSeries)
private
FAxisIndexX: Integer;
FAxisIndexY: Integer;
procedure SetAxisIndexX(AValue: Integer);
procedure SetAxisIndexY(AValue: Integer);
protected
procedure SetActive(AValue: Boolean); override;
procedure SetDepth(AValue: TChartDistance); override;
@ -37,8 +46,17 @@ type
procedure SetZPosition(AValue: TChartDistance); override;
procedure StyleChanged(Sender: TObject);
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
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;
TChartGetMarkEvent = procedure (
@ -114,6 +132,21 @@ type
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
{ TChartSeriesListener }
@ -147,11 +180,33 @@ end;
{ 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);
begin
inherited Create(AOwner);
FActive := 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;
procedure TCustomChartSeries.SetActive(AValue: Boolean);
@ -161,6 +216,20 @@ begin
UpdateParentChart;
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);
begin
if FDepth = AValue then exit;
@ -453,5 +522,8 @@ begin
ListSource.SetYValue(AIndex, AValue);
end;
initialization
VIdentityTransformation := TChartAxisTransformation.Create;
end.

View File

@ -84,6 +84,8 @@ type
procedure Draw(ACanvas: TCanvas); override;
function Extent: TDoubleRect; override;
published
property AxisIndexX;
property AxisIndexY;
property BarBrush: TBrush read FBarBrush write SetBarBrush;
property BarPen: TPen read FBarPen write SetBarPen;
property BarWidthPercent: Integer
@ -136,6 +138,8 @@ type
procedure Draw(ACanvas: TCanvas); override;
published
property AxisIndexX;
property AxisIndexY;
property AreaBrush: TBrush read FAreaBrush write SetAreaBrush;
property AreaLinesPen: TPen read FAreaLinesPen write FAreaLinesPen;
property Depth;
@ -184,6 +188,8 @@ type
procedure BeginUpdate;
procedure EndUpdate;
published
property AxisIndexX;
property AxisIndexY;
property Depth;
property LinePen: TPen read FLinePen write SetLinePen;
property LineType: TLineType