home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 October / Chip_2001-10_cd1.bin / zkuste / delphi / kompon / d123456 / CHEMPLOT.ZIP / TPlot / Axis.pas < prev    next >
Pascal/Delphi Source File  |  2001-07-23  |  72KB  |  2,208 lines

  1. unit Axis;
  2.  
  3. {$I Plot.inc}
  4.  
  5. {-----------------------------------------------------------------------------
  6. The contents of this file are subject to the Q Public License
  7. ("QPL"); you may not use this file except in compliance
  8. with the QPL. You may obtain a copy of the QPL from 
  9. the file QPL.html in this distribution, derived from:
  10.  
  11. http://www.trolltech.com/products/download/freelicense/license.html
  12.  
  13. The QPL prohibits development of proprietary software. 
  14. There is a Professional Version of this software available for this. 
  15. Contact sales@chemware.hypermart.net for more information.
  16.  
  17. Software distributed under the QPL is distributed on an "AS IS" basis,
  18. WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the QPL for
  19. the specific language governing rights and limitations under the QPL.
  20.  
  21. The Original Code is: Axis.pas, released 12 September 2000.
  22.  
  23. The Initial Developer of the Original Code is Mat Ballard.
  24. Portions created by Mat Ballard are Copyright (C) 1999 Mat Ballard.
  25. Portions created by Microsoft are Copyright (C) 1998, 1999 Microsoft Corp.
  26. All Rights Reserved.
  27.  
  28. Contributor(s): Mat Ballard                 e-mail: mat.ballard@chemware.hypermart.net.
  29.  
  30. Last Modified: 04/09/2001
  31. Current Version: 2.00
  32.  
  33. You may retrieve the latest version of this file from:
  34.  
  35.         http://Chemware.hypermart.net/
  36.  
  37. This work was created with the Project JEDI VCL guidelines:
  38.  
  39.         http://www.delphi-jedi.org/Jedi:VCLVCL
  40.  
  41. in mind. 
  42.  
  43. Purpose:
  44. To implement an Axis component for use by the main TPlot graphing component.
  45.  
  46. Known Issues:
  47.  
  48. History:
  49.  1.01 21 September 2000: fix FontWidth bug in TAxis.Draw
  50.         add LabelText property to TAxis (for columns)
  51. -----------------------------------------------------------------------------}
  52.  
  53. interface
  54.  
  55. uses
  56.   Classes, SysUtils,
  57. {$IFDEF WINDOWS}
  58.   WinTypes, WinProcs,
  59.   Graphics,
  60. {$ENDIF}
  61. {$IFDEF WIN32}
  62.   Windows,
  63.   Graphics,
  64. {$ENDIF}
  65. {$IFDEF LINUX}
  66.   Types,
  67.   QGraphics,
  68. {$ENDIF}
  69.  
  70. {$IFNDEF NO_MATH}
  71.   Math,
  72. {$ENDIF}
  73.   Misc, NoMath, Plotdefs, Titles;
  74.  
  75. {const}
  76.  
  77. type
  78.   TAxisType = (atPrimary, atSecondary, atTertiary, atZ);
  79.  
  80.   TLabelFormat = (
  81.     lfGeneral, lfExponent, lfFixed, lfNumber, lfCurrency,
  82.     lfSI, lfPercent,
  83.     lfSeconds, lfMinutes, lfHours, lfDays, lfShortTime, lfShortDate);
  84. {lfGeneral ... lfCurrency are just TFloatFormat.}
  85. {}
  86. {We then add SI and Percentage, then the rest are so that we can display times in various formats.}
  87. {}
  88. {NOTE: SI means the standard SI postfixes: p, n u, m, -, K, M, G, T}
  89.  
  90. {  TOnPositionChangeEvent = procedure(
  91.     Sender: TObject;
  92.     bIntercept: Boolean; did the Intercept change ? or the screen position ?
  93.     var TheIntercept: Single;
  94.     var ThePosition: Integer) of object;}
  95.  
  96. {Begin TAxisLabel declarations ------------------------------------------------}
  97.   TAxisLabel = class(TCaption)
  98.   private
  99.     FDirection: TDirection;
  100.     FDigits: Byte;
  101.     FPrecision: Byte;
  102.     FNumberFormat: TLabelFormat;
  103.  
  104.     {OnChange: TNotifyEvent; is in TRectangle !}
  105.  
  106.     procedure SetDirection(Value: TDirection);
  107.     procedure SetDigits(Value: Byte);
  108.     procedure SetPrecision(Value: Byte);
  109.     procedure SetNumberFormat(Value: TLabelFormat);
  110.  
  111.   protected
  112.  
  113.   public
  114.     Constructor Create(AOwner: TPersistent); override;
  115. {The standard constructor, where standard properties are set.}
  116.     Destructor Destroy; override;
  117. {The standard destructor, where the OnChange event is "freed".}
  118.  
  119.     {procedure Assign(Source: TPersistent); override;}
  120.     procedure AssignTo(Dest: TPersistent); override;
  121.  
  122.   published
  123.     Property Direction: TDirection read FDirection write SetDirection;
  124. {Is the Label Horizontal (X) or Vertical (Y or Y2).}
  125.     Property Digits: Byte read FDigits write SetDigits;
  126. {This (and Precision) control the numeric format of the Axis Labels.
  127.  See the Borland documentation on FloatToStrF for the precise meaning of
  128.  this property, or simply experiment in the IDE designer.}
  129.     Property Precision: Byte read FPrecision write SetPrecision;
  130. {This (and Digits) control the numeric format of the Axis Labels.
  131.  See the Borland documentation on FloatToStrF for the precise meaning of
  132.  this property, or simply experiment in the IDE designer.}
  133.     Property NumberFormat: TLabelFormat read FNumberFormat write SetNumberFormat;
  134. {This property controls how the numbers of the Axis labels are displayed.}
  135.  
  136.   end;
  137.  
  138. {Begin TAxis declarations ---------------------------------------------------}
  139.   TAxis = class(TRectangle)
  140.   private
  141.     FArrowSize: Byte;
  142.     FAutoScale: Boolean;
  143.     FAutoZero: Boolean;
  144.     FAxisType: TAxisType;
  145.     FDirection: TDirection;
  146.     FIntercept: Single;
  147.     FLabels: TAxisLabel;
  148.     FLabelSeries: TPersistent;
  149.     FLimitLower: Single;
  150.     FLimitUpper: Single;
  151.     FLimitsVisible: Boolean;
  152.     FLogScale: Boolean;
  153.     FLogSpan: Single;
  154.     FMin: Single;
  155.     FMax: Single;
  156.     FPen: TPen;
  157.     FStepSize: Single;
  158.     FStepStart: Single;
  159.     FSpan: Single;
  160.     FTickMinor: Byte;
  161.     FTickSign: Integer;
  162.     FTickSize: Byte;
  163.     FTickDirection: TOrientation;
  164.     FTickNum: Byte;
  165.     FTitle: TTitle;
  166.     FZoomIntercept: Single;
  167.     FZoomMin: Single;
  168.     FZoomMax: Single;
  169.  
  170.     PrecisionAdded: Integer;
  171.  
  172.     procedure SetupHorizontalEnvelope;
  173.     procedure SetupVerticalEnvelope;
  174.  
  175.   protected
  176. {Set procedures:}
  177.     procedure SetArrowSize(Value: Byte);
  178.     procedure SetAutoScale(Value: Boolean);
  179.     procedure SetAutoZero(Value: Boolean);
  180.     procedure SetDirection(Value: TDirection);
  181.     procedure SetIntercept(Value: Single);
  182.     procedure SetLimitLower(Value: Single);
  183.     procedure SetLimitUpper(Value: Single);
  184.     procedure SetLimitsVisible(Value: Boolean);
  185.     procedure SetLogScale(Value: Boolean);
  186.     procedure SetMin(Value: Single);
  187.     procedure SetMax(Value: Single);
  188.     procedure SetPen(Value: TPen);
  189.     procedure SetStepSize(Value: Single);
  190.     procedure SetStepStart(Value: Single);
  191.     procedure SetTickMinor(Value: Byte);
  192.     {procedure SetTickNum(Value: Byte);}
  193.     procedure SetTickSize(Value: Byte);
  194.     procedure SetOrientation(Value: TOrientation);
  195.  
  196.     procedure StyleChange(Sender: TObject); virtual;
  197.     procedure TitleChange(Sender: TObject); virtual;
  198.  
  199.   public
  200.     procedure ReScale;
  201.  
  202.     Property AxisType: TAxisType read FAxisType write FAxisType;
  203. {What sort of axis is this ?}
  204.     Property ZoomIntercept: Single read FZoomIntercept write FZoomIntercept;
  205. {The (old) ZOOMED OUT Intercept in data co-ordinates.}
  206.     Property ZoomMin: Single read FZoomMin write FZoomMin;
  207. {The (old) ZOOMED OUT minimum, Left or Bottom of the Axis, in data co-ordinates.}
  208.     Property ZoomMax: Single read FZoomMax write FZoomMax;
  209. {The (old) ZOOMED OUT maximum, Right or Top of the Axis, in data co-ordinates.}
  210.  
  211.     Constructor Create(AOwner: TPersistent); {$IFDEF DELPHI4_UP}reintroduce;{$ENDIF} {squelch the error message}
  212. {The standard constructor, where sub-components are created, and standard
  213.  properties are set.}
  214.  
  215.  
  216.     Destructor Destroy; override;
  217. {The standard destructor, where sub-components and the OnChange event is "freed".}
  218.  
  219.     procedure Draw(ACanvas: TCanvas; LimitPos: Integer); virtual;
  220. {This draws the Axis on the given Canvas.}
  221.     function GetNextXValue(XValue: Single): Single;
  222. {This calculates the next tick point. Used externally by TCustomPlot.DrawGrid}
  223.     function LabelToStrF(Value: Single): String;
  224. {This method converts a number to a string, given the current Labels' NumberFormat.}
  225.     function StrToLabel(Value: String): Single;
  226. {This method converts a string to a number, given the current Labels' NumberFormat.}
  227.     function FofX(X: Single): Integer;
  228. {This converts an X data value to a screen X co-ordinate.}
  229.     function FofY(Y: Single): Integer;
  230. {This converts a Y data value to a screen Y co-ordinate.}
  231.     function XofF(F: Integer): Single;
  232. {This converts a screen X co-ordinate to a X data value.}
  233.     function YofF(F: Integer): Single;
  234. {This converts a screen Y co-ordinate to a Y data value.}
  235.     procedure SetLabelSeries(Value: TPersistent);
  236. {This is called by a series to set the X data as strings.}
  237.     procedure SetMinFromSeries(Value: Single);
  238. {This sets the Min property of the Axis. It is used exclusively by TSeries.}
  239.     procedure SetMaxFromSeries(Value: Single);
  240. {This sets the Max property of the Axis. It is used exclusively by TSeries.
  241.  Exactly how it affects the Axis depends on TPlot.DisplayMode.}
  242.     procedure SetMinMaxFromSeries(AMin, AMax: Single);
  243. {This sets the Min and Max properties of the Axis. It is used exclusively by TSeries.
  244.  Exactly how it affects the Axis depends on TPlot.DisplayMode.}
  245.  
  246.     {procedure Assign(Source: TPersistent); override;}
  247.     procedure AssignTo(Dest: TPersistent); override;
  248.  
  249.   published
  250.     Property ArrowSize: Byte read FArrowSize write SetArrowSize;
  251. {This is the size (in pixels) of the arrowhead on the Axis.}
  252.     Property AutoScale: Boolean read FAutoScale write SetAutoScale default TRUE;
  253. {Do we use the StepSize property or does TPlot work them out ?}
  254.     Property AutoZero: Boolean read FAutoZero write SetAutoZero;
  255. {Do we use the StepSize property or does TPlot work them out ?}
  256.     Property Title: TTitle read FTitle write FTitle;
  257. {The Title on and of the Axis. Note that the Title can be clicked and dragged
  258.  around the Axis.}
  259.     Property Direction: TDirection read FDirection write SetDirection;
  260. {Is the Axis Horizontal (X) or Vertical (Y or Y2).}
  261.     Property Intercept: Single read FIntercept write SetIntercept;
  262. {The intercept of this Axis on the complementary Axis.}
  263.     Property Labels: TAxisLabel read FLabels write FLabels;
  264. {The numerals on the Axis.}
  265.     property LimitLower: Single read FLimitLower write SetLimitLower;
  266. {The lower limit, drawn perpendicular to the axis with a dashed line, if LimitsVisible.}
  267.     property LimitUpper: Single read FLimitUpper write SetLimitUpper;
  268. {The upper limit, drawn perpendicular to the axis with a dashed line, if LimitsVisible.}
  269.     property LimitsVisible: Boolean read FLimitsVisible write SetLimitsVisible;
  270. {Determines if Limits perpendicular to the Axis are drawn.}
  271.     Property LogScale: Boolean read FLogScale write SetLogScale;
  272. {Is this Axis on a logarithmic scale ?}
  273.     Property Min: Single read FMin write SetMin;
  274. {The minimum, Left or Bottom of the Axis, in data co-ordinates.}
  275.     Property Max: Single read FMax write SetMax;
  276. {The maximum, Right or Top of the Axis, in data co-ordinates.}
  277.     Property Pen: TPen read FPen write SetPen;
  278. {The Pen that the Axis is drawn with.}
  279.     Property StepSize: Single read FStepSize write SetStepSize;
  280. {The interval between tick (and labels) on the Axis.}
  281. {}
  282. {If the axis is a Log Scale, then this is the multiple, not the interval !}
  283.     Property StepStart: Single read FStepStart write SetStepStart;
  284. {The interval between tick (and labels) on the Axis.}
  285.     Property TickMinor: Byte read FTickMinor write SetTickMinor;
  286. {Sets the number of minor ticks between labels.}
  287.     Property TickSize: Byte read FTickSize write SetTickSize;
  288. {The Length of the Ticks, in screen pixels.}
  289.     Property TickDirection: TOrientation read FTickDirection write SetOrientation;
  290. {Are the Ticks to the left or right of the Axis ?}
  291.     {Property TickNum: Byte read FTickNum write SetTickNum;}
  292. {The approximate number of ticks: TPlot recalculates the number of ticks
  293.  depending on the StepSize.}
  294.  
  295.   end;
  296.  
  297.   TAngleAxis = class(TAxis)
  298. {The TAngleAxis class is a TAxis that is at any angle.
  299.  It will be used in the 3D and Polar PlotTypes.}
  300. {Note that the (Left, Top) is now interpreted as the origin}
  301.   private
  302.     FAngle: Word;
  303.     FAngleRadians: Single;
  304.     FLength: Word;
  305.     FZInterceptY: Single;
  306.  
  307.     FEndX,
  308.     FEndY: Integer;
  309.     FSin,
  310.     FCos,
  311.     FSinM30,
  312.     FCosM30,
  313.     FSinP30,
  314.     FCosP30: Extended;
  315.   protected
  316.     procedure SetAngle(Value: Word);
  317.     procedure SetLength(Value: Word);
  318.     procedure SetZInterceptY(Value: Single);
  319.  
  320.   public
  321.     property EndX: Integer read FEndX;
  322.     property EndY: Integer read FEndY;
  323.  
  324.     constructor Create(AOwner: TPersistent);
  325.     destructor Destroy; override;
  326.  
  327.     function ClickedOn(iX, iY: Integer): Boolean; override;
  328. {Was this Z Axis clicked on ?}
  329.     procedure Outline(ACanvas: TCanvas); override;
  330.  
  331.     function FofZ(Z: Single): Integer;
  332.     function dFofZ(Z: Single): TPoint;
  333.  
  334.     procedure Draw(ACanvas: TCanvas; LimitPos: Integer); override;
  335.  
  336.   published
  337.     property Angle: Word read FAngle write SetAngle;
  338. {Angle is the angle (in degrees) between the vertical Y Axis, and this axis,
  339.  in a clockwise direction.}
  340.     property Length: Word read FLength write SetLength;
  341. {This is the (screen) length of the axis.}
  342.     property ZInterceptY: Single read FZInterceptY write SetZInterceptY;
  343. {The intercept of this Z Axis on the Y Axis.}
  344. {}
  345. {Z Axex have _TWO_ intercepts - an X and a Y.}
  346. {}
  347. {Note that we now, in TAngleAxis, interpret the Intercept property as the
  348.  intercept of the Z Axis with the X Axis.}
  349.   end;
  350.  
  351.   
  352. implementation
  353.  
  354. uses
  355.   Data, Plot;
  356.  
  357. {TAxislabel methods ---------------------------------------------------------}
  358. {Constructor and Destructor:-------------------------------------------------}
  359. {------------------------------------------------------------------------------
  360.   Constructor: TAxisLabel.Create
  361.   Description: standard Constructor
  362.        Author: Mat Ballard
  363.  Date created: 04/25/2000
  364. Date modified: 04/25/2000 by Mat Ballard
  365.       Purpose: sets the Precision and Digits Properties
  366.  Known Issues:
  367.  ------------------------------------------------------------------------------}
  368. Constructor TAxisLabel.Create(AOwner: TPersistent);
  369. begin
  370. {First call the ancestor:}
  371.   inherited Create(AOwner);
  372.  
  373. {Put your own initialisation (memory allocation, etc) here:}
  374.  
  375. {we insert the default values that cannot be "defaulted":}
  376.   FPrecision := 3;
  377.   FDigits := 1;
  378. end;
  379.  
  380. {------------------------------------------------------------------------------
  381.   Destructor: TAxisLabel.Destroy
  382.   Description: standard Destructor
  383.        Author: Mat Ballard
  384.  Date created: 04/25/2000
  385. Date modified: 04/25/2000 by Mat Ballard
  386.       Purpose: frees the OnChange event
  387.  Known Issues:
  388.  ------------------------------------------------------------------------------}
  389. Destructor TAxisLabel.Destroy;
  390. begin
  391.   OnChange := nil;
  392. {Put your de-allocation, etc, here:}
  393.  
  394. {then call ancestor:}
  395.  inherited Destroy;
  396. end;
  397.  
  398. {End Constructor and Destructor:---------------------------------------------}
  399.  
  400. {------------------------------------------------------------------------------
  401.     Procedure: TAxisLabel.Assign
  402.   Description: standard Assign method
  403.        Author: Mat Ballard
  404.  Date created: 07/06/2000
  405. Date modified: 07/06/2000 by Mat Ballard
  406.       Purpose: implements Assign
  407.  Known Issues:
  408.  ------------------------------------------------------------------------------}
  409. {procedure TAxisLabel.Assign(Source: TPersistent);
  410. begin
  411.   inherited Assign(Source);
  412.   FDigits := TAxisLabel(Source).Digits;
  413.   FNumberFormat := TAxisLabel(Source).NumberFormat;
  414.   FPrecision := TAxisLabel(Source).Precision;
  415. end;}
  416.  
  417. {------------------------------------------------------------------------------
  418.     Procedure: TAxisLabel.Assign
  419.   Description: standard Assign method
  420.        Author: Mat Ballard
  421.  Date created: 07/06/2000
  422. Date modified: 07/06/2000 by Mat Ballard
  423.       Purpose: implements Assign
  424.  Known Issues:
  425.  ------------------------------------------------------------------------------}
  426. procedure TAxisLabel.AssignTo(Dest: TPersistent);
  427. begin
  428.   inherited AssignTo(Dest);
  429.   TAxisLabel(Dest).Digits := FDigits;
  430.   TAxisLabel(Dest).NumberFormat := FNumberFormat;
  431.   TAxisLabel(Dest).Precision := FPrecision;
  432. end;
  433.  
  434. {Begin Set Procedures --------------------------------------------------------}
  435. {------------------------------------------------------------------------------
  436.     Procedure: TAxisLabel.SetDirection
  437.   Description: standard property Set procedure
  438.        Author: Mat Ballard
  439.  Date created: 03/25/2001
  440. Date modified: 03/25/2001 by Mat Ballard
  441.       Purpose: sets the Direction Property
  442.  Known Issues:
  443.  ------------------------------------------------------------------------------}
  444. procedure TAxisLabel.SetDirection(Value: TDirection);
  445. begin
  446.   if (FDirection = Value) then exit;
  447.  
  448.   FDirection := Value;
  449.   if Assigned(OnChange) then OnChange(Self);
  450. end;
  451.  
  452. {------------------------------------------------------------------------------
  453.     Procedure: TAxisLabel.SetDigits
  454.   Description: standard property Set procedure
  455.        Author: Mat Ballard
  456.  Date created: 04/25/2000
  457. Date modified: 04/25/2000 by Mat Ballard
  458.       Purpose: sets the Digits Property
  459.  Known Issues:
  460.  ------------------------------------------------------------------------------}
  461. procedure TAxisLabel.SetDigits(Value: Byte);
  462. begin
  463.   if (FDigits = Value) then exit;
  464.  
  465.   if (FDigits > 18) then exit;
  466.  
  467.   case FNumberFormat of
  468.     lfGeneral:  if (FDigits > 4) then exit;
  469.     lfExponent: if (FDigits > 4) then exit;
  470.   end;
  471.   FDigits := Value;
  472.  
  473.   if Assigned(OnChange) then OnChange(Self);
  474. end;
  475.  
  476. {------------------------------------------------------------------------------
  477.     Procedure: TAxisLabel.SetPrecision
  478.   Description: standard property Set procedure
  479.        Author: Mat Ballard
  480.  Date created: 04/25/2000
  481. Date modified: 04/25/2000 by Mat Ballard
  482.       Purpose: sets the Precision Property
  483.  Known Issues:
  484.  ------------------------------------------------------------------------------}
  485. procedure TAxisLabel.SetPrecision(Value: Byte);
  486. begin
  487.   if (FPrecision = Value) then exit;
  488.   if (FPrecision > 7) then exit;
  489.   FPrecision := Value;
  490.  
  491.   if Assigned(OnChange) then OnChange(Self);
  492. end;
  493.  
  494. {------------------------------------------------------------------------------
  495.     Procedure: TAxisLabel.SetNumberFormat
  496.   Description: standard property Set procedure
  497.        Author: Mat Ballard
  498.  Date created: 04/25/2000
  499. Date modified: 04/25/2000 by Mat Ballard
  500.       Purpose: sets the NumberFormat Property
  501.  Known Issues:
  502.  ------------------------------------------------------------------------------}
  503. procedure TAxisLabel.SetNumberFormat(Value: TLabelFormat);
  504. begin
  505.   if (FNumberFormat = Value) then exit;
  506.   FNumberFormat := Value;
  507.   case FNumberFormat of
  508.     lfGeneral:  if (FDigits > 4) then FDigits := 4;
  509.     lfExponent: if (FDigits > 4) then FDigits := 4;
  510.   end;
  511.  
  512.   if Assigned(OnChange) then OnChange(Self);
  513. end;
  514.  
  515. {TAxis methods --------------------------------------------------------------}
  516. {Constructor and Destructor:-------------------------------------------------}
  517. {------------------------------------------------------------------------------
  518.   Constructor: TAxis.Create
  519.   Description: standard Constructor
  520.        Author: Mat Ballard
  521.  Date created: 04/25/2000
  522. Date modified: 04/25/2000 by Mat Ballard
  523.       Purpose: creates the subcomponents and sets various Properties
  524.  Known Issues:
  525.  ------------------------------------------------------------------------------}
  526. Constructor TAxis.Create(AOwner: TPersistent);
  527. begin
  528. {First call the ancestor:}
  529.   inherited Create(AOwner);
  530.  
  531. {Create Pen:}
  532.   FPen := TPen.Create;
  533.   FPen.Color := clRed;
  534.  
  535.   FLabels := TAxisLabel.Create(Self);
  536.   FLabels.OnChange := StyleChange;
  537.   FLabelSeries := nil;
  538.  
  539. {create the Title geometry manager:}
  540.   FTitle := TTitle.Create(Self);
  541.   FTitle.OnChange := StyleChange;
  542.   FTitle.OnCaptionChange := TitleChange;
  543.   FTitle.Caption := 'X-' + sAxis;
  544.   FTitle.Font.Size := MEDIUM_FONT_SIZE;
  545.  
  546.   FArrowSize := 10;
  547.   FAutoScale := TRUE;
  548.   FAxisType := atPrimary;
  549.   SetDirection(drHorizontal);
  550.   FIntercept := 0;
  551.   FMin := 0;
  552.   FMax := 10;
  553.   FLimitLower := 3;
  554.   FLimitUpper := 7;
  555.   FTickDirection := orRight;
  556.   FTickSize := 10;
  557.   FTickNum := 5;
  558.   Alignment := taRightJustify;
  559.   Visible := TRUE;
  560.   ReScale;
  561. end;
  562.  
  563. {------------------------------------------------------------------------------
  564.   Destructor: TAxis.Destroy
  565.   Description: standard Destructor
  566.        Author: Mat Ballard
  567.  Date created: 04/25/2000
  568. Date modified: 04/25/2000 by Mat Ballard
  569.       Purpose: frees the subcomponents and the OnChange event
  570.  Known Issues:
  571.  ------------------------------------------------------------------------------}
  572. Destructor TAxis.Destroy;
  573. begin
  574.   OnChange := nil;
  575. {Put your de-allocation, etc, here:}
  576.   FLabels.Free;
  577.   FPen.Free;
  578.   FTitle.Free;
  579.  
  580. {then call ancestor:}
  581.   inherited Destroy;
  582. end;
  583. {End Constructor and Destructor:---------------------------------------------}
  584.  
  585. {------------------------------------------------------------------------------
  586.     Procedure: TAxis.TitleChange
  587.   Description: sets the Name and Label's Name
  588.        Author: Mat Ballard
  589.  Date created: 04/25/2000
  590. Date modified: 04/25/2000 by Mat Ballard
  591.       Purpose: responds to a change in the Title
  592.  Known Issues:
  593.  ------------------------------------------------------------------------------}
  594. procedure TAxis.TitleChange(Sender: TObject);
  595. begin
  596.   if (Pos('xis', FTitle.Caption) > 0) then
  597.   begin
  598.     Name := FTitle.Caption;
  599.     FLabels.Name := FTitle.Caption + ' ' + sLabels;
  600.   end
  601.   else
  602.   begin
  603. {Stick Axis in in the names:}
  604.     Name := FTitle.Caption + ' ' + sAxis;
  605.     FLabels.Name := FTitle.Caption + ' ' + sAxis + ' ' + sLabels;
  606.   end;
  607. end;
  608.  
  609. {Begin normal Set Procedures -------------------------------------------------}
  610. {------------------------------------------------------------------------------
  611.     Procedure: TAxis.SetArrowSize
  612.   Description: standard property Set procedure
  613.        Author: Mat Ballard
  614.  Date created: 04/25/2000
  615. Date modified: 04/25/2000 by Mat Ballard
  616.       Purpose: sets the ArrowSize Property
  617.  Known Issues:
  618.  ------------------------------------------------------------------------------}
  619. procedure TAxis.SetArrowSize(Value: Byte);
  620. begin
  621.   if (Value = FArrowSize) then exit;
  622.  
  623.   FArrowSize := Value;
  624.   StyleChange(Self);
  625. end;
  626.  
  627. {------------------------------------------------------------------------------
  628.     Procedure: TAxis.SetAutoScale
  629.   Description: standard property Set procedure
  630.        Author: Mat Ballard
  631.  Date created: 04/25/2000
  632. Date modified: 04/25/2000 by Mat Ballard
  633.       Purpose: sets the AutoScale Property
  634.  Known Issues:
  635.  ------------------------------------------------------------------------------}
  636. procedure TAxis.SetAutoScale(Value: Boolean);
  637. begin
  638.   if (Value = FAutoScale) then exit;
  639.  
  640.   FAutoScale := Value;
  641.   StyleChange(Self);
  642. end;
  643.  
  644. {------------------------------------------------------------------------------
  645.     Procedure: TAxis.SetAutoZero
  646.   Description: standard property Set procedure
  647.        Author: Mat Ballard
  648.  Date created: 04/25/2000
  649. Date modified: 04/25/2000 by Mat Ballard
  650.       Purpose: sets the AutoZero Property
  651.  Known Issues:
  652.  ------------------------------------------------------------------------------}
  653. procedure TAxis.SetAutoZero(Value: Boolean);
  654. begin
  655.   if (Value = FAutoZero) then exit;
  656.  
  657.   FAutoZero := Value;
  658.   StyleChange(Self);
  659. end;
  660.  
  661. {------------------------------------------------------------------------------
  662.     Procedure: TAxis.SetDirection
  663.   Description: standard property Set procedure
  664.        Author: Mat Ballard
  665.  Date created: 04/25/2000
  666. Date modified: 04/25/2000 by Mat Ballard
  667.       Purpose: sets the Direction Property
  668.  Known Issues:
  669.  ------------------------------------------------------------------------------}
  670. procedure TAxis.SetDirection(Value: TDirection);
  671. begin
  672.   if (Value = FDirection) then exit;
  673.  
  674.   FDirection := Value;
  675.   FTitle.Direction := Value;
  676. {TTitle.SetDirection usually fires the OnChange:}
  677.   if ((not FTitle.Visible) and
  678.       assigned(OnChange) and
  679.       Visible) then OnChange(Self);
  680. end;
  681.  
  682. {------------------------------------------------------------------------------
  683.     Procedure: TAxis.SetIntercept
  684.   Description: standard property Set procedure
  685.        Author: Mat Ballard
  686.  Date created: 04/25/2000
  687. Date modified: 04/25/2000 by Mat Ballard
  688.       Purpose: sets the Intercept virtual Property
  689.  Known Issues:
  690.  ------------------------------------------------------------------------------}
  691. procedure TAxis.SetIntercept(Value: Single);
  692. begin
  693.   if (FIntercept = Value) then exit;
  694.   FIntercept := Value;
  695.   {FAutoScale := FALSE;}
  696.   StyleChange(Self);
  697. end;
  698.  
  699. procedure TAxis.SetLimitLower(Value: Single);
  700. begin
  701.   FLimitLower := Value;
  702.   if (FLimitLower > FLimitUpper) then
  703.     FLimitUpper := Value;
  704.   StyleChange(Self);
  705. end;
  706.  
  707. procedure TAxis.SetLimitUpper(Value: Single);
  708. begin
  709.   FLimitUpper := Value;
  710.   if (FLimitUpper < FLimitLower) then
  711.     FLimitLower := Value;
  712.   StyleChange(Self);
  713. end;
  714.  
  715. procedure TAxis.SetLimitsVisible(Value: Boolean);
  716. begin
  717.   FLimitsVisible := Value;
  718.   StyleChange(Self);
  719. end;
  720.  
  721. {------------------------------------------------------------------------------
  722.     Procedure: TAxis.SetLogScale
  723.   Description: standard property Set procedure
  724.        Author: Mat Ballard
  725.  Date created: 04/25/2000
  726. Date modified: 04/25/2000 by Mat Ballard
  727.       Purpose: sets the LogScale Property
  728.  Known Issues:
  729.  ------------------------------------------------------------------------------}
  730. procedure TAxis.SetLogScale(Value: Boolean);
  731. begin
  732.   if (Value = FLogScale) then exit;
  733.   if (Value = TRUE) then
  734.   begin {we are going to a log scale:}
  735.     if (FMin <= 0) then exit;
  736.     if (FMax <= 0) then exit;
  737.   end;
  738.  
  739.   FLogScale := Value;
  740.   ReScale;
  741. end;
  742.  
  743. {------------------------------------------------------------------------------
  744.     Procedure: TAxis.SetMin
  745.   Description: standard property Set procedure
  746.        Author: Mat Ballard
  747.  Date created: 04/25/2000
  748. Date modified: 04/25/2000 by Mat Ballard
  749.       Purpose: sets the Min Property
  750.  Known Issues:
  751.  ------------------------------------------------------------------------------}
  752. procedure TAxis.SetMin(Value: Single);
  753. begin
  754.   if (Value = FMin) then exit;
  755.   if (Value >= FMax) then exit;
  756.   if ((Value <= 0) and (FLogScale)) then exit;
  757.  
  758.   FMin := Value;
  759.   ReScale;
  760. end;
  761.  
  762. {------------------------------------------------------------------------------
  763.     Procedure: TAxis.SetMax
  764.   Description: standard property Set procedure
  765.        Author: Mat Ballard
  766.  Date created: 04/25/2000
  767. Date modified: 04/25/2000 by Mat Ballard
  768.       Purpose: sets the Max Property
  769.  Known Issues:
  770.  ------------------------------------------------------------------------------}
  771. procedure TAxis.SetMax(Value: Single);
  772. begin
  773.   if (Value = FMax) then exit;
  774.   if (Value <= FMin) then exit;
  775.  
  776.   FMax := Value;
  777.   ReScale;
  778. end;
  779.  
  780. {------------------------------------------------------------------------------
  781.     Procedure: TAxis.SetMinFromSeries
  782.   Description: property Setting procedure for calling by a Series
  783.        Author: Mat Ballard
  784.  Date created: 04/25/2000
  785. Date modified: 04/25/2000 by Mat Ballard
  786.       Purpose: sets the Min Property when new data is added to a Series
  787.  Known Issues:
  788.  ------------------------------------------------------------------------------}
  789. procedure TAxis.SetMinFromSeries(Value: Single);
  790. begin
  791.   if (Value >= FMin) then exit;
  792.   if ((Value <= 0) and (FLogScale)) then exit;
  793.  
  794.   FMin := Value;
  795.   Rescale;
  796. end;
  797.  
  798. {------------------------------------------------------------------------------
  799.     Procedure: TAxis.SetMaxFromSeries
  800.   Description: property Setting procedure for calling by a Series
  801.        Author: Mat Ballard
  802.  Date created: 04/25/2000
  803. Date modified: 04/25/2000 by Mat Ballard
  804.       Purpose: sets the Max Property when new data is added to a Series
  805.  Known Issues:
  806.  ------------------------------------------------------------------------------}
  807. procedure TAxis.SetMaxFromSeries(Value: Single);
  808. begin
  809.   if (Value <= FMax) then exit;
  810.  
  811.   FMax := Value;
  812.   if ((TPlot(Owner).DisplayMode = dmRun) and
  813.       (FDirection = drHorizontal)) then
  814.   begin
  815. {We are in a "run", and so we can expect more data with increasing X values.
  816.  Rather than force a complete screen re-draw every time a data point is
  817.  added, we extend the X Axis by 100%:}
  818.     FMax := 2.0 * FMax;
  819.   end;
  820.   Rescale;
  821. end;
  822.  
  823. {------------------------------------------------------------------------------
  824.     Procedure: TAxis.SetMinMaxFromSeries
  825.   Description: multiple property Setting procedure for calling by a Series
  826.        Author: Mat Ballard
  827.  Date created: 05/29/2001
  828. Date modified: 05/29/2001 by Mat Ballard
  829.       Purpose: sets the Min Property when new data is added to a Series
  830.  Known Issues:
  831.  ------------------------------------------------------------------------------}
  832. procedure TAxis.SetMinMaxFromSeries(AMin, AMax: Single);
  833. begin
  834.   if (AMin >= AMax) then exit;
  835.   if ((AMin = FMin) and (AMax = FMax)) then exit;
  836.   if ((AMin <= 0) and (FLogScale)) then exit;
  837.  
  838.   FMin := AMin;
  839.   FMax := AMax;
  840.   Rescale;
  841. end;
  842.  
  843.  
  844. {------------------------------------------------------------------------------
  845.     Procedure: TAxis.SetPen
  846.   Description: standard property Set procedure
  847.        Author: Mat Ballard
  848.  Date created: 04/25/2000
  849. Date modified: 04/25/2000 by Mat Ballard
  850.       Purpose: sets the Pen Property
  851.  Known Issues:
  852.  ------------------------------------------------------------------------------}
  853. procedure TAxis.SetPen(Value: TPen);
  854. begin
  855.   FPen.Assign(Value);
  856.   {FFont.Color := FPen.Color;
  857.   FLabels.Font.Color := FPen.Color;}
  858.   StyleChange(Self);
  859. end;
  860.  
  861. {------------------------------------------------------------------------------
  862.     Procedure: TAxis.SetOrientation
  863.   Description: standard property Set procedure
  864.        Author: Mat Ballard
  865.  Date created: 04/25/2000
  866. Date modified: 04/25/2000 by Mat Ballard
  867.       Purpose: sets the Orientation Property
  868.  Known Issues:
  869.  ------------------------------------------------------------------------------}
  870. procedure TAxis.SetOrientation(Value: TOrientation);
  871. begin
  872.   {if (Value = FTickDirection) then exit;}
  873.  
  874.   FTickDirection := Value;
  875.   if (FTickDirection = orRight) then
  876.     FTickSign := 1
  877.    else
  878.     FTickSign := -1;
  879. {check the names of the titles and labels}
  880.   {TitleChange(Self);}
  881.   StyleChange(Self);
  882. end;
  883.  
  884. {------------------------------------------------------------------------------
  885.     Procedure: TAxis.SetStepSize
  886.   Description: standard property Set procedure
  887.        Author: Mat Ballard
  888.  Date created: 04/25/2000
  889. Date modified: 04/25/2000 by Mat Ballard
  890.       Purpose: sets the StepSize (distance between ticks) Property
  891.  Known Issues:
  892.  ------------------------------------------------------------------------------}
  893. procedure TAxis.SetStepSize(Value: Single);
  894. begin
  895.   if (FAutoScale) then exit;
  896.   if (Value = FStepSize) then exit;
  897.  
  898.   FStepSize := Value;
  899.   StyleChange(Self);
  900. end;
  901.  
  902. {------------------------------------------------------------------------------
  903.     Procedure: TAxis.SetStepStart
  904.   Description: standard property Set procedure
  905.        Author: Mat Ballard
  906.  Date created: 04/25/2000
  907. Date modified: 04/25/2000 by Mat Ballard
  908.       Purpose: sets the StepStart (where ticks start) Property
  909.  Known Issues:
  910.  ------------------------------------------------------------------------------}
  911. procedure TAxis.SetStepStart(Value: Single);
  912. begin
  913.   if (FAutoScale) then exit;
  914.   if (Value = FStepStart) then exit;
  915.  
  916.   FStepStart := Value;
  917.   StyleChange(Self);
  918. end;
  919.  
  920. {------------------------------------------------------------------------------
  921.     Procedure: TAxis.SetTickMinor
  922.   Description: standard property Set procedure
  923.        Author: Mat Ballard
  924.  Date created: 04/25/2000
  925. Date modified: 04/25/2000 by Mat Ballard
  926.       Purpose: sets the TickMinor (number of minor ticks) Property
  927.  Known Issues:
  928.  ------------------------------------------------------------------------------}
  929. procedure TAxis.SetTickMinor(Value: Byte);
  930. begin
  931.   if (Value = FTickMinor) then exit;
  932. {limit the number of minors:}
  933.   if (Value > 9) then
  934.     Value := 9;
  935.  
  936.   FTickMinor := Value;
  937.   StyleChange(Self);
  938. end;
  939.  
  940. {------------------------------------------------------------------------------
  941.     Procedure: TAxis.SetTickNum
  942.   Description: standard property Set procedure
  943.        Author: Mat Ballard
  944.  Date created: 04/25/2000
  945. Date modified: 04/25/2000 by Mat Ballard
  946.       Purpose: sets the TickNum Property
  947.  Known Issues:
  948.  ------------------------------------------------------------------------------
  949. procedure TAxis.SetTickNum(Value: Byte);
  950. begin
  951.   if (Value = FTickNum) then exit;
  952.  
  953.   FTickNum := Value;
  954.   ReScale;
  955. end;}
  956.  
  957. {------------------------------------------------------------------------------
  958.     Procedure: TAxis.SetTickSize
  959.   Description: standard property Set procedure
  960.        Author: Mat Ballard
  961.  Date created: 04/25/2000
  962. Date modified: 04/25/2000 by Mat Ballard
  963.       Purpose: sets the TickSize Property
  964.  Known Issues:
  965.  ------------------------------------------------------------------------------}
  966. procedure TAxis.SetTickSize(Value: Byte);
  967. begin
  968.   if (Value = FTickSize) then exit;
  969.  
  970.   FTickSize := Value;
  971.   ReScale;
  972. end;
  973.  
  974. {Various other Functions and Procedures--------------------------------------}
  975. {------------------------------------------------------------------------------
  976.     Procedure: TAxis.StyleChange
  977.   Description: event firing proedure
  978.        Author: Mat Ballard
  979.  Date created: 04/25/2000
  980. Date modified: 04/25/2000 by Mat Ballard
  981.       Purpose: fires the OnChange event
  982.  Known Issues:
  983.  ------------------------------------------------------------------------------}
  984. procedure TAxis.StyleChange(Sender: TObject);
  985. begin
  986.   if (assigned(OnChange) and Visible) then OnChange(Sender);
  987. end;
  988.  
  989. {------------------------------------------------------------------------------
  990.     Procedure: TAxis.ReScale
  991.   Description: geometry manager
  992.        Author: Mat Ballard
  993.  Date created: 04/25/2000
  994. Date modified: 04/25/2000 by Mat Ballard
  995.       Purpose: determines the ticks and labels
  996.  Known Issues:
  997.  ------------------------------------------------------------------------------}
  998. procedure TAxis.ReScale;
  999. {This method determines the Axis geometry (StepStart and StepSize).}
  1000. var
  1001.   Exponent: Integer;
  1002.   RoughStepSize: Single;
  1003.   Mantissa: Extended;
  1004. begin
  1005.   PrecisionAdded := 0;
  1006.   
  1007.   if (not FAutoScale) then
  1008.   begin
  1009.     FStepStart := FMin;
  1010.     FSpan := FMax - FMin;
  1011.     exit;
  1012.   end;
  1013.  
  1014.   if (FLogScale) then
  1015.   begin
  1016.     FLogSpan := Log10(FMax / FMin);
  1017.     DeSci(FMin, Mantissa, Exponent);
  1018. {work out a starting point, 1 x 10^Exponent:}
  1019.     FStepStart := IntPower(10.0, Exponent);
  1020.  
  1021.     if (not FAutoScale) then
  1022.     begin
  1023.       if (FLogSpan >= 2) then
  1024.       begin
  1025. {many decades of data:}
  1026.         if (not FAutoScale) then
  1027.           FStepSize := 10;
  1028.       end
  1029.       else
  1030.       begin
  1031.         RoughStepSize := FLogSpan / (FTickNum+1);
  1032.         RoughStepSize := Power(10.0, RoughStepSize);
  1033.         if (RoughStepSize > 1.5) then
  1034.         begin
  1035. {get the Mantissa and Exponent:}
  1036.           DeSci(RoughStepSize, Mantissa, Exponent);
  1037.           FStepSize := Round(Mantissa) * IntPower(10.0, Exponent);
  1038.         end
  1039.         else
  1040.         begin
  1041.           FStepSize := RoughStepSize;
  1042.         end;
  1043. {$IFDEF DELPHI3_UP}
  1044.         Assert(FStepSize > 1.0,
  1045.           'TAxis.ReScale ' + sRescale1 +
  1046.             FloatToStr(FStepSize));
  1047. {$ENDIF}
  1048.       end; {how big is FLogSpan ?}
  1049.     end; {not AutoScale}
  1050.     while (FStepStart <= FMin) do
  1051. {go to next multiple of FStepSize:}
  1052.       FStepStart := FStepSize * FStepStart;
  1053.   end
  1054.   else
  1055.   begin {normal linear scale:}
  1056.     FSpan := FMax - FMin;
  1057.     if ((FAutoScale) or (FStepSize <= 0)) then
  1058.     begin
  1059.       RoughStepSize := FSpan / (FTickNum+1);
  1060. {get the Mantissa and Exponent:}
  1061.       DeSci(RoughStepSize, Mantissa, Exponent);
  1062.  
  1063.       FStepSize := Round(Mantissa) * IntPower(10.0, Exponent);
  1064.       {FTickNum := Trunc(FSpan / FStepSize);}
  1065.     end;
  1066.     FStepStart := FStepSize * Int((FMin / FStepSize) + 0.999);
  1067. {increase FStepStart by FStepSize:}
  1068.     while (FStepStart <= FMin) do
  1069.       FStepStart := FStepSize + FStepStart;
  1070.  
  1071. {PrecisionAdded is the added precision needed to display numerical labels with
  1072.  sufficient precision to be distinguishable:}
  1073.     if (Exponent <= -FLabels.FDigits) then
  1074.       PrecisionAdded := 1 - FLabels.FDigits - Exponent;
  1075.   end;
  1076.  
  1077.   StyleChange(Self);
  1078. end;
  1079.  
  1080. {------------------------------------------------------------------------------
  1081.     Procedure: TAxis.GetNextXValue
  1082.   Description: auxilary procedure for  Drawing 
  1083.        Author: Mat Ballard
  1084.  Date created: 02/28/2001
  1085. Date modified: 02/28/2001 by Mat Ballard
  1086.       Purpose: calculates the next tick point
  1087.  Known Issues:
  1088.  ------------------------------------------------------------------------------}
  1089. function TAxis.GetNextXValue(XValue: Single): Single;
  1090. begin
  1091.   if (FLogScale) then
  1092.     GetNextXValue := XValue * FStepSize
  1093.    else
  1094.     GetNextXValue := XValue + FStepSize;
  1095. end;
  1096.  
  1097.  
  1098. {------------------------------------------------------------------------------
  1099.     Procedure: TAxis.Draw
  1100.   Description: standard Drawing procedure
  1101.        Author: Mat Ballard
  1102.  Date created: 04/25/2000
  1103. Date modified: 04/25/2000 by Mat Ballard
  1104.       Purpose: draws the Axis on a given canvas
  1105.  Known Issues:
  1106.  ------------------------------------------------------------------------------}
  1107. procedure TAxis.Draw(ACanvas: TCanvas; LimitPos: Integer);
  1108. {Comments:
  1109.  This method is quite complex, in a tedious way.
  1110.  It has to account for the following variations:
  1111.     1. Visible or not;
  1112.     2. Arrows visible or not;
  1113.     3. Axis direction (Horizontal or vertical);
  1114.     4. Tick (and Label and Title) direction);
  1115.     5. Title Alignment Direction and Orientation;
  1116.     6. Tick, Label and Title visibility.
  1117.  An added complication is that we must generate a vertical font for the Title
  1118.  of vertical axes. Note that this only works with TrueType fonts - NOT fonts
  1119.  that are purely screen or printer.}
  1120. var
  1121.   i,
  1122.   iX, iY,
  1123.   iXLabel, iYLabel,
  1124.   iXTick, iYTick,
  1125.   FontHeight,
  1126.   FontWidth,
  1127.   iFontWidth,
  1128.   FontDescent,
  1129.   MinorTickSize: Integer;
  1130.   MinorStepSize,
  1131.   MinorStepStart,
  1132.   YValue,
  1133.   XValue: Single;
  1134.   DoTextLabels: Boolean;
  1135.   TheText: String;
  1136.  
  1137.   function GetNextMinorXValue(XValue: Single): Single;
  1138.   begin
  1139.     if (FLogScale) then
  1140.       GetNextMinorXValue := XValue * MinorStepSize
  1141.      else
  1142.       GetNextMinorXValue := XValue + MinorStepSize;
  1143.   end;
  1144.  
  1145.   procedure XLabelOut;
  1146.   begin
  1147.     iFontWidth := ACanvas.TextWidth(TheText);
  1148.     if (iFontWidth > FontWidth) then
  1149.       FontWidth := iFontWidth;
  1150.     if (FLabels.Direction = drHorizontal) then
  1151.       ACanvas.TextOut(iX - iFontWidth div 2, iYLabel, TheText)
  1152.      else
  1153.       if (FTickDirection = orLeft) then
  1154.         TextOutAngle(ACanvas, 90, iX - FontHeight div 2, iYLabel, TheText)
  1155.        else
  1156.         TextOutAngle(ACanvas, 90, iX - FontHeight div 2, iYLabel + FontWidth, TheText);
  1157.   end;
  1158.  
  1159.   procedure YLabelOut;
  1160.   begin
  1161.     iFontWidth := ACanvas.TextWidth(TheText);
  1162.     if (iFontWidth > FontWidth) then
  1163.       FontWidth := iFontWidth;
  1164.     if (FLabels.Direction = drHorizontal) then
  1165.     begin
  1166.       if (FTickDirection = orLeft) then
  1167.         ACanvas.TextOut(iXLabel - iFontWidth, iY - FontHeight + FontDescent, TheText)
  1168.        else
  1169.         ACanvas.TextOut(iXLabel, iY - FontHeight + FontDescent, TheText)
  1170.     end
  1171.     else
  1172.       if (FTickDirection = orLeft) then
  1173.         TextOutAngle(ACanvas, 90, iXLabel - FontHeight, iY + FontWidth div 2, TheText)
  1174.        else
  1175.         TextOutAngle(ACanvas, 90, iXLabel, iY + FontWidth div 2, TheText);
  1176.   end;
  1177.  
  1178.   procedure DoHorzArrow(Point, Size: Integer);
  1179.   begin
  1180.     ACanvas.MoveTo(Point + Size, Top);
  1181.     ACanvas.LineTo(Point, MidY);
  1182.     ACanvas.LineTo(Point + Size, Bottom);
  1183.   end;
  1184.  
  1185.   procedure DoArrow(P1, P2, P3: TPoint);
  1186.   begin
  1187.     ACanvas.MoveTo(P1.x, P1.y);
  1188.     ACanvas.LineTo(P2.x, P2.y);
  1189.     ACanvas.LineTo(P3.x, P3.y);
  1190.   end;
  1191.  
  1192. begin
  1193. {the most common reason for exit:}
  1194.   if (not Visible) then exit;
  1195. {$IFDEF DELPHI3_UP}
  1196.   Assert(ACanvas <> nil, 'TAxis.Draw: ' + sACanvasIsNil);
  1197. {$ENDIF}
  1198.  
  1199.   FontWidth := 1;
  1200.   ACanvas.Pen.Assign(FPen);
  1201.  
  1202.   if (FLabels.Visible) then
  1203.   begin
  1204.     ACanvas.Font.Assign(FLabels.Font);
  1205.     FontHeight := ACanvas.TextHeight('9');
  1206.     FontWidth := ACanvas.TextWidth('9');
  1207. {We could call GetOutlineTextMetrics to get
  1208.  the Descent (gap between baseline and bottom of a font), but:}
  1209.     FontDescent := FontHeight div 5;
  1210.   end;
  1211.  
  1212. {Provide ability for Y Axis labels:}
  1213.   DoTextLabels := FALSE;
  1214.   if (FLabelSeries <> nil) then
  1215.     if (TSeries(FLabelSeries).XStringData <> nil) then
  1216.       if (TSeries(FLabelSeries).XStringData.Count > 0) then
  1217.         DoTextLabels := TRUE;
  1218.  
  1219.   if (FDirection = drHorizontal) then
  1220.   begin
  1221. {Draw the axis:}
  1222.     ACanvas.MoveTo(Left, MidY);
  1223.     ACanvas.LineTo(Right, MidY);
  1224. {Draw the arrows on the axis:}
  1225.     if (FArrowSize > 0) then
  1226.     begin {taCenter therefore means no arrows !}
  1227.       if (Alignment = taLeftJustify) then
  1228.         DoArrow(Point(Left+FArrowSize, Top), Point(Left, MidY), Point(Left+FArrowSize, Bottom));
  1229.       if (Alignment = taRightJustify) then
  1230.         DoArrow(Point(Right-FArrowSize, Top), Point(Right, MidY), Point(Right-FArrowSize, Bottom));
  1231.     end;
  1232.  
  1233.     if (Self.LimitsVisible) then
  1234.     begin
  1235.       ACanvas.Pen.Style := psDot;
  1236.       iX := Self.FofX(FLimitLower);
  1237.       ACanvas.MoveTo(iX, Self.MidY);
  1238.       ACanvas.LineTo(iX, LimitPos);
  1239.       iX := Self.FofX(FLimitUpper);
  1240.       ACanvas.MoveTo(iX, Self.MidY);
  1241.       ACanvas.LineTo(iX, LimitPos);
  1242.       ACanvas.Pen.Style := Self.Pen.Style;
  1243.     end;
  1244.  
  1245.     iY := MidY;
  1246.     iYTick := MidY + FTickSign*FTickSize;
  1247.     iYLabel := iYTick;
  1248.  
  1249.     if ((FTickDirection = orLeft) and
  1250.         (FLabels.Direction = drHorizontal)) then
  1251.       Dec(iYLabel, FontHeight);
  1252.  
  1253.     if (DoTextLabels) then
  1254.     begin
  1255. {Text instead of Numeric Labels on the axis:}
  1256.       for i := 0 to TSeries(FLabelSeries).XStringData.Count-1 do
  1257.       begin
  1258.         iX := FofX(TSeries(FLabelSeries).XData^[i]);
  1259. {Major Ticks on the axis:}
  1260.         if (FTickSize > 0) then
  1261.         begin
  1262.           ACanvas.MoveTo(iX, iY);
  1263.           ACanvas.LineTo(iX, iYTick);
  1264.         end;
  1265.         if (FLabels.Visible) then
  1266.         begin
  1267.           TheText := TSeries(FLabelSeries).XStringData.Strings[i];
  1268.           XLabelOut;
  1269.         end;
  1270.       end;
  1271.     end
  1272.     else
  1273.     begin
  1274. {Normal numeric labels:}
  1275.       XValue := FStepStart;
  1276.       while (XValue < FMax) do
  1277.       begin
  1278.         iX := FofX(XValue);
  1279. {Major Ticks on the axis:}
  1280.         if (FTickSize > 0) then
  1281.         begin
  1282.           ACanvas.MoveTo(iX, iY);
  1283.           ACanvas.LineTo(iX, iYTick);
  1284.         end;
  1285. {Numeric labels:}
  1286.         if (FLabels.Visible) then
  1287.         begin
  1288.           TheText := LabelToStrF(XValue);
  1289.           XLabelOut;
  1290.         end;
  1291.         XValue := GetNextXValue(XValue);
  1292.       end;
  1293.  
  1294. {Minor Ticks on the axis:}
  1295.       if ((FTickMinor > 0) and
  1296.           (FTickSize > 0)) then
  1297.       begin
  1298. {find out where the minors start:}
  1299.         MinorStepSize := FStepSize / (FTickMinor+1);
  1300.         MinorStepStart := FStepStart;
  1301.         MinorTickSize := FTickSign * FTickSize div 2;
  1302.         while ((MinorStepStart - MinorStepSize) >= FMin) do
  1303.           MinorStepStart := MinorStepStart - MinorStepSize;
  1304.         iY := MidY;
  1305.         XValue := MinorStepStart;
  1306.         while (XValue < FMax) do
  1307.         begin
  1308.           iX := FofX(XValue);
  1309.           ACanvas.MoveTo(iX, iY);
  1310.           ACanvas.LineTo(iX, iY + MinorTickSize);
  1311.           XValue := GetNextMinorXValue(XValue);
  1312.         end;
  1313.       end; {minors}
  1314.     end; {Ticks}
  1315.  
  1316. {record the position of the labels for use by TPlot in moving labels and ticks:}
  1317.     if (FLabels.Direction = drHorizontal) then
  1318.     begin
  1319.       iFontWidth := FontWidth div 2;
  1320.       FLabels.Left := FofX(FStepStart) - iFontWidth;
  1321.       FLabels.Right := iX + iFontWidth;
  1322.       if (FTickDirection = orLeft) then
  1323.       begin
  1324.         FLabels.Top := iYLabel;
  1325.         FLabels.Bottom := iYLabel + FontHeight;
  1326.       end
  1327.       else
  1328.       begin
  1329.         FLabels.Top := iYLabel;
  1330.         FLabels.Bottom := iYLabel + FontHeight;
  1331.       end;
  1332.     end
  1333.     else
  1334.     begin
  1335.       iFontWidth := FontHeight div 2;
  1336.       FLabels.Left := FofX(FStepStart) - iFontWidth;
  1337.       FLabels.Right := iX + iFontWidth;
  1338.       if (FTickDirection = orLeft) then
  1339.       begin
  1340.         FLabels.Top := iYLabel - FontWidth;
  1341.         FLabels.Bottom := iYLabel;
  1342.       end
  1343.       else
  1344.       begin
  1345.         FLabels.Top := iYLabel;
  1346.         FLabels.Bottom := iYLabel + FontWidth;
  1347.       end;
  1348.     end;
  1349.     SetupHorizontalEnvelope;
  1350.   end
  1351.   else {Draw the Vertical axis:}
  1352.   begin
  1353.     ACanvas.MoveTo(MidX, Bottom);
  1354.     ACanvas.LineTo(MidX, Top);
  1355. {Draw the arrows on the axis:}
  1356.     if (FArrowSize > 0) then
  1357.     begin
  1358. {taCenter therefore means no arrows !}
  1359.       if (Alignment = taLeftJustify) then
  1360.         DoArrow(Point(Left, Bottom-FArrowSize), Point(MidX, Bottom), Point(Right, Bottom-FArrowSize));
  1361.       if (Alignment = taRightJustify) then
  1362.         DoArrow(Point(Left, Top+FArrowSize), Point(MidX, Top), Point(Right, Top+FArrowSize));
  1363.     end;
  1364.  
  1365.     if (Self.LimitsVisible) then
  1366.     begin
  1367.       ACanvas.Pen.Style := psDot;
  1368.       iY := Self.FofY(LimitLower);
  1369.       ACanvas.MoveTo(Self.MidX, iY);
  1370.       ACanvas.LineTo(LimitPos, iY);
  1371.       iY := Self.FofY(LimitUpper);
  1372.       ACanvas.MoveTo(Self.MidX, iY);
  1373.       ACanvas.LineTo(LimitPos, iY);
  1374.       ACanvas.Pen.Style := Self.Pen.Style;
  1375.     end;
  1376.  
  1377.     iX := MidX;
  1378.     iXLabel := MidX + FTickSign*(FTickSize + FontWidth div 5);
  1379.     iXTick := MidX + FTickSign*FTickSize;
  1380.     iY := 0; {see below}
  1381.  
  1382.     if (DoTextLabels) then
  1383.     begin
  1384. {Text instead of Numeric Labels on the axis:}
  1385.       for i := 0 to TSeries(FLabelSeries).XStringData.Count-1 do
  1386.       begin
  1387.         iY := FofY(TSeries(FLabelSeries).YData^[i]);
  1388. {Major Ticks on the axis:}
  1389.         if (FTickSize > 0) then
  1390.         begin
  1391.           ACanvas.MoveTo(iX, iY);
  1392.           ACanvas.LineTo(iXTick, iY);
  1393.         end;
  1394.         if (FLabels.Visible) then
  1395.         begin
  1396.           TheText := TSeries(FLabelSeries).XStringData.Strings[i];
  1397.           YLabelOut;
  1398.         end;
  1399.       end;
  1400.     end
  1401.     else
  1402.     begin
  1403. {Normal numeric labels:}
  1404.       YValue := FStepStart;
  1405.       while (YValue < FMax) do
  1406.       begin
  1407.         iY := FofY(YValue);
  1408. {Major Ticks on the axis:}
  1409.         if (FTickSize > 0) then
  1410.         begin
  1411.           ACanvas.MoveTo(iX, iY);
  1412.           ACanvas.LineTo(iXTick, iY);
  1413.         end;
  1414. {Numeric labels:}
  1415.         if (FLabels.Visible) then
  1416.         begin
  1417.           TheText := LabelToStrF(YValue);
  1418.           YLabelOut;
  1419.         end;
  1420.         YValue := GetNextXValue(YValue);
  1421.       end;
  1422.  
  1423. {Minor Ticks on the axis:}
  1424.       if ((FTickMinor > 0) and
  1425.           (FTickSize > 0)) then
  1426.       begin
  1427. {find out where the minors start:}
  1428.         MinorStepSize := FStepSize / (FTickMinor+1);
  1429.         MinorStepStart := FStepStart;
  1430.         MinorTickSize := FTickSign * FTickSize div 2;
  1431.         while ((MinorStepStart - MinorStepSize) >= FMin) do
  1432.           MinorStepStart := MinorStepStart - MinorStepSize;
  1433.         YValue := MinorStepStart;
  1434.         while (YValue < FMax) do
  1435.         begin
  1436.           iY := FofY(YValue);
  1437.           ACanvas.MoveTo(iX, iY);
  1438.           ACanvas.LineTo(iX + MinorTickSize, iY);
  1439.           YValue := GetNextMinorXValue(YValue);
  1440.         end;
  1441.       end; {minors}
  1442.     end; {Ticks}
  1443.  
  1444. {record the position of the labels for use by TPlot:}
  1445.     if (FLabels.Direction = drHorizontal) then
  1446.     begin
  1447.       FLabels.Top := iY - FontHeight;
  1448.       FLabels.Bottom := FofY(FStepStart);
  1449.       if (FTickDirection = orLeft) then
  1450.       begin
  1451.         FLabels.Left := iXLabel - FontWidth;
  1452.         FLabels.Right := iXlabel;
  1453.       end
  1454.       else
  1455.       begin
  1456.         FLabels.Left := iXLabel;
  1457.         FLabels.Right := iXLabel + FontWidth;
  1458.       end;
  1459.     end
  1460.     else
  1461.     begin
  1462.       iFontWidth := FontWidth div 2;
  1463.       FLabels.Top := iY - iFontWidth;
  1464.       FLabels.Bottom := FofY(FStepStart) + iFontWidth;
  1465.       if (FTickDirection = orLeft) then
  1466.       begin
  1467.         FLabels.Left := iXLabel - FontHeight;
  1468.         FLabels.Right := iXlabel;
  1469.       end
  1470.       else
  1471.       begin
  1472.         FLabels.Left := iXLabel;
  1473.         FLabels.Right := iXLabel + FontHeight;
  1474.       end;
  1475.     end;
  1476.  
  1477.     SetupVerticalEnvelope;
  1478.   end; {Horizontal or Vertical}
  1479. {Print the axis Title:}
  1480.   FTitle.Draw(ACanvas);
  1481. end;
  1482.  
  1483. {------------------------------------------------------------------------------
  1484.      Function: TAxis.FofX
  1485.   Description: standard X transform
  1486.        Author: Mat Ballard
  1487.  Date created: 04/25/2000
  1488. Date modified: 04/25/2000 by Mat Ballard
  1489.       Purpose: returns the pixel position on screen as a function of the real data ordinate X
  1490.  Known Issues:
  1491.  ------------------------------------------------------------------------------}
  1492. function TAxis.FofX(X: Single): Integer;
  1493. begin
  1494. {$IFDEF DELPHI3_UP}
  1495.   Assert(FDirection = drHorizontal, sFofX1);
  1496. {$ENDIF}
  1497.  
  1498.   if (FLogScale) then
  1499.     FofX := Round(Left + Width * ((Log10(X / FMin)) / FLogSpan))
  1500.    else
  1501.     FofX := Round(Left + Width * ((X - FMin) / (FSpan)));
  1502. end;
  1503.  
  1504. {------------------------------------------------------------------------------
  1505.      Function: TAxis.FofY
  1506.   Description: standard Y transform
  1507.        Author: Mat Ballard
  1508.  Date created: 04/25/2000
  1509. Date modified: 04/25/2000 by Mat Ballard
  1510.       Purpose: returns the pixel position on screen as a function of the real data co-ordinate Y
  1511.  Known Issues:
  1512.  ------------------------------------------------------------------------------}
  1513. function TAxis.FofY(Y: Single): Integer;
  1514. begin
  1515. {$IFDEF DELPHI3_UP}
  1516.   Assert(FDirection = drVertical, sFofY1);
  1517. {$ENDIF}
  1518.  
  1519.   if (FLogScale) then
  1520.     FofY := Round(Bottom - Height * ((Log10(Y / FMin)) / FLogSpan))
  1521.    else
  1522.     FofY := Round(Bottom - Height * ((Y - FMin) / (FSpan)));
  1523. end;
  1524.  
  1525. {------------------------------------------------------------------------------
  1526.      Function: TAxis.XofF
  1527.   Description: inverse X transform
  1528.        Author: Mat Ballard
  1529.  Date created: 04/25/2000
  1530. Date modified: 04/25/2000 by Mat Ballard
  1531.       Purpose: returns the real data ordinate X as a function of the pixel position on screen
  1532.  Known Issues:
  1533.  ------------------------------------------------------------------------------}
  1534. function TAxis.XofF(F: Integer): Single;
  1535. {this function returns the real data ordinate X
  1536.  as a function of the pixel position F on screen:}
  1537. begin
  1538. {$IFDEF DELPHI3_UP}
  1539.   Assert(FDirection = drHorizontal, sFofX1);
  1540. {$ENDIF}
  1541.  
  1542.   if (FLogScale) then
  1543.     XofF := FMin * Power(10.0, (FLogSpan * (F-Left) / Width))
  1544.    else
  1545.     XofF := FSpan * ((F-Left) / Width) + FMin;
  1546. end;
  1547.  
  1548. {------------------------------------------------------------------------------
  1549.      Function: TAxis.YofF
  1550.   Description: inverse Y transform
  1551.        Author: Mat Ballard
  1552.  Date created: 04/25/2000
  1553. Date modified: 04/25/2000 by Mat Ballard
  1554.       Purpose: returns the real data ordinate Y as a function of the pixel position on screen
  1555.  Known Issues:
  1556.  ------------------------------------------------------------------------------}
  1557. function TAxis.YofF(F: Integer): Single;
  1558. {this function returns the real data ordinate X
  1559.  as a function of the pixel position F on screen:}
  1560. begin
  1561. {$IFDEF DELPHI3_UP}
  1562.   Assert(FDirection = drVertical, sFofY1);
  1563. {$ENDIF}
  1564.  
  1565.   if (FLogScale) then
  1566.     YofF := FMin * Power(10.0, (FLogSpan * (Bottom-F) / Height))
  1567.    else
  1568.     YofF := FSpan * ((Bottom-F) / Height) + FMin;
  1569. end;
  1570.  
  1571. {------------------------------------------------------------------------------
  1572.      Function: TAxis.StrToLabel
  1573.   Description: converts a string to a number, depending on the NumberFormat
  1574.        Author: Mat Ballard
  1575.  Date created: 04/25/2000
  1576. Date modified: 04/25/2000 by Mat Ballard
  1577.       Purpose: user IO
  1578.  Known Issues:
  1579.  ------------------------------------------------------------------------------}
  1580. function TAxis.StrToLabel(Value: String): Single;
  1581. begin
  1582.   case (FLabels.NumberFormat) of
  1583.     lfGeneral .. lfCurrency:
  1584.       StrToLabel := StrToFloat(Value);
  1585.     lfPercent:
  1586.       StrToLabel := StrToFloat(Value) / 100;
  1587.     lfSeconds:
  1588.       StrToLabel := StrToFloat(Value);
  1589.     lfMinutes:
  1590.       StrToLabel := 60 * StrToFloat(Value);
  1591.     lfHours:
  1592.       StrToLabel := 3600 * StrToFloat(Value);
  1593.     lfDays:
  1594.       StrToLabel := 86400 * StrToFloat(Value);
  1595.     lfShortTime:
  1596.       StrToLabel := StrToDateTime(Value);
  1597.     lfShortDate:
  1598.       StrToLabel := StrToDateTime(Value);
  1599.     else
  1600.       StrToLabel := 0.0;
  1601.   end;
  1602. end;
  1603.  
  1604. {------------------------------------------------------------------------------
  1605.      Function: TAxis.LabelToStrF
  1606.   Description: converts a number to a string, depending on the NumberFormat
  1607.        Author: Mat Ballard
  1608.  Date created: 04/25/2000
  1609. Date modified: 04/25/2000 by Mat Ballard
  1610.       Purpose: user IO
  1611.  Known Issues:
  1612.  ------------------------------------------------------------------------------}
  1613. function TAxis.LabelToStrF(Value: Single): String;
  1614. var
  1615.   TheText: String;
  1616.   Mantissa: Extended;
  1617.   Exponent: Integer;
  1618.   TheDateTime: TDateTime;
  1619. begin
  1620.   case (FLabels.NumberFormat) of
  1621.     lfGeneral .. lfCurrency:
  1622. {See Rescale for definition of PrecisionAdded}
  1623.       TheText := FloatToStrF(Value, TFloatFormat(FLabels.NumberFormat),
  1624.         FLabels.Precision + PrecisionAdded, FLabels.Digits);
  1625.     lfSI:
  1626.       begin
  1627.         DeSci(Value, Mantissa, Exponent);
  1628.         case Exponent of {p, n u, m, -, K, M, G, T}
  1629.           -12 .. -10: TheText := 'p';
  1630.           -9 .. -7: TheText := 'n';
  1631.           -6 .. -4: TheText := 'u';
  1632.           -3 .. -1: TheText := 'm';
  1633.           3 .. 5: TheText := 'K';
  1634.           6 .. 8: TheText := 'M';
  1635.           9 .. 11: TheText := 'G';
  1636.           12 .. 14: TheText := 'T';
  1637.         else TheText := '';
  1638.         end;
  1639.         if (Length(TheText) > 0) then
  1640.         begin
  1641.           Exponent := (Exponent + 99) mod 3;
  1642.           Mantissa := Mantissa * IntPower(10, Exponent);
  1643.           TheText := FloatToStrF(Mantissa, TFloatFormat(lfFixed),
  1644.             FLabels.Precision, FLabels.Digits) + TheText;
  1645.         end
  1646.         else
  1647.           TheText := FloatToStrF(Value, TFloatFormat(lfGeneral),
  1648.             FLabels.Precision, FLabels.Digits);
  1649.       end;
  1650.     lfPercent:
  1651.       TheText := FloatToStrF(100 * Value, TFloatFormat(FLabels.NumberFormat),
  1652.         FLabels.Precision, FLabels.Digits);
  1653.     lfSeconds:
  1654.       TheText := FloatToStrF(Round(Value), ffGeneral,
  1655.         FLabels.Precision, FLabels.Digits);
  1656.     lfMinutes:
  1657.       TheText := FloatToStrF(Round(Value / 60), ffGeneral,
  1658.         FLabels.Precision, FLabels.Digits);
  1659.     lfHours:
  1660.       TheText := FloatToStrF(Round(Value / 3600), ffGeneral,
  1661.         FLabels.Precision, FLabels.Digits);
  1662.     lfDays:
  1663.       TheText := FloatToStrF(Round(Value / 86400), ffGeneral,
  1664.         FLabels.Precision, FLabels.Digits);
  1665.     lfShortTime:
  1666.       begin
  1667.         TheDateTime := Value;
  1668.         TheText := FormatDateTime('t', TheDateTime);
  1669.       end;
  1670.     lfShortDate:
  1671.       begin
  1672.         TheDateTime := Value;
  1673.         TheText := FormatDateTime('ddddd', TheDateTime);
  1674.       end;
  1675.   end;
  1676.  
  1677.   LabelToStrF := TheText;
  1678. end;
  1679.  
  1680. {------------------------------------------------------------------------------
  1681.     Procedure: TAxis.SetupHorizontalEnvelope
  1682.   Description: sets up the Horizontal (X Axis) envelope around which the Title dances
  1683.        Author: Mat Ballard
  1684.  Date created: 04/25/2000
  1685. Date modified: 04/25/2000 by Mat Ballard
  1686.       Purpose: manages the appearance of the Axis
  1687.  Known Issues:
  1688.  ------------------------------------------------------------------------------}
  1689. procedure TAxis.SetupHorizontalEnvelope;
  1690. var
  1691.   TheRect: TRect;
  1692. begin
  1693.   TheRect.Left := Left;
  1694.   TheRect.Right := Right;
  1695.   if (FTickDirection = orLeft) then
  1696.   begin
  1697.     TheRect.Top := MidY - FTickSize;
  1698.     if (FLabels.Visible) then
  1699.       TheRect.Top := TheRect.Top - FLabels.Height;
  1700.     TheRect.Bottom := MidY + 1;
  1701.   end
  1702.   else  {oRight}
  1703.   begin
  1704.     TheRect.Top := MidY - 1;
  1705.     TheRect.Bottom := MidY + FTickSize;
  1706.     if (FLabels.Visible) then
  1707.       TheRect.Bottom := TheRect.Bottom + FLabels.Height;
  1708.   end; {FTickDirection}
  1709.   FTitle.Envelope := TheRect;
  1710. end;
  1711.  
  1712. {------------------------------------------------------------------------------
  1713.     Procedure: TAxis.SetupVerticalEnvelope
  1714.   Description: sets up the Vertical (Y Axis) envelope around which the Title dances
  1715.        Author: Mat Ballard
  1716.  Date created: 04/25/2000
  1717. Date modified: 04/25/2000 by Mat Ballard
  1718.       Purpose: manages the appearance of the Axis
  1719.  Known Issues:
  1720.  ------------------------------------------------------------------------------}
  1721. procedure TAxis.SetupVerticalEnvelope;
  1722. var
  1723.   TheRect: TRect;
  1724. begin
  1725.   TheRect.Top := Top;
  1726.   TheRect.Bottom := Bottom;
  1727.   if (FTickDirection = orLeft) then
  1728.   begin
  1729.     TheRect.Left := MidX - FTickSize;
  1730.     if (FLabels.Visible) then
  1731.       TheRect.Left := TheRect.Left - FLabels.Width;
  1732.     TheRect.Right := MidX + 1;
  1733.   end
  1734.   else {oRight}
  1735.   begin
  1736.     TheRect.Left := MidX - 1;
  1737.     TheRect.Right := MidX + FTickSize;
  1738.     if (FLabels.Visible) then
  1739.       TheRect.Right := TheRect.Right + FLabels.Width;
  1740.   end; {FTickDirection}
  1741.   FTitle.Envelope := TheRect;
  1742. end;
  1743.  
  1744. {------------------------------------------------------------------------------
  1745.     Procedure: TAxis.Assign
  1746.   Description: standard Assign method
  1747.        Author: Mat Ballard
  1748.  Date created: 07/06/2000
  1749. Date modified: 07/06/2000 by Mat Ballard
  1750.       Purpose: implements Assign
  1751.  Known Issues:
  1752.  ------------------------------------------------------------------------------}
  1753. {procedure TAxis.Assign(Source: TPersistent);
  1754. begin
  1755.   inherited Assign(Source);
  1756.   FArrowSize := TAxis(Source).ArrowSize;
  1757.   FDirection := TAxis(Source).Direction;
  1758.   FIntercept := TAxis(Source).Intercept;
  1759.   FLogscale := TAxis(Source).Logscale;
  1760.   FMax := TAxis(Source).Max;
  1761.   FMin := TAxis(Source).Min;
  1762.   FStepSize := TAxis(Source).StepSize;
  1763.   FTickDirection := TAxis(Source).TickDirection;
  1764.   FTickNum := TAxis(Source).TickNum;
  1765.   FTickSize := TAxis(Source).TickSize;
  1766.  
  1767.   FLabels.Assign(TAxis(Source).Labels);
  1768.   FPen.Assign(TAxis(Source).Pen);
  1769.   FTitle.Assign(TAxis(Source).Title);
  1770. end;}
  1771.  
  1772. {------------------------------------------------------------------------------
  1773.     Procedure: TAxis.AssignTo
  1774.   Description: standard AssignTo method
  1775.        Author: Mat Ballard
  1776.  Date created: 07/06/2000
  1777. Date modified: 07/06/2000 by Mat Ballard
  1778.       Purpose: implements AssignTo
  1779.  Known Issues:
  1780.  ------------------------------------------------------------------------------}
  1781. procedure TAxis.AssignTo(Dest: TPersistent);
  1782. begin
  1783.   inherited AssignTo(Dest);
  1784.   TAxis(Dest).ArrowSize := FArrowSize;
  1785.   TAxis(Dest).Direction := FDirection;
  1786.   {TAxis(Dest).Intercept := FIntercept;}
  1787.   TAxis(Dest).Logscale := FLogscale;
  1788.   TAxis(Dest).Max := FMax;
  1789.   TAxis(Dest).Min := FMin;
  1790.   TAxis(Dest).StepSize := FStepSize;
  1791.   TAxis(Dest).TickDirection := FTickDirection;
  1792.   TAxis(Dest).TickSize := FTickSize;
  1793.  
  1794.   TAxis(Dest).Labels.Assign(FLabels);
  1795.   TAxis(Dest).Pen.Assign(FPen);
  1796.   TAxis(Dest).Title.Assign(FTitle);
  1797. end;
  1798.  
  1799. procedure TAxis.SetLabelSeries(Value: TPersistent);
  1800. begin
  1801. {Note: Labeltext is maintained within the TSeries, NOT in TAxis !}
  1802.   FLabelSeries := Value;
  1803.   StyleChange(Self);
  1804. end;
  1805.  
  1806. {TAngleAxis methods ---------------------------------------------------------}
  1807. {Constructor and Destructor:-------------------------------------------------}
  1808. {------------------------------------------------------------------------------
  1809.   Constructor: TAngleAxis.Create
  1810.   Description: standard Constructor
  1811.        Author: Mat Ballard
  1812.  Date created: 04/25/2000
  1813. Date modified: 04/25/2000 by Mat Ballard
  1814.       Purpose: sets the Precision and Digits Properties
  1815.  Known Issues:
  1816.  ------------------------------------------------------------------------------}
  1817. Constructor TAngleAxis.Create(AOwner: TPersistent);
  1818. begin
  1819. {First call the ancestor:}
  1820.   inherited Create(AOwner);
  1821.  
  1822.   FireEvents := FALSE;
  1823.   FLength := 100;
  1824.   Angle := 225;
  1825.   FireEvents := TRUE;
  1826. end;
  1827.  
  1828. {------------------------------------------------------------------------------
  1829.   Destructor: TAngleAxis.Destroy
  1830.   Description: standard Destructor
  1831.        Author: Mat Ballard
  1832.  Date created: 01/16/2001
  1833. Date modified: 01/16/2001 by Mat Ballard
  1834.       Purpose:
  1835.  Known Issues:
  1836.  ------------------------------------------------------------------------------}
  1837. Destructor TAngleAxis.Destroy;
  1838. begin
  1839.   inherited Destroy;
  1840. end;
  1841.  
  1842.  
  1843. {------------------------------------------------------------------------------
  1844.     Procedure: TAxis.SetAngle
  1845.   Description: standard property Set procedure
  1846.        Author: Mat Ballard
  1847.  Date created: 01/16/2001
  1848. Date modified: 01/16/2001 by Mat Ballard
  1849.       Purpose: sets the Angle Property
  1850.  Known Issues:
  1851.  ------------------------------------------------------------------------------}
  1852. procedure TAngleAxis.SetAngle(Value: Word);
  1853. begin
  1854.   FAngle := Value Mod 360;
  1855.   FAngleRadians := Pi * FAngle / 180;
  1856. {this is twice as fast as calling them individually:}
  1857.   SinCos(FAngleRadians, FSin, FCos);
  1858. {look back along the axis, then 30 degrees less, for the arrow:}
  1859.   SinCos(FAngleRadians + Pi*(1/2 - 1/6), FSinM30, FCosM30);
  1860. {look back along the axis, then 30 degrees more:}
  1861.   SinCos(FAngleRadians + Pi*(1/2 + 1/6), FSinP30, FCosP30);
  1862.  
  1863.   StyleChange(Self);
  1864. end;
  1865.  
  1866. {------------------------------------------------------------------------------
  1867.     Procedure: TAxis.SetLength
  1868.   Description: standard property Set procedure
  1869.        Author: Mat Ballard
  1870.  Date created: 01/16/2001
  1871. Date modified: 01/16/2001 by Mat Ballard
  1872.       Purpose: sets the Length Property
  1873.  Known Issues:
  1874.  ------------------------------------------------------------------------------}
  1875. procedure TAngleAxis.SetLength(Value: Word);
  1876. begin
  1877.   if (Value = FLength) then exit;
  1878.  
  1879.   FLength := Value;
  1880.   StyleChange(Self);
  1881. end;
  1882.  
  1883. {------------------------------------------------------------------------------
  1884.     Procedure: TAxis.SetZInterceptY
  1885.   Description: standard property Set procedure
  1886.        Author: Mat Ballard
  1887.  Date created: 04/25/2000
  1888. Date modified: 04/25/2000 by Mat Ballard
  1889.       Purpose: sets the ZInterceptY Property: the intercept of the Z Axis with the Y Axis
  1890.  Known Issues:
  1891.  ------------------------------------------------------------------------------}
  1892. procedure TAngleAxis.SetZInterceptY(Value: Single);
  1893. begin
  1894.   if (FZInterceptY = Value) then exit;
  1895.   FZInterceptY := Value;
  1896.   StyleChange(Self);
  1897. end;
  1898.  
  1899.  
  1900. {------------------------------------------------------------------------------
  1901.     Procedure: TAxis.Draw
  1902.   Description: standard Drawing procedure
  1903.        Author: Mat Ballard
  1904.  Date created: 04/25/2000
  1905. Date modified: 04/25/2000 by Mat Ballard
  1906.       Purpose: draws the Axis on a given canvas
  1907.  Known Issues:
  1908.  ------------------------------------------------------------------------------}
  1909. procedure TAngleAxis.Draw(ACanvas: TCanvas; LimitPos: Integer);
  1910. {Comments:
  1911.  This method is quite complex, in a tedious way.
  1912.  It has to account for the following variations:
  1913.     1. Visible or not;
  1914.     2. Arrows visible or not;
  1915.     3. Axis direction (Horizontal or vertical);
  1916.     4. Tick (and Label and Title) direction);
  1917.     5. Title Alignment Direction and Orientation;
  1918.     6. Tick, Label and Title visibility.
  1919.     7. Angle !
  1920.  An added complication is that we must generate a vertical font for the Title
  1921.  of vertical axes. Note that this only works with TrueType fonts - NOT fonts
  1922.  that are purely screen or printer.}
  1923. var
  1924.   OldFireEvents: Boolean;
  1925.   i,
  1926.   iX,
  1927.   iY,
  1928.   FontHeight,
  1929.   FontWidth,
  1930.   iFontWidth,
  1931.   FontDescent,
  1932.   MinorTickSize: Integer;
  1933.   MinorStepSize,
  1934.   MinorStepStart,
  1935.   {NewAngle,}
  1936.   ZValue: Single;
  1937.   TheText: String;
  1938.   dTick,
  1939.   TheTickStart: TPoint;
  1940.  
  1941. {begin internal functions:}  
  1942.   function GetNextXValue(XValue: Single): Single;
  1943.   begin
  1944.     if (FLogScale) then
  1945.       GetNextXValue := XValue * FStepSize
  1946.      else
  1947.       GetNextXValue := XValue + FStepSize;
  1948.   end;
  1949.  
  1950.   function GetNextMinorXValue(XValue: Single): Single;
  1951.   begin
  1952.     if (FLogScale) then
  1953.       GetNextMinorXValue := XValue * MinorStepSize
  1954.      else
  1955.       GetNextMinorXValue := XValue + MinorStepSize;
  1956.   end;
  1957.  
  1958. begin
  1959. {the most common reason for exit:}
  1960.   if (not Visible) then exit;
  1961. {$IFDEF DELPHI3_UP}
  1962.   Assert(ACanvas <> nil, 'TAngleAxis.Draw: ' + sACanvasIsNil);
  1963. {$ENDIF}
  1964.  
  1965.   FontWidth := 1;
  1966.   ACanvas.Pen.Assign(FPen);
  1967.  
  1968. {Do the geometry:}
  1969. {first, squelch any "OnChange" events:}
  1970.   OldFireEvents := FireEvents;
  1971.   FireEvents := FALSE;
  1972.   FEndX := Left + Round(FLength * FSin);
  1973.   FEndY := Top + Round(-FLength * FCos);
  1974.  
  1975. {Draw the axis:}
  1976.   ACanvas.MoveTo(Left, Top);
  1977.   ACanvas.LineTo(FEndX, FEndY);
  1978. {Draw the arrows on the axis:}
  1979.   if (FArrowSize > 0) then
  1980.   begin
  1981.     if (Alignment = taRightJustify) then
  1982.     begin
  1983.       ACanvas.MoveTo(FEndX, FEndY);
  1984.       iX := FEndX + Round(FArrowSize * FCosM30);
  1985.       iY := FEndY + Round(FArrowSize * FSinM30);
  1986.       ACanvas.LineTo(iX, iY);
  1987.       ACanvas.MoveTo(FEndX, FEndY);
  1988. {look back along the axis, then 30 degrees less:}
  1989.       iX := FEndX + Round(FArrowSize * FCosP30);
  1990.       iY := FEndY + Round(FArrowSize * FSinP30);
  1991.       ACanvas.LineTo(iX, iY);
  1992.     end; {taLeftJustify and taCenter therefore means no arrows !}
  1993.   end;
  1994.  
  1995. {Prepare fonts for Labels on the axis:}
  1996.   if (FLabels.Visible) then
  1997.   begin
  1998.     ACanvas.Font.Assign(FLabels.Font);
  1999.     FontWidth := ACanvas.TextWidth('9');
  2000.     FontHeight := ACanvas.TextHeight('9');
  2001. {We could call GetOutlineTextMetrics to get
  2002. the Descent (gap between baseline and bottom of a font), but:}
  2003.     {FontDescent := FontHeight div 5;}
  2004.   end;
  2005.  
  2006. {Ticks on the axis:}
  2007.  
  2008.   dTick.x := 0;
  2009.   dTick.y := 0;
  2010.   case FAngle of
  2011.     0: dTick.x := -FTickSize;
  2012.     1 .. 60: dTick.x := FTickSize;
  2013.     61 .. 120: dTick.y := FTickSize;
  2014.     121 .. 180: dTick.x := FTickSize;
  2015.     181 .. 240: dTick.x := -FTickSize;
  2016.     241 .. 300: dTick.y := FTickSize;
  2017.     301 .. 359: dTick.x := -FTickSize;
  2018.   end;
  2019.  
  2020.   ZValue := FStepStart;
  2021.   //i := 0;
  2022.   while (ZValue < FMax) do
  2023.   begin
  2024.     TheTickStart := dFofZ(ZValue);
  2025.     Inc(TheTickStart.x, Left);
  2026.     Inc(TheTickStart.y, Top);
  2027.     if (FTickSize > 1) then
  2028.       ACanvas.MoveTo(TheTickStart.x, TheTickStart.y);
  2029.     Inc(TheTickStart.x, dTick.x);
  2030.     Inc(TheTickStart.y, dTick.y);
  2031.     if (FTickSize > 1) then
  2032.       ACanvas.LineTo(TheTickStart.x, TheTickStart.y);
  2033.  
  2034.     if (FLabels.Visible) then
  2035.     begin
  2036.       {if (FLabelSeries <> nil) then
  2037.         if (i < FLabelSeries.Count) then
  2038.           TheText := FLabelSeries.Strings[i]
  2039.          else
  2040.           break
  2041.       else}
  2042.         TheText := LabelToStrF(ZValue);
  2043.       iFontWidth := ACanvas.TextWidth(TheText);
  2044.       if (iFontWidth > FontWidth) then
  2045.         FontWidth := iFontWidth;
  2046.       if (dTick.x < 0) then
  2047.         Dec(TheTickStart.x, iFontWidth);
  2048.       if (dTick.y > 0) then
  2049.       begin
  2050.         Inc(TheTickStart.y, FontHeight);
  2051.         Dec(TheTickStart.x, iFontWidth div 2);
  2052.       end;
  2053. {$IFDEF MSWINDOWS}
  2054.       ACanvas.TextOut(
  2055.         TheTickStart.x,
  2056.         TheTickStart.y - Abs(ACanvas.Font.Height),
  2057.         TheText);
  2058. {$ENDIF}
  2059. {$IFDEF LINUX}
  2060.       ACanvas.TextOut(
  2061.         TheTickStart.x,
  2062.         TheTickStart.y {+ Abs(ACanvas.Font.Height)},
  2063.         TheText);
  2064. {$ENDIF}
  2065.     end;
  2066.  
  2067.     //Inc(i);
  2068.     ZValue := GetNextXValue(ZValue);
  2069.   end; {while ZValue < FMax}
  2070.  
  2071. {Minor Ticks on the axis:}
  2072.   if ((FTickSize > 1) and (FTickMinor > 0)) then
  2073.   begin
  2074. {find out where the minors start:}
  2075.     MinorStepSize := FStepSize / (FTickMinor+1);
  2076.     MinorStepStart := FStepStart;
  2077.     while ((MinorStepStart - MinorStepSize) >= FMin) do
  2078.       MinorStepStart := MinorStepStart - MinorStepSize;
  2079.     //iY := MidY;
  2080.     dTick.x := dTick.x div 2;
  2081.     dTick.y := dTick.y div 2;
  2082.  
  2083.     ZValue := MinorStepStart;
  2084.     //i := 0;
  2085.     while (ZValue < FMax) do
  2086.     begin
  2087.       TheTickStart := dFofZ(ZValue);
  2088.       Inc(TheTickStart.x, Left);
  2089.       Inc(TheTickStart.y, Top);
  2090.       if (FTickSize > 1) then
  2091.         ACanvas.MoveTo(TheTickStart.x, TheTickStart.y);
  2092.       Inc(TheTickStart.x, dTick.x);
  2093.       Inc(TheTickStart.y, dTick.y);
  2094.       if (FTickSize > 1) then
  2095.         ACanvas.LineTo(TheTickStart.x, TheTickStart.y);
  2096.       ZValue := GetNextMinorXValue(ZValue);
  2097.     end;
  2098.   end; {minor ticks}
  2099.  
  2100.   FireEvents := OldFireEvents;
  2101. end;
  2102.  
  2103. {------------------------------------------------------------------------------
  2104.      Function: TAngleAxis.FofZ
  2105.   Description: standard Z transform
  2106.        Author: Mat Ballard
  2107.  Date created: 07/25/2001
  2108. Date modified: 07/25/2001 by Mat Ballard
  2109.       Purpose: returns the 3D pixel position as a function of the real data ordinate X
  2110.  Known Issues:
  2111.  ------------------------------------------------------------------------------}
  2112. function TAngleAxis.FofZ(Z: Single): Integer;
  2113. begin
  2114.   if (FLogScale) then
  2115.     FofZ := Round(Left + Width * ((Log10(Z / FMin)) / FLogSpan))
  2116.    else
  2117.     FofZ := Round(Left + Width * ((Z - FMin) / (FSpan)));
  2118. end;
  2119.  
  2120. {------------------------------------------------------------------------------
  2121.      Function: TAngleAxis.FofZ
  2122.   Description: standard Z transform
  2123.        Author: Mat Ballard
  2124.  Date created: 01/18/2001
  2125. Date modified: 01/18/2001 by Mat Ballard
  2126.       Purpose: returns the change in pixel position on screen as a function of the real data ordinate Z
  2127.  Known Issues:
  2128.  ------------------------------------------------------------------------------}
  2129. function TAngleAxis.dFofZ(Z: Single): TPoint;
  2130. begin
  2131.   if (FLogScale) then
  2132.   begin
  2133.     Result.x := Round(FSin * FLength * ((Log10(Z / FMin)) / FLogSpan));
  2134.     Result.y := -Round(FCos * FLength * ((Log10(Z / FMin)) / FLogSpan));
  2135.   end
  2136.   else
  2137.   begin
  2138.     Result.x := Round(FSin * FLength * ((Z - FMin) / (FSpan)));
  2139.     Result.y := -Round(FCos * FLength * ((Z - FMin) / (FSpan)));
  2140.   end;
  2141. end;
  2142.  
  2143. {------------------------------------------------------------------------------
  2144.     Procedure: TAngleAxis.ClickedOn
  2145.   Description: Was this TRectangle clicked on ?
  2146.        Author: Mat Ballard
  2147.  Date created: 01/17/2001
  2148. Date modified: 01/17/2001 by Mat Ballard
  2149.       Purpose: screen click management
  2150.  Known Issues: overrides TRectangle.ClickedOn
  2151.  ------------------------------------------------------------------------------}
  2152. function TAngleAxis.ClickedOn(iX, iY: Integer): Boolean;
  2153. var
  2154.   Slope, TheIntercept, Distance: Single;
  2155. begin
  2156.   if ((FAngle = 0) or
  2157.       (FAngle = 90) or
  2158.       (FAngle = 180) or
  2159.       (FAngle = 270)) then
  2160.     Result := inherited ClickedOn(iX, iY)
  2161.   else
  2162.   begin
  2163.     Result := FALSE;
  2164.  
  2165.     if (iX < NoMath.Min(Left, FEndX)) then exit;
  2166.     if (iX > NoMath.Max(Left, FEndX)) then exit;
  2167.     if (iY < NoMath.Min(Top, FEndY)) then exit;
  2168.     if (iY > NoMath.Max(Top, FEndY)) then exit;
  2169.  
  2170.     Slope := - (Top - FEndY) / (Left - FEndX);
  2171.     TheIntercept := Top + Slope * Left;
  2172.     Distance := Abs((Slope * iX - TheIntercept + iY) * Sin(FAngleRadians));
  2173.     if (Distance < FTicksize) then
  2174.       Result := TRUE;
  2175.   end;
  2176. end;
  2177.  
  2178. {------------------------------------------------------------------------------
  2179.     Procedure: TAngleAxis.Outline
  2180.   Description: Draws an Outline around this AngleAxis
  2181.        Author: Mat Ballard
  2182.  Date created: 01/22/2001
  2183. Date modified: 01/22/2001 by Mat Ballard
  2184.       Purpose: gives the user a guide to what they are moving with the mouse
  2185.  Known Issues:
  2186.  ------------------------------------------------------------------------------}
  2187. procedure TAngleAxis.Outline(ACanvas: TCanvas);
  2188. var
  2189.   dP: TPoint;
  2190. begin
  2191.   ACanvas.Pen.Color := clBlack;
  2192.   ACanvas.Pen.Mode := pmNotXOR;
  2193.   ACanvas.Pen.Style := psDash;
  2194.  
  2195.   dP.x := Round(FTickSize * FCos);
  2196.   dP.y := -Round(FTickSize * FSin);
  2197.  
  2198.   ACanvas.Polygon([
  2199.     Point(Left + dP.x, Top + dP.y),
  2200.     Point(Left - dP.x, Top - dP.y),
  2201.     Point(FEndX - dP.x, FEndY - dP.y),
  2202.     Point(FEndX + dP.x, FEndY + dP.y)]);
  2203. end;
  2204.  
  2205.  
  2206.  
  2207. end.
  2208.