mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-11 04:48:03 +02:00
TAChart: In the stateseries demo, split the machine state and Gantt charts off into separate frames.
This commit is contained in:
parent
20c09edcab
commit
315ee83f9e
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -10,7 +10,7 @@ uses
|
||||
athreads,
|
||||
{$ENDIF}
|
||||
Interfaces, // this includes the LCL widgetset
|
||||
Forms, tachartlazaruspkg, Main;
|
||||
Forms, tachartlazaruspkg, main;
|
||||
|
||||
{$R *.res}
|
||||
|
||||
|
89
components/tachart/demo/stateseries/uganttframe.lfm
Normal file
89
components/tachart/demo/stateseries/uganttframe.lfm
Normal 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
|
114
components/tachart/demo/stateseries/uganttframe.pas
Normal file
114
components/tachart/demo/stateseries/uganttframe.pas
Normal 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.
|
||||
|
210
components/tachart/demo/stateseries/umachinestateframe.lfm
Normal file
210
components/tachart/demo/stateseries/umachinestateframe.lfm
Normal 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
|
314
components/tachart/demo/stateseries/umachinestateframe.pas
Normal file
314
components/tachart/demo/stateseries/umachinestateframe.pas
Normal 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.
|
||||
|
Loading…
Reference in New Issue
Block a user