Skip to content

高级用法

本节介绍 GanttFlow 的高级功能,帮助你构建更复杂的甘特图应用。

拖拽交互

GanttFlow 提供流畅的拖拽交互,包括任务拖拽、尺寸调整和进度拖拽。

启用拖拽

tsx
<EnhancedGanttChart
  tasks={tasks}
  enableDrag={true}        // 启用任务拖拽
  enableResize={true}      // 启用尺寸调整
  enableProgressDrag={true} // 启用进度拖拽
  snapToGuides={true}     // 磁吸辅助线
/>

拖拽事件

tsx
<EnhancedGanttChart
  tasks={tasks}
  onTaskDragStart={(task) => {
    console.log("开始拖拽:", task.name)
  }}
  onTaskDrag={(task, e, newStart, newEnd) => {
    console.log(`拖拽中: ${task.name} -> ${newStart} ~ ${newEnd}`)
  }}
  onTaskDragEnd={(task, newStart, newEnd) => {
    console.log("拖拽完成:", task.name, newStart, newEnd)
    // 更新任务数据
    updateTask(task.id, { start: newStart, end: newEnd })
  }}
  onTaskResize={(task, e, newStart, newEnd) => {
    console.log("调整大小:", task.name, newStart, newEnd)
  }}
/>

磁吸辅助线

拖拽时显示时间对齐辅助线:

tsx
<EnhancedGanttChart
  tasks={tasks}
  snapToGuides={true}           // 启用磁吸
  guideColor="#4f46e5"           // 辅助线颜色
  showSnapGuides={true}         // 显示对齐辅助线
  snapThreshold={5}              // 吸附阈值(像素)
/>

拖拽限制

可以限制任务只能在特定范围内拖动:

tsx
<EnhancedGanttChart
  tasks={tasks}
  draggable={(task) => {
    // 只允许未锁定的任务拖动
    return !task.locked
  }}
  minDragDistance={10}           // 最小拖拽距离(防止误触)
/>

依赖关系

任务之间可以建立多种依赖关系。

定义依赖

tsx
const dependencies = [
  { fromId: "1", toId: "2", type: "finish_to_start" },
  { fromId: "2", toId: "3", type: "finish_to_start" },
]

<EnhancedGanttChart
  tasks={tasks}
  dependencies={dependencies}
/>

依赖类型

类型说明图示
finish_to_startFS: A 结束后,B 开始A ████→ ████ B
start_to_startSS: A 开始后,B 开始A ████ ⟷ B
finish_to_finishFF: A 结束后,B 结束A ████ ←▸ ████ B
start_to_finishSF: A 开始后,B 结束A ████ ⟵ B

关键路径

关键路径高亮显示:

tsx
<EnhancedGanttChart
  tasks={tasks}
  dependencies={dependencies}
  enableCriticalPath={true}
  criticalPathColor="#ef4444"
/>

循环依赖检测

自动检测并阻止循环依赖:

tsx
// 如果添加会导致循环的依赖,会抛出错误
const dependencies = [
  { fromId: "1", toId: "2", type: "finish_to_start" },
  { fromId: "2", toId: "3", type: "finish_to_start" },
  { fromId: "3", toId: "1", type: "finish_to_start" }, // 循环!
]
// Error: 检测到循环依赖: 任务1 → 任务2 → 任务3 → 任务1

依赖事件

tsx
<EnhancedGanttChart
  tasks={tasks}
  dependencies={dependencies}
  onDependencyAdd={(dependency) => {
    console.log("添加依赖:", dependency)
  }}
  onDependencyDelete={(dependency) => {
    console.log("删除依赖:", dependency)
  }}
/>

虚拟滚动

当任务数量超过 100 个时,强烈建议启用虚拟滚动。

启用虚拟滚动

tsx
<EnhancedGanttChart
  tasks={largeTaskList}
  virtualScrolling={true}
  visibleTaskCount={50}   // 可见区域任务数
  bufferSize={10}         // 上下缓冲区大小
/>

配置参数

参数类型默认值说明
virtualScrollingbooleanfalse是否启用虚拟滚动
visibleTaskCountnumber50可见区域渲染的任务数
bufferSizenumber10上下缓冲区渲染的任务数

性能对比

任务数量无虚拟滚动启用虚拟滚动
50✅ 流畅✅ 流畅
200⚠️ 卡顿✅ 流畅
500❌ 卡顿✅ 流畅
1000+❌ 无法使用✅ 流畅

自动启用

tsx
const shouldEnableVirtualScroll = tasks.length > 100

<EnhancedGanttChart
  tasks={tasks}
  virtualScrolling={shouldEnableVirtualScroll}
/>

导出功能

GanttFlow 支持导出为 PNG、PDF 和 Excel 格式。

导出 PNG

