Class TxyGraph (unit xyGraph)

Inherits from

TCustomPanel

-------------------------- TxyGraph ------------------------------

Constructors


constructor Create(AOwner: TComponent);

--------------------------------------------------------------------- #6a.


Functions

procedure Addmark(id: Integer; x1,y1, x2,y2: Double; c: Tcolor; name: string; marktype:et_marktype; status:boolean);


procedure Assign(source:TPersistent);

saving graph to a file/stream These procedures save the graph to a file.

procedure ClearAll;


procedure ClearMarks;

Marks

--------------------------------------------------------------------- #6h.


procedure CopyToClipboard;

--------------------------------------------------------------------- #6i.

function DeleteMark(id: Integer): Boolean;

insert in list

destructor Destroy;

Create

procedure DrawFunction(F: PlotFunction; var parms; x1, x2: Double; color: TColor; style: TPenStyle; steps: Word);

A convenient way to graph a function; automatically fills graph; handles singularities in the function.

procedure FillBitmap(bmp:TBitmap);

thanks to the following people for their help with the Metafiles routine: Frank Schmidt, John Biddiscombe, Hendrik Levsen

procedure FillMetafile(wmf:TMetafile);

fill metafile requires a valid TMetafile to be supplied to it - resource allocation/deallocation issues.

function findNearestPoint({var }series, x,y:integer):pgPoint;

FindNearestPoint - get the handle to the nearest point to the mouse.

function FindSeries(i:integer): Boolean;

ignore

function GetMouseVals(sN, x: Integer; var index: Integer; var xNearest, yNearest: Double): Boolean;

GetMouseVals returns the value of the data point matching the mouse point best, or false if the mouse is outside the plot area

function GetMouseX(x: Integer): Double;

getmousex/y return the value as determined by the scales

function GetMouseXY(sN, x, y: Integer; var index: Integer; var xScaled, yScaled, xNearest, yNearest: Double): Boolean;

---------------------- Reverse Metric Routines -------------------------------

function GetMouseY(y: Integer): Double;


function GetMouseY2(y: Integer): Double;


procedure HookedSeriesEvent(Sender:TObject; TheMessage:TDSChangeType);


procedure Hookseries(Source:TSeries; Ahooktype:THooktype; Dest:Integer; WantPersist:boolean);

hooking other graph series

--------------------------------------------------------------------- #6g.


procedure PasteFromClipboard;


procedure Print;

stop re-entrancy problems if a window - such as a print dialog box - is cleared just before printing, calling a paint and screwing the printer metrics up

procedure PrintOnPage;

PrintOnPage allows more than one graph to be printed on a page; calls to it must be preceded by BeginDoc amd followed by EndDoc.

procedure readfromfile(fname:string);

write number of bytes left - for future compatibility

procedure readfromStream(f:TStream);


procedure SaveToBitmap(const fname:string);


procedure savetofile(fname:string; savedata:boolean);


procedure savetostream(f:TStream; savedata:boolean);


procedure savetoWMF(const fname:string);

not sure why this is required?? Why kill the clipboard memory? It's required above because in the copy routine it may not have been handed to the clipboard.

procedure unhookseries(source:TSeries; WantPersist:boolean);

dsClearUpdates = anything might have changed

procedure CalcMetrics;

procedure TxyGraph.

function CheckScalesOK: Boolean;


procedure ClipGraph;

function TxyGraph.

procedure ColorBackground;

DrawMarks

function DataFound(whichaxis:TAxis): Boolean;

--------------------------------------------------------------------- #6g.

procedure DoRescaleEvent;

--------------------------------------------------------------------- #6c.

procedure DoTightFit;

---------------------- graph scaling ------------------------------------

procedure DrawAxes;

DrawY2Axis

procedure DrawGraphTitle;

DrawYLabels

procedure DrawLegend;


procedure DrawLineSegment(x1, y1, x2, y2: Integer);

note for confused readers: the shortcut to unclip that is valid for screen metrics is not valid for printers :)

procedure DrawMarks(when: Boolean);

DrawGraphTitle

procedure DrawXAxis;

