Class TxyGraph (unit xyGraph) |
Inherits from
TCustomPanel
-------------------------- TxyGraph ------------------------------
constructor Create(AOwner: TComponent);
- ---------------------------------------------------------------------
#6a.
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 imageroom 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);
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
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
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;
constructor Create(AOwner: TComponent);
---------------------------------------------------------------------
#6a. TxyGraph - administration
---------------------------------------------------------------------
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);
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
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
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;