In our first step, we descended from a TRSCustomChart class to create our new chart type. We decided we wanted to create a graph, or network, chart composed of nodes and links (or connections). For a graph chart, we chose to inherit from the TRSShapeChart class because it has the ability to display unlimited number of shapes, or nodes, in arbitrary locations, shapes, and sizes.
However, that is not the only requirement we have for our graph chart. We also want to display links as arrows with labels (or captions) between the nodes. So, we need to inherited from the TRSChartValue and TRSChartValues classes. For our purposes, the decision is easy because we have already chosen the shape chart class so we need to inherit from the TRSShapeChartValue and TRSShapeChartValue classes. Using the New Collection wizard available from the RiverSoftAVG.com web site, this is easy.
The New Collection Wizard can fill in most of the information we need. First, we make sure the unit that contains our TRSGraphChart is showing in Delphi and then we start the New Collection Wizard (File->New->Other). We fill in the wizard as shown, click OK, and voila! The wizard has taken care of most of our work for us. We will just add a few more Add methods to the collection and then is what we've got:
TRSGraphChartValues = class;
TRSGraphChartValue = class(TCollectionItem)
{ Purpose: }
private
{ Private declarations }
function GetCollection: TRSGraphChartValues;
procedure SetCollection(const Value: TRSGraphChartValues); reintroduce;
protected
{ Protected declarations }
function GetDisplayName: String; override;
public
{ Public declarations }
procedure Assign(Source: TPersistent); override;
property Collection: TRSGraphChartValues read GetCollection write SetCollection;
published
{ Published declarations }
end; { TRSGraphChartValue }
TRSGraphChartValues = class(TRSShapeChartValues)
{ Purpose: }
private
{ Private declarations }
function GetItem(Index: Integer): TRSGraphChartValue;
procedure SetItem(Index: Integer; const Value: TRSGraphChartValue);
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TRSGraphChart);
function Add: TRSGraphChartValue;
function Add: TRSGraphChartValue; overload;
function Add( X: TRSChartValueType; Caption: TCaption = ''; Color: TColor = chtDefaultColor; ImageIndex: Integer = -1 ): TRSGraphChartValue; overload;
function Add( X, Y: TRSChartValueType; Caption: TCaption = ''; Color: TColor = chtDefaultColor; ImageIndex: Integer = -1 ): TRSGraphChartValue; overload;
function Add( ARect: TRSRect; Style: TRSShapeStyle = ssRectangle; Caption: TCaption = ''; Color: TColor = chtDefaultColor; ImageIndex: Integer = -1 ): TRSGraphChartValue; function FindItemID(ID: Integer): TRSGraphChartValue;
function Insert(Index: Integer): TRSGraphChartValue;
property Items[Index: Integer]: TRSGraphChartValue read GetItem write SetItem; default;
function Owner: TRSGraphChart; reintroduce;
published
{ Published declarations }
end; { TRSGraphChartValues }
{ TRSGraphChartValue }
procedure TRSGraphChartValue.Assign(Source: TPersistent);
begin
if Source is TRSGraphChartValue then
begin
// Copy properties here
Changed(False);
end
else
inherited Assign(Source);
end;
function TRSGraphChartValue.GetCollection: TRSGraphChartValues;
begin
result := TRSGraphChartValues(inherited Collection);
end;
procedure TRSGraphChartValue.SetCollection(const Value: TRSGraphChartValues);
begin
inherited Collection := Value;
end;
function TRSGraphChartValue.GetDisplayName: String;
begin
result := ''; {TODO: Update code for Display Name based on your properties}
if result = '' then
result := inherited GetDisplayName;
end;
{ TRSGraphChartValues }
function TRSGraphChartValues.Add: TRSGraphChartValue;
begin
result := TRSGraphChartValue(inherited Add);
end;
function TRSGraphChartValues.Add(X: TRSChartValueType; Caption: TCaption;
Color: TColor; ImageIndex: Integer): TRSGraphChartValue;
begin
result := TRSGraphChartValue(inherited Add( X, Caption, Color, ImageIndex ));
end;
function TRSGraphChartValues.Add(ARect: TRSRect; Style: TRSShapeStyle;
Caption: TCaption; Color: TColor; ImageIndex: Integer): TRSGraphChartValue;
begin
result := TRSGraphChartValue(inherited Add( ARect, Style, Caption, Color, ImageIndex ));
end;
function TRSGraphChartValues.Add(X, Y: TRSChartValueType; Caption: TCaption;
Color: TColor; ImageIndex: Integer): TRSGraphChartValue;
begin
result := TRSGraphChartValue(inherited Add( X, Y, Caption, Color, ImageIndex ));
end;
function TRSGraphChartValues.FindItemID(ID: Integer): TRSGraphChartValue;
begin
result := TRSGraphChartValue(inherited FindItemID(ID));
end;
function TRSGraphChartValues.GetItem(Index: Integer): TRSGraphChartValue;
begin
result := TRSGraphChartValue(inherited Items[Index]);
end;
function TRSGraphChartValues.Owner: TRSGraphChart;
var
AOwner: TPersistent;
begin
AOwner := inherited Owner;
if AOwner is TRSGraphChart then
result := TRSGraphChart(AOwner)
else
result := nil;
end;
function TRSGraphChartValues.Insert(Index: Integer): TRSGraphChartValue;
begin
result := TRSGraphChartValue(inherited Insert(Index));
end;
procedure TRSGraphChartValues.SetItem(Index: Integer; const Value: TRSGraphChartValue);
begin
inherited Items[Index] := Value;
end;
constructor TRSGraphChartValues.Create(AOwner: TRSGraphChart);
begin
inherited Create(AOwner, TRSGraphChartValue);
end;
Now that we have the basics of the chart value, we need to Customize your TRSChartValue and TRSChartValues descendants.