TAChart: In the stateseries demo, split the machine state and Gantt charts off into separate frames.

This commit is contained in:
wp_xyz 2025-03-01 12:47:56 +01:00
parent 20c09edcab
commit 315ee83f9e
8 changed files with 761 additions and 668 deletions

View File

@ -1,308 +1,27 @@
object MainForm: TMainForm
Left = 314
Height = 292
Height = 312
Top = 130
Width = 690
Caption = 'StateSeries Demos'
ClientHeight = 292
ClientHeight = 312
ClientWidth = 690
LCLVersion = '4.99.0.0'
OnCreate = FormCreate
object PageControl1: TPageControl
Left = 0
Height = 292
Height = 312
Top = 0
Width = 690
ActivePage = pgStatePlot
ActivePage = pgMachineStateChart
Align = alClient
TabIndex = 0
TabOrder = 0
object pgStatePlot: TTabSheet
object pgMachineStateChart: TTabSheet
Caption = 'State plot'
ClientHeight = 264
ClientWidth = 682
object FlowPanel1: TFlowPanel
Left = 6
Height = 44
Top = 214
Width = 670
Align = alBottom
AutoSize = True
BevelOuter = bvNone
BorderSpacing.Around = 6
ControlList = <
item
Control = cbSeriesMarks
WrapAfter = waAuto
Index = 0
end
item
Control = cbShowPopupHints
WrapAfter = waAuto
Index = 1
end
item
Control = cbRotated
WrapAfter = waAuto
Index = 2
end
item
Control = cbAdjustMargin
WrapAfter = waForce
Index = 3
end
item
Control = Panel1
WrapAfter = waAuto
Index = 4
end>
FlowLayout = tlTop
FlowStyle = fsLeftRightTopBottom
TabOrder = 0
object cbSeriesMarks: TCheckBox
Left = 0
Height = 19
Top = 0
Width = 114
Anchors = []
BorderSpacing.Right = 16
Caption = 'Show series marks'
Checked = True
State = cbChecked
TabOrder = 0
OnChange = cbSeriesMarksChange
end
object cbShowPopupHints: TCheckBox
AnchorSideLeft.Side = asrBottom
Left = 130
Height = 19
Top = 0
Width = 114
Anchors = []
BorderSpacing.Right = 16
Caption = 'Show popup hints'
TabOrder = 1
OnChange = cbShowPopupHintsChange
end
object cbRotated: TCheckBox
AnchorSideTop.Side = asrBottom
Left = 260
Height = 19
Top = 0
Width = 59
Anchors = []
BorderSpacing.Right = 16
Caption = 'Rotated'
TabOrder = 2
OnChange = cbRotatedChange
end
object cbAdjustMargin: TCheckBox
Left = 335
Height = 19
Top = 0
Width = 93
Anchors = []
Caption = 'Adjust margin'
TabOrder = 4
OnChange = cbAdjustMarginChange
end
object Panel1: TPanel
Left = 0
Height = 25
Top = 19
Width = 226
Anchors = []
AutoSize = True
BevelOuter = bvNone
ClientHeight = 25
ClientWidth = 226
TabOrder = 3
object Label1: TLabel
AnchorSideLeft.Control = Panel1
AnchorSideTop.Control = TrackBar1
AnchorSideTop.Side = asrCenter
Left = 0
Height = 15
Top = 5
Width = 54
BorderSpacing.Right = 8
Caption = 'Bar height'
end
object TrackBar1: TTrackBar
AnchorSideLeft.Control = Label1
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Panel1
Left = 62
Height = 25
Top = 0
Width = 164
Frequency = 10
Max = 100
Position = 70
OnChange = TrackBar1Change
TabOrder = 0
end
end
end
object Bevel1: TBevel
Left = 0
Height = 3
Top = 205
Width = 682
Align = alBottom
Shape = bsBottomLine
end
object State_Chart: TChart
Left = 0
Height = 205
Top = 0
Width = 682
AxisList = <
item
Grid.Color = clSilver
Marks.Alignment = taCenter
Marks.Distance = 8
Marks.LabelBrush.Style = bsClear
Minors = <>
Title.LabelFont.Orientation = 900
Title.LabelBrush.Style = bsClear
end
item
Grid.Color = clSilver
Alignment = calBottom
Marks.Alignment = taCenter
Marks.Format = '%2:s'
Marks.LabelBrush.Style = bsClear
Marks.Source = DateTimeIntervalChartSource
Marks.Style = smsLabel
Minors = <>
Title.LabelBrush.Style = bsClear
OnGetMarkText = Chart1AxisList1GetMarkText
end>
Title.Text.Strings = (
'TAChart'
)
Toolset = StateChartToolset
Align = alClient
object MachineA_Series: TStateSeries
Title = 'Machine A'
BarBrush.Color = clRed
end
object MachineB_Series: TStateSeries
Title = 'Machine B'
BarBrush.Color = clRed
end
object MachineC_Series: TStateSeries
Title = 'Machine C'
BarBrush.Color = clRed
end
end
end
object pgGanttPlot: TTabSheet
object pgGanttChart: TTabSheet
Caption = 'Gantt plot'
ClientHeight = 264
ClientWidth = 682
object GanttChart: TChart
Left = 0
Height = 264
Top = 0
Width = 682
AxisList = <
item
Grid.Visible = False
Marks.LabelBrush.Style = bsClear
Minors = <>
Title.LabelFont.Orientation = 900
Title.LabelBrush.Style = bsClear
end
item
Grid.Color = clSilver
Grid.Style = psSolid
Alignment = calBottom
Marks.Format = '%2:s'
Marks.LabelBrush.Style = bsClear
Marks.Source = DateTimeIntervalChartSource
Marks.Style = smsLabel
Minors = <>
Title.LabelBrush.Style = bsClear
end>
Margins.Left = 0
Margins.Top = 10
Margins.Right = 24
Margins.Bottom = 24
Title.Text.Strings = (
'TAChart'
)
Toolset = GanttChartToolset
Align = alClient
object GanttSeries: TStateSeries
OnGetMarkText = GanttSeriesGetMarkText
BarBrush.Color = clSilver
BarHeight = 0.7
BarPen.Color = clMedGray
end
object MilestoneSeries: TLineSeries
LinePen.Color = clBlue
LineType = ltNone
Pointer.Brush.Color = clBlue
Pointer.HorizSize = 12
Pointer.Style = psDiamond
Pointer.VertSize = 12
Pointer.Visible = True
ShowPoints = True
end
object GanttCompletedSeries: TStateSeries
OnGetMarkText = GanttSeriesGetMarkText
BarBrush.Color = clGreen
BarHeight = 0.7
OnBarHeightChanged = GanttCompletedSeriesBarHeightChanged
end
end
end
end
object DateTimeIntervalChartSource: TDateTimeIntervalChartSource
Params.MaxLength = 100
DateTimeStepFormat.HourFormat = 'hh:nn'
Left = 134
Top = 40
end
object MachineLabelsChartSource: TListChartSource
Left = 134
Top = 96
end
object StateChartToolset: TChartToolset
Left = 134
Top = 152
object StateChartDataPointHintTool: TDataPointHintTool
Enabled = False
end
object StateChartZoomDragTool: TZoomDragTool
Shift = [ssLeft]
Brush.Style = bsClear
end
object StateChartPanDragTool: TPanDragTool
Shift = [ssRight]
end
object StateChartDataPointDragTool: TDataPointDragTool
Shift = [ssCtrl, ssLeft]
KeepDistance = True
end
end
object TasksChartSource: TListChartSource
Left = 344
Top = 96
end
object GanttChartToolset: TChartToolset
Left = 344
Top = 152
object GanttZoomDragTool: TZoomDragTool
Shift = [ssLeft]
Brush.Style = bsClear
end
object GanttPanDragTool: TPanDragTool
Shift = [ssRight]
end
object GanttDataPointHintTool: TDataPointHintTool
end
end
end