ColorBackground

procedure DrawXGridlines;


function DrawXLabels(base:integer; reverse:boolean):integer;

very small or very large

procedure DrawXTickMarks(base:integer; reverse:boolean);

DrawYGridlines

procedure DrawY2Axis;

DrawYAxis

procedure DrawYAxis;

DrawXAxis

procedure DrawYGridlines(CYAxis: TAxis);

DrawXGridlines

function DrawYLabels(CYAxis: TAxis; base:integer; reverse:boolean):integer;

DrawXLabels

procedure DrawYTickMarks(CYAxis: TAxis; base:integer; reverse:boolean);

DrawXTickMarks

function fx(v: Double): Integer;


function fy(v: Double): Integer;

20000 is large compared with device pixel size; this avoids range error if some points are far outside the axis range

function fy2(v: Double): Integer;

if not FYAxis.

procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

Implements dragging and resizing:

--------------------------------------------------------------------- #6b.


procedure MouseMove(Shift: TShiftState; X,Y: Integer);


procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X,Y: Integer);


procedure Paint;

Printing: linewidth for series, points thinner than for axes

procedure PaintCross;

skip out-of-support x's

procedure PaintGraph;


procedure SetUpDragging(X,Y: Integer);

MouseDown

procedure UnclipGraph;


function CreateNewSeries(i:integer):TSeries;


procedure defineproperties(Filer: TFiler);

routines concerned with writing a full image of the graph to the component image

room for future expansion


function GetSeriesInt(i:integer):TSeries;

These two are needed for Series[] property:

--------------------------------------------------------------------- #6f.


procedure ReadAllMarks(Stream: TStream);


procedure ReadAllSeries(Stream: TStream);


procedure ReadMarkCount(Reader: TReader);


procedure ReadSeriesCount(Reader: TReader);


procedure setDefaultPropertyValues;

initialise all properties.

procedure SetHasDragged(v:boolean);


procedure SetPlotting(v: Boolean);

--------------------------------------------------------------------- #6e.

procedure WriteAllMarks(Stream: TStream);


procedure WriteAllSeries(Stream: TStream);


procedure writeMarkCount(writer: TWriter);


procedure writeseriescount(writer: TWriter);


Properties

property Align :


property Appearance : TAppearance


property BevelInner :


property BevelOuter :


property BevelWidth :


property BorderStyle :


property BorderWidth :


property Ctl3D :


property Cursor :


property Dimensions : TDimensions


property DragAllowed : Boolean


property Legend : TLegend


property ParentCtl3D :


property ParentFont :


property Plotting : Boolean


property PopupMenu :


property Visible :


property XAxis : TAxis


property YAxis : TAxis


property YAxis_Second : TAxis


property checkScales : boolean


property HasDragged : boolean

for mouse events

property LastSeriesIndex : integer

provided to iterate through existing series

property Series : TSeries


property serieshandle : TSeries

data routines

Events

event OnClick :


event OnDblClick :


event OnDeleteSeries : TSeriesEvent


event OnDragDrop :


event OnDragOver :


event OnEndDrag :


event OnEnter :


event OnExit :


event OnLogError : TSeriesEvent


event OnMouseDown :


event OnMouseMove :


event OnMouseUp :


event OnNewSeries : TSeriesEvent


event OnPaintEnd : TPaintEvent


event OnRescale : TNotifyEvent


event OnResize :


event OnScaleError : TNotifyEvent


event OnTooManyPoints : TSeriesEvent


event OnWantDesigner : TNotifyEvent


Variables

AllScalesOK : Boolean;


dRect : tRect;

dragging:

dx : Integer;


dy : Integer;


FAltCanvas : TCanvas;


FAppearance : TAppearance;


FCanvas : TCanvas;

Private declarations

FCurrHeight : Word;


FCurrWidth : Word;


FDimensions : TDimensions;


FDraggable : Boolean;


FDragging : Boolean;


FFilingMarksCount : word;


FFilingSeriesCount : word;


FHasDragged : Boolean;


FHoldXAS : boolean;


