home *** CD-ROM | disk | FTP | other *** search
- unit Axis;
-
- {$I Plot.inc}
-
- {-----------------------------------------------------------------------------
- The contents of this file are subject to the Q Public License
- ("QPL"); you may not use this file except in compliance
- with the QPL. You may obtain a copy of the QPL from
- the file QPL.html in this distribution, derived from:
-
- http://www.trolltech.com/products/download/freelicense/license.html
-
- The QPL prohibits development of proprietary software.
- There is a Professional Version of this software available for this.
- Contact sales@chemware.hypermart.net for more information.
-
- Software distributed under the QPL is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the QPL for
- the specific language governing rights and limitations under the QPL.
-
- The Original Code is: Axis.pas, released 12 September 2000.
-
- The Initial Developer of the Original Code is Mat Ballard.
- Portions created by Mat Ballard are Copyright (C) 1999 Mat Ballard.
- Portions created by Microsoft are Copyright (C) 1998, 1999 Microsoft Corp.
- All Rights Reserved.
-
- Contributor(s): Mat Ballard e-mail: mat.ballard@chemware.hypermart.net.
-
- Last Modified: 04/09/2001
- Current Version: 2.00
-
- You may retrieve the latest version of this file from:
-
- http://Chemware.hypermart.net/
-
- This work was created with the Project JEDI VCL guidelines:
-
- http://www.delphi-jedi.org/Jedi:VCLVCL
-
- in mind.
-
- Purpose:
- To implement an Axis component for use by the main TPlot graphing component.
-
- Known Issues:
-
- History:
- 1.01 21 September 2000: fix FontWidth bug in TAxis.Draw
- add LabelText property to TAxis (for columns)
- -----------------------------------------------------------------------------}
-
- interface
-
- uses
- Classes, SysUtils,
- {$IFDEF WINDOWS}
- WinTypes, WinProcs,
- Graphics,
- {$ENDIF}
- {$IFDEF WIN32}
- Windows,
- Graphics,
- {$ENDIF}
- {$IFDEF LINUX}
- Types,
- QGraphics,
- {$ENDIF}
-
- {$IFNDEF NO_MATH}
- Math,
- {$ENDIF}
- Misc, NoMath, Plotdefs, Titles;
-
- {const}
-
- type
- TAxisType = (atPrimary, atSecondary, atTertiary);
-
- TLabelFormat = (
- lfGeneral, lfExponent, lfFixed, lfNumber, lfCurrency,
- lfSI, lfPercent,
- lfSeconds, lfMinutes, lfHours, lfDays, lfShortTime, lfShortDate);
- {lfGeneral ... lfCurrency are just TFloatFormat.}
- {}
- {We then add SI and Percentage, then the rest are so that we can display times in various formats.}
- {}
- {NOTE: SI means the standard SI postfixes: p, n u, m, -, K, M, G, T}
-
- { TOnPositionChangeEvent = procedure(
- Sender: TObject;
- bIntercept: Boolean; did the Intercept change ? or the screen position ?
- var TheIntercept: Single;
- var ThePosition: Integer) of object;}
-
- {Begin TAxisLabel declarations ------------------------------------------------}
- TAxisLabel = class(TCaption)
- private
- FDirection: TDirection;
- FDigits: Byte;
- FPrecision: Byte;
- FNumberFormat: TLabelFormat;
-
- {OnChange: TNotifyEvent; is in TRectangle !}
-
- procedure SetDirection(Value: TDirection);
- procedure SetDigits(Value: Byte);
- procedure SetPrecision(Value: Byte);
- procedure SetNumberFormat(Value: TLabelFormat);
-
- protected
-
- public
- Constructor Create(AOwner: TPersistent); override;
- {The standard constructor, where standard properties are set.}
- Destructor Destroy; override;
- {The standard destructor, where the OnChange event is "freed".}
-
- {procedure Assign(Source: TPersistent); override;}
- procedure AssignTo(Dest: TPersistent); override;
-
- published
- Property Direction: TDirection read FDirection write SetDirection;
- {Is the Label Horizontal (X) or Vertical (Y or Y2).}
- Property Digits: Byte read FDigits write SetDigits;
- {This (and Precision) control the numeric format of the Axis Labels.
- See the Borland documentation on FloatToStrF for the precise meaning of
- this property, or simply experiment in the IDE designer.}
- Property Precision: Byte read FPrecision write SetPrecision;
- {This (and Digits) control the numeric format of the Axis Labels.
- See the Borland documentation on FloatToStrF for the precise meaning of
- this property, or simply experiment in the IDE designer.}
- Property NumberFormat: TLabelFormat read FNumberFormat write SetNumberFormat;
- {This property controls how the numbers of the Axis labels are displayed.}
-
- end;
-
- {Begin TAxis declarations ---------------------------------------------------}
- TAxis = class(TRectangle)
- private
- FArrowSize: Byte;
- FAutoScale: Boolean;
- FAxisType: TAxisType;
- FDirection: TDirection;
- FIntercept: Single;
- FLabels: TAxisLabel;
- FLabelSeries: TPersistent;
- FLogScale: Boolean;
- FLogSpan: Single;
- FMin: Single;
- FMax: Single;
- FPen: TPen;
- FStepSize: Single;
- FStepStart: Single;
- FSpan: Single;
- FTickMinor: Byte;
- FTickSign: Integer;
- FTickSize: Byte;
- FTickDirection: TOrientation;
- FTickNum: Byte;
- FTitle: TTitle;
- FZoomIntercept: Single;
- FZoomMin: Single;
- FZoomMax: Single;
-
- PrecisionAdded: Integer;
-
- procedure SetupHorizontalEnvelope;
- procedure SetupVerticalEnvelope(StrWidth: Integer);
-
- protected
- {Set procedures:}
- procedure SetArrowSize(Value: Byte);
- procedure SetAutoScale(Value: Boolean);
- procedure SetDirection(Value: TDirection);
- procedure SetIntercept(Value: Single);
- procedure SetLogScale(Value: Boolean);
- procedure SetMin(Value: Single);
- procedure SetMax(Value: Single);
- procedure SetPen(Value: TPen);
- procedure SetStepSize(Value: Single);
- procedure SetStepStart(Value: Single);
- procedure SetTickMinor(Value: Byte);
- {procedure SetTickNum(Value: Byte);}
- procedure SetTickSize(Value: Byte);
- procedure SetOrientation(Value: TOrientation);
-
- procedure StyleChange(Sender: TObject); virtual;
- procedure TitleChange(Sender: TObject); virtual;
-
- public
- procedure ReScale;
-
- Property AxisType: TAxisType read FAxisType write FAxisType;
- {What sort of axis is this ?}
- Property ZoomIntercept: Single read FZoomIntercept write FZoomIntercept;
- {The (old) ZOOMED OUT Intercept in data co-ordinates.}
- Property ZoomMin: Single read FZoomMin write FZoomMin;
- {The (old) ZOOMED OUT minimum, Left or Bottom of the Axis, in data co-ordinates.}
- Property ZoomMax: Single read FZoomMax write FZoomMax;
- {The (old) ZOOMED OUT maximum, Right or Top of the Axis, in data co-ordinates.}
-
- Constructor Create(AOwner: TPersistent); {$IFDEF DELPHI4_UP}reintroduce;{$ENDIF} {squelch the error message}
- {The standard constructor, where sub-components are created, and standard
- properties are set.}
-
-
- Destructor Destroy; override;
- {The standard destructor, where sub-components and the OnChange event is "freed".}
-
- procedure Draw(ACanvas: TCanvas); virtual;
- {This draws the Axis on the given Canvas.}
- function GetNextXValue(XValue: Single): Single;
- {This calculates the next tick point. Used externally by TCustomPlot.DrawGrid}
- function LabelToStrF(Value: Single): String;
- {This method converts a number to a string, given the current Labels' NumberFormat.}
- function StrToLabel(Value: String): Single;
- {This method converts a string to a number, given the current Labels' NumberFormat.}
- function FofX(X: Single): Integer;
- {This converts an X data value to a screen X co-ordinate.}
- function FofY(Y: Single): Integer;
- {This converts a Y data value to a screen Y co-ordinate.}
- function XofF(F: Integer): Single;
- {This converts a screen X co-ordinate to a X data value.}
- function YofF(F: Integer): Single;
- {This converts a screen Y co-ordinate to a Y data value.}
- procedure SetLabelSeries(Value: TPersistent);
- {This is called by a series to set the X data as strings.}
- procedure SetMinFromSeries(Value: Single);
- {This sets the Min property of the Axis. It is used exclusively by TSeries.}
- procedure SetMaxFromSeries(Value: Single);
- {This sets the Max property of the Axis. It is used exclusively by TSeries.
- Exactly how it affects the Axis depends on TPlot.DisplayMode.}
- procedure SetMinMaxFromSeries(AMin, AMax: Single);
- {This sets the Min and Max properties of the Axis. It is used exclusively by TSeries.
- Exactly how it affects the Axis depends on TPlot.DisplayMode.}
-
- {procedure Assign(Source: TPersistent); override;}
- procedure AssignTo(Dest: TPersistent); override;
-
- published
- Property ArrowSize: Byte read FArrowSize write SetArrowSize;
- {This is the size (in pixels) of the arrowhead on the Axis.}
- Property AutoScale: Boolean read FAutoScale write SetAutoScale default TRUE;
- {Do we use the StepSize property or does TPlot work them out ?}
- Property Title: TTitle read FTitle write FTitle;
- {The Title on and of the Axis. Note that the Title can be clicked and dragged
- around the Axis.}
- Property Direction: TDirection read FDirection write SetDirection;
- {Is the Axis Horizontal (X) or Vertical (Y or Y2).}
- Property Intercept: Single read FIntercept write SetIntercept;
- {The intercept of this Axis on the complementary Axis.}
- Property Labels: TAxisLabel read FLabels write FLabels;
- {The numerals on the Axis.}
- Property LogScale: Boolean read FLogScale write SetLogScale;
- {Is this Axis on a logarithmic scale ?}
- Property Min: Single read FMin write SetMin;
- {The minimum, Left or Bottom of the Axis, in data co-ordinates.}
- Property Max: Single read FMax write SetMax;
- {The maximum, Right or Top of the Axis, in data co-ordinates.}
- Property Pen: TPen read FPen write SetPen;
- {The Pen that the Axis is drawn with.}
- Property StepSize: Single read FStepSize write SetStepSize;
- {The interval between tick (and labels) on the Axis.}
- {}
- {If the axis is a Log Scale, then this is the multiple, not the interval !}
- Property StepStart: Single read FStepStart write SetStepStart;
- {The interval between tick (and labels) on the Axis.}
- Property TickMinor: Byte read FTickMinor write SetTickMinor;
- {Sets the number of minor ticks between labels.}
- Property TickSize: Byte read FTickSize write SetTickSize;
- {The Length of the Ticks, in screen pixels.}
- Property TickDirection: TOrientation read FTickDirection write SetOrientation;
- {Are the Ticks to the left or right of the Axis ?}
- {Property TickNum: Byte read FTickNum write SetTickNum;}
- {The approximate number of ticks: TPlot recalculates the number of ticks
- depending on the StepSize.}
-
- end;
-
- TAngleAxis = class(TAxis)
- {The TAngleAxis class is a TAxis that is at any angle.
- It will be used in the 3D and Polar PlotTypes.}
- {Note that the (Left, Top) is now interpreted as the origin}
- private
- FAngle: Word;
- FAngleRadians: Single;
- FLength: Word;
-
- FEndX,
- FEndY: Integer;
- FSin,
- FCos,
- FSinM30,
- FCosM30,
- FSinP30,
- FCosP30: Extended;
- protected
- procedure SetAngle(Value: Word);
- procedure SetLength(Value: Word);
-
- public
- constructor Create(AOwner: TPersistent);
- destructor Destroy; override;
-
- function ClickedOn(iX, iY: Integer): Boolean; override;
- {Was this Z Axis clicked on ?}
- procedure Outline(ACanvas: TCanvas);
-
- function dFofZ(Z: Single): TPoint;
-
- procedure Draw(ACanvas: TCanvas); override;
-
- published
- property Angle: Word read FAngle write SetAngle;
- {Angle is the angle (in degrees) between the vertical Y Axis, and this axis,
- in a clockwise direction.}
- property Length: Word read FLength write SetLength;
- {This is the (screen) length of the axis.}
- end;
-
- implementation
-
- uses
- Data, Plot;
-
- {TAxislabel methods ---------------------------------------------------------}
- {Constructor and Destructor:-------------------------------------------------}
- {------------------------------------------------------------------------------
- Constructor: TAxisLabel.Create
- Description: standard Constructor
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Precision and Digits Properties
- Known Issues:
- ------------------------------------------------------------------------------}
- Constructor TAxisLabel.Create(AOwner: TPersistent);
- begin
- {First call the ancestor:}
- inherited Create(AOwner);
-
- {Put your own initialisation (memory allocation, etc) here:}
-
- {we insert the default values that cannot be "defaulted":}
- FPrecision := 3;
- FDigits := 1;
- end;
-
- {------------------------------------------------------------------------------
- Destructor: TAxisLabel.Destroy
- Description: standard Destructor
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: frees the OnChange event
- Known Issues:
- ------------------------------------------------------------------------------}
- Destructor TAxisLabel.Destroy;
- begin
- OnChange := nil;
- {Put your de-allocation, etc, here:}
-
- {then call ancestor:}
- inherited Destroy;
- end;
-
- {End Constructor and Destructor:---------------------------------------------}
-
- {------------------------------------------------------------------------------
- Procedure: TAxisLabel.Assign
- Description: standard Assign method
- Author: Mat Ballard
- Date created: 07/06/2000
- Date modified: 07/06/2000 by Mat Ballard
- Purpose: implements Assign
- Known Issues:
- ------------------------------------------------------------------------------}
- {procedure TAxisLabel.Assign(Source: TPersistent);
- begin
- inherited Assign(Source);
- FDigits := TAxisLabel(Source).Digits;
- FNumberFormat := TAxisLabel(Source).NumberFormat;
- FPrecision := TAxisLabel(Source).Precision;
- end;}
-
- {------------------------------------------------------------------------------
- Procedure: TAxisLabel.Assign
- Description: standard Assign method
- Author: Mat Ballard
- Date created: 07/06/2000
- Date modified: 07/06/2000 by Mat Ballard
- Purpose: implements Assign
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxisLabel.AssignTo(Dest: TPersistent);
- begin
- inherited AssignTo(Dest);
- TAxisLabel(Dest).Digits := FDigits;
- TAxisLabel(Dest).NumberFormat := FNumberFormat;
- TAxisLabel(Dest).Precision := FPrecision;
- end;
-
- {Begin Set Procedures --------------------------------------------------------}
- {------------------------------------------------------------------------------
- Procedure: TAxisLabel.SetDirection
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 03/25/2001
- Date modified: 03/25/2001 by Mat Ballard
- Purpose: sets the Direction Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxisLabel.SetDirection(Value: TDirection);
- begin
- if (FDirection = Value) then exit;
-
- FDirection := Value;
- if Assigned(OnChange) then OnChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxisLabel.SetDigits
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Digits Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxisLabel.SetDigits(Value: Byte);
- begin
- if (FDigits = Value) then exit;
-
- if (FDigits > 18) then exit;
-
- case FNumberFormat of
- lfGeneral: if (FDigits > 4) then exit;
- lfExponent: if (FDigits > 4) then exit;
- end;
- FDigits := Value;
-
- if Assigned(OnChange) then OnChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxisLabel.SetPrecision
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Precision Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxisLabel.SetPrecision(Value: Byte);
- begin
- if (FPrecision = Value) then exit;
- if (FPrecision > 7) then exit;
- FPrecision := Value;
-
- if Assigned(OnChange) then OnChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxisLabel.SetNumberFormat
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the NumberFormat Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxisLabel.SetNumberFormat(Value: TLabelFormat);
- begin
- if (FNumberFormat = Value) then exit;
- FNumberFormat := Value;
- case FNumberFormat of
- lfGeneral: if (FDigits > 4) then FDigits := 4;
- lfExponent: if (FDigits > 4) then FDigits := 4;
- end;
-
- if Assigned(OnChange) then OnChange(Self);
- end;
-
- {TAxis methods --------------------------------------------------------------}
- {Constructor and Destructor:-------------------------------------------------}
- {------------------------------------------------------------------------------
- Constructor: TAxis.Create
- Description: standard Constructor
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: creates the subcomponents and sets various Properties
- Known Issues:
- ------------------------------------------------------------------------------}
- Constructor TAxis.Create(AOwner: TPersistent);
- begin
- {First call the ancestor:}
- inherited Create(AOwner);
-
- {Create Pen:}
- FPen := TPen.Create;
- FPen.Color := clRed;
-
- FLabels := TAxisLabel.Create(Self);
- FLabels.OnChange := StyleChange;
- FLabelSeries := nil;
-
- {create the Title geometry manager:}
- FTitle := TTitle.Create(Self);
- FTitle.OnChange := StyleChange;
- FTitle.OnCaptionChange := TitleChange;
- FTitle.Caption := 'X-Axis';
- FTitle.Font.Size := MEDIUM_FONT_SIZE;
-
- FArrowSize := 10;
- FAutoScale := TRUE;
- FAxisType := atPrimary;
- SetDirection(drHorizontal);
- FIntercept := 0;
- FMin := 0;
- FMax := 10;
- FTickDirection := orRight;
- FTickSize := 10;
- FTickNum := 5;
- Alignment := taRightJustify;
- Visible := TRUE;
- ReScale;
- end;
-
- {------------------------------------------------------------------------------
- Destructor: TAxis.Destroy
- Description: standard Destructor
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: frees the subcomponents and the OnChange event
- Known Issues:
- ------------------------------------------------------------------------------}
- Destructor TAxis.Destroy;
- begin
- OnChange := nil;
- {Put your de-allocation, etc, here:}
- FLabels.Free;
- FPen.Free;
- FTitle.Free;
-
- {then call ancestor:}
- inherited Destroy;
- end;
- {End Constructor and Destructor:---------------------------------------------}
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.TitleChange
- Description: sets the Name and Label's Name
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: responds to a change in the Title
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.TitleChange(Sender: TObject);
- begin
- if (Pos('xis', FTitle.Caption) > 0) then
- begin
- Name := FTitle.Caption;
- FLabels.Name := FTitle.Caption + ' Labels';
- end
- else
- begin
- {Stick Axis in in the names:}
- Name := FTitle.Caption + ' Axis';
- FLabels.Name := FTitle.Caption + ' Axis Labels';
- end;
- end;
-
- {Begin normal Set Procedures -------------------------------------------------}
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetArrowSize
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the ArrowSize Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetArrowSize(Value: Byte);
- begin
- if (Value = FArrowSize) then exit;
-
- FArrowSize := Value;
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetAutoScale
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the AutoScale Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetAutoScale(Value: Boolean);
- begin
- if (Value = FAutoScale) then exit;
-
- FAutoScale := Value;
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetDirection
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Direction Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetDirection(Value: TDirection);
- begin
- if (Value = FDirection) then exit;
-
- FDirection := Value;
- FTitle.Direction := Value;
- {TTitle.SetDirection usually fires the OnChange:}
- if ((not FTitle.Visible) and
- assigned(OnChange) and
- Visible) then OnChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetIntercept
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Intercept virtual Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetIntercept(Value: Single);
- begin
- if (FIntercept = Value) then exit;
- FIntercept := Value;
- {FAutoScale := FALSE;}
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetLogScale
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the LogScale Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetLogScale(Value: Boolean);
- begin
- if (Value = FLogScale) then exit;
- if (Value = TRUE) then
- begin {we are going to a log scale:}
- if (FMin <= 0) then exit;
- if (FMax <= 0) then exit;
- end;
-
- FLogScale := Value;
- ReScale;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetMin
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Min Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetMin(Value: Single);
- begin
- if (Value = FMin) then exit;
- if (Value >= FMax) then exit;
- if ((Value <= 0) and (FLogScale)) then exit;
-
- FMin := Value;
- ReScale;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetMax
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Max Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetMax(Value: Single);
- begin
- if (Value = FMax) then exit;
- if (Value <= FMin) then exit;
-
- FMax := Value;
- ReScale;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetMinFromSeries
- Description: property Setting procedure for calling by a Series
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Min Property when new data is added to a Series
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetMinFromSeries(Value: Single);
- begin
- if (Value >= FMin) then exit;
- if ((Value <= 0) and (FLogScale)) then exit;
-
- FMin := Value;
- Rescale;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetMaxFromSeries
- Description: property Setting procedure for calling by a Series
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Max Property when new data is added to a Series
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetMaxFromSeries(Value: Single);
- begin
- if (Value <= FMax) then exit;
-
- FMax := Value;
- if ((TPlot(Owner).DisplayMode = dmRun) and
- (FDirection = drHorizontal)) then
- begin
- {We are in a "run", and so we can expect more data with increasing X values.
- Rather than force a complete screen re-draw every time a data point is
- added, we extend the X Axis by 100%:}
- FMax := 2.0 * FMax;
- end;
- Rescale;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetMinMaxFromSeries
- Description: multiple property Setting procedure for calling by a Series
- Author: Mat Ballard
- Date created: 05/29/2001
- Date modified: 05/29/2001 by Mat Ballard
- Purpose: sets the Min Property when new data is added to a Series
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetMinMaxFromSeries(AMin, AMax: Single);
- begin
- if (AMin >= AMax) then exit;
- if ((AMin = FMin) and (AMax = FMax)) then exit;
- if ((AMin <= 0) and (FLogScale)) then exit;
-
- FMin := AMin;
- FMax := AMax;
- Rescale;
- end;
-
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetPen
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Pen Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetPen(Value: TPen);
- begin
- FPen.Assign(Value);
- {FFont.Color := FPen.Color;
- FLabels.Font.Color := FPen.Color;}
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetOrientation
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Orientation Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetOrientation(Value: TOrientation);
- begin
- {if (Value = FTickDirection) then exit;}
-
- FTickDirection := Value;
- if (FTickDirection = orRight) then
- FTickSign := 1
- else
- FTickSign := -1;
- {check the names of the titles and labels}
- {TitleChange(Self);}
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetStepSize
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the StepSize (distance between ticks) Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetStepSize(Value: Single);
- begin
- if (FAutoScale) then exit;
- if (Value = FStepSize) then exit;
-
- FStepSize := Value;
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetStepStart
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the StepStart (where ticks start) Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetStepStart(Value: Single);
- begin
- if (FAutoScale) then exit;
- if (Value = FStepStart) then exit;
-
- FStepStart := Value;
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetTickMinor
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the TickMinor (number of minor ticks) Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetTickMinor(Value: Byte);
- begin
- if (Value = FTickMinor) then exit;
- {limit the number of minors:}
- if (Value > 9) then
- Value := 9;
-
- FTickMinor := Value;
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetTickNum
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the TickNum Property
- Known Issues:
- ------------------------------------------------------------------------------
- procedure TAxis.SetTickNum(Value: Byte);
- begin
- if (Value = FTickNum) then exit;
-
- FTickNum := Value;
- ReScale;
- end;}
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetTickSize
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the TickSize Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetTickSize(Value: Byte);
- begin
- if (Value = FTickSize) then exit;
-
- FTickSize := Value;
- ReScale;
- end;
-
- {Various other Functions and Procedures--------------------------------------}
- {------------------------------------------------------------------------------
- Procedure: TAxis.StyleChange
- Description: event firing proedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: fires the OnChange event
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.StyleChange(Sender: TObject);
- begin
- if (assigned(OnChange) and Visible) then OnChange(Sender);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.ReScale
- Description: geometry manager
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: determines the ticks and labels
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.ReScale;
- {This method determines the Axis geometry (StepStart and StepSize).}
- var
- i,
- Exponent: Integer;
- RoughStepSize: Single;
- Mantissa: Extended;
- begin
- PrecisionAdded := 0;
-
- if (not FAutoScale) then
- begin
- FStepStart := FMin;
- FSpan := FMax - FMin;
- exit;
- end;
-
- if (FLogScale) then
- begin
- FLogSpan := Log10(FMax / FMin);
- DeSci(FMin, Mantissa, Exponent);
- {work out a starting point, 1 x 10^Exponent:}
- FStepStart := IntPower(10.0, Exponent);
-
- if (not FAutoScale) then
- begin
- if (FLogSpan >= 2) then
- begin
- {many decades of data:}
- if (not FAutoScale) then
- FStepSize := 10;
- end
- else
- begin
- RoughStepSize := FLogSpan / (FTickNum+1);
- RoughStepSize := Power(10.0, RoughStepSize);
- if (RoughStepSize > 1.5) then
- begin
- {get the Mantissa and Exponent:}
- DeSci(RoughStepSize, Mantissa, Exponent);
- FStepSize := Round(Mantissa) * IntPower(10.0, Exponent);
- end
- else
- begin
- FStepSize := RoughStepSize;
- end;
- {$IFDEF DELPHI3_UP}
- Assert(FStepSize > 1.0,
- 'TAxis.ReScale Error: The calculated StepSize on a Log scale is ' +
- FloatToStr(FStepSize));
- {$ENDIF}
- end; {how big is FLogSpan ?}
- end; {not AutoScale}
- while (FStepStart < FMin) do
- {go to next multiple of FStepSize:}
- FStepStart := FStepSize * FStepStart;
- end
- else
- begin {normal linear scale:}
- FSpan := FMax - FMin;
- if ((FAutoScale) or (FStepSize <= 0)) then
- begin
- RoughStepSize := FSpan / (FTickNum+1);
- {get the Mantissa and Exponent:}
- DeSci(RoughStepSize, Mantissa, Exponent);
-
- {FStepSize := Round(Mantissa);
- if (Exponent < 0) then
- begin
- for i := 1 to -Exponent do
- FStepSize := FStepSize / 10;
- end
- else
- begin
- for i := 1 to Exponent do
- FStepSize := FStepSize * 10;
- end;}
-
- FStepSize := Round(Mantissa) * IntPower(10.0, Exponent);
- {FTickNum := Trunc(FSpan / FStepSize);}
- end;
- FStepStart := FStepSize * Int((FMin / FStepSize) + 0.999);
- {increase FStepStart by FStepSize:}
- while (FStepStart < FMin) do
- FStepStart := FStepSize + FStepStart;
-
- {PrecisionAdded is the added precision needed to display numerical labels with
- sufficient precision to be distinguishable:}
- if (Exponent <= -FLabels.FDigits) then
- PrecisionAdded := 1 - FLabels.FDigits - Exponent;
- end;
-
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.GetNextXValue
- Description: auxilary procedure for Drawing
- Author: Mat Ballard
- Date created: 02/28/2001
- Date modified: 02/28/2001 by Mat Ballard
- Purpose: calculates the next tick point
- Known Issues:
- ------------------------------------------------------------------------------}
- function TAxis.GetNextXValue(XValue: Single): Single;
- begin
- if (FLogScale) then
- GetNextXValue := XValue * FStepSize
- else
- GetNextXValue := XValue + FStepSize;
- end;
-
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.Draw
- Description: standard Drawing procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: draws the Axis on a given canvas
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.Draw(ACanvas: TCanvas);
- {Comments:
- This method is quite complex, in a tedious way.
- It has to account for the following variations:
- 1. Visible or not;
- 2. Arrows visible or not;
- 3. Axis direction (Horizontal or vertical);
- 4. Tick (and Label and Title) direction);
- 5. Title Alignment Direction and Orientation;
- 6. Tick, Label and Title visibility.
- An added complication is that we must generate a vertical font for the Title
- of vertical axes. Note that this only works with TrueType fonts - NOT fonts
- that are purely screen or printer.}
- var
- i,
- iX,
- iY,
- iYLabel,
- FontHeight,
- FontWidth,
- iFontWidth,
- FontDescent,
- MinorTickSize: Integer;
- MinorStepSize,
- MinorStepStart,
- YValue,
- XValue: Single;
- DoTextLabels: Boolean;
- TheText: String;
-
- function GetNextMinorXValue(XValue: Single): Single;
- begin
- if (FLogScale) then
- GetNextMinorXValue := XValue * MinorStepSize
- else
- GetNextMinorXValue := XValue + MinorStepSize;
- end;
-
- procedure LabelOut;
- begin
- iFontWidth := ACanvas.TextWidth(TheText);
- if (iFontWidth > FontWidth) then
- FontWidth := iFontWidth;
- if (FLabels.Direction = drHorizontal) then
- ACanvas.TextOut(iX - iFontWidth div 2, iYLabel, TheText)
- else
- if (FTickDirection = orLeft) then
- TextOutAngle(ACanvas, 90, iX - FontHeight div 2, iYLabel, TheText)
- else
- TextOutAngle(ACanvas, 90, iX - FontHeight div 2, iYLabel + FontWidth, TheText);
- end;
-
- begin
- {the most common reason for exit:}
- if (not Visible) then exit;
- {$IFDEF DELPHI3_UP}
- Assert(ACanvas <> nil, 'TAxis.Draw: ACanvas is nil !');
- {$ENDIF}
-
- FontWidth := 1;
- ACanvas.Pen.Assign(FPen);
- if (FDirection = drHorizontal) then
- begin
- DoTextLabels := FALSE;
- if (FLabelSeries <> nil) then
- if (TSeries(FLabelSeries).XStringData <> nil) then
- if (TSeries(FLabelSeries).XStringData.Count > 0) then
- DoTextLabels := TRUE;
-
- {Draw the axis:}
- ACanvas.MoveTo(Left, MidY);
- ACanvas.LineTo(Right, MidY);
- {Draw the arrows on the axis:}
- if (FArrowSize > 0) then
- begin
- if (Alignment = taLeftJustify) then
- begin
- ACanvas.MoveTo(Left+FArrowSize, Top);
- ACanvas.LineTo(Left, MidY);
- ACanvas.LineTo(Left+FArrowSize, Bottom);
- end;
- if (Alignment = taRightJustify) then
- begin
- ACanvas.LineTo(Right-FArrowSize, Top);
- ACanvas.MoveTo(Right, MidY);
- ACanvas.LineTo(Right-FArrowSize, Bottom);
- end; {taCenter therefore means no arrows !}
- end;
-
- if (FLabels.Visible) then
- begin
- ACanvas.Font.Assign(FLabels.Font);
- FontHeight := ACanvas.TextHeight('9');
- if ((FTickDirection = orLeft) and
- (FLabels.Direction = drHorizontal)) then
- Dec(iYLabel, FontHeight);
- end;
-
- iY := MidY;
- iYLabel := MidY + FTickSign*FTickSize;
- {Major Ticks on the axis:}
- if ((FTickSize > 0) and
- (not DoTextLabels)) then
- begin
- XValue := FStepStart;
- while (XValue < FMax) do
- begin
- iX := FofX(XValue);
- ACanvas.MoveTo(iX, iY);
- ACanvas.LineTo(iX, iYLabel);
- XValue := GetNextXValue(XValue);
- end;
- {Minor Ticks on the axis:}
- if (FTickMinor > 0) then
- begin
- {find out where the minors start:}
- MinorStepSize := FStepSize / (FTickMinor+1);
- MinorStepStart := FStepStart;
- MinorTickSize := FTickSign * FTickSize div 2;
- while ((MinorStepStart - MinorStepSize) >= FMin) do
- MinorStepStart := MinorStepStart - MinorStepSize;
- iY := MidY;
- XValue := MinorStepStart;
- while (XValue < FMax) do
- begin
- iX := FofX(XValue);
- ACanvas.MoveTo(iX, iY);
- ACanvas.LineTo(iX, iY + MinorTickSize);
- XValue := GetNextMinorXValue(XValue);
- end;
- end; {minors}
- end; {Ticks}
-
- {Set text output orientation.}
- {Labels on the axis:}
- if (FLabels.Visible) then
- begin
- if (DoTextLabels) then
- begin
- for i := 0 to TSeries(FLabelSeries).XStringData.Count-1 do
- begin
- iX := FofX(TSeries(FLabelSeries).XData^[i]);
- ACanvas.MoveTo(iX, iY);
- ACanvas.LineTo(iX, iYLabel);
- TheText := TSeries(FLabelSeries).XStringData.Strings[i];
- LabelOut;
- end;
- end
- else
- begin
- //i := 0;
- iX := 0;
- XValue := FStepStart;
- while (XValue < FMax) do
- begin
- iX := FofX(XValue);
- ACanvas.MoveTo(iX, iY);
- ACanvas.LineTo(iX, iYLabel);
- TheText := LabelToStrF(XValue);
- XValue := GetNextXValue(XValue);
- LabelOut;
- //Inc(i);
- end;
-
- {record the position of the labels for use by TPlot:}
- FLabels.Left := FofX(FStepStart) - FontWidth div 2;
- FLabels.Top := iY;
- FLabels.Bottom := iY + FontHeight;
- FLabels.Right := iX + FontWidth div 2;
- end;
- end;
-
- SetupHorizontalEnvelope;
- end
- else
- begin
- {Draw the Vertical axis:}
- ACanvas.MoveTo(MidX, Bottom);
- ACanvas.LineTo(MidX, Top);
- {Draw the arrows on the axis:}
- if (FArrowSize > 0) then
- begin
- ACanvas.LineTo(Left, Top+FArrowSize);
- ACanvas.MoveTo(MidX, Top);
- ACanvas.LineTo(Right, Top+FArrowSize);
- end;
-
- {Ticks on the axis:}
- if (FTickSize > 0) then
- begin
- iX := MidX;
- YValue := FStepStart;
- while (YValue < FMax) do
- begin
- iY := FofY(YValue);
- ACanvas.MoveTo(iX, iY);
- ACanvas.LineTo(iX + FTickSign*FTickSize, iY);
- YValue := GetNextXValue(YValue);
- end;
- {Minor Ticks on the axis:}
- if (FTickMinor > 0) then
- begin
- {find out where the minors start:}
- MinorStepSize := FStepSize / (FTickMinor + 1);
- MinorStepStart := FStepStart;
- MinorTickSize := FTickSign * FTickSize div 2;
- while ((MinorStepStart - MinorStepSize) >= FMin) do
- MinorStepStart := MinorStepStart - MinorStepSize;
- iX := MidX;
- YValue := MinorStepStart;
- while (YValue < FMax) do
- begin
- iY := FofY(YValue);
- ACanvas.MoveTo(iX, iY);
- ACanvas.LineTo(iX + MinorTickSize, iY);
- YValue := GetNextMinorXValue(YValue);
- end;
- end; {minors}
- end; {Ticks}
-
- FontWidth := 1; {see below}
- {Labels on the axis:}
- if (FLabels.Visible) then
- begin
- ACanvas.Font.Assign(FLabels.Font);
- FontWidth := ACanvas.TextWidth('9');
- FontHeight := ACanvas.TextHeight('9');
- {We could call GetOutlineTextMetrics to get
- the Descent (gap between baseline and bottom of a font), but:}
- FontDescent := FontHeight div 5;
- iX := MidX + FTickSign*(FTickSize + FontWidth div 5);
- iY := 0; {see below}
- YValue := FStepStart;
- //i := 0;
- while (YValue < FMax) do
- begin
- {if (FLabelSeries <> nil) then
- if (i < FLabelSeries.Count) then
- TheText := FLabelSeries.Strings[i]
- else
- break
- else}
- TheText := LabelToStrF(YValue);
- iY := FofY(YValue) - FontHeight + FontDescent;
- iFontWidth := ACanvas.TextWidth(TheText);
- {remember which label is widest:}
- if (FontWidth < iFontWidth) then
- FontWidth := iFontWidth;
- if (FTickDirection = orRight) then
- ACanvas.TextOut(iX, iY, TheText)
- else
- ACanvas.TextOut(iX - iFontWidth, iY, TheText);
- YValue := GetNextXValue(YValue);
- end;
-
- FLabels.Bottom := FofY(FStepStart);
- {record the position of the labels for use by TPlot:}
- FLabels.Top := iY - Abs(ACanvas.Font.Height);
- if (FTickDirection = orRight) then
- begin
- FLabels.Left := iX;
- FLabels.Right := iX + FontWidth;
- end
- else
- begin
- FLabels.Left := iX - FontWidth;
- FLabels.Right := iX;
- end;
- end; {Labels Visible}
-
- SetupVerticalEnvelope(FontWidth);
- end; {Horizontal or Vertical}
- {Print the axis Title:}
- FTitle.Draw(ACanvas);
- end;
-
- {------------------------------------------------------------------------------
- Function: TAxis.FofX
- Description: standard X transform
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: returns the pixel position on screen as a function of the real data ordinate X
- Known Issues:
- ------------------------------------------------------------------------------}
- function TAxis.FofX(X: Single): Integer;
- begin
- {$IFDEF DELPHI3_UP}
- Assert(FDirection = drHorizontal, 'A vertical Axis cannot return F(X) !');
- {$ENDIF}
-
- if (FLogScale) then
- FofX := Round(Left + Width * ((Log10(X / FMin)) / FLogSpan))
- else
- FofX := Round(Left + Width * ((X - FMin) / (FSpan)));
- end;
-
- {------------------------------------------------------------------------------
- Function: TAxis.FofY
- Description: standard Y transform
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: returns the pixel position on screen as a function of the real data co-ordinate Y
- Known Issues:
- ------------------------------------------------------------------------------}
- function TAxis.FofY(Y: Single): Integer;
- begin
- {$IFDEF DELPHI3_UP}
- Assert(FDirection = drVertical, 'A Horizontal Axis cannot return F(Y) !');
- {$ENDIF}
-
- if (FLogScale) then
- FofY := Round(Bottom - Height * ((Log10(Y / FMin)) / FLogSpan))
- else
- FofY := Round(Bottom - Height * ((Y - FMin) / (FSpan)));
- end;
-
- {------------------------------------------------------------------------------
- Function: TAxis.XofF
- Description: inverse X transform
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: returns the real data ordinate X as a function of the pixel position on screen
- Known Issues:
- ------------------------------------------------------------------------------}
- function TAxis.XofF(F: Integer): Single;
- {this function returns the real data ordinate X
- as a function of the pixel position F on screen:}
- begin
- {$IFDEF DELPHI3_UP}
- Assert(FDirection = drHorizontal, 'A Vertical Axis cannot return F(X) !');
- {$ENDIF}
-
- if (FLogScale) then
- XofF := FMin * Power(10.0, (FLogSpan * (F-Left) / Width))
- else
- XofF := FSpan * ((F-Left) / Width) + FMin;
- end;
-
- {------------------------------------------------------------------------------
- Function: TAxis.YofF
- Description: inverse Y transform
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: returns the real data ordinate Y as a function of the pixel position on screen
- Known Issues:
- ------------------------------------------------------------------------------}
- function TAxis.YofF(F: Integer): Single;
- {this function returns the real data ordinate X
- as a function of the pixel position F on screen:}
- begin
- {$IFDEF DELPHI3_UP}
- Assert(FDirection = drVertical, 'A Horizontal Axis cannot return F(Y) !');
- {$ENDIF}
-
- if (FLogScale) then
- YofF := FMin * Power(10.0, (FLogSpan * (Bottom-F) / Height))
- else
- YofF := FSpan * ((Bottom-F) / Height) + FMin;
- end;
-
- {------------------------------------------------------------------------------
- Function: TAxis.StrToLabel
- Description: converts a string to a number, depending on the NumberFormat
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: user IO
- Known Issues:
- ------------------------------------------------------------------------------}
- function TAxis.StrToLabel(Value: String): Single;
- begin
- case (FLabels.NumberFormat) of
- lfGeneral .. lfCurrency:
- StrToLabel := StrToFloat(Value);
- lfPercent:
- StrToLabel := StrToFloat(Value) / 100;
- lfSeconds:
- StrToLabel := StrToFloat(Value);
- lfMinutes:
- StrToLabel := 60 * StrToFloat(Value);
- lfHours:
- StrToLabel := 3600 * StrToFloat(Value);
- lfDays:
- StrToLabel := 86400 * StrToFloat(Value);
- lfShortTime:
- StrToLabel := StrToDateTime(Value);
- lfShortDate:
- StrToLabel := StrToDateTime(Value);
- else
- StrToLabel := 0.0;
- end;
- end;
-
- {------------------------------------------------------------------------------
- Function: TAxis.LabelToStrF
- Description: converts a number to a string, depending on the NumberFormat
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: user IO
- Known Issues:
- ------------------------------------------------------------------------------}
- function TAxis.LabelToStrF(Value: Single): String;
- var
- TheText: String;
- Mantissa: Extended;
- Exponent: Integer;
- TheDateTime: TDateTime;
- begin
- case (FLabels.NumberFormat) of
- lfGeneral .. lfCurrency:
- {See Rescale for definition of PrecisionAdded}
- TheText := FloatToStrF(Value, TFloatFormat(FLabels.NumberFormat),
- FLabels.Precision + PrecisionAdded, FLabels.Digits);
- lfSI:
- begin
- DeSci(Value, Mantissa, Exponent);
- case Exponent of {p, n u, m, -, K, M, G, T}
- -12 .. -10: TheText := 'p';
- -9 .. -7: TheText := 'n';
- -6 .. -4: TheText := 'u';
- -3 .. -1: TheText := 'm';
- 3 .. 5: TheText := 'K';
- 6 .. 8: TheText := 'M';
- 9 .. 11: TheText := 'G';
- 12 .. 14: TheText := 'T';
- else ;
- TheText := '';
- end;
- if (Length(TheText) > 0) then
- begin
- Exponent := (Exponent + 99) mod 3;
- Mantissa := Mantissa * IntPower(10, Exponent);
- TheText := FloatToStrF(Mantissa, TFloatFormat(lfFixed),
- FLabels.Precision, FLabels.Digits) + TheText;
- end
- else
- TheText := FloatToStrF(Value, TFloatFormat(lfGeneral),
- FLabels.Precision, FLabels.Digits);
- end;
- lfPercent:
- TheText := FloatToStrF(100 * Value, TFloatFormat(FLabels.NumberFormat),
- FLabels.Precision, FLabels.Digits);
- lfSeconds:
- TheText := FloatToStrF(Round(Value), ffGeneral,
- FLabels.Precision, FLabels.Digits);
- lfMinutes:
- TheText := FloatToStrF(Round(Value / 60), ffGeneral,
- FLabels.Precision, FLabels.Digits);
- lfHours:
- TheText := FloatToStrF(Round(Value / 3600), ffGeneral,
- FLabels.Precision, FLabels.Digits);
- lfDays:
- TheText := FloatToStrF(Round(Value / 86400), ffGeneral,
- FLabels.Precision, FLabels.Digits);
- lfShortTime:
- begin
- TheDateTime := Value;
- TheText := FormatDateTime('t', TheDateTime);
- end;
- lfShortDate:
- begin
- TheDateTime := Value;
- TheText := FormatDateTime('ddddd', TheDateTime);
- end;
- end;
-
- LabelToStrF := TheText;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetupHorizontalEnvelope
- Description: sets up the Horizontal (X Axis) envelope around which the Title dances
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: manages the appearance of the Axis
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetupHorizontalEnvelope;
- var
- TheRect: TRect;
- begin
- TheRect.Left := Left;
- TheRect.Right := Right;
- if (FTickDirection = orLeft) then
- begin
- TheRect.Top := MidY - FTickSize;
- TheRect.Bottom := MidY + 1;
- if (FLabels.Visible) then
- TheRect.Top := TheRect.Top - Abs(FLabels.Font.Height);
- end
- else {oRight}
- begin
- TheRect.Top := MidY - 1;
- TheRect.Bottom := MidY + FTickSize;
- if (FLabels.Visible) then
- TheRect.Bottom := TheRect.Bottom + Abs(FLabels.Font.Height);
- end; {FTickDirection}
- FTitle.Envelope := TheRect;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetupVerticalEnvelope
- Description: sets up the Vertical (Y Axis) envelope around which the Title dances
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: manages the appearance of the Axis
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.SetupVerticalEnvelope(StrWidth: Integer);
- var
- TheRect: TRect;
- begin
- TheRect.Top := Top;
- TheRect.Bottom := Bottom;
- if (FTickDirection = orLeft) then
- begin
- TheRect.Left := MidX - FTickSize - Abs(FLabels.Font.Height) div 2;
- TheRect.Right := MidX + 1;
- if (FLabels.Visible) then
- TheRect.Left := TheRect.Left - StrWidth;
- end
- else {oRight}
- begin
- TheRect.Left := MidX - 1;
- TheRect.Right := MidX + FTickSize;
- if (FLabels.Visible) then
- TheRect.Right := TheRect.Right + StrWidth;
- end; {FTickDirection}
- FTitle.Envelope := TheRect;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.Assign
- Description: standard Assign method
- Author: Mat Ballard
- Date created: 07/06/2000
- Date modified: 07/06/2000 by Mat Ballard
- Purpose: implements Assign
- Known Issues:
- ------------------------------------------------------------------------------}
- {procedure TAxis.Assign(Source: TPersistent);
- begin
- inherited Assign(Source);
- FArrowSize := TAxis(Source).ArrowSize;
- FDirection := TAxis(Source).Direction;
- FIntercept := TAxis(Source).Intercept;
- FLogscale := TAxis(Source).Logscale;
- FMax := TAxis(Source).Max;
- FMin := TAxis(Source).Min;
- FStepSize := TAxis(Source).StepSize;
- FTickDirection := TAxis(Source).TickDirection;
- FTickNum := TAxis(Source).TickNum;
- FTickSize := TAxis(Source).TickSize;
-
- FLabels.Assign(TAxis(Source).Labels);
- FPen.Assign(TAxis(Source).Pen);
- FTitle.Assign(TAxis(Source).Title);
- end;}
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.AssignTo
- Description: standard AssignTo method
- Author: Mat Ballard
- Date created: 07/06/2000
- Date modified: 07/06/2000 by Mat Ballard
- Purpose: implements AssignTo
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAxis.AssignTo(Dest: TPersistent);
- begin
- inherited AssignTo(Dest);
- TAxis(Dest).ArrowSize := FArrowSize;
- TAxis(Dest).Direction := FDirection;
- {TAxis(Dest).Intercept := FIntercept;}
- TAxis(Dest).Logscale := FLogscale;
- TAxis(Dest).Max := FMax;
- TAxis(Dest).Min := FMin;
- TAxis(Dest).StepSize := FStepSize;
- TAxis(Dest).TickDirection := FTickDirection;
- TAxis(Dest).TickSize := FTickSize;
-
- TAxis(Dest).Labels.Assign(FLabels);
- TAxis(Dest).Pen.Assign(FPen);
- TAxis(Dest).Title.Assign(FTitle);
- end;
-
- procedure TAxis.SetLabelSeries(Value: TPersistent);
- begin
- {Note: Labeltext is maintained within the TSeries, NOT in TAxis !}
- FLabelSeries := Value;
- StyleChange(Self);
- end;
-
- {TAngleAxis methods ---------------------------------------------------------}
- {Constructor and Destructor:-------------------------------------------------}
- {------------------------------------------------------------------------------
- Constructor: TAngleAxis.Create
- Description: standard Constructor
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: sets the Precision and Digits Properties
- Known Issues:
- ------------------------------------------------------------------------------}
- Constructor TAngleAxis.Create(AOwner: TPersistent);
- begin
- {First call the ancestor:}
- inherited Create(AOwner);
-
- FireEvents := FALSE;
- FLength := 100;
- Angle := 225;
- FireEvents := TRUE;
- end;
-
- {------------------------------------------------------------------------------
- Destructor: TAngleAxis.Destroy
- Description: standard Destructor
- Author: Mat Ballard
- Date created: 01/16/2001
- Date modified: 01/16/2001 by Mat Ballard
- Purpose:
- Known Issues:
- ------------------------------------------------------------------------------}
- Destructor TAngleAxis.Destroy;
- begin
- inherited Destroy;
- end;
-
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetAngle
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 01/16/2001
- Date modified: 01/16/2001 by Mat Ballard
- Purpose: sets the Angle Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAngleAxis.SetAngle(Value: Word);
- begin
- FAngle := Value Mod 360;
- FAngleRadians := Pi * FAngle / 180;
- {this is twice as fast as calling them individually:}
- SinCos(FAngleRadians, FSin, FCos);
- {look back along the axis, then 30 degrees less, for the arrow:}
- SinCos(FAngleRadians + Pi*(1/2 - 1/6), FSinM30, FCosM30);
- {look back along the axis, then 30 degrees more:}
- SinCos(FAngleRadians + Pi*(1/2 + 1/6), FSinP30, FCosP30);
-
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.SetLength
- Description: standard property Set procedure
- Author: Mat Ballard
- Date created: 01/16/2001
- Date modified: 01/16/2001 by Mat Ballard
- Purpose: sets the Length Property
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAngleAxis.SetLength(Value: Word);
- begin
- if (Value = FLength) then exit;
-
- FLength := Value;
- StyleChange(Self);
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAxis.Draw
- Description: standard Drawing procedure
- Author: Mat Ballard
- Date created: 04/25/2000
- Date modified: 04/25/2000 by Mat Ballard
- Purpose: draws the Axis on a given canvas
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAngleAxis.Draw(ACanvas: TCanvas);
- {Comments:
- This method is quite complex, in a tedious way.
- It has to account for the following variations:
- 1. Visible or not;
- 2. Arrows visible or not;
- 3. Axis direction (Horizontal or vertical);
- 4. Tick (and Label and Title) direction);
- 5. Title Alignment Direction and Orientation;
- 6. Tick, Label and Title visibility.
- 7. Angle !
- An added complication is that we must generate a vertical font for the Title
- of vertical axes. Note that this only works with TrueType fonts - NOT fonts
- that are purely screen or printer.}
- var
- OldFireEvents: Boolean;
- i,
- iX,
- iY,
- FontHeight,
- FontWidth,
- iFontWidth,
- FontDescent,
- MinorTickSize: Integer;
- MinorStepSize,
- MinorStepStart,
- {NewAngle,}
- ZValue: Single;
- TheText: String;
- dTick,
- TheTickStart: TPoint;
-
- {begin internal functions:}
- function GetNextXValue(XValue: Single): Single;
- begin
- if (FLogScale) then
- GetNextXValue := XValue * FStepSize
- else
- GetNextXValue := XValue + FStepSize;
- end;
-
- function GetNextMinorXValue(XValue: Single): Single;
- begin
- if (FLogScale) then
- GetNextMinorXValue := XValue * MinorStepSize
- else
- GetNextMinorXValue := XValue + MinorStepSize;
- end;
-
- begin
- {the most common reason for exit:}
- if (not Visible) then exit;
- {$IFDEF DELPHI3_UP}
- Assert(ACanvas <> nil, 'TAngleAxis.Draw: ACanvas is nil !');
- {$ENDIF}
-
- FontWidth := 1;
- ACanvas.Pen.Assign(FPen);
-
- {Do the geometry:}
- {first, squelch any "OnChange" events:}
- OldFireEvents := FireEvents;
- FireEvents := FALSE;
- FEndX := Left + Round(FLength * FSin);
- FEndY := Top + Round(-FLength * FCos);
-
- {Draw the axis:}
- ACanvas.MoveTo(Left, Top);
- ACanvas.LineTo(FEndX, FEndY);
- {Draw the arrows on the axis:}
- if (FArrowSize > 0) then
- begin
- if (Alignment = taRightJustify) then
- begin
- ACanvas.MoveTo(FEndX, FEndY);
- iX := FEndX + Round(FArrowSize * FCosM30);
- iY := FEndY + Round(FArrowSize * FSinM30);
- ACanvas.LineTo(iX, iY);
- ACanvas.MoveTo(FEndX, FEndY);
- {look back along the axis, then 30 degrees less:}
- iX := FEndX + Round(FArrowSize * FCosP30);
- iY := FEndY + Round(FArrowSize * FSinP30);
- ACanvas.LineTo(iX, iY);
- end; {taLeftJustify and taCenter therefore means no arrows !}
- end;
-
- {Prepare fonts for Labels on the axis:}
- if (FLabels.Visible) then
- begin
- ACanvas.Font.Assign(FLabels.Font);
- FontWidth := ACanvas.TextWidth('9');
- FontHeight := ACanvas.TextHeight('9');
- {We could call GetOutlineTextMetrics to get
- the Descent (gap between baseline and bottom of a font), but:}
- {FontDescent := FontHeight div 5;}
- end;
-
- {Ticks on the axis:}
-
- dTick.x := 0;
- dTick.y := 0;
- case FAngle of
- 0: dTick.x := -FTickSize;
- 1 .. 60: dTick.x := FTickSize;
- 61 .. 120: dTick.y := FTickSize;
- 121 .. 180: dTick.x := FTickSize;
- 181 .. 240: dTick.x := -FTickSize;
- 241 .. 300: dTick.y := FTickSize;
- 301 .. 359: dTick.x := -FTickSize;
- end;
-
- ZValue := FStepStart;
- //i := 0;
- while (ZValue < FMax) do
- begin
- TheTickStart := dFofZ(ZValue);
- Inc(TheTickStart.x, Left);
- Inc(TheTickStart.y, Top);
- if (FTickSize > 1) then
- ACanvas.MoveTo(TheTickStart.x, TheTickStart.y);
- Inc(TheTickStart.x, dTick.x);
- Inc(TheTickStart.y, dTick.y);
- if (FTickSize > 1) then
- ACanvas.LineTo(TheTickStart.x, TheTickStart.y);
-
- if (FLabels.Visible) then
- begin
- {if (FLabelSeries <> nil) then
- if (i < FLabelSeries.Count) then
- TheText := FLabelSeries.Strings[i]
- else
- break
- else}
- TheText := LabelToStrF(ZValue);
- iFontWidth := ACanvas.TextWidth(TheText);
- if (iFontWidth > FontWidth) then
- FontWidth := iFontWidth;
- if (dTick.x < 0) then
- Dec(TheTickStart.x, iFontWidth);
- if (dTick.y > 0) then
- begin
- Inc(TheTickStart.y, FontHeight);
- Dec(TheTickStart.x, iFontWidth div 2);
- end;
- {$IFDEF MSWINDOWS}
- ACanvas.TextOut(
- TheTickStart.x,
- TheTickStart.y - Abs(ACanvas.Font.Height),
- TheText);
- {$ENDIF}
- {$IFDEF LINUX}
- ACanvas.TextOut(
- TheTickStart.x,
- TheTickStart.y {+ Abs(ACanvas.Font.Height)},
- TheText);
- {$ENDIF}
- end;
-
- //Inc(i);
- ZValue := GetNextXValue(ZValue);
- end; {while ZValue < FMax}
-
- {Minor Ticks on the axis:}
- if ((FTickSize > 1) and (FTickMinor > 0)) then
- begin
- {find out where the minors start:}
- MinorStepSize := FStepSize / (FTickMinor+1);
- MinorStepStart := FStepStart;
- while ((MinorStepStart - MinorStepSize) >= FMin) do
- MinorStepStart := MinorStepStart - MinorStepSize;
- //iY := MidY;
- dTick.x := dTick.x div 2;
- dTick.y := dTick.y div 2;
-
- ZValue := MinorStepStart;
- //i := 0;
- while (ZValue < FMax) do
- begin
- TheTickStart := dFofZ(ZValue);
- Inc(TheTickStart.x, Left);
- Inc(TheTickStart.y, Top);
- if (FTickSize > 1) then
- ACanvas.MoveTo(TheTickStart.x, TheTickStart.y);
- Inc(TheTickStart.x, dTick.x);
- Inc(TheTickStart.y, dTick.y);
- if (FTickSize > 1) then
- ACanvas.LineTo(TheTickStart.x, TheTickStart.y);
- ZValue := GetNextMinorXValue(ZValue);
- end;
- end; {minor ticks}
-
- FireEvents := OldFireEvents;
- end;
-
- {------------------------------------------------------------------------------
- Function: TAngleAxis.FofZ
- Description: standard Z transform
- Author: Mat Ballard
- Date created: 01/18/2001
- Date modified: 01/18/2001 by Mat Ballard
- Purpose: returns the change in pixel position on screen as a function of the real data ordinate Z
- Known Issues:
- ------------------------------------------------------------------------------}
- function TAngleAxis.dFofZ(Z: Single): TPoint;
- begin
- if (FLogScale) then
- begin
- Result.x := Round(FSin * FLength * ((Log10(Z / FMin)) / FLogSpan));
- Result.y := -Round(FCos * FLength * ((Log10(Z / FMin)) / FLogSpan));
- end
- else
- begin
- Result.x := Round(FSin * FLength * ((Z - FMin) / (FSpan)));
- Result.y := -Round(FCos * FLength * ((Z - FMin) / (FSpan)));
- end;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAngleAxis.ClickedOn
- Description: Was this TRectangle clicked on ?
- Author: Mat Ballard
- Date created: 01/17/2001
- Date modified: 01/17/2001 by Mat Ballard
- Purpose: screen click management
- Known Issues: overrides TRectangle.ClickedOn
- ------------------------------------------------------------------------------}
- function TAngleAxis.ClickedOn(iX, iY: Integer): Boolean;
- var
- Slope, Intercept, Distance: Single;
- begin
- if ((FAngle = 0) or
- (FAngle = 90) or
- (FAngle = 180) or
- (FAngle = 270)) then
- Result := inherited ClickedOn(iX, iY)
- else
- begin
- Result := FALSE;
-
- if (iX < NoMath.Min(Left, FEndX)) then exit;
- if (iX > NoMath.Max(Left, FEndX)) then exit;
- if (iY < NoMath.Min(Top, FEndY)) then exit;
- if (iY > NoMath.Max(Top, FEndY)) then exit;
-
- Slope := - (Top - FEndY) / (Left - FEndX);
- Intercept := Top + Slope * Left;
- Distance := Abs((Slope * iX - Intercept + iY) * Sin(FAngleRadians));
- if (Distance < FTicksize) then
- Result := TRUE;
- end;
- end;
-
- {------------------------------------------------------------------------------
- Procedure: TAngleAxis.Outline
- Description: Draws an Outline around this AngleAxis
- Author: Mat Ballard
- Date created: 01/22/2001
- Date modified: 01/22/2001 by Mat Ballard
- Purpose: gives the user a guide to what they are moving with the mouse
- Known Issues:
- ------------------------------------------------------------------------------}
- procedure TAngleAxis.Outline(ACanvas: TCanvas);
- var
- dP: TPoint;
- begin
- ACanvas.Pen.Color := clBlack;
- ACanvas.Pen.Mode := pmNotXOR;
- ACanvas.Pen.Style := psDash;
-
- dP.x := Round(FTickSize * FCos);
- dP.y := -Round(FTickSize * FSin);
-
- ACanvas.Polygon([
- Point(Left + dP.x, Top + dP.y),
- Point(Left - dP.x, Top - dP.y),
- Point(FEndX - dP.x, FEndY - dP.y),
- Point(FEndX + dP.x, FEndY + dP.y)]);
- end;
-
-
- end.
-