View File

@ -1,79 +1,25 @@
unit Main;
unit main;
{$mode objfpc}{$H+}
interface
uses
ComCtrls, SysUtils, Classes, Math,
Graphics, Forms, Controls, StdCtrls, ExtCtrls, Dialogs, LCLVersion,
TAGraph, TAIntervalSources, TASources, TAChartUtils, TATextElements, TATools,
TAChartAxisUtils, TACustomSeries, TASeries, TAMultiSeries, TACustomSource, TADrawUtils;
SysUtils, Classes, Controls, Forms, ComCtrls,
uMachineStateFrame, uGanttFrame;
type
{ TMainForm }
TMainForm = class(TForm)
Bevel1: TBevel;
GanttChartToolset: TChartToolset;
GanttChart: TChart;
GanttDataPointHintTool: TDataPointHintTool;
GanttPanDragTool: TPanDragTool;
GanttZoomDragTool: TZoomDragTool;
GanttCompletedSeries: TStateSeries;
TasksChartSource: TListChartSource;
MilestoneSeries: TLineSeries;
GanttSeries: TStateSeries;
State_Chart: TChart;
cbAdjustMargin: TCheckBox;
FlowPanel1: TFlowPanel;
Label1: TLabel;
MachineA_Series: TStateSeries;
MachineB_Series: TStateSeries;
MachineC_Series: TStateSeries;
StateChartToolset: TChartToolset;
cbSeriesMarks: TCheckBox;
cbShowPopupHints: TCheckBox;
StateChartDataPointDragTool: TDataPointDragTool;
StateChartPanDragTool: TPanDragTool;
StateChartZoomDragTool: TZoomDragTool;
cbRotated: TCheckBox;
StateChartDataPointHintTool: TDataPointHintTool;
DateTimeIntervalChartSource: TDateTimeIntervalChartSource;
MachineLabelsChartSource: TListChartSource;
PageControl1: TPageControl;
Panel1: TPanel;
pgStatePlot: TTabSheet;
pgGanttPlot: TTabSheet;
TrackBar1: TTrackBar;
procedure cbRotatedChange(Sender: TObject);
procedure cbSeriesMarksChange(Sender: TObject);
procedure cbShowPopupHintsChange(Sender: TObject);
procedure cbAdjustMarginChange(Sender: TObject);
procedure Chart1AxisList1GetMarkText(Sender: TObject; var AText: String;
AMark: Double);
pgMachineStateChart: TTabSheet;
pgGanttChart: TTabSheet;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
private
// State chart
procedure CreateStateChart;
procedure GetMarkTextHandler(ASeries: TChartSeries;
APointIndex, {%H-}AXIndex, {%H-}AYIndex: Integer; var AFormattedMark: String);
procedure PrepareMarks(ASeries: TStateSeries);
procedure SetupNormalAxes;
procedure SetupRotatedAxes;
private
// Gantt chart
procedure CreateGanttChart;
published
procedure GanttCompletedSeriesBarHeightChanged(Sender: TObject);
procedure GanttSeriesGetMarkText(ASeries: TChartSeries;
APointIndex, AXIndex, AYIndex: Integer; var AFormattedMark: String);
public
FMachineStateFrame: TMachineStateFrame;
FGanttFrame: TGanttFrame;
end;
var
@ -83,327 +29,15 @@ implementation
{$R *.lfm}
const
clRepair = $4040FF; // red
clProduction = $00C800; // green
clDevelopment = $FC8B70; // blue
clMaintainance = clYellow; // yellow
idxMachineA = 0;
idxMachineB = 1;
idxMachineC = 2;
procedure TMainForm.cbAdjustMarginChange(Sender: TObject);
var
ext: TDoubleRect;
begin
if cbAdjustMargin.Checked then
begin
ext := State_Chart.LogicalExtent;
if MachineA_Series.IsRotated then
begin
State_Chart.Extent.XMin := Floor(ext.a.x) + 0.5;
State_Chart.Extent.XMax := Ceil(ext.b.x) - 0.5;
State_Chart.Extent.UseXMin := true;
State_Chart.Extent.UseXMax := true;
end else
begin
State_Chart.Extent.YMin := Floor(ext.a.y) + 0.5;
State_Chart.Extent.YMax := Ceil(ext.b.y) - 0.5;
State_Chart.Extent.UseYMin := true;
State_Chart.Extent.UseYMax := true;
end;
end else
begin
State_Chart.Extent.UseXMin := false;
State_Chart.Extent.UseXMax := false;
State_Chart.Extent.UseYMin := false;
State_Chart.Extent.UseYMax := false;
end;
end;
// Toggles between "normal" and "rotated" state series (horizontal or
// vertical orientation)
procedure TMainForm.cbRotatedChange(Sender: TObject);
var
w, h, i: Integer;
begin
w := Width;
h := Height;
SetBounds(Left, Top, h, w);
for i := 0 to State_Chart.SeriesCount-1 do
if State_Chart.Series[i] is TStateSeries then
with TStateSeries(State_Chart.Series[i]) do
if cbRotated.Checked then
begin
AxisIndexX := 0;
AxisIndexY := 1;
end else
begin
AxisIndexX := 1;
AxisIndexY := 0;
end;
if cbRotated.Checked then
SetupRotatedAxes
else
SetupNormalAxes;
end;
// Shows/hides series marks
procedure TMainForm.cbSeriesMarksChange(Sender: TObject);
var
i: Integer;
begin
for i := 0 to State_Chart.SeriesCount-1 do
if State_Chart.Series[i] is TStateSeries then
with TStateSeries(State_Chart.Series[i]) do
if cbSeriesMarks.Checked then
Marks.Style := smsLabel
else
Marks.Style := smsNone;
end;
// Shows/hides mouse-over popup hints
procedure TMainForm.cbShowPopupHintsChange(Sender: TObject);
begin
StateChartDataPointHintTool.Enabled := cbShowPopupHints.Checked;
end;
// Displays the last time tick on the x axis as '24:00' rather than '0:00'
procedure TMainForm.Chart1AxisList1GetMarkText(Sender: TObject; var AText: String;
AMark: Double);
begin
if AMark = 1.0 then AText := '24:00';
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
CreateStateChart;
CreateGanttChart;
end;
FMachineStateFrame := TMachineStateFrame.Create(Self);
FMachineStateFrame.Parent := pgMachinestateChart;
FMachineStateFrame.Align := alClient;
procedure TMainForm.GanttSeriesGetMarkText(ASeries: TChartSeries;
APointIndex, AXIndex, AYIndex: Integer; var AFormattedMark: String);
var
tPlan1, tPlan2: Double;
tComplete1, tComplete2: Double;
txt: String;
begin
txt := GanttSeries.Source.Item[APointIndex]^.Text;
tPlan1 := GanttSeries.XValues[APointIndex, 0];
tPlan2 := GanttSeries.XValues[APointIndex, 1];
tComplete1 := GanttCompletedSeries.XValues[APointIndex, 0];
tComplete2 := GanttCompletedSeries.XValues[APointIndex, 1];
AFormattedMark := Format('Task "%s": %.0f %% complete', [txt, (tComplete2 - tComplete1)/(tPlan2 - tPlan1)*100]);
end;
procedure TMainForm.GanttCompletedSeriesBarHeightChanged(Sender: TObject);
var
h: Integer;
begin
if GanttChart.ScalingValid then
begin
h := round(GanttSeries.GetImgBarHeight * 0.66);
MilestoneSeries.Pointer.HorizSize := h;
MilestoneSeries.Pointer.VertSize := h;
end;
end;
procedure TMainForm.CreateGanttChart;
begin
TasksChartSource.Add(0, 0, 'Kick-off');
TasksChartSource.Add(1, 1, 'Activity 1');
TasksChartSource.Add(2, 2, 'Activity 2');
TasksChartSource.Add(3, 3, 'Activity 3');
TasksChartSource.Add(4, 4, 'Intermediate Milestone');
TasksChartSource.Add(5, 5, 'Activity 4');
TasksChartSource.Add(6, 6, 'Activity 5');
TasksChartSource.Add(7, 7, 'Final Milestone');
// The x/y values in the TasksChartSource are the y values for the
// GanttSeries data.
// GanttSeries represents the project plan
GanttSeries.AddXY(EncodeDate(2024,2,3), EncodeDate(2024,2,4), 0, TasksChartSource.Item[0]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,4), EncodeDate(2024,2,8), 1, TasksChartSource.Item[1]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,8), EncodeDate(2024,2,11), 2, TasksChartSource.Item[2]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,11), EncodeDate(2024,2,21), 3, TasksChartSource.Item[3]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,21), EncodeDate(2024,2,28), 5, TasksChartSource.Item[5]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,28), EncodeDate(2024,3,7), 6, TasksChartSource.Item[6]^.Text);
// GanttCompletedSeries contains only the activities from GanttSeries which
// are completed to some extent
GanttCompletedSeries.AddXY(GanttSeries.XValues[0,0], GanttSeries.XValues[0,1], 0); // Kick-off is 100% finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[1,0], GanttSeries.XValues[1,1], 1); // Activity 1 is 100% finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[2,0], GanttSeries.XValues[2,1], 2); // Activity 2 is 100% finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[3,0], GanttSeries.XValues[3,1], 3); // Activity 3 is 100% finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[4,0], GanttSeries.XValues[4,0]+6, 5); // Activity 4 is almost finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[5,0], GanttSeries.XValues[5,0]+1, 6); // Activity 6 has a lot left to be done
GanttCompletedSeries.ZPosition := 1; // draw this series over the GanttSeries
// Milestones
Milestoneseries.AddXY(EncodeDate(2024,2,21), 4, '', clGreen); // Milestone 1 reached
Milestoneseries.AddXY(EncodeDate(2024,3,7), 7, '', clSilver); // Milestone 2 open
GanttChart.LeftAxis.Marks.Source := TasksChartSource;
GanttChart.LeftAxis.Marks.Style := smsLabel;
GanttChart.LeftAxis.Inverted := true;
end;
procedure TMainForm.CreateStateChart;
begin
// Provide y axis labels
MachineLabelsChartSource.Add(idxMachineA, idxMachineA, 'Machine'+LineEnding+'A');
MachineLabelsChartSource.Add(idxMachineB, idxMachineB, 'Machine'+LineEnding+'B');
MachineLabelsChartSource.Add(idxMachineC, idxMachineC, 'Machine'+LineEnding+'C');
SetupNormalAxes;
//DateTimeIntervalChartSource.DateTimeStepFormat.HourFormat := 'hh:nn';
DateTimeIntervalChartSource.SuppressPrevUnit := false;
// Create the series and add their values
MachineA_Series.AddXY(EncodeTime( 5, 0, 0, 0), EncodeTime( 9, 0, 0, 0), idxMachineA, 'Production', clProduction);
MachineA_Series.AddXY(EncodeTime(10,30, 0, 0), EncodeTime(12,10, 0, 0), idxMachineA, 'Repair', clRepair);
MachineA_Series.AddXY(EncodeTime(12,30, 0, 0), EncodeTime(18, 0, 0, 0), idxMachineA, 'Development', clDevelopment);
MachineA_Series.AddXY(EncodeTime(20, 0, 0, 0), EncodeTime(23, 0, 0, 0), idxMachineA, 'Maintainance', clMaintainance);
PrepareMarks(MachineA_Series);
MachineB_Series.AddXY(EncodeTime( 0, 0, 0, 0), EncodeTime( 8, 0, 0, 0), idxMachineB, 'Repair', clRepair);
MachineB_Series.AddXY(EncodeTime( 9, 0, 0, 0), EncodeTime(12,55, 0, 0), idxMachineB, 'Production', clProduction);
MachineB_Series.AddXY(EncodeTime(13, 0, 0, 0), EncodeTime(17,25, 0, 0), idxMachineB, 'Production', clProduction);
MachineB_Series.AddXY(EncodeTime(19, 0, 0, 0), EncodeTime(21,42, 0, 0), idxMachineB, 'Development', clDevelopment);
PrepareMarks(MachineB_Series);
MachineC_Series.AddXY(EncodeTime( 0, 0, 0, 0), EncodeTime( 6, 0, 0, 0), idxMachineC, 'Production', clProduction);
MachineC_Series.AddXY(EncodeTime( 6,10, 0, 0), EncodeTime( 8,45, 0, 0), idxMachineC, 'Production', clProduction);
MachineC_Series.AddXY(EncodeTime( 9, 0, 0, 0), EncodeTime(12, 0, 0, 0), idxMachineC, 'Production', clProduction);
MachineC_Series.AddXY(EncodeTime(13, 0, 0, 0), EncodeTime(18,55, 0, 0), idxMachineC, 'Production', clProduction);
MachineC_Series.AddXY(EncodeTime(19, 0, 0, 0), EncodeTime(23,50, 0, 0), idxMachineC, 'Maintainance', clMaintainance);
PrepareMarks(MachineC_Series);
end;
// Composes the label text from the label value and each data point's
// state duration.
procedure TMainForm.GetMarkTextHandler(ASeries: TChartSeries;
APointIndex, AXIndex, AYIndex: Integer; var AFormattedMark: String);
var
txt: String;
t1, t2: TDateTime;
begin
with ASeries.Source[APointIndex]^ do
begin
txt := Text;
t1 := GetX(0);
t2 := GetX(1);
end;
AFormattedMark := Format('%s'+LineEnding+'%s', [txt, FormatDateTime('[hh]:nn', t2-t1, [fdoInterval])]);
end;
// Prepares the marks for the series and for the popup hints:
// no border, no background, centered, user-defined text (see GetMarkTextHandler)
procedure TMainForm.PrepareMarks(ASeries: TStateSeries);
begin
ASeries.Marks.Style := smsLabel;
ASeries.Marks.Frame.Visible := false;
ASeries.Marks.LabelBrush.Style := bsClear;
ASeries.Marks.LinkPen.Visible := false;
ASeries.Marks.Distance := 0;
ASeries.Marks.Alignment := taCenter;
ASeries.Marks.Attachment := maCenter;
ASeries.MarkPositions := lmpInside;
ASeries.OnGetMarkText := @GetMarkTextHandler;
end;
// Sets axis properties for "normal" (horizontally oriented) state series
procedure TMainForm.SetupNormalAxes;
begin
// Left axis marks
State_Chart.LeftAxis.Marks.Source := MachineLabelsChartSource;
State_Chart.LeftAxis.Marks.Style := smsLabel;
State_Chart.LeftAxis.OnGetMarkText := nil;
State_Chart.LeftAxis.TickLength := 0;
// Bottom axis marks
State_Chart.BottomAxis.Marks.Source := DateTimeIntervalChartSource;
State_Chart.BottomAxis.Marks.Style := smsLabel;
State_Chart.BottomAxis.OnGetMarkText := @Chart1AxisList1GetMarkText;
State_Chart.BottomAxis.TickLength := 4;
// Nicer grid for the y axis
State_Chart.LeftAxis.Grid.Visible := false;
State_Chart.BottomAxis.Grid.Visible := true;
if State_Chart.LeftAxis.Minors.Count = 0 then
with State_Chart.LeftAxis.Minors.Add do
begin
Intervals.Count := 1;
Grid.Color := clSilver;
Grid.Style := psSolid;
end;
State_Chart.LeftAxis.Minors[0].Visible := true;
if State_Chart.BottomAxis.Minors.Count > 0 then
State_Chart.BottomAxis.Minors[0].Visible := false;
// Show a full day on the x axis
State_Chart.BottomAxis.Range.Max := 1.0;
State_Chart.BottomAxis.Range.Min := 0.0;
State_Chart.BottomAxis.Range.UseMax := true;
State_Chart.BottomAxis.Range.UseMin := true;
State_Chart.LeftAxis.Range.UseMin := false;
State_Chart.LeftAxis.Range.UseMax := false;
// For top-to-bottom order of the machines (or use negative idxMachineXXXX values)
State_Chart.LeftAxis.Inverted := true;
State_Chart.BottomAxis.Inverted := false;
end;
// Sets axis properties for the case of "rotated" (vertically oriented) state series
procedure TMainForm.SetupRotatedAxes;
begin
// Bottom axis marks
State_Chart.BottomAxis.Marks.Source := MachineLabelsChartSource;
State_Chart.BottomAxis.Marks.Style := smsLabel;
State_Chart.BottomAxis.OnGetMarkText := nil;
State_Chart.BottomAxis.TickLength := 0;
// Left axis marks
State_Chart.LeftAxis.Marks.Source := DateTimeIntervalChartSource;
State_Chart.LeftAxis.Marks.Style := smsLabel;
State_Chart.LeftAxis.OnGetMarkText := @Chart1AxisList1GetMarkText;
State_Chart.LeftAxis.TickLength := 4;
// Nicer grid for the x axis
State_Chart.BottomAxis.Grid.Visible := false;
State_Chart.LeftAxis.Grid.Visible := true;
if State_Chart.BottomAxis.Minors.Count = 0 then
with State_Chart.BottomAxis.Minors.Add do
begin
Intervals.Count := 1;
Grid.Color := clSilver;
Grid.Style := psSolid;
end;
State_Chart.BottomAxis.Minors[0].Visible := true;
if State_Chart.LeftAxis.Minors.Count > 0 then
State_Chart.LeftAxis.Minors[0].Visible := false;
// Show a full day on the y axis
State_Chart.LeftAxis.Range.Max := 1.0;
State_Chart.LeftAxis.Range.Min := 0.0;
State_Chart.LeftAxis.Range.UseMax := true;
State_Chart.LeftAxis.Range.UseMin := true;
State_Chart.BottomAxis.Range.UseMin := false;
State_Chart.BottomAxis.Range.UseMax := false;
// Restore left axis direction
State_Chart.LeftAxis.Inverted := false;
end;
// A change in the trackbar position should be applied as new series BarHeight value.
procedure TMainForm.TrackBar1Change(Sender: TObject);
begin
MachineA_Series.BarHeight := Trackbar1.Position * 0.01;
MachineB_Series.BarHeight := Trackbar1.Position * 0.01;
MachineC_Series.BarHeight := Trackbar1.Position * 0.01;
FGanttFrame := TGanttFrame.Create(self);
FGanttFrame.Parent := pgGanttChart;
FGanttFrame.Align := alClient;
end;
end.