FHoldXmax : double;


FHoldXmin : double;


FHoldY2AS : boolean;


FHoldY2max : double;


FHoldY2min : double;


FHoldYAS : boolean;


FHoldYmax : double;


FHoldYmin : double;


FHookedSeries : pHookedSeries;


FLastSeries : integer;


FLegDragging : Boolean;


FLegend : TLegend;


FMarks : pMark;


FNoGridlines : Boolean;


FOnDeleteSeries : TSeriesEvent;


FOnLogError : TSeriesEvent;


FOnNewSeries : TSeriesEvent;

Events:

FOnPaintEnd : TPaintEvent;


FOnRescale : TNotifyEvent;


FOnScaleError : TNotifyEvent;


FOnTooManyPoints : TSeriesEvent;


FOnWantDesigner : TNotifyEvent;


FPainting : Boolean;


FPlotting : Boolean;

Graph property data:

FSaveData : boolean;


FScale : Double;


FSeries : TSeries;

FAltCanvas always points a full FCanvas.

FXAxis : TAxis;


FXOffset : Word;


FYAxis : TAxis;


FYAxis2 : TAxis;


FYOffset : Word;



Constructors


constructor Create(AOwner: TComponent);

--------------------------------------------------------------------- #6a. TxyGraph - administration ---------------------------------------------------------------------


Functions


procedure Addmark(id: Integer; x1,y1, x2,y2: Double; c: Tcolor; name: string; marktype:et_marktype; status:boolean);


procedure Assign(source:TPersistent);

saving graph to a file/stream These procedures save the graph to a file. As well as creating a special file, these also stream series to the .dfm file so that series created at design time are saved when compiled. Because the .dfm file includes a number of properties that shouldn't change - parents, events, etc - a whole separate subsystem has been created for savetofile methods. The 2 subsystems show marks and series procedures. The file format is intended to be forwards compatible(!). The file version number written at the start of the stream is different to the version of xyGraph - it will change when a new format is created that is not backwards compatible. use savetostream to include the same info in a stream of your wish. Format: (for file - a subset is relevent for the .dfm) header: constants declared at the top of this unit. - arbitrary identifier - file version identifier - code version of writing xygraph sections - in order: Appearance, FDimensions, FXAxis, FYAxis, FYAXis2 and FLegend followed by 2 blocks - series count & Marks Count sections - a section for each series, and then a section for each mark bytes left - 4 byte indicator of number of bytes remaining in the stream - to allow future versions to add information Each Section consists of a series of blocks ending in a block with a identifier of 0. identifier 99 is reserved for a descriptor. The Series Section consists of 3 separate sections, a TSeries section, followed by a TDataSeries section, followed by the data for the series. Each block consists of an identifier (integer < 100) and a format identifier, written as a string (optionally with the identifier name appended), followed by the value in the format indicated. Where possible, formats will be converted when reading. Because with the exception of the bytes left field all information is written with TWriter descendants each individual piece of information is separated by the TWriter separator. WantCompact can be used to increase the amount information written as strings or decrease the file size. Information not saved at all for design reasons. Hooked series - all hooks will be lost Series indexes will be changed Intercept info will be lost regression data is not saved (but will be automatically rebuilt) Pointwarning limit is not saved HoldUpdates will be ignored Function plotting will not be saved Known Bugs: When you copy to clipboard at designtime, with no series in the graph. I don't know why. Even though the error is raised, the copy had still worked successfully and you will be pasting - converting the series numbers - the reason is again unknown. Keep trying! It generally works in the end!


procedure ClearAll;


procedure ClearMarks;

Marks

--------------------------------------------------------------------- #6h. TxyGraph - Marks routines ---------------------------------------------------------------------


procedure CopyToClipboard;

--------------------------------------------------------------------- #6i. TxyGraph - External interaction ---------------------------------------------------------------------} {copy and paste routines modelled on Delphi Developers Guide, Pacheco & Teixeira p 352


function DeleteMark(id: Integer): Boolean;

insert in list


destructor Destroy;

Create


