TTMSFNCChart
Virtual vs Collection based mode
When dropping a new instance of the TTMSFNCChart
on the form, the chart is initialized with some sample data, this contains a set of points added through the Points
collection. This is called a collection-based mode which is also the default mode. When taking a look at the events, you will notice that some events have a virtual equivalent that is only called when implementing a virtual mode. The reason for having these events is to make a clear difference between virtual and collection based modes whenever a point is passed through as a parameter. All the other events can access the internal record data that holds a reference to the point collection item (Reference
property), or the virtual point record data (VirtualReference
property).
The virtual mode is enabled as soon as you implement the OnGetNumberOfPoints
. Virtual mode is a global chart mode, so it is not possible to combine a collection-based and a virtual mode series. After implementing the OnGetNumberOfPoints
, the OnGetPoint
event is called to retrieve the data for a point. This is done through a record that can be directly accessed and manipulated. The advantage is that the event signature will not change when adding more properties in the future. There is no difference between virtual and collection-based mode in terms of series. The series are through the Series
collection. Below is a sample that demonstrates this.
const
PointArray: array[0..10] of Double = (10.5, 40.4, 3, 15, 60, 18, 34,
40.5, 15.9, 35, 4);
procedure TForm1.FormCreate(Sender: TObject);
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Series.Clear;
TMSFNCChart1.Series.Add;
TMSFNCChart1.EndUpdate;
end;
procedure TForm1.TMSFNCChart1GetNumberOfPoints(Sender: TObject;
ASerie: TTMSFNCChartSerie; var ANumberOfPoints: Integer);
begin
ANumberOfPoints := Length(PointArray);
end;
procedure TForm1.TMSFNCChart1GetPoint(Sender: TObject;
ASerie: TTMSFNCChartSerie; AIndex: Integer;
var APoint: TTMSFNCChartPointVirtual);
begin
APoint.YValue := PointArray[AIndex];
APoint.XValue := AIndex;
end;
The virtual equivalent for annotations is available through the OnGetNumberOfAnnotations
and OnGetAnnotation
events as demonstrated in the sample below.
const
PointArray: array[0..10] of Double = (10.5, 40.4, 3, 15, 60, 18, 34,
40.5, 15.9, 35, 4);
procedure TForm1.FormCreate(Sender: TObject);
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Series.Clear;
TMSFNCChart1.Series.Add;
TMSFNCChart1.EndUpdate;
end;
procedure TForm1.TMSFNCChart1GetAnnotation(Sender: TObject;
ASerie: TTMSFNCChartSerie; APoint: TTMSFNCChartPointVirtual; AIndex:
Integer;
var AAnnotation: TTMSFNCChartAnnotationVirtual);
begin
AAnnotation.Text := 'Hello World !';
end;
procedure TForm1.TMSFNCChart1GetNumberOfAnnotations(Sender: TObject;
ASerie: TTMSFNCChartSerie; APoint: TTMSFNCChartPointVirtual;
var ANumberOfAnnotations: Integer);
begin
if APoint.Index = 7 then
ANumberOfAnnotations := 1;
end;
procedure TForm1.TMSFNCChart1GetNumberOfPoints(Sender: TObject;
ASerie: TTMSFNCChartSerie; var ANumberOfPoints: Integer);
begin
ANumberOfPoints := Length(PointArray);
end;
procedure TForm1.TMSFNCChart1GetPoint(Sender: TObject;
ASerie: TTMSFNCChartSerie; AIndex: Integer;
var APoint: TTMSFNCChartPointVirtual);
begin
APoint.YValue := PointArray[AIndex];
APoint.XValue := AIndex;
end;
Persistence
The chart is capable of saving its published properties (settings), to a file or stream. The format that is being used is JSON. To save the chart settings, use the code below.
To load an existing settings stream/file use the following code. The Chart additionally exposes events to control which properties need to be saved to the settings file. In some circumstances, it might be required to only save a specific set of properties. TheOnCanLoadProperty
and OnCanSaveProperty
events are responsible for this. Below is a sample that excludes a property ‘Extra’
from the persistence list.
procedure TForm1.TMSFNCChart1CanLoadProperty(Sender, AObject: TObject;
APropertyName: string; APropertyType: TTypeKind; var ACanLoad: Boolean);
begin
ACanLoad := ACanLoad and not (APropertyName = ‘Extra’);
end;
procedure TForm1. TMSFNCChart1CanSaveProperty(Sender, AObject: TObject;
APropertyName: string; APropertyType: TTypeKind; var ACanSave: Boolean);
begin
ACanSave := ACanSave and not (APropertyName = ‘Extra’);
end;
AND
operation is crucial to maintain the existing exclusion list. Returning a true
for each property will additionally save its default published properties such as Align
, Position
and many more.
Adding and removing series
The Chart has a collection of series that can be accessed programmatically or through the editor. The code below shows you how to add a new series based on a default Chart. With the code, the Chart is cleared, and a new series is added.
To delete a series, you will need to know the index of the series you wish to delete. By default, the Chart adds 3 series with random values. With the following code, the last 2 series in the collection are removed.TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Series.Delete(1);
TMSFNCChart1.Series.Delete(1);
TMSFNCChart1.EndUpdate;
When adding a new series, the series does not contain any points, so the Chart will not draw any lines, bars or other chosen Chart types. Adding and removing points is explained in the chapter Adding and removing points.
Accessing series
When adding a new series, the series automatically adds an identifier, set with the LegendText
property. This property is used in the legend, and in the editor. In code, you can access the series with the index in the collection, but more convenient, with a function called SerieByName
. Below is a sample that demonstrates how this function can be used.
var
I: Integer;
s: TTMSFNCChartSerie;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
TMSFNCChart1.Series.Add; //adds ‘Serie 0’ by default
TMSFNCChart1.Series.Add; //adds ‘Serie 1’ by default
s := TMSFNCChart1.SerieByName['Serie 0'];
for I := 0 to 7 do
s.AddPoint(Random(100));
s := TMSFNCChart1.SerieByName['Serie 1'];
for I := 0 to 7 do
s.AddPoint(Random(100));
TMSFNCChart1.EndUpdate;
end;
var
I: Integer;
s: TTMSFNCChartSerie;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.LegendText := 'Mercedes';
TMSFNCChart1.EndUpdate;
end;
var
s: TTMSFNCChartSerie;
begin
s := TMSFNCChart1.SerieByName['Mercedes'];
for I := 0 to 7 do
s.AddPoint(Random(100));
end;
Adding and removing points
Adding or removing points is as easy as adding or removing series. Simply use the new series or retrieve an already existing series and use the Points
collection property to add or remove new or existing points. By default, the Points
collection already adds a random value to the YValue
property. The XValue
property is automatically incremented and has a direct relation to the number of points.
To add a new point, use the following code:
var
s: TTMSFNCChartSerie;
begin
TMSFNCChart1.BeginUpdate;
s := TMSFNCChart1.Series.Add;
s.Points.Add;
TMSFNCChart1.EndUpdate;
end;
var
s: TTMSFNCChartSerie;
pt: TTMSFNCChartPoint;
begin
TMSFNCChart1.BeginUpdate;
s := TMSFNCChart1.Series.Add;
pt := s.Points.Add;
pt.YValue := 123;
TMSFNCChart1.EndUpdate;
end;
YValue
property, and a value on the x-axis
. The value on the x-axis
is set with the XValue
property but is only used in XY type charts such as the ctXYLine
or the ctXYMarker
types.
An alternative to add a new point with a value is to use one of the AddPoint
or AddXYPoint
overloads that are publically accessible on serie level. The code below has an identical result as the
previous code.
var
s: TTMSFNCChartSerie;
begin
TMSFNCChart1.BeginUpdate;
s := TMSFNCChart1.Series.Add;
s.AddPoint(Random(100));
TMSFNCChart1.EndUpdate;
end;
Annotations
Annotations can be used to attach additional information to a specific point, shaped in a rectangle or an ellipse, with many customization options. Annotations are added and deleted in the same way as series, but on point level. Below is a sample which adds an annotation to a specific point in a line Chart.
var
s: TTMSFNCChartSerie;
I: Integer;
an: TTMSFNCChartAnnotation;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
for I := 0 to 10 do
begin
s.Points.Add;
if I = 7 then
begin
an := s.Points[I].Annotations.Add;
an.Text := 'Hello World !';
end;
end;
TMSFNCChart1.EndUpdate;
Annotations are auto-sized by default but can be configured to allow text alignment and wordwrapping.
Labels
Each series has the ability to show labels, which display a formatted string based on the YValue
of the point. Labels have the same appearance, and are added to each point. Through events, labels can optionally be hidden, but are less configurable compared to annotations.
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
s.AutoYRange := arDisabled;
s.MinY := 0;
s.MaxY := 130;
s.Labels.Visible := True;
for I := 0 to 10 do
s.Points.Add;
TMSFNCChart1.EndUpdate;
end;
The labels shown in the sample are already formatted with the Delphi Format
function which can be optionally modified to format floating point values or datetime values. The type of formatting can be changed with the FormatType
property.
X-axis and y-axis values
By default, the Chart enables the x-axis
and the y-axis
for the first series only, but each series has its own x-axis
and y-axis
range and can configure the position and formatting for each axis separately. The amount of values that are shown depend on a number of properties, the available width / height, the major and minor unit and the font size are the most important properties.
Each series can position its x-axis
top, center, bottom or a combination of those three values and the same applies for the y-axis
, but with a left, center and right position. Further customization can be done with one of the various events for custom drawing, formatting, positioning, etc…
The x-axis
has an additional feature that is based on the collection of points inside a series. Each point has an XValueText
property that is linked to the XValue
of that point. When the XValueText
is set, the series will automatically detect and display the text at that point. Below is a sample which adds the months of the year as values of the x-axis
.
var
s: TTMSFNCChartSerie;
I: Integer;
pt: TTMSFNCChartPoint;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
s.AutoXRange := arEnabled;
s.XValues.Angle := -90;
for I := 1 to 12 do
begin
pt := s.Points.Add;
pt.XValueText := FormatSettings.LongMonthNames[I];
end;
TMSFNCChart1.EndUpdate;
end;
The values of the x-axis
are now replaced with the months set via the XValueText
property. In the sample, the values are rotated, because there isn’t enough room to place all values horizontally. This is achieved with the Angle
property of the series object.
The MajorUnit
and MinorUnit
properties that are available for the x-axis
values at serie level can be used to change the appearance. By default the MajorUnit
is 1
and the MinorUnit
is 0
. The x-axis
values do not automatically calculate the units as the y-axis
does with the AutoUnits
property. This property is false by default on the x-axis
. Without a value assigned to the XValueText
property, the x-axis
will draw the floating point values with a specific formatting, based on the MajorUnit
and MinorUnit
.
Below is a sample which sets the MinorUnit
to 0.5
for the x-axis
.
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
s.AutoXRange := arEnabled;
s.XValues.MinorUnit := 0.5;
s.XValues.MinorUnitFormat := '%.1f';
for I := 0 to 9 do
s.Points.Add;
TMSFNCChart1.EndUpdate;
end;
In this sample, we have also changed the MinorUnitFormat
to display the fractional part of the MinorUnit
set to 0.5
.
The y-axis
automatically calculates the best possible MajorUnit
and MinorUnit
by default. Changing the MajorUnit
and MinorUnit
on the y-axis
will only be possible when the AutoUnits
property is set to false.
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
s.AutoXRange := arEnabled;
s.AutoYRange := arEnabledZeroBased;
s.XValues.MinorUnit := 0.5;
s.XValues.MinorUnitFormat := '%.1f';
s.YValues.AutoUnits := False;
s.YValues.MajorUnit := 10;
s.YValues.MinorUnit := 5;
for I := 0 to 9 do
s.Points.Add;
TMSFNCChart1.EndUpdate;
end;
When the default formatting, or adding text to a point with the XValueText property is not sufficient, you can implement an event that returns a string at a specific x-axis
value. This can be applied for both the x-axis
and the y-axis
and is demonstrated in the code below based on the previous sample.
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
s.AutoXRange := arEnabled;
s.AutoYRange := arEnabledZeroBased;
s.XValues.MinorUnit := 0.5;
s.XValues.MinorUnitFormat := '%.1f';
s.YValues.AutoUnits := False;
s.YValues.MajorUnit := 10;
s.YValues.MinorUnit := 5;
s.XValues.Angle := -90;
for I := 0 to 9 do
s.Points.Add;
TMSFNCChart1.EndUpdate;
end;
procedure TForm1.TMSFNCChart1GetSerieXValue(Sender: TObject;
ASerie: TTMSFNCChartSerie; AIndex: Integer;
AKind: TTMSFNCChartDrawXYValueKind; AValue: Double; var AValueString:
string);
begin
if (AKind = vkMajor) and (AValue = 6) then
AValueString := 'Custom X Value';
end;
procedure TForm1.TMSFNCChart1GetSerieYValue(Sender: TObject;
ASerie: TTMSFNCChartSerie; AIndex: Integer;
AKind: TTMSFNCChartDrawXYValueKind; AValue: Double; var AValueString:
string);
begin
if (AKind = vkMinor) and (AValue = 25) then
AValueString := 'Custom Y Value';
end;
Autorange
Each series has an AutoXRange
and an AutoYRange
property. By default the AutoXRange
property is set to arDisabled
and the AutoYRange
is set to arEnabled
. When one of those properties has a disabled auto range, the range is set with the MinX
and MaxX
properties for the x-axis
, and the MinY
and MaxY
properties for the y-axis
. Each range can be extended with the percentage variant for each property.
The autorange is especially useful for common ranges, ranges which have the same minimum and maximum for all series. Below is a sample with 2 series with random values which have a common range. This sample also shows each common range at the left and right side y-axis
.
var
s: TTMSFNCChartSerie;
I, J: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
for I := 0 to 1 do
begin
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
s.AutoYRange := arCommonZeroBased;
s.XValues.MinorUnit := 0.5;
s.XValues.MinorUnitFormat := '%.1f';
s.YValues.AutoUnits := False;
s.YValues.MajorUnit := 10;
s.YValues.MinorUnit := 5;
if I = 0 then
begin
s.Stroke.Color := gcRed;
s.YValues.Positions := [ypLeft, ypRight];
s.XValues.Positions := [xpBottom];
end
else
begin
s.YValues.Positions := [];
s.XValues.Positions := [];
end;
for J := 0 to 10 do
s.Points.Add;
end;
TMSFNCChart1.EndUpdate;
end;
Crosshair
The chart supports displaying and detecting values based on the mouse/cursor position. This feature can be enabled by setting
There are 2 options available that can be used simultaneously.
- Continuous (based on a series index, set with ContinuousSeriesIndex)
- Point based (shows all matching point values, closest to the mouse position)
By default Continuous is activated. Based on a default chart with three series this produces the following result. As you can see, in the screenshot, there is a blue line, which matches the first series.
To switch to point based mode, set TMSFNCChart1.Crosshair.Modes := [ccmPointBased];
. This will procude the following chart output:
The default formatting for the detected values are based on the YValues.MajorUnitFormatting and XValues.MajorUnitFormatting (and formatting type). The x-values also automatically detect labels and show the closest match possible. If for some reason you wish to change the formatting, or change the text, use the OnGetYAxisCrosshairText
or OnGetXAxisCrosshairText
events. The labels appearance can be configured for each series separately. By default the appearance follows the global appearance at chart level. If you want to add additional custom graphics, the OnBeforeDrawSerieXAxisCrosshairText
, OnAfterDrawSerieXAxisCrosshairText
,OnBeforeDrawSerieYAxisCrosshairText
and OnAfterDrawSerieYAxisCrosshairText
can be of help. The horizontal and vertical line drawn to indicate where the point is located can be further fine-tuned with the respective events, or via the properties at TMSFNCChart1.Series[Index].Crosshair
. At this level, you can also exclude series from being detected by setting TMSFNCChart1.Series[Index].Crosshair.XPositions := [];
and TMSFNCChart1.Series[Index].Crosshair.YPositions := [];
. These properties are also used to add values to the center and right Y-Axis, and the top and center X-Axis if they are made visible at chart level.
Logarithmic scale
In some cases it's important to be able to display data with a very wide range of values in a single view. Typically, the largest values are 10, 100 or even 1000 times larger than the smallest values. They are typically referred to as exponential growth curves, or logarithmic scale charts. TTMSFNCChart is capable of configuring the X and Y scale in one of the following options:
- Log-Log (both X and Y scale are logarithmic)
- Semi-Log (X or Y scale is logarithmic)
The default logarithm base number is 10, which is the common logarithm. Enabling logarithmic scales, or changing the base number for both X and Y scale can be done with the following code. As you can see in the sample below, we change the Y scale base logarithmic value to 2, which maps on a binary logarithm.
Semi-Log
To visualize a logarithmic scale, we start by creating a function in linear mode.
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.Stroke.Kind := gskNone;
TMSFNCChart1.Title.Line := False;
Fill.Color := gcWhite;
Fill.Kind := TBrushKind.Solid;
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.AutoXRange := arEnabled;
s.AutoYRange := arEnabled;
s.XValues.AutoUnits := False;
s.XValues.MajorUnit := 1;
s.XValues.MinorUnit := 0;
s.YValues.AutoUnits := True;
s.Mode := smStatistical;
for I := 0 to 14 do
s.AddPoint(Power(2, I));
TMSFNCChart1.EndUpdate;
end;
Now when we add the following 2 lines to the above code, we switch to a logarithmic scale
We produce the following chartYou might notice the line is now linear, but the values matching the scale are logarithmic, this way, we can compact a chart and show more data in one view.
Log-Log
Log-Log is a chart where both X & Y scale are logarithmic. We can demonstrate this with the following code. Note that this requires the chart-type to be ctXYLine, because of the wide range of values
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.Stroke.Kind := gskNone;
TMSFNCChart1.Title.Line := False;
Fill.Color := gcWhite;
Fill.Kind := TBrushKind.Solid;
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.LogarithmicY := True;
s.LogarithmicYBase := 10;
s.LogarithmicX := True;
s.LogarithmicXBase := 10;
s.ChartType := ctXYLine;
s.AutoXRange := arEnabled;
s.AutoYRange := arEnabled;
s.XValues.AutoUnits := False;
s.XValues.MajorUnit := 1;
s.XValues.MinorUnit := 0;
s.YValues.AutoUnits := True;
s.Mode := smStatistical;
for I := 0 to 14 do
begin
s.AddXYPoint(Power(2, I), Power(2, I));
end;
TMSFNCChart1.EndUpdate;
end;
Mathemathical vs Statistical
The Chart can display each series in a different mode. The default mode for each series is Mathematical
. In mathematical mode, the X-axis
zero value is at the crossing point of X-axis
and Y-axis
and thus the first value is displayed at the Y-axis
. Further, it uses the complete available width of the series rectangle. The alternative is Statistical
mode, which automatically calculates and applies an offset on the x-axis
to evenly distribute the values across the available chart width.
Statistical | Mathematical |
---|---|
Multi-Point Series
The Chart supports three types of multi-points series: ctOHLC
, ctCandleStick
and ctBoxPlot
. Points can be added by using one of the AddMultiPoint
overload methods. For the ctCandleStick
and ctBoxPlot
types, a separate increase and decrease fill and stroke color can be set under the series MultiPoints
property. Below is a sample that demonstrates this.
var
s: TTMSFNCChartSerie;
c: Integer;
I: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Series.Clear;
TMSFNCChart1.SeriesMargins.Left := 10;
TMSFNCChart1.SeriesMargins.Top := 10;
TMSFNCChart1.SeriesMargins.Right := 10;
TMSFNCChart1.SeriesMargins.Bottom := 10;
s := TMSFNCChart1.Series.Add;
s.ChartType := ctOHLC;
s.AutoXRange := arCommonZeroBased;
s.AutoYRange := arCommon;
for I := 0 to 29 do
begin
c := Random(100);
if Random(c) mod (Random(10) + 1) = 0 then
s.AddMultiPoint(c + Random(20), c + 20, c - 20, c - Random(20))
else
s.AddMultiPoint(c - Random(20), c + 20, c - 20, c + Random(20));
end;
TMSFNCChart1.EndUpdate;
Pie
Changing the chart-type of one or multiple series to ctPie
will automatically hide the x- and y-axis
and the x- and y-grid
. By default, the slices of the Pie
will automatically take over the fill color of the series.
By default, the points that are added when initializing the series are reflected as separate slices. Adding points can be done with one of the AddPoint
overloads. The general properties of a pie series can be changed at the Pie
property. In the below sample, the main legend is hidden, the pie legend is shown and the colors for each slice are changed.
var
s: TTMSFNCChartSerie;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Legend.Visible := False;
TMSFNCChart1.Series.Clear;
s := TMSFNCChart1.Series.Add;
s.ChartType := ctPie;
s.Pie.Size := 250;
s.Points.Clear;
s.Legend.Visible := True;
s.Pie.AutoSize := False;
s.Pie.Size := 250;
s.Stroke.Color := gcBlack;
s.AddPoint(Random(100) + 40, gcDarkred, 'Dark Red');
s.AddPoint(Random(100) + 40, gcSteelblue, 'Steel Blue');
s.AddPoint(Random(100) + 40, gcYellowgreen, 'Yellow Green');
s.AddPoint(Random(100) + 40, gcLightseagreen, 'Light Sea Green');
s.AddPoint(Random(100) + 40, gcOrange, 'Orange');
TMSFNCChart1.EndUpdate;
end;
Labels and annotations are supported in the same way as they are for the other chart types. You simply add annotations and/or turn on the labels by setting the visible property to true.
There are 2 variants for this charttype that allow handling more types of data. When setting the ChartType
to ctSizedPie
, the slices are equally divided, but the radius depends on the value of the point. When setting the ChartType
to ctVariableRadiusPie
, the slices are calculated as they are with a normal pie chart, but the radius can be controlled with an additional property called YValueVariable
. This property can be accessed through the AddVariablePoint
overload or directly at point level. Below is a sample of a ctSizedPie
.
var
s: TTMSFNCChartSerie;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Legend.Visible := False;
TMSFNCChart1.Series.Clear;
s := TMSFNCChart1.Series.Add;
s.ChartType := ctSizedPie;
s.Pie.Size := 400;
s.Points.Clear;
s.Legend.Visible := True;
s.Pie.AutoSize := False;
s.Pie.Size := 250;
s.Stroke.Color := gcBlack;
s.Labels.Visible := True;
s.Labels.OffsetX := 0;
s.Labels.OffsetY := 0;
s.AddPoint(Random(100) + 75, gcDarkred, 'Dark Red');
s.AddPoint(Random(100) + 75, gcSteelblue, 'Steel Blue');
s.AddPoint(Random(100) + 75, gcYellowgreen, 'Yellow Green');
s.AddPoint(Random(100) + 75, gcLightseagreen, 'Light Sea Green');
s.AddPoint(Random(100) + 75, gcOrange, 'Orange');
TMSFNCChart1.EndUpdate;
end;
Spider
When changing the ChartType
property to ctSpider
, the properties of the YValues
and YGrid
properties are used to configure the visuals of the grid, while the start, sweep angles and dimensions are stored under the Pie
property. Additionally, the Spider*
properties under YValues
and YGrid
are used to further fine-tune spider chart specific features such as the grid kind and the values rotation angle. Applying the ctSpider
chart type on the previous sample, changing the value labels, and applying the Spider properties to change Spider specific features generates the output below.
var
s: TTMSFNCChartSerie;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Legend.Visible := False;
TMSFNCChart1.Series.Clear;
s := TMSFNCChart1.Series.Add;
s.ChartType := ctSpider;
s.Pie.Size := 400;
s.Points.Clear;
s.Legend.Visible := True;
s.Pie.AutoSize := False;
s.Pie.Size := 250;
s.Fill.Opacity := 0.2; (FireMonkey only)
s.Stroke.Color := gcBlack;
s.Labels.Visible := True;
s.Labels.OffsetX := 0;
s.Labels.OffsetY := 0;
s.YGrid.SpiderLegend := True;
s.MaxY := 200;
s.AutoYRange := arDisabled;
s.YValues.AutoUnits := False;
s.YValues.MajorUnit := 50;
s.YValues.MinorUnit := 0;
s.AddPoint(Random(100) + 75, 0, 'Value 1');
s.AddPoint(Random(100) + 75, 0, 'Value 2');
s.AddPoint(Random(100) + 75, 0, 'Value 3');
s.AddPoint(Random(100) + 75, 0, 'Value 4');
s.AddPoint(Random(100) + 75, 0, 'Value 5');
TMSFNCChart1.EndUpdate;
end;
The ctSpider
chart type follows the AutoYRange
property to determine the maximum. When set to arDisabled
(default), the MaxY
property can be used to set a maximum for the grid drawing anspider chart calculation. Additionally, the enabled and common auto ranges can be used in combination with the stacked property on Pie
level to compare multiple series in one chart. The above screenshot demonstrates this, and the code to accomplish this is demonstrated in the “Desktop” demo, available after installation.
Legend
The legend displays the amount of series, each with their own legend text. If you want to display a legend for each series, with an entry for each point, you can turn off the Legend
on chart level, and turn on the legend on series level. The properties are identical, and have the same customization events. In the previous chapter on the Pie
chart type, the legend was displayed at the right side of the chart, with the typical chart type icon next to each entry. If you want further customization for
this icon, you can override the OnBeforeDrawSerieLegendIcon
. Below is a sample that demonstrates this.
procedure TForm1.TMSFNCChart1BeforeDrawSerieLegendIcon(Sender: TObject;
ACanvas: TCanvas; ASerie: TTMSFNCChartSerie; APoint: TTMSFNCChartPoint;
ARect: TRectF; var ADefaultDraw: Boolean);
begin
ADefaultDraw := False;
ACanvas.FillRect(ARect, 2, 2, AllCorners, 1);
ACanvas.DrawRect(ARect, 2, 2, AllCorners, 1);
end;
Markers
Each series has the ability to show markers. Markers have an ellipse shape by default but can be changed to draw a triangle, square, diamond and an image. Further customization can be achieved through the OnBeforeDrawSerieMarker
and the OnAfterDrawSerieMarker
.
Below is a sample that shows how to enable the markers on a serie and how to change the shape to a bitmap.
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
s.Markers.Visible := True;
s.AutoYRange := arDisabled;
s.MinY := 0;
s.MaxY := 100;
for I := 0 to 10 do
s.AddPoint(RandomRange(25, 75));
TMSFNCChart1.EndUpdate;
end;
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.Mode := smStatistical;
s.Markers.Visible := True;
s.Markers.Bitmap.LoadFromFile('icecream.png');
s.Markers.Width := 32;
s.Markers.Height := 32;
s.Markers.Shape := msBitmap;
s.AutoYRange := arDisabled;
s.MinY := 0;
s.MaxY := 100;
for I := 0 to 10 do
s.AddPoint(RandomRange(25, 75));
TMSFNCChart1.EndUpdate;
end;
Stacked series
When choosing a bar or area chart, and adding multiple series, you are able to combine those series in stacked variants based on the type of chart and the GroupIndex
property on series level. The requirement is that each of those combined series have the same range, and have a value that is larger than 0
. There are 2 types of stacked charts: the normal stacked charts combine the values for each group and the percentage stacked charts that represent the values of each series as a percentage of a maximum of 100
.
Below is a sample that adds 4 bar series in 2 stacked groups.
var
s: TTMSFNCChartSerie;
I, J: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
for I := 0 to 3 do
begin
s := TMSFNCChart1.Series.Add;
s.ChartType := ctStackedBar;
s.Mode := smStatistical;
s.AutoYRange := arCommonZeroBased;
s.GroupIndex := I div 2;
case I of
1: s.Fill.Color := gcRed;
2: s.Fill.Color := gcOrange;
3: s.Fill.Color := gcBlue;
end;
s.Stroke.Color := gcBlack;
if I > 0 then
begin
s.YValues.Positions := [];
s.XValues.Positions := [];
end;
for J := 0 to 10 do
s.AddPoint(RandomRange(25, 75));
end;
TMSFNCChart1.EndUpdate;
end;
In this sample, the GroupIndex
is 0
for the first 2 series and 1
for the last 2 series resulting in a multi-group stacked bar series Chart
.
Changing the GroupIndex
property to 0
for all series gives the result below.
For an area type, the GroupIndex
doesn’t have any effect. With this type, all series are stacked like the previous sample with a GroupIndex
that equals 0
for all series.
The second type of stacked series are based on a minimum of 0
and a maximum of 100
. The values that needs to be added can remain identical to the previous stacked chart and will internally be recalculated to match the 0
to 100
range. Below is a sample that demonstrates this.
var
s: TTMSFNCChartSerie;
I, J: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
for I := 0 to 3 do
begin
s := TMSFNCChart1.Series.Add;
s.ChartType := ctStackedPercentageBar;
s.Mode := smStatistical;
s.AutoYRange := arCommonZeroBased;
s.GroupIndex := I div 2;
case I of
1: s.Fill.Color := gcRed;
2: s.Fill.Color := gcOrange;
3: s.Fill.Color := gcBlue;
end;
s.Stroke.Color := gcBlack;
if I > 0 then
begin
s.YValues.Positions := [];
s.XValues.Positions := [];
end;
for J := 0 to 10 do
s.AddPoint(RandomRange(25, 75));
end;
TMSFNCChart1.EndUpdate;
end;
3D
Each series has an Enable3D
property that enables 2D
rendering of a 3D
like environment. The Offset3DX
and Offset3DY
properties on serie level determine the “depth” of the 3D visualization.Using the following code on an area chart, displays the chart with the following result:
var
s: TTMSFNCChartSerie;
I: Integer;
begin
TMSFNCChart1.BeginUpdate;
TMSFNCChart1.Clear;
s := TMSFNCChart1.Series.Add;
s.ChartType := ctArea;
s.Mode := smStatistical;
s.AutoYRange := arEnabledZeroBased;
s.Enable3D := True;
s.XGrid.Visible := True;
s.YGrid.Visible := True;
s.Fill.Opacity := 0.5; (FireMonkey only)
for I := 0 to 10 do
s.AddPoint(RandomRange(25, 75));
TMSFNCChart1.EndUpdate;
end;
Interaction
The Chart supports interaction, which is enabled by default. Interaction enables click detection on a point or a bar and triggers the appropriate event. Additionally, panning and scaling can be performed in X
and Y
direction, depending on the property values under InteractionOptions
. Below is a sample that implements the OnSerieBarClick
event.
procedure TForm1.TMSFNCChart1SerieBarClick(Sender: TObject;
APoint: TTMSFNCChartPoint);
begin
ShowMessage('Bar with value ' + floattostr(APoint.YValue) + ' clicked
!');
end;
The alternative for all other chart types (except for the pie variants) is the OnSeriePointClick
event which detects clicks on a point that lies within the ClickMargin
boundaries relative from the point X
and Y
value. The ClickMargin
is a property on Chart level. For the pie variants, the OnSerieSliceClick
is executed.
Load Data
Note
More examples can be found in the Demos folder after installation.
From File, Stream or Text
There are a couple of ways that you can load data into your chart. Each of these methods can be used for a normal YValue, XValue and/or XLabel. The Ex-overload where you can add the YVariableValue and/or YSecondValue. And the Multi-Point overload where you set the high, low, open, close and if desired the median values.
When you call these methods you can use the DefaultLoadOptions or create a new instance of TTMSFNCChartLoadOptions
and add this parameter to the call.
LoadFromDataArray, gives you the ability to load data in a serie or add a new serie with the data.
var
loadOptions: TTMSFNCChartLoadOptions;
begin
loadOptions := TTMSFNCChartLoadOptions.Create;
loadOptions.YRange := arEnabledZeroBased;
// Will change the values of the first Series in the chart, in case it doesn't exist, it will create a new.
// We add the YValues, the XValues are nil and not used, and we set the XLabels, with the options that we've set.
TMSFNCBarChart.LoadFromDataArray(loadOptions, 0, [123, 98, 54, 154, 128, 87, 103], nil, ['Apple', 'Watermelon', 'Pineapple', 'Pear', 'Banana', 'Lemon','Grapefruit', 'Peach']).LegendText := 'Sold';
TMSFNCOHLCChart.LoadFromMultiPointDataArray(0, [82.63, 81.81, 82.44, 91.24, 95.92], [79.11, 79.99, 77.13, 75.71, 88.51], [81.56, 80.34, 80.94, 77.19, 91.01], [80.37, 80.94, 77.25, 91.00, 95.48]);
end;
LoadFromCSV, you can load data from a CSV-file by setting the indices of the different columns that you want to use. You can load the CSV from a file, url, stream or as text.
// This method will create two series with the YValues and second values. The -1 values are the XValues and XLabels and those aren't used.
TMSFNCBandChart.LoadFromCSVEx(myCSVStream, [0,2], -1, -1 [1,3]);
// This method will create an additional series with the values in the file. The -1 value is the Median which isn't used.
TMSFNCCandleStickChart.DefaultLoadOptions.ClearSeries := False;
TMSFNCCandleStickChart.LoadFromCSVMultiPointData('myFile.csv', 3, 4, 2, 1, -1, 0);
LoadFromJSON, you can load the JSON from a file, url, stream or as text. The JSON values are set by choosing the name for each value. You can set the Series, Points, YValues are possible as a string or an array of strings if you have multiple values, ...
procedure Load;
begin
TMSFNCBarChart1.LoadFromJSONData('my.json', 'series', 'points', 'sold', '', 'label', SeriesCallBack, PointsCallBack);
end;
procedure PointsCallBack(ASerie: TTMSFNCChartSerie; APoint: TTMSFNCChartPoint; APointJSONValue: TJSONValue);
var
j: TJSONValue;
begin
j := TTMSFNCUtils.GetJSONValue(APointJSONValue, 'fill');
if Assigned(j) then
APoint.Color := TTMSFNCUtils.GetJSONProp(APointJSONValue, 'fill');
end;
{
"series": {
"type": "pie",
"points": [
{"label": "Apples", "sold": "128.14", "fill": "green"},
{"label": "Oranges", "sold": "66.72", "fill": "orange"},
{"label": "Lemons", "sold": "84.39", "fill": "yellow"}
],
"other": "additional values"
}
}
Load From Database
The chart can be filled with a dataset and the Adapter property set to an instance of the TTMSFNCChartDatabaseAdapter
.
Load From TMS FNC Grid
This requires to have TMS FNC UI Pack installed as well.
You can link the data from the cells of a TMSFNCGrid
with Adapter property set to an instance of the TTMSFNCChartGridAdapter
.