View File

@ -43,7 +43,20 @@
<ComponentName Value="MainForm"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="Main"/>
</Unit>
<Unit>
<Filename Value="uganttframe.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="GanttFrame"/>
<ResourceBaseClass Value="Frame"/>
<UnitName Value="uGanttFrame"/>
</Unit>
<Unit>
<Filename Value="umachinestateframe.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="MachineStateFrame"/>
<ResourceBaseClass Value="Frame"/>
<UnitName Value="uMachineStateFrame"/>
</Unit>
</Units>
</ProjectOptions>

View File

@ -10,7 +10,7 @@ uses
athreads,
{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, tachartlazaruspkg, Main;
Forms, tachartlazaruspkg, main;
{$R *.res}

View File

@ -0,0 +1,89 @@
object GanttFrame: TGanttFrame
Left = 0
Height = 381
Top = 0
Width = 935
ClientHeight = 381
ClientWidth = 935
TabOrder = 0
DesignLeft = 615
DesignTop = 307
object GanttChart: TChart
Left = 0
Height = 381
Top = 0
Width = 935
AxisList = <
item
Grid.Visible = False
Marks.LabelBrush.Style = bsClear
Minors = <>
Title.LabelFont.Orientation = 900
Title.LabelBrush.Style = bsClear
end
item
Grid.Color = clSilver
Grid.Style = psSolid
Alignment = calBottom
Marks.Format = '%2:s'
Marks.LabelBrush.Style = bsClear
Marks.Source = DateTimeIntervalChartSource
Marks.Style = smsLabel
Minors = <>
Title.LabelBrush.Style = bsClear
end>
Margins.Left = 0
Margins.Top = 10
Margins.Right = 24
Margins.Bottom = 24
Title.Text.Strings = (
'TAChart'
)
Toolset = GanttChartToolset
Align = alClient
object GanttSeries: TStateSeries
OnGetMarkText = GanttSeriesGetMarkText
BarBrush.Color = clSilver
BarHeight = 0.7
BarPen.Color = clMedGray
OnBarHeightChanged = GanttSeriesBarHeightChanged
end
object MilestoneSeries: TLineSeries
LinePen.Color = clBlue
LineType = ltNone
Pointer.Brush.Color = clBlue
Pointer.HorizSize = 12
Pointer.Style = psDiamond
Pointer.VertSize = 12
Pointer.Visible = True
ShowPoints = True
end
object GanttCompletedSeries: TStateSeries
BarBrush.Color = clGreen
BarHeight = 0.7
end
end
object TasksChartSource: TListChartSource
Left = 120
Top = 40
end
object GanttChartToolset: TChartToolset
Left = 120
Top = 184
object GanttZoomDragTool: TZoomDragTool
Shift = [ssLeft]
Brush.Style = bsClear
end
object GanttPanDragTool: TPanDragTool
Shift = [ssRight]
end
object GanttDataPointHintTool: TDataPointHintTool
end
end
object DateTimeIntervalChartSource: TDateTimeIntervalChartSource
Params.MinLength = 100
SuppressPrevUnit = False
Left = 120
Top = 104
end
end

View File

@ -0,0 +1,114 @@
unit uGanttFrame;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, Graphics, Forms, Controls,
TAGraph, TAChartUtils, TAIntervalSources, TASources, TATools,
TACustomSeries, TASeries, TAMultiSeries;
type
TGanttFrame = class(TFrame)
DateTimeIntervalChartSource: TDateTimeIntervalChartSource;
GanttChart: TChart;
GanttChartToolset: TChartToolset;
GanttCompletedSeries: TStateSeries;
GanttDataPointHintTool: TDataPointHintTool;
GanttPanDragTool: TPanDragTool;
GanttSeries: TStateSeries;
GanttZoomDragTool: TZoomDragTool;
MilestoneSeries: TLineSeries;
TasksChartSource: TListChartSource;
procedure GanttSeriesBarHeightChanged(Sender: TObject);
procedure GanttSeriesGetMarkText(ASeries: TChartSeries; APointIndex, AXIndex
, AYIndex: Integer; var AFormattedMark: String);
private
procedure PrepareData;
public
constructor Create(AOwner: TComponent); override;
end;
implementation
{$R *.lfm}
constructor TGanttFrame.Create(AOwner: TComponent);
begin
inherited;
PrepareData;
end;
procedure TGanttFrame.GanttSeriesGetMarkText(ASeries: TChartSeries;
APointIndex, AXIndex, AYIndex: Integer; var AFormattedMark: String);
var
tPlan1, tPlan2: Double;
tComplete1, tComplete2: Double;
txt: String;
begin
txt := GanttSeries.Source.Item[APointIndex]^.Text;
tPlan1 := GanttSeries.XValues[APointIndex, 0];
tPlan2 := GanttSeries.XValues[APointIndex, 1];
tComplete1 := GanttCompletedSeries.XValues[APointIndex, 0];
tComplete2 := GanttCompletedSeries.XValues[APointIndex, 1];
AFormattedMark := Format('Task "%s": %.0f %% complete', [txt, (tComplete2 - tComplete1)/(tPlan2 - tPlan1)*100]);
end;
procedure TGanttFrame.GanttSeriesBarHeightChanged(Sender: TObject);
var
h: Integer;
begin
if GanttChart.ScalingValid then
begin
h := round(GanttSeries.GetImgBarHeight * 0.66);
MilestoneSeries.Pointer.HorizSize := h;
MilestoneSeries.Pointer.VertSize := h;
end;
end;
procedure TGanttFrame.PrepareData;
begin
TasksChartSource.Add(0, 0, 'Kick-off');
TasksChartSource.Add(1, 1, 'Activity 1');
TasksChartSource.Add(2, 2, 'Activity 2');
TasksChartSource.Add(3, 3, 'Activity 3');
TasksChartSource.Add(4, 4, 'Intermediate Milestone');
TasksChartSource.Add(5, 5, 'Activity 4');
TasksChartSource.Add(6, 6, 'Activity 5');
TasksChartSource.Add(7, 7, 'Final Milestone');
// The x/y values in the TasksChartSource are the y values for the
// GanttSeries data.
// GanttSeries represents the project plan
GanttSeries.AddXY(EncodeDate(2024,2,3), EncodeDate(2024,2,4), 0, TasksChartSource.Item[0]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,4), EncodeDate(2024,2,8), 1, TasksChartSource.Item[1]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,8), EncodeDate(2024,2,11), 2, TasksChartSource.Item[2]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,11), EncodeDate(2024,2,21), 3, TasksChartSource.Item[3]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,21), EncodeDate(2024,2,28), 5, TasksChartSource.Item[5]^.Text);
GanttSeries.AddXY(EncodeDate(2024,2,28), EncodeDate(2024,3,7), 6, TasksChartSource.Item[6]^.Text);
// GanttCompletedSeries contains only the activities from GanttSeries which
// are completed to some extent
GanttCompletedSeries.AddXY(GanttSeries.XValues[0,0], GanttSeries.XValues[0,1], 0); // Kick-off is 100% finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[1,0], GanttSeries.XValues[1,1], 1); // Activity 1 is 100% finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[2,0], GanttSeries.XValues[2,1], 2); // Activity 2 is 100% finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[3,0], GanttSeries.XValues[3,1], 3); // Activity 3 is 100% finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[4,0], GanttSeries.XValues[4,0]+6, 5); // Activity 4 is almost finished
GanttCompletedSeries.AddXY(GanttSeries.XValues[5,0], GanttSeries.XValues[5,0]+1, 6); // Activity 6 has a lot left to be done
GanttCompletedSeries.ZPosition := 1; // draw this series over the GanttSeries
// Milestones
Milestoneseries.AddXY(EncodeDate(2024,2,21), 4, '', clGreen); // Milestone 1 reached
Milestoneseries.AddXY(EncodeDate(2024,3,7), 7, '', clSilver); // Milestone 2 open
GanttChart.LeftAxis.Marks.Source := TasksChartSource;
GanttChart.LeftAxis.Marks.Style := smsLabel;
GanttChart.LeftAxis.Inverted := true;
end;
end.