procedure DrawFunction(F: PlotFunction; var parms; x1, x2: Double; color: TColor; style: TPenStyle; steps: Word);

A convenient way to graph a function; automatically fills graph; handles singularities in the function. F must be far; parms may be of any type (usu. array of Double) -- no error checks; the graph of the function will be drawn from x=x1 to x=x2; if x1=x2, will be set to XMin, XMax; if larger, will be clipped to XMin, XMax if steps=0, will choose "enough" to be smooth


procedure FillBitmap(bmp:TBitmap);

thanks to the following people for their help with the Metafiles routine: Frank Schmidt, John Biddiscombe, Hendrik Levsen


procedure FillMetafile(wmf:TMetafile);

fill metafile requires a valid TMetafile to be supplied to it - resource allocation/deallocation issues. The internally created metafile is produced first, and then copied into the external one


function findNearestPoint({var }series, x,y:integer):pgPoint;

FindNearestPoint - get the handle to the nearest point to the mouse. x,y: mouse position. series: a series to search, or 0 for all series. returns the series in series (hence var pars) FindNearestPoint finds the point nearest _visually_. (if scales are logged, it may not be the point closest to the data value of x,y) comment: Yes, I know, this is a slow way to do it. You could probably think of faster ways. But this is enough for me.


function FindSeries(i:integer): Boolean;

ignore


function GetMouseVals(sN, x: Integer; var index: Integer; var xNearest, yNearest: Double): Boolean;

GetMouseVals returns the value of the data point matching the mouse point best, or false if the mouse is outside the plot area


function GetMouseX(x: Integer): Double;

getmousex/y return the value as determined by the scales


function GetMouseXY(sN, x, y: Integer; var index: Integer; var xScaled, yScaled, xNearest, yNearest: Double): Boolean;

---------------------- Reverse Metric Routines -------------------------------


function GetMouseY(y: Integer): Double;


function GetMouseY2(y: Integer): Double;


procedure HookedSeriesEvent(Sender:TObject; TheMessage:TDSChangeType);


procedure Hookseries(Source:TSeries; Ahooktype:THooktype; Dest:Integer; WantPersist:boolean);

hooking other graph series

--------------------------------------------------------------------- #6g. TxyGraph - series hooking routines ---------------------------------------------------------------------


procedure PasteFromClipboard;


procedure Print;

stop re-entrancy problems if a window - such as a print dialog box - is cleared just before printing, calling a paint and screwing the printer metrics up


procedure PrintOnPage;

PrintOnPage allows more than one graph to be printed on a page; calls to it must be preceded by BeginDoc amd followed by EndDoc. Print prints only the current graph on its own sheet. The graph is printed without change in aspect ratio. The size of the printed graph is controlled by PrintScalePct, which makes the dimension of the printed graph a percentage of the page dimension (on the axis with the larger Screen/Page ratio) The location of the upper left corner of the graph is controlled by PrintX(Y)OffsetPct, which locate the corner as percentages of the page height and width


procedure readfromfile(fname:string);

write number of bytes left - for future compatibility


procedure readfromStream(f:TStream);


procedure SaveToBitmap(const fname:string);


procedure savetofile(fname:string; savedata:boolean);


procedure savetostream(f:TStream; savedata:boolean);


procedure savetoWMF(const fname:string);

not sure why this is required?? Why kill the clipboard memory? It's required above because in the copy routine it may not have been handed to the clipboard. But I'm not so sure here


procedure unhookseries(source:TSeries; WantPersist:boolean);

dsClearUpdates = anything might have changed


procedure CalcMetrics;

