Indicators, Sections, and Annotations
TTMSFNCTimeline displays two kinds of items on the timeline: indicators (point-in-time markers) and sections (spans with a start and end). Both support rich appearance customisation, hover and selected states, and an optional annotation label.
Value and position concepts
Timeline positions are stored as Double values.
- TimelineValue / TimelineDate — the logical position on the timeline.
TimelineDateandTimelineValueare linked: setting one updates the other automatically. - Position — the pixel coordinate on screen for drawing. Convert between the two using
GetPositionForValueandGetValueAtPosition.
Indicators
An TTMSFNCTimelineIndicator marks a single point in time. Add one via the helper method or through the Indicators collection:
uses
System.SysUtils, FMX.Dialogs, FMX.TMSFNCTimeline;
procedure TFormMain.AddIndicators;
var
ind: TTMSFNCTimelineIndicator;
begin
TMSFNCTimeline1.BeginUpdate;
// Quick add via helper method
TMSFNCTimeline1.AddIndicator(EncodeDate(2025, 6, 10), 'Release');
// Full control via the Indicators collection
ind := TMSFNCTimeline1.Indicators.Add;
ind.TimelineDate := EncodeDate(2025, 6, 15);
ind.Annotation.Text := 'Review';
ind.Annotation.Position := tlapTopLeft;
// Appearance overrides for this indicator
ind.Appearance.Shape := tlisSquare;
ind.Appearance.Fill.Color := gcRed;
ind.Appearance.Size := 16;
// Prevent user from moving this indicator
ind.Fixed := True;
TMSFNCTimeline1.EndUpdate;
end;
// Navigate to a specific indicator by date
procedure TFormMain.ScrollToToday;
begin
TMSFNCTimeline1.CenterValue(Now);
end;
// React to indicator selection
procedure TFormMain.TMSFNCTimeline1IndicatorSelectionChanged(Sender: TObject;
AIndicator: TTMSFNCTimelineIndicator;
ASelectionParameters: TTMSFNCTimelineIndicatorSelectionParameters);
begin
if ASelectionParameters.Selected then
ShowMessage(AIndicator.Annotation.Text);
end;
Indicator properties
| Property | Description |
|---|---|
TimelineDate / TimelineValue |
Position on the timeline. Setting one updates the other. |
Annotation |
Label shown alongside the marker. |
Fixed |
When True, the user cannot drag the indicator. |
Selectable |
When False, the indicator cannot be clicked/selected. |
Selected |
Read or set selection state in code. |
Hint / ShowHint |
Tooltip text when hovered. |
Tag |
Custom integer for app-level data association. |
Indicator appearance
Every built-in Shape value drawn on one bar, each indicator labelled with
the enum member that produced it:
Override the default appearance (set via Appearance.DefaultIndicatorAppearance) per indicator:
| Property | Description |
|---|---|
Shape |
tlisCircle, tlisSquare, tlisDiamond, tlisTriangleUp/Down/Left/Right, tlisBitmap. |
Size |
Pixel size of the marker. -1 inherits the timeline bar size. |
Fill / Stroke |
Normal state background and border. |
HoverFill / HoverStroke |
Hover state overrides. |
SelectedFill / SelectedStroke |
Selected state overrides. |
Bitmap / BitmapName |
Custom image when Shape = tlisBitmap. |
tlisBitmap is absent from the capture because it draws Appearance.Bitmap
and renders nothing until an image is assigned.
Size is measured in pixels, so a value that reads well against a thin bar
looks cramped on a thick one — set it after Layout.Size. Leaving it at -1
scales the marker to the bar instead.
Annotations
Every indicator has an TTMSFNCTimelineAnnotation sub-object accessible via Annotation.
| Property | Description |
|---|---|
Text |
HTML-capable label text. |
Position |
tlapTopLeft, tlapMiddle, tlapBottomRight — which side of the timeline the annotation appears on. |
Width / Height |
Annotation box dimensions. -1 = auto-size. |
Visible |
Show or hide the annotation without removing the indicator. |
Annotation appearance:
| Property | Description |
|---|---|
Font / HoverFont / SelectedFont |
Font for normal, hover, and selected states. |
Fill / Stroke / HoverFill / etc. |
Background and border for each state. |
Alignment |
Horizontal alignment relative to the indicator: gtaLeading, gtaCenter, gtaTrailing. |
TextHorizontalAlign / TextVerticalAlign |
Text alignment within the annotation box. |
TextMargins |
Padding between text and box edges. |
TextWordWrap |
Wrap long text. |
Rounding / RoundedCorners |
Corner radius of the annotation box. |
AnnotationLine / AnnotationLineVisible |
Line connecting annotation to indicator. |
TextOrientation |
Rotate annotation text. |
Sections
A TTMSFNCTimelineSection spans a range from StartTimelineDate to EndTimelineDate:
uses
System.SysUtils, FMX.TMSFNCTimeline;
procedure TFormMain.AddSections;
var
sec: TTMSFNCTimelineSection;
begin
TMSFNCTimeline1.BeginUpdate;
// Quick add via helper method
TMSFNCTimeline1.AddSection(
EncodeDate(2025, 1, 6), EncodeDate(2025, 1, 10), 'Phase 1');
// Full control via the Sections collection
sec := TMSFNCTimeline1.Sections.Add;
sec.StartTimelineDate := EncodeDate(2025, 1, 13);
sec.EndTimelineDate := EncodeDate(2025, 1, 17);
sec.Text := 'Phase 2';
sec.Appearance.Fill.Color := gcLightBlue;
sec.Appearance.Rounding := 4;
sec.Fixed := False; // user can move and resize
TMSFNCTimeline1.EndUpdate;
end;
// Constrain section movement in OnSectionMove
procedure TFormMain.TMSFNCTimeline1SectionMove(Sender: TObject;
ASection: TTMSFNCTimelineSection;
var AMoveParams: TTMSFNCTimelineSectionMoveParameters; var AAllow: Boolean);
begin
// Prevent moving past the overall range start
if AMoveParams.NewStartValue < TMSFNCTimeline1.Range.MinimumValue then
AAllow := False;
end;
Section properties
| Property | Description |
|---|---|
StartTimelineDate / StartTimelineValue |
Span start. Setting the date updates the value and vice versa. |
EndTimelineDate / EndTimelineValue |
Span end. |
Text |
Label shown inside the section. |
Fixed |
Prevents user from moving or resizing. |
Selectable / Selected |
Selection state. |
Section appearance
The first section below takes the shared DefaultSectionAppearance; the
second overrides Fill, Font and Rounding per item:
| Property | Description |
|---|---|
Fill / Stroke |
Normal state. |
HoverFill / HoverStroke |
Hover state. |
SelectedFill / SelectedStroke |
Selected state. |
TextHorizontalAlign / TextVerticalAlign |
Text alignment within the section. |
TextOrientation |
Rotate the section label. |
Rounding / RoundedCorners |
Rounded corners. |
TextWordWrap |
Wrap long section labels. |
In the capture the captions are lifted to the top of the band with
TextVerticalAlign := gtaLeading so they do not overlap the division labels
underneath, and the three indicators show Shape, Size and
Annotation.Position varying per item.
Overlapping sections
Layout.OverlapSections is True by default, which lets sections that share a
span draw on top of each other. Set it to False to stack them in separate rows
instead — each section then occupies the row given by its Row property, or a
row the timeline calculates when Row is negative. Row has no effect while
sections are allowed to overlap.
Navigating items
Use these helper methods to iterate through items within a value range:
| Method | Description |
|---|---|
GetFirstIndicator(AMin, AMax) |
First indicator in the range. |
GetNextIndicator(AIndicator, AMax) |
Next indicator after the given one. |
GetPreviousIndicator(AIndicator, AMin) |
Previous indicator before the given one. |
GetLastIndicator(AMin, AMax) |
Last indicator in the range. |
GetFirstSection / GetNextSection / … |
Same navigation for sections. |
Hit testing
Convert a screen coordinate to a timeline item:
uses
System.Types, FMX.Dialogs, FMX.TMSFNCTimeline;
procedure TFormMain.ShowIndicatorAt(APoint: TPointF);
var
item: TTMSFNCTimelineIndicator;
begin
item := TMSFNCTimeline1.GetIndicatorAtXY(APoint);
if Assigned(item) then
ShowMessage(item.Annotation.Text);
end;
| Method | Returns |
|---|---|
GetIndicatorAtXY(APoint) |
Indicator under the point. |
GetIndicatorAnnotationAtXY(APoint) |
Annotation under the point. |
GetItemAtXY(APoint) |
Item (indicator or section) under the point. |
GetValueAtXY(APoint) |
Timeline value at the point. |
GetPositionAtXY(APoint) |
Pixel position at the point. |
All five take a TPointF.
Combining sections, indicators, annotations, and navigation
The example below builds the styled sections and annotated indicators from the sections above in one pass, then reads them back with the navigation helpers to produce a milestone summary — so the same code covers item creation, per-item appearance, annotation placement, and traversal.
uses
System.SysUtils, System.Classes,
FMX.TMSFNCTypes, FMX.TMSFNCGraphics, FMX.TMSFNCGraphicsTypes,
FMX.TMSFNCTimeline;
// Sections, indicators and annotations built in one pass, then read back with
// the navigation helpers. Mirrors the capture under "Section appearance".
procedure TFormMain.BuildSprintTimeline;
var
sec: TTMSFNCTimelineSection;
ind: TTMSFNCTimelineIndicator;
begin
TMSFNCTimeline1.BeginUpdate;
try
TMSFNCTimeline1.Range.MinimumDate := EncodeDate(2026, 3, 1);
TMSFNCTimeline1.Range.MaximumDate := EncodeDate(2026, 3, 11);
TMSFNCTimeline1.Range.RangeType := tlrDay;
TMSFNCTimeline1.Range.DivisionSpan := 1;
TMSFNCTimeline1.Range.DivisionSpace := 74;
TMSFNCTimeline1.Layout.Size := 64;
// Sections paint over the bar and would clip the division labels, so draw
// them beneath and lift the captions to the top of the band instead.
TMSFNCTimeline1.Layout.DrawSectionsBeneathDivisions := True;
TMSFNCTimeline1.Appearance.DefaultSectionAppearance.TextVerticalAlign := gtaLeading;
TMSFNCTimeline1.Appearance.DefaultSectionAppearance.TextHorizontalAlign := gtaCenter;
// Section on the shared default appearance.
sec := TMSFNCTimeline1.Sections.Add;
sec.StartTimelineDate := EncodeDate(2026, 3, 2);
sec.EndTimelineDate := EncodeDate(2026, 3, 4);
sec.Text := 'Design';
// Section overriding the default per item.
sec := TMSFNCTimeline1.Sections.Add;
sec.StartTimelineDate := EncodeDate(2026, 3, 5);
sec.EndTimelineDate := EncodeDate(2026, 3, 9);
sec.Text := 'Build';
sec.Appearance.Fill.Kind := gfkSolid;
sec.Appearance.Fill.Color := gcMediumpurple;
sec.Appearance.Font.Color := gcWhite;
sec.Appearance.Rounding := 10;
// Three annotated indicators, each a different shape.
ind := TMSFNCTimeline1.Indicators.Add;
ind.TimelineDate := EncodeDate(2026, 3, 3);
ind.Annotation.Text := 'Kickoff';
ind.Appearance.Shape := tlisCircle;
ind := TMSFNCTimeline1.Indicators.Add;
ind.TimelineDate := EncodeDate(2026, 3, 6);
ind.Annotation.Text := 'Review';
ind.Appearance.Shape := tlisSquare;
ind.Appearance.Size := 16;
ind := TMSFNCTimeline1.Indicators.Add;
ind.TimelineDate := EncodeDate(2026, 3, 9);
ind.Annotation.Text := 'Release';
// Push this label to the other side of the bar so it clears the section.
ind.Annotation.Position := tlapBottomRight;
ind.Appearance.Shape := tlisDiamond;
ind.Appearance.Size := 16;
finally
TMSFNCTimeline1.EndUpdate;
end;
MemoSummary.Lines.Text := SummarizeMilestones;
end;
// Walks the indicators with the navigation helpers instead of indexing the
// collection, so the order follows the timeline rather than insertion order.
// The range arguments are plain Doubles - a TDateTime is one, so date bounds
// can be passed directly.
function TFormMain.SummarizeMilestones: string;
var
ind: TTMSFNCTimelineIndicator;
lines: TStringList;
begin
lines := TStringList.Create;
try
ind := TMSFNCTimeline1.GetFirstIndicator(TMSFNCTimeline1.Range.MinimumDate,
TMSFNCTimeline1.Range.MaximumDate);
while Assigned(ind) do
begin
lines.Add(Format('%s %s', [FormatDateTime('ddd dd/mm', ind.TimelineDate),
ind.Annotation.Text]));
ind := TMSFNCTimeline1.GetNextIndicator(ind,
TMSFNCTimeline1.Range.MaximumDate);
end;
Result := lines.Text;
finally
lines.Free;
end;
end;