Table of Contents

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. TimelineDate and TimelineValue are linked: setting one updates the other automatically.
  • Position — the pixel coordinate on screen for drawing. Convert between the two using GetPositionForValue and GetValueAtPosition.

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:

Timeline showing every indicator shape: circle, square, diamond, and the four triangle orientations Timeline showing every indicator shape: circle, square, diamond, and the four triangle orientations

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:

Timeline with two differently styled sections and three indicators with annotations above and below the bar Timeline with two differently styled sections and three indicators with annotations above and below the bar
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.


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;

See also