procedure TxyGraph.CalcXMetrics; begin with FXAxis do begin if (FMin>=FMax) then raise Exception.Create('CalcXMetrics: XMin>=XMax'); if FLogging then FM := (FCurrWidth - FDimensions.FLeft - FDimensions.FRight) / (Ln(FMax) - Ln(FMin)) else FM := (FCurrWidth - FDimensions.FLeft - FDimensions.FRight) / (FMax - FMin); end; end; procedure TxyGraph.CalcYMetrics; begin with FYAxis do begin if (FMin>=FMax) then raise Exception.Create('CalcYMetrics: YMin>=YMax'); if FLogging then FM := (FCurrHeight - FDimensions.FTop - FDimensions.FBottom) / (Ln(FMax) - Ln(FMin)) else FM := (FCurrHeight - FDimensions.FTop - FDimensions.FBottom) / (FMax - FMin); end; end; procedure TxyGraph.CalcY2Metrics; begin with FYAxis2 do begin if (FMin>=FMax) then raise Exception.Create('CalcY2Metrics: YMin>=YMax'); if FLogging then FM := (FCurrHeight - FDimensions.FTop - FDimensions.FBottom) / (Ln(FMax) - Ln(FMin)) else FM := (FCurrHeight - FDimensions.FTop - FDimensions.FBottom) / (FMax - FMin); end; end;


function CheckScalesOK: Boolean;


procedure ClipGraph;

function TxyGraph.DoResize: Boolean; var b: Boolean; begin b := FYAxis.DoResize; {force evaluation of both functions - need side effects!} b := FYAxis2.DoResize or b; Result := FXAxis.DoResize or b; end;*) {--------------------------------------------------------------------- #6d. TxyGraph - painting routines ---------------------------------------------------------------------


procedure ColorBackground;

DrawMarks


function DataFound(whichaxis:TAxis): Boolean;

--------------------------------------------------------------------- #6g. TxyGraph - data manipulation ---------------------------------------------------------------------


procedure DoRescaleEvent;

--------------------------------------------------------------------- #6c. TxyGraph - metrics routines ---------------------------------------------------------------------


procedure DoTightFit;

---------------------- graph scaling ------------------------------------


procedure DrawAxes;

DrawY2Axis


procedure DrawGraphTitle;

DrawYLabels


procedure DrawLegend;


procedure DrawLineSegment(x1, y1, x2, y2: Integer);

note for confused readers: the shortcut to unclip that is valid for screen metrics is not valid for printers :)


procedure DrawMarks(when: Boolean);

DrawGraphTitle


procedure DrawXAxis;

ColorBackground


procedure DrawXGridlines;


function DrawXLabels(base:integer; reverse:boolean):integer;

very small or very large


procedure DrawXTickMarks(base:integer; reverse:boolean);

DrawYGridlines


procedure DrawY2Axis;

DrawYAxis


procedure DrawYAxis;

DrawXAxis


procedure DrawYGridlines(CYAxis: TAxis);

DrawXGridlines


function DrawYLabels(CYAxis: TAxis; base:integer; reverse:boolean):integer;

DrawXLabels


procedure DrawYTickMarks(CYAxis: TAxis; base:integer; reverse:boolean);

DrawXTickMarks


function fx(v: Double): Integer;


function fy(v: Double): Integer;

20000 is large compared with device pixel size; this avoids range error if some points are far outside the axis range


function fy2(v: Double): Integer;

if not FYAxis.ScaledOk then raise exception.create('call to fy when y fails');


procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

Implements dragging and resizing:

--------------------------------------------------------------------- #6b. TxyGraph - mouse routines ---------------------------------------------------------------------} {general outline of responding to mouse events: if it's not the left mouse button, just call the inherited handler if the shift button is down, the user wants to change the plot area if the ctrl button is down, the user wants to run the designer if Draggable is set to true: if the mouse is in the top left corner, the user wants to move the graph if the mouse is in the bottom right corner, the user wants to resize the graph


procedure MouseMove(Shift: TShiftState; X,Y: Integer);


procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X,Y: Integer);


procedure Paint;

Printing: linewidth for series, points thinner than for axes


procedure PaintCross;

skip out-of-support x's


procedure PaintGraph;


procedure SetUpDragging(X,Y: Integer);

MouseDown


procedure UnclipGraph;


function CreateNewSeries(i:integer):TSeries;


procedure defineproperties(Filer: TFiler);

routines concerned with writing a full image of the graph to the component image

room for future expansion


function GetSeriesInt(i:integer):TSeries;

These two are needed for Series[] property:

