緒言
こちらやこちらの記事でタスク管理について書いてきましたが、上司やプロジェクトリーダーが見たいのはガントチャート。全体感を見たかったり、直近の細かい予定を見たかったりで縮尺可変が望ましい!ということでチャレンジしてみました。PlannerにもScheduleビューが用意されてるけど、ちょっと使いにくい。。。
完成イメージは以下
作り方
1. データ用意
バケット(Bucket
)で分類された開始日(StartDate
)と納期(DueDate
)を持つタスクリストをデモデータPlannerPlus
とする。
Title | Bucket | StartDate | DueDate |
---|---|---|---|
ベンチプレス | 胸トレ | 2024/12/09 | 2024/12/13 |
ダンベルフライ | 胸トレ | 2024/12/11 | 2024/12/14 |
プッシュアップ | 胸トレ | 2024/12/03 | 2024/12/17 |
レッグプレス | 足トレ | 2024/12/16 | 2024/12/27 |
カーフレイズ | 足トレ | 2024/12/23 | 2024/12/27 |
スクワット | 足トレ | 2024/12/08 | 2025/01/10 |
デッドリフト | 背中トレ | 2025/01/01 | 2025/01/09 |
ラットプルダウン | 背中トレ | 2025/01/06 | 2025/01/16 |
このデータを使って以下のコレクションや変数を作成。
ClearCollect(ColPlannerPlus,AddColumns(PlannerPlus,RowIndex,0));
ForAll(
Sequence(CountRows(ColPlannerPlus)) As i,
Patch(ColPlannerPlus,Index(ColPlannerPlus,i.Value),{RowIndex:i.Value})
);
UpdateContext({_maxDate:Max(ColPlannerPlus,DueDate),_minDate:Min(ColPlannerPlus,StartDate)});
UpdateContext({_dateDuration:DateDiff(_minDate,_maxDate,TimeUnit.Days)})
ColPlannerPlus
:PlannerPlus
に行インデックス列を追加したコレクション
_maxDate
:全データ中の日付最大値
_minDate
:全データ中の日付最小値
_dateDuration
:_maxDate
とminDate
の差(日)
2.画面設計
コンテナ内にパーツを配置。特に重要なパーツは以下の6種類。
RadioGroupMag
:倍率選択ラジオボタン
SliderZoom
:Zoom操作スライダー
SliderScroll
:拡大時のスクロール用スライダー
RectangleBlind
:目隠し用の図形
GalleryDate
:日付ラベル用のギャラリー
GalleryMain
:ガントチャートのメインギャラリー
GalleryMain
内部に入れ子でギャラリーを下図のように配置。
LabelID
:非表示だがText
プロパティで子ギャラリーに親ギャラリーのレコード情報を渡す役割。
LabelTitle
:タスクタイトル表示
LabelBucket
:バケット表示
GallerySub
:ガントチャート表示用ギャラリー
GallerySub
の内容は今日の目印やスケジュール塗りつぶし用の図形。
3.ロジック
スライダーやラジオボタンの値に応じて幅や座標を可変にしている。
- ContainerGantt:
Children:
- GalleryMain:
Properties:
Items: =ColPlannerPlus
Width: =Parent.Width*(1+(SliderZoom.Value-1)/10*RadioGroupMag.Selected.value)
Children:
- LabelID:
Properties:
Text: =ThisItem.ID
- LabelTitle:
Properties:
Text: =ThisItem.Title
- LabelBucket:
Properties:
Text: |-
=If(
And(
ThisItem.RowIndex>1,
Index(ColPlannerPlus,ThisItem.RowIndex-1).Bucket=ThisItem.Bucket
),
"",
ThisItem.Bucket
)
- GallerySub:
Properties:
Items: =Sequence(_dateDuration)
TemplateSize: =Self.Width/_dateDuration
Width: =Parent.Width-(LabelTitle.X+LabelTitle.Width)
X: =LabelTitle.X+LabelTitle.Width-(SliderScroll.Value-1)*(GalleryMain.Width-ContainerGantt.Width)/SliderScroll.Max
Children:
- RectangleSchedule:
Properties:
Visible: |-
=With({rec:LookUp(ColPlannerPlus,ID=Value(LabelID.Text))},
And(
DateDiff(_minDate,rec.StartDate,TimeUnit.Days)<=ThisItem.Value-1,
DateDiff(_minDate,rec.DueDate,TimeUnit.Days)>=ThisItem.Value-1
)
)
Width: =Parent.TemplateWidth+1
Y: =Parent.TemplateHeight/2-Self.Height/2
- RectangleToday:
Properties:
Visible: =DateAdd(_minDate,ThisItem.Value-1)=Today()
- GalleryDate:
Properties:
Items: =Sequence(_dateDuration)
TemplateSize: =Self.Width/_dateDuration
Width: =Parent.Width*(1+(SliderZoom.Value-1)/10*RadioGroupMag.Selected.value)-(LabelTitle.X+LabelTitle.Width)
X: =LabelTitle.X+LabelTitle.Width-(SliderScroll.Value-1)*(GalleryMain.Width-ContainerGantt.Width)/SliderScroll.Max
Children:
- TextCanvasDate:
Properties:
Text: =Text(DateAdd(_minDate,ThisItem.Value-1),"m/d")
Visible: =Mod(ThisItem.Value,Int(_dateDuration/10))=1
結言
そんなに苦労せず見やすいガントチャートができた!