跳转至

15 · 甘特图

gantt.Widget 用于展示带时间区间的任务排程,支持任务依赖、进度、基线计划、里程碑、分组图例、层级任务和时间窗口导航。

基础任务

start := time.Date(2025, time.January, 1, 0, 0, 0, 0, time.UTC)
day := func(offset int) time.Time { return start.AddDate(0, 0, offset) }

tasks := []gantt.Task{
    gantt.NewTask("design", "设计", day(0), day(5)).
        Group("产品").Progress(.8),
    gantt.NewTask("build", "开发", day(4), day(12)).
        Group("工程").DependsOn("design"),
    gantt.NewMilestone("launch", "发布", day(12)).
        Group("发布").DependsOn("build"),
}

plan := gantt.New("release-plan", tasks).
    TimeRange(day(-1), day(14)).
    Legend(true).
    TaskLabels(true).
    TaskAxis("任务").
    TimeAxis("2025 年 1 月")

gantt.NewTask 的结束时间必须晚于开始时间;零时长节点使用 gantt.NewMilestone。 DependsOn 使用任务 key,组件会拒绝空 key、未知任务、自依赖和依赖环。

基线与进度

gantt.NewTask("build", "开发", day(4), day(12)).
    Baseline(day(3), day(10)).
    Progress(.6)

基线显示在当前任务条下方,进度显示为当前任务条的实色部分。颜色可通过 Group 或 Color 指定,默认颜色来自主题。

层级任务

gantt.NewTask("platform", "平台", day(0), day(20)),
gantt.NewTask("api", "公共 API", day(2), day(10)).Parent("platform"),
gantt.NewTask("ui", "工作台", day(6), day(16)).Parent("platform"),

父任务会显示展开/折叠控件。没有回调时折叠状态由组件保留;需要受控状态时使用:

plan.OnTaskToggle(func(key string, collapsed bool) {
    // 更新 Model,再用 Collapsed(collapsed) 重建对应任务
})

初始状态可以由 gantt.NewTask(...).Collapsed(true) 设置。父任务引用必须存在,且不能形成父子循环。

时间窗口

plan.TimeWindow(day(2), day(10)).OnTimeWindowChange(func(start, end time.Time) {
    // 保存或同步当前窗口
    _ = gantt.TimeWindow{Start: start, End: end}
})

启用回调后,图表支持滚轮缩放、拖拽平移和双击恢复完整范围。TimeWindow 只作为初始/受控窗口;组件不会在每次重绘时覆盖用户的手势结果。

拖拽编辑

任务条中部可拖拽移动,左右边缘可调整开始或结束时间。编辑必须显式启用,并通过回调把变更写回 Model:

plan.Editable(true).OnTaskChange(func(change gantt.TaskChange) {
    // 用 change.Key 定位任务,并保存 change.Start / change.End
    // change.PreviousStart / change.PreviousEnd 可用于审计或撤销
})

组件只在释放鼠标时提交一次 OnTaskChange,拖动过程显示本地预览。里程碑不支持区间拖拽。

主题与布局

甘特图维护自己的默认行高、条高、圆角、层级缩进、折叠控件尺寸、依赖线和图例间距。需要调整单个图表的外观时,使用实例样式或组件提供的配置,不要通过全局主题覆盖组件专用几何。

本章代码为用法片段;完整组件测试位于仓库 widget/gantt。