YOUSEFUL / DELPHI / COMPONENTS
TAtlasCustomChart
Base class of the Atlas Plot Pro controls: painting, off-screen rendering, export, title, footnote, legend and batching.
Description
The shared base of TAtlasBoxPlot, TAtlasHeatMap and TAtlasPolarPlot, and the starting point for new chart types. It is a TCustomControl that owns everything the charts share: painting through an Atlas Plot drawing surface, off-screen rendering to bitmaps, SVG and files, the title and footnote, a legend helper and update batching. A descendant overrides the protected DrawChart and ResetLayout and nothing else.
Every render, on screen or off, runs the same steps: ResetLayout; fill the bounds with Color; measure LineH from Font; draw the bold Title at the top and the Footnote at the bottom; then call DrawChart with the remaining area if it is at least four text lines wide and three high. Pixel queries of the descendants describe the most recent render. RenderTo, CreateBitmap, ToSVG and SaveToFile re-run the on-screen layout afterwards when the control has a window handle, so an export at another size does not break mouse hit testing; Render does not.
Besides the members below, the class publishes the standard Align, Anchors, Constraints, Enabled, ParentFont, PopupMenu, Visible, OnClick, OnDblClick, OnMouseDown, OnMouseUp and OnResize. The unit also declares the colours AtlasGridColor ($00E6E6E6) and AtlasAxisColor ($00808080) used for grid and axis lines. The members marked protected are for descendants only. Use the controls from the main thread. The class is not on the palette itself; there is no FMX version.
Members
| Member | Kind | What it does |
|---|---|---|
Create | constructor | Sets up a double-buffered, opaque control of 480 x 320 pixels with a white background. |
BeginUpdate | method | Starts a batch of changes: until the matching EndUpdate, property changes and added data do not repaint the control. |
EndUpdate | method | Ends a batch started by BeginUpdate. |
Render | method | Draws the chart into any TAtlasPlotSurface (for example a TAtlasSvgSurface or a TAtlasCanvasSurface over your own canvas), filling Bounds. |
RenderTo | method | Draws the chart onto a VCL canvas, for example a printer canvas or a bitmap you own, filling Bounds. |
CreateBitmap | method | Returns a new 24-bit bitmap of the given size with the chart drawn on it; the caller frees it. |
ToSVG | method | Returns the chart as an SVG document of the given size (1 to 16384 pixels). |
SaveToFile | method | Writes the chart to .png, .bmp, .emf or .svg, chosen by the extension (case does not matter); any other extension raises EAtlasPlotError before anything is written. |
PaletteColor | method | One of ten built-in series colours (blue, orange, green, red, purple, olive, dark blue, teal, salmon, grey). |
Title | property | Bold caption centred at the top. |
Footnote | property | Caption centred at the bottom. |
Color | property | Background colour, clWhite by default. |
Font | property | Font of every caption; the title uses it in bold. |
OnMouseMove | event | The standard VCL mouse event, published by the base class. |
DrawChart | method | Protected; override it to draw the chart. |
ResetLayout | method | Protected; override it to forget hit regions and pixel mappings. |
ChartChanged | method | Protected. |
DrawLegend | method | Protected; call it from DrawChart. |
UseFontColor | method | Protected; selects the control's Font in another colour, optionally bold, on Surface for the following Text calls. |
Surface | property | Protected. |
LineH | property | Protected. |
Constructors
Create constructor
constructor Create(AOwner: TComponent); override;Sets up a double-buffered, opaque control of 480 x 320 pixels with a white background. Descendants call inherited first and then create their own data.
Properties
Title property
property Title: string read FTitle write SetTitle;Bold caption centred at the top. Empty (the default) leaves no room for it.
Footnote property
property Footnote: string read FFootnote write SetFootnote;Caption centred at the bottom. Empty (the default) leaves no room for it.
Color property
property Color default clWhite;Background colour, clWhite by default. Chart parts are blended towards it (box fills, radar fills), and heat map cells are outlined with it.
Font property
property Font;Font of every caption; the title uses it in bold. The height of Ag in this font (at least 8 pixels) sets the chart's margins, label spacing and marker sizes. Changing it repaints the control.
Surface property
property Surface: TAtlasPlotSurface read FSurface;Protected. The TAtlasPlotSurface being drawn on; valid only while ResetLayout and DrawChart run, nil otherwise.
LineH property
property LineH: Integer read FLineH;Protected. The height of Ag in Font on the current surface, at least 8 pixels; use it for margins and spacing so the chart scales with the font. Valid during a render.
Events
OnMouseMove event
property OnMouseMove;The standard VCL mouse event, published by the base class. Pass X and Y to HitTest to find what is under the pointer.
Methods
BeginUpdate method
procedure BeginUpdate;Starts a batch of changes: until the matching EndUpdate, property changes and added data do not repaint the control. Calls nest.
Chart.BeginUpdate;
try
Chart.Title := 'Updated';
Chart.Footnote := 'Source: monitoring';
finally
Chart.EndUpdate;
end;EndUpdate method
procedure EndUpdate;Ends a batch started by BeginUpdate. When the outermost batch ends the control is invalidated once. A call without a matching BeginUpdate is ignored.
Render method
procedure Render(ASurface: TAtlasPlotSurface; const Bounds: TRect);Draws the chart into any TAtlasPlotSurface (for example a TAtlasSvgSurface or a TAtlasCanvasSurface over your own canvas), filling Bounds. Raises EAtlasPlotError when ASurface is nil. Pixel queries such as HitTest then describe this render; unlike the other output methods, Render does not restore the on-screen layout afterwards.
Svg := TAtlasSvgSurface.Create(600, 400);
try
Chart.Render(Svg, Rect(0, 0, 600, 400));
Text := Svg.Document;
finally
Svg.Free;
end;RenderTo method
procedure RenderTo(Target: TCanvas; const Bounds: TRect);Draws the chart onto a VCL canvas, for example a printer canvas or a bitmap you own, filling Bounds. When the control has a window handle it then re-runs its on-screen layout, so hit tests keep matching the screen.
Chart.RenderTo(Bitmap.Canvas, Rect(0, 0, Bitmap.Width, Bitmap.Height));CreateBitmap method
function CreateBitmap(AWidth, AHeight: Integer): Vcl.Graphics.TBitmap;Returns a new 24-bit bitmap of the given size with the chart drawn on it; the caller frees it. Both sizes must be 1 to 16384 pixels, otherwise EAtlasPlotError is raised. Works without a window, for example in a console program or a service.
Bitmap := Chart.CreateBitmap(800, 500);
try
Bitmap.SaveToFile('chart.bmp');
finally
Bitmap.Free;
end;ToSVG method
function ToSVG(AWidth, AHeight: Integer): string;Returns the chart as an SVG document of the given size (1 to 16384 pixels). Text is XML-escaped. Works without a window.
Text := Chart.ToSVG(640, 420);SaveToFile method
procedure SaveToFile(const FileName: string; AWidth: Integer = 0; AHeight: Integer = 0);Writes the chart to .png, .bmp, .emf or .svg, chosen by the extension (case does not matter); any other extension raises EAtlasPlotError before anything is written. A size of 0 or less uses the control's Width and Height; sizes above 16384 raise. The image is written to FileName.part and then renamed over the target, so a failed export keeps an existing file. Works without a window.
Chart.SaveToFile('chart.png', 800, 500);
Chart.SaveToFile('chart.svg'); // the control's own sizePaletteColor method
class function PaletteColor(Index: Integer): TColor; static;One of ten built-in series colours (blue, orange, green, red, purple, olive, dark blue, teal, salmon, grey). The index wraps: PaletteColor(10) equals PaletteColor(0), and negative indexes use their absolute value. Categories and series with colour clDefault take PaletteColor of their index.
Chart.Color := TAtlasCustomChart.PaletteColor(3);DrawChart method
procedure DrawChart(const Area: TRect); virtual; abstract;Protected; override it to draw the chart. Area is what is left of the render bounds after a half-line margin, the title and the footnote. Draw with Surface only, so the same code produces the screen image, bitmaps, EMF and SVG. Record whatever your pixel queries need here. It is not called when Area is less than four text lines wide or three high.
ResetLayout method
procedure ResetLayout; virtual; abstract;Protected; override it to forget hit regions and pixel mappings. It is called at the start of every render, before anything is drawn, including renders where DrawChart is then skipped.
ChartChanged method
procedure ChartChanged;Protected. Invalidates the control unless a BeginUpdate batch is open. Call it from every setter and data method of a descendant. (It is not called Changed because TControl already has one.)
DrawLegend method
function DrawLegend(const Area: TRect; const Entries: TArray<TAtlasLegendEntry>): TRect;Protected; call it from DrawChart. Draws a vertical legend, one colour swatch and caption per TAtlasLegendEntry, vertically centred at the right of Area, and returns Area without the legend and a one-line gap. The column is at most two fifths of the width, long captions end in ..., and entries that do not fit the height are left out. With no entries, or no room, it draws nothing and returns Area unchanged.
UseFontColor method
procedure UseFontColor(AColor: TColor; Bold: Boolean = False);Protected; selects the control's Font in another colour, optionally bold, on Surface for the following Text calls. Call Surface.UseFont(Font) to return to the normal font.
Examples
Write a new chart type
A minimal progress chart: one bar per goal against its target, with a legend. The CustomChartType sample develops it with hit testing and checks.
uses
System.Classes, System.Types, System.Math, Atlas.PlotAxis, Atlas.PlotSurface, Atlas.ProChart;
type
TGoalChart = class(TAtlasCustomChart)
private
FNames: TStringList;
FShares: TArray<Double>; // done / target
protected
procedure DrawChart(const Area: TRect); override;
procedure ResetLayout; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure AddGoal(const Name: string; const Done, Target: Double);
end;
constructor TGoalChart.Create(AOwner: TComponent);
begin
inherited;
FNames := TStringList.Create;
end;
destructor TGoalChart.Destroy;
begin
FNames.Free;
inherited;
end;
procedure TGoalChart.AddGoal(const Name: string; const Done, Target: Double);
begin
CheckPlotValue(Done);
if Target <= 0 then raise EAtlasPlotError.Create('A target must be positive');
FNames.Add(Name);
FShares := FShares + [Min(Max(Done / Target, 0), 1.25)];
ChartChanged; // repaint unless inside BeginUpdate/EndUpdate
end;
procedure TGoalChart.ResetLayout;
begin
// Nothing recorded between renders in this minimal version.
end;
procedure TGoalChart.DrawChart(const Area: TRect);
var Legend: TArray<TAtlasLegendEntry>; Plot: TRect; I, Row, Left: Integer;
begin
SetLength(Legend, 1);
Legend[0].Caption := 'Done';
Legend[0].Color := PaletteColor(0);
Plot := DrawLegend(Area, Legend);
if FNames.Count = 0 then Exit;
Left := Plot.Left + Plot.Width div 4;
Row := Plot.Height div FNames.Count;
for I := 0 to FNames.Count - 1 do
begin
Surface.UseFont(Font);
Surface.Text(Left - LineH div 2, Plot.Top + I * Row + (Row - LineH) div 2,
AtlasFitText(Surface, FNames[I], Left - Plot.Left - LineH), taRightJustify);
Surface.UsePen(PaletteColor(0));
Surface.UseBrush(PaletteColor(0));
Surface.Box(Rect(Left, Plot.Top + I * Row + Row div 4,
Left + Round(FShares[I] * (Plot.Right - Left) * 0.8), Plot.Top + (I + 1) * Row - Row div 4));
end;
Surface.UsePen(AtlasAxisColor, 2);
Surface.Line(Left + Round((Plot.Right - Left) * 0.8), Plot.Top, Left + Round((Plot.Right - Left) * 0.8), Plot.Bottom);
end;
procedure SaveGoals(const FileName: string);
var Chart: TGoalChart;
begin
Chart := TGoalChart.Create(nil);
try
Chart.Title := 'Quarterly goals';
Chart.AddGoal('Signups', 1200, 1500);
Chart.AddGoal('Releases', 4, 3);
Chart.SaveToFile(FileName, 600, 300);
finally
Chart.Free;
end;
end;Render any chart into an SVG string
Works for every Atlas Plot Pro control, with or without a window.
uses
System.SysUtils, Atlas.ProChart;
function ChartAsSvg(Chart: TAtlasCustomChart): string;
begin
Chart.BeginUpdate;
try
Chart.Title := 'Snapshot';
Chart.Footnote := DateToStr(Date);
finally
Chart.EndUpdate;
end;
Result := Chart.ToSVG(800, 500);
end;Related
TAtlasLegendEntry · TAtlasBoxPlot · TAtlasHeatMap · TAtlasPolarPlot · TAtlasPlotSurface · TAtlasSvgSurface