--------------------------------------------------------------------- #6f. TxyGraph - series routines ---------------------------------------------------------------------


procedure ReadAllMarks(Stream: TStream);


procedure ReadAllSeries(Stream: TStream);


procedure ReadMarkCount(Reader: TReader);


procedure ReadSeriesCount(Reader: TReader);


procedure setDefaultPropertyValues;

initialise all properties. Run on create and before readfromfile

Create


procedure SetHasDragged(v:boolean);


procedure SetPlotting(v: Boolean);

--------------------------------------------------------------------- #6e. TxyGraph - property servers ---------------------------------------------------------------------


procedure WriteAllMarks(Stream: TStream);


procedure WriteAllSeries(Stream: TStream);


procedure writeMarkCount(writer: TWriter);


procedure writeseriescount(writer: TWriter);


Properties


property Align :


property Appearance : TAppearance


property BevelInner :


property BevelOuter :


property BevelWidth :


property BorderStyle :


property BorderWidth :


property Ctl3D :


property Cursor :


property Dimensions : TDimensions


property DragAllowed : Boolean


property Legend : TLegend


property ParentCtl3D :


property ParentFont :


property Plotting : Boolean


property PopupMenu :


property Visible :


property XAxis : TAxis


property YAxis : TAxis


property YAxis_Second : TAxis


property checkScales : boolean


property HasDragged : boolean

for mouse events


property LastSeriesIndex : integer

provided to iterate through existing series


property Series : TSeries


property serieshandle : TSeries

data routines


Events


event OnClick :


event OnDblClick :


event OnDeleteSeries : TSeriesEvent


event OnDragDrop :


event OnDragOver :


event OnEndDrag :


event OnEnter :


event OnExit :


event OnLogError : TSeriesEvent


event OnMouseDown :


event OnMouseMove :


event OnMouseUp :


event OnNewSeries : TSeriesEvent


event OnPaintEnd : TPaintEvent


event OnRescale : TNotifyEvent


event OnResize :


event OnScaleError : TNotifyEvent


event OnTooManyPoints : TSeriesEvent


event OnWantDesigner : TNotifyEvent


Variables


AllScalesOK : Boolean;


dRect : tRect;

dragging:


dx : Integer;


dy : Integer;


FAltCanvas : TCanvas;


FAppearance : TAppearance;


FCanvas : TCanvas;

Private declarations


FCurrHeight : Word;


FCurrWidth : Word;


FDimensions : TDimensions;


FDraggable : Boolean;


FDragging : Boolean;


FFilingMarksCount : word;


FFilingSeriesCount : word;


FHasDragged : Boolean;


FHoldXAS : boolean;


FHoldXmax : double;


FHoldXmin : double;


FHoldY2AS : boolean;


FHoldY2max : double;


FHoldY2min : double;


FHoldYAS : boolean;


FHoldYmax : double;


FHoldYmin : double;


FHookedSeries : pHookedSeries;


FLastSeries : integer;


FLegDragging : Boolean;


FLegend : TLegend;


FMarks : pMark;


FNoGridlines : Boolean;


FOnDeleteSeries : TSeriesEvent;


FOnLogError : TSeriesEvent;


FOnNewSeries : TSeriesEvent;

Events:


FOnPaintEnd : TPaintEvent;


FOnRescale : TNotifyEvent;


FOnScaleError : TNotifyEvent;


FOnTooManyPoints : TSeriesEvent;


FOnWantDesigner : TNotifyEvent;


FPainting : Boolean;


FPlotting : Boolean;

Graph property data:


FSaveData : boolean;


FScale : Double;


FSeries : TSeries;

FAltCanvas always points a full FCanvas. this is important when a metafile is being drawn, as some information, such as textwidth is not available from FCanvas (D1.0) i.e. when painting, FCanvas = FAltCanvas = Canvas when printing, FCanvas = FAltCanvas = printer.canvas when metafiling, FCanvas = Metafile.canvas, and FAltCanvas := Canvas


FXAxis : TAxis;


FXOffset : Word;


FYAxis : TAxis;


FYAxis2 : TAxis;


FYOffset : Word;