tsx
// 通过 ref 调用导出方法
const handleExportPNG = async () => {
  const dataUrl = await ganttRef.current?.exportToPNG({
    backgroundColor: "#ffffff",
    scale: 2,  // 分辨率缩放
    quality: 1.0
  })
  
  // 下载
  const link = document.createElement("a")
  link.download = "gantt.png"
  link.href = dataUrl
  link.click()
}

<EnhancedGanttChart ref={ganttRef} tasks={tasks} />

<button onClick={handleExportPNG}>导出 PNG</button>

导出 PDF

tsx
const handleExportPDF = async () => {
  await ganttRef.current?.exportToPDF({
    filename: "project-gantt.pdf",
    orientation: "landscape",  // 或 "portrait"
    margin: 20,
    header: "项目甘特图",
    footer: "Generated by GanttFlow"
  })
}

导出 Excel

tsx
const handleExportExcel = async () => {
  await ganttRef.current?.exportToExcel({
    filename: "tasks.xlsx",
    includeDependencies: true,  // 包含依赖关系
    dateFormat: "YYYY-MM-DD"
  })
}

导出配置

typescript
interface ExportOptions {
  // PNG/PDF 通用
  backgroundColor?: string
  padding?: number
  
  // PNG 专用
  scale?: number         // 1-3,分辨率缩放
  quality?: number        // 0-1,图片质量
  
  // PDF 专用
  orientation?: "portrait" | "landscape"
  filename?: string
  
  // Excel 专用
  includeDependencies?: boolean
  dateFormat?: string
}

滚动控制

滚动到指定日期

tsx
ganttRef.current?.scrollToDate("2024-01-15")
ganttRef.current?.scrollToTask("task-1")

自适应屏幕

tsx
ganttRef.current?.fitToScreen()
// 自动调整视图以显示所有任务

任务操作

动态更新任务

tsx
// 添加任务
const addTask = (newTask) => {
  setTasks([...tasks, newTask])
}

// 更新任务
const updateTask = (taskId, updates) => {
  setTasks(tasks.map(t => 
    t.id === taskId ? { ...t, ...updates } : t
  ))
}

// 删除任务
const deleteTask = (taskId) => {
  setTasks(tasks.filter(t => t.id !== taskId))
}

任务选择

tsx
// 选中任务
ganttRef.current?.selectTask("task-1")

// 获取选中任务
const selected = ganttRef.current?.getSelectedTask()

// 清除选中
ganttRef.current?.clearSelection()

// 多选(按住 Ctrl/Cmd)
ganttRef.current?.selectTask("task-2", { multi: true })

完整示例

tsx
import React, { useRef, useState } from "react"
import { EnhancedGanttChart } from "@agions/gantt-flow"
import "@agions/gantt-flow/style"

const tasks = [
  { id: "1", name: "需求分析", start: "2024-01-01", end: "2024-01-05", progress: 100 },
  { id: "2", name: "系统设计", start: "2024-01-06", end: "2024-01-10", progress: 80 },
  { id: "3", name: "后端开发", start: "2024-01-11", end: "2024-01-20", progress: 50 },
  { id: "4", name: "前端开发", start: "2024-01-11", end: "2024-01-20", progress: 30 },
  { id: "5", name: "测试验收", start: "2024-01-21", end: "2024-01-25", progress: 0 },
]

const dependencies = [
  { fromId: "1", toId: "2", type: "finish_to_start" },
  { fromId: "2", toId: "3", type: "finish_to_start" },
  { fromId: "2", toId: "4", type: "finish_to_start" },
  { fromId: "3", toId: "5", type: "finish_to_start" },
  { fromId: "4", toId: "5", type: "finish_to_start" },
]

function AdvancedGantt() {
  const ganttRef = useRef(null)
  const [viewMode, setViewMode] = useState("week")

  return (
    <div>
      {/* 工具栏 */}
      <div style={{ marginBottom: 16 }}>
        <button onClick={() => setViewMode("day")}>日</button>
        <button onClick={() => setViewMode("week")}>周</button>
        <button onClick={() => setViewMode("month")}>月</button>
        <button onClick={() => ganttRef.current?.fitToScreen()}>适应屏幕</button>
        <button onClick={() => ganttRef.current?.exportToPNG()}>导出 PNG</button>
      </div>

      {/* 甘特图 */}
      <div style={{ height: "600px" }}>
        <EnhancedGanttChart
          ref={ganttRef}
          tasks={tasks}
          dependencies={dependencies}
          viewMode={viewMode}
          enableCriticalPath={true}
          virtualScrolling={true}
          onTaskClick={(task) => console.log("点击:", task.name)}
          onTaskDragEnd={(task, newStart, newEnd) => {
            console.log("拖拽完成:", task.id, newStart, newEnd)
          }}
        />
      </div>
    </div>
  )
}

下一步

基于 MIT 许可证发布