View File

@ -0,0 +1,210 @@
object MachineStateFrame: TMachineStateFrame
Left = 0
Height = 343
Top = 0
Width = 988
ClientHeight = 343
ClientWidth = 988
TabOrder = 0
DesignLeft = 587
DesignTop = 331
object Chart: TChart
Left = 0
Height = 287
Top = 0
Width = 988
AxisList = <
item
Grid.Color = clSilver
Marks.Alignment = taCenter
Marks.Distance = 8
Marks.LabelBrush.Style = bsClear
Minors = <>
Title.LabelFont.Orientation = 900
Title.LabelBrush.Style = bsClear
end
item
Grid.Color = clSilver
Alignment = calBottom
Marks.Alignment = taCenter
Marks.Format = '%2:s'
Marks.LabelBrush.Style = bsClear
Marks.Source = DateTimeIntervalChartSource
Marks.Style = smsLabel
Minors = <>
Title.LabelBrush.Style = bsClear
OnGetMarkText = TimeAxisGetMarkText
end>
Title.Text.Strings = (
'TAChart'
)
Toolset = StateChartToolset
Align = alClient
object MachineA_Series: TStateSeries
Title = 'Machine A'
OnGetMarkText = StateSeriesGetMarkText
BarBrush.Color = clRed
end
object MachineB_Series: TStateSeries
Title = 'Machine B'
OnGetMarkText = StateSeriesGetMarkText
BarBrush.Color = clRed
end
object MachineC_Series: TStateSeries
Title = 'Machine C'
OnGetMarkText = StateSeriesGetMarkText
BarBrush.Color = clRed
end
end
object FlowPanel1: TFlowPanel
Left = 6
Height = 44
Top = 293
Width = 976
Align = alBottom
AutoSize = True
BevelOuter = bvNone
BorderSpacing.Around = 6
ControlList = <
item
Control = cbSeriesMarks
WrapAfter = waAuto
Index = 0
end
item
Control = cbShowPopupHints
WrapAfter = waAuto
Index = 1
end
item
Control = cbRotated
WrapAfter = waAuto
Index = 2
end
item
Control = cbAdjustMargin
WrapAfter = waForce
Index = 3
end
item
Control = Panel1
WrapAfter = waAuto
Index = 4
end>
FlowLayout = tlTop
FlowStyle = fsLeftRightTopBottom
TabOrder = 1
object cbSeriesMarks: TCheckBox
Left = 0
Height = 19
Top = 0
Width = 114
Anchors = []
BorderSpacing.Right = 16
Caption = 'Show series marks'
Checked = True
State = cbChecked
TabOrder = 0
OnChange = cbSeriesMarksChange
end
object cbShowPopupHints: TCheckBox
AnchorSideLeft.Side = asrBottom
Left = 130
Height = 19
Top = 0
Width = 114
Anchors = []
BorderSpacing.Right = 16
Caption = 'Show popup hints'
TabOrder = 1
OnChange = cbShowPopupHintsChange
end
object cbRotated: TCheckBox
AnchorSideTop.Side = asrBottom
Left = 260
Height = 19
Top = 0
Width = 59
Anchors = []
BorderSpacing.Right = 16
Caption = 'Rotated'
TabOrder = 2
OnChange = cbRotatedChange
end
object cbAdjustMargin: TCheckBox
Left = 335
Height = 19
Top = 0
Width = 93
Anchors = []
Caption = 'Adjust margin'
TabOrder = 4
OnChange = cbAdjustMarginChange
end
object Panel1: TPanel
Left = 0
Height = 25
Top = 19
Width = 226
Anchors = []
AutoSize = True
BevelOuter = bvNone
ClientHeight = 25
ClientWidth = 226
TabOrder = 3
object Label1: TLabel
AnchorSideLeft.Control = Panel1
AnchorSideTop.Control = tbBarHeight
AnchorSideTop.Side = asrCenter
Left = 0
Height = 15
Top = 5
Width = 54
BorderSpacing.Right = 8
Caption = 'Bar height'
end
object tbBarHeight: TTrackBar
AnchorSideLeft.Control = Label1
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Panel1
Left = 62
Height = 25
Top = 0
Width = 164
Frequency = 10
Max = 100
Position = 70
OnChange = tbBarHeightChange
TabOrder = 0
end
end
end
object DateTimeIntervalChartSource: TDateTimeIntervalChartSource
Params.MaxLength = 100
DateTimeStepFormat.HourFormat = 'hh:nn'
Left = 162
Top = 44
end
object MachineLabelsChartSource: TListChartSource
Left = 162
Top = 100
end
object StateChartToolset: TChartToolset
Left = 162
Top = 156
object StateChartDataPointHintTool: TDataPointHintTool
Enabled = False
end
object StateChartZoomDragTool: TZoomDragTool
Shift = [ssLeft]
Brush.Style = bsClear
end
object StateChartPanDragTool: TPanDragTool
Shift = [ssRight]
end
object StateChartDataPointDragTool: TDataPointDragTool
Shift = [ssCtrl, ssLeft]
KeepDistance = True
end
end
end

View File

@ -0,0 +1,314 @@
unit uMachineStateFrame;
{$mode ObjFPC}{$H+}
interface
uses
SysUtils, Classes, Math,
Graphics, Forms, Controls, StdCtrls, ExtCtrls, ComCtrls,
TAGraph, TAChartUtils, TAChartAxisUtils, TASources, TAIntervalSources,
TATextElements, TATools, TACustomSeries, TASeries, TAMultiSeries;
type
TMachineStateFrame = class(TFrame)
cbAdjustMargin: TCheckBox;
cbRotated: TCheckBox;
cbSeriesMarks: TCheckBox;
cbShowPopupHints: TCheckBox;
DateTimeIntervalChartSource: TDateTimeIntervalChartSource;
FlowPanel1: TFlowPanel;
Label1: TLabel;
MachineA_Series: TStateSeries;
MachineB_Series: TStateSeries;
MachineC_Series: TStateSeries;
MachineLabelsChartSource: TListChartSource;
Panel1: TPanel;
StateChartDataPointDragTool: TDataPointDragTool;
StateChartDataPointHintTool: TDataPointHintTool;
StateChartPanDragTool: TPanDragTool;
StateChartToolset: TChartToolset;
StateChartZoomDragTool: TZoomDragTool;
Chart: TChart;
tbBarHeight: TTrackBar;
procedure cbAdjustMarginChange(Sender: TObject);
procedure cbRotatedChange(Sender: TObject);
procedure cbSeriesMarksChange(Sender: TObject);
procedure cbShowPopupHintsChange(Sender: TObject);
procedure TimeAxisGetMarkText(Sender: TObject;
var AText: String; AMark: Double);
procedure StateSeriesGetMarkText(ASeries: TChartSeries; APointIndex,
AXIndex, AYIndex: Integer; var AFormattedMark: String);
procedure tbBarHeightChange(Sender: TObject);
private
procedure PrepareData;
procedure PrepareMarks(ASeries: TStateSeries);
procedure SetupNormalAxes;
procedure SetupRotatedAxes;
public
constructor Create(AOwner: TComponent); override;
end;
implementation
{$R *.lfm}
const
clRepair = $4040FF; // red
clProduction = $00C800; // green
clDevelopment = $FC8B70; // blue
clMaintainance = clYellow; // yellow
idxMachineA = 0;
idxMachineB = 1;
idxMachineC = 2;
constructor TMachineStateFrame.Create(AOwner: TComponent);
begin
inherited;
PrepareData;
end;
// Checkbox click to center the outermost bars, or not.
procedure TMachineStateFrame.cbAdjustMarginChange(Sender: TObject);
var
ext: TDoubleRect;
begin
if cbAdjustMargin.Checked then
begin
ext := Chart.LogicalExtent;
if MachineA_Series.IsRotated then
begin
Chart.Extent.XMin := Floor(ext.a.x) + 0.5;
Chart.Extent.XMax := Ceil(ext.b.x) - 0.5;
Chart.Extent.UseXMin := true;
Chart.Extent.UseXMax := true;
end else
begin
Chart.Extent.YMin := Floor(ext.a.y) + 0.5;
Chart.Extent.YMax := Ceil(ext.b.y) - 0.5;
Chart.Extent.UseYMin := true;
Chart.Extent.UseYMax := true;
end;
end else
begin
Chart.Extent.UseXMin := false;
Chart.Extent.UseXMax := false;
Chart.Extent.UseYMin := false;
Chart.Extent.UseYMax := false;
end;
end;
// Checkbox clicked to toggle between "normal" and "rotated" state series
// (horizontal or vertical orientation)
procedure TMachineStateFrame.cbRotatedChange(Sender: TObject);
var
w, h, i: Integer;
begin
w := Width;
h := Height;
SetBounds(Left, Top, h, w);
for i := 0 to Chart.SeriesCount-1 do
if Chart.Series[i] is TStateSeries then
with TStateSeries(Chart.Series[i]) do
if cbRotated.Checked then
begin
AxisIndexX := 0;
AxisIndexY := 1;
end else
begin
AxisIndexX := 1;
AxisIndexY := 0;
end;
if cbRotated.Checked then
SetupRotatedAxes
else
SetupNormalAxes;
end;
// Checkbox clicked to show/hide series marks
procedure TMachineStateFrame.cbSeriesMarksChange(Sender: TObject);
var
i: Integer;
begin
for i := 0 to Chart.SeriesCount-1 do
if Chart.Series[i] is TStateSeries then
with TStateSeries(Chart.Series[i]) do
if cbSeriesMarks.Checked then
Marks.Style := smsLabel
else
Marks.Style := smsNone;
end;
procedure TMachineStateFrame.cbShowPopupHintsChange(Sender: TObject);
begin
StateChartDataPointHintTool.Enabled := cbShowPopupHints.Checked;
end;
procedure TMachineStateFrame.PrepareData;
begin
// Provide y axis labels
MachineLabelsChartSource.Add(idxMachineA, idxMachineA, 'Machine'+LineEnding+'A');
MachineLabelsChartSource.Add(idxMachineB, idxMachineB, 'Machine'+LineEnding+'B');
MachineLabelsChartSource.Add(idxMachineC, idxMachineC, 'Machine'+LineEnding+'C');
SetupNormalAxes;
//DateTimeIntervalChartSource.DateTimeStepFormat.HourFormat := 'hh:nn';
DateTimeIntervalChartSource.SuppressPrevUnit := false;
// Create the series and add their values
MachineA_Series.AddXY(EncodeTime( 5, 0, 0, 0), EncodeTime( 9, 0, 0, 0), idxMachineA, 'Production', clProduction);
MachineA_Series.AddXY(EncodeTime(10,30, 0, 0), EncodeTime(12,10, 0, 0), idxMachineA, 'Repair', clRepair);
MachineA_Series.AddXY(EncodeTime(12,30, 0, 0), EncodeTime(18, 0, 0, 0), idxMachineA, 'Development', clDevelopment);
MachineA_Series.AddXY(EncodeTime(20, 0, 0, 0), EncodeTime(23, 0, 0, 0), idxMachineA, 'Maintainance', clMaintainance);
PrepareMarks(MachineA_Series);
MachineB_Series.AddXY(EncodeTime( 0, 0, 0, 0), EncodeTime( 8, 0, 0, 0), idxMachineB, 'Repair', clRepair);
MachineB_Series.AddXY(EncodeTime( 9, 0, 0, 0), EncodeTime(12,55, 0, 0), idxMachineB, 'Production', clProduction);
MachineB_Series.AddXY(EncodeTime(13, 0, 0, 0), EncodeTime(17,25, 0, 0), idxMachineB, 'Production', clProduction);
MachineB_Series.AddXY(EncodeTime(19, 0, 0, 0), EncodeTime(21,42, 0, 0), idxMachineB, 'Development', clDevelopment);
PrepareMarks(MachineB_Series);
MachineC_Series.AddXY(EncodeTime( 0, 0, 0, 0), EncodeTime( 6, 0, 0, 0), idxMachineC, 'Production', clProduction);
MachineC_Series.AddXY(EncodeTime( 6,10, 0, 0), EncodeTime( 8,45, 0, 0), idxMachineC, 'Production', clProduction);
MachineC_Series.AddXY(EncodeTime( 9, 0, 0, 0), EncodeTime(12, 0, 0, 0), idxMachineC, 'Production', clProduction);
MachineC_Series.AddXY(EncodeTime(13, 0, 0, 0), EncodeTime(18,55, 0, 0), idxMachineC, 'Production', clProduction);
MachineC_Series.AddXY(EncodeTime(19, 0, 0, 0), EncodeTime(23,50, 0, 0), idxMachineC, 'Maintainance', clMaintainance);
PrepareMarks(MachineC_Series);
end;
// Prepares the marks for the series and for the popup hints:
// no border, no background, centered, user-defined text (see GetMarkTextHandler)
procedure TMachineStateFrame.PrepareMarks(ASeries: TStateSeries);
begin
ASeries.Marks.Style := smsLabel;
ASeries.Marks.Frame.Visible := false;
ASeries.Marks.LabelBrush.Style := bsClear;
ASeries.Marks.LinkPen.Visible := false;
ASeries.Marks.Distance := 0;
ASeries.Marks.Alignment := taCenter;
ASeries.Marks.Attachment := maCenter;
ASeries.MarkPositions := lmpInside;
ASeries.OnGetMarkText := @StateSeriesGetMarkText;
end;
// Sets axis properties for "normal" (horizontally oriented) state series
procedure TMachineStateFrame.SetupNormalAxes;
begin
// Left axis marks
Chart.LeftAxis.Marks.Source := MachineLabelsChartSource;
Chart.LeftAxis.Marks.Style := smsLabel;
Chart.LeftAxis.OnGetMarkText := nil;
Chart.LeftAxis.TickLength := 0;
// Bottom axis marks
Chart.BottomAxis.Marks.Source := DateTimeIntervalChartSource;
Chart.BottomAxis.Marks.Style := smsLabel;
Chart.BottomAxis.OnGetMarkText := @TimeAxisGetMarkText;
Chart.BottomAxis.TickLength := 4;
// Nicer grid for the y axis
Chart.LeftAxis.Grid.Visible := false;
Chart.BottomAxis.Grid.Visible := true;
if Chart.LeftAxis.Minors.Count = 0 then
with Chart.LeftAxis.Minors.Add do
begin
Intervals.Count := 1;
Grid.Color := clSilver;
Grid.Style := psSolid;
end;
Chart.LeftAxis.Minors[0].Visible := true;
if Chart.BottomAxis.Minors.Count > 0 then
Chart.BottomAxis.Minors[0].Visible := false;
// Show a full day on the x axis
Chart.BottomAxis.Range.Max := 1.0;
Chart.BottomAxis.Range.Min := 0.0;
Chart.BottomAxis.Range.UseMax := true;
Chart.BottomAxis.Range.UseMin := true;
Chart.LeftAxis.Range.UseMin := false;
Chart.LeftAxis.Range.UseMax := false;
// For top-to-bottom order of the machines (or use negative idxMachineXXXX values)
Chart.LeftAxis.Inverted := true;
Chart.BottomAxis.Inverted := false;
end;
// Sets axis properties for the case of "rotated" (vertically oriented) state series
procedure TMachineStateFrame.SetupRotatedAxes;
begin
// Bottom axis marks
Chart.BottomAxis.Marks.Source := MachineLabelsChartSource;
Chart.BottomAxis.Marks.Style := smsLabel;
Chart.BottomAxis.OnGetMarkText := nil;
Chart.BottomAxis.TickLength := 0;
// Left axis marks
Chart.LeftAxis.Marks.Source := DateTimeIntervalChartSource;
Chart.LeftAxis.Marks.Style := smsLabel;
Chart.LeftAxis.OnGetMarkText := @TimeAxisGetMarkText;
Chart.LeftAxis.TickLength := 4;
// Nicer grid for the x axis
Chart.BottomAxis.Grid.Visible := false;
Chart.LeftAxis.Grid.Visible := true;
if Chart.BottomAxis.Minors.Count = 0 then
with Chart.BottomAxis.Minors.Add do
begin
Intervals.Count := 1;
Grid.Color := clSilver;
Grid.Style := psSolid;
end;
Chart.BottomAxis.Minors[0].Visible := true;
if Chart.LeftAxis.Minors.Count > 0 then
Chart.LeftAxis.Minors[0].Visible := false;
// Show a full day on the y axis
Chart.LeftAxis.Range.Max := 1.0;
Chart.LeftAxis.Range.Min := 0.0;
Chart.LeftAxis.Range.UseMax := true;
Chart.LeftAxis.Range.UseMin := true;
Chart.BottomAxis.Range.UseMin := false;
Chart.BottomAxis.Range.UseMax := false;
// Restore left axis direction
Chart.LeftAxis.Inverted := false;
end;
// Composes the label text from the label value and each data point's
// state duration.
procedure TMachineStateFrame.StateSeriesGetMarkText(ASeries: TChartSeries;
APointIndex, AXIndex, AYIndex: Integer; var AFormattedMark: String);
var
txt: String;
t1, t2: TDateTime;
begin
with ASeries.Source[APointIndex]^ do
begin
txt := Text;
t1 := GetX(0);
t2 := GetX(1);
end;
AFormattedMark := Format('%s'+LineEnding+'%s', [txt, FormatDateTime('[hh]:nn', t2-t1, [fdoInterval])]);
end;
// A change in the trackbar position should be applied as new series BarHeight value.
procedure TMachineStateFrame.tbBarHeightChange(Sender: TObject);
begin
MachineA_Series.BarHeight := tbBarHeight.Position * 0.01;
MachineB_Series.BarHeight := tbBarHeight.Position * 0.01;
MachineC_Series.BarHeight := tbBarHeight.Position * 0.01;
end;
// Displays the last time tick on the x axis as '24:00' rather than '0:00'
procedure TMachineStateFrame.TimeAxisGetMarkText(Sender: TObject;
var AText: String; AMark: Double);
begin
if AMark = 1.0 then AText := '24:00';
end;
end.