npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wimi/gantt

v0.1.8

Published

Framework-agnostic SVG scheduling gantt chart.

Readme

@wimi/gantt

基于 SVG + DOM foreignObject 的通用排产甘特图组件,不绑定 Vue/React 等框架。组件只接收一个 DOM 容器和一份 options,通过 setOptions 增量更新。

安装和引入

npm install @wimi/gantt
import { VanillaGantt } from '@wimi/gantt'
import '@wimi/gantt/style.css'

浏览器直接引入 UMD:

<link rel="stylesheet" href="./dist/VanillaGantt.css" />
<script src="./dist/VanillaGantt.umd.js"></script>
<script>
  const { VanillaGantt } = window.VanillaGantt
</script>

独立开发和打包

packages/gantt 是独立 TypeScript 工具包,不依赖外层 Vue demo 工程。进入包目录后可单独安装依赖并打包:

cd packages/gantt
npm install
npm run build

打包工具使用 Vite library mode,入口为 src/index.ts,产物输出到 dist

| 格式 | 文件 | | --- | --- | | ES Module | dist/VanillaGantt.es.js | | CommonJS | dist/VanillaGantt.cjs | | UMD | dist/VanillaGantt.umd.js | | CSS | dist/VanillaGantt.css |

TypeScript 类型入口为 types/index.d.ts,由 package.jsontypesexports["."].types 暴露。

最小示例

<div id="gantt" style="height: 420px"></div>
const gantt = new VanillaGantt(document.querySelector('#gantt'), {
  minDate: '2026-03-30T00:00:00',
  maxDate: '2026-03-31T00:00:00',
  records: [
    {
      id: 'unit-1',
      name: '机组 1',
      tasks: [
        {
          id: 'task-1',
          title: '计划工单',
          subtitle: 'A001',
          startDate: '2026-03-30T08:00:00',
          endDate: '2026-03-30T14:00:00',
          progress: 40
        }
      ]
    }
  ],
  taskListTable: {
    columns: [
      { field: 'name', title: '资源', width: 160, tree: true }
    ]
  },
  timelineHeader: {
    scales: [
      { unit: 'day', step: 1, rowHeight: 24 },
      { unit: 'hour', step: 2, colWidth: 56, rowHeight: 24 }
    ]
  }
})

表格列和自定义单元格

左侧表格通过 taskListTable.columns 配置,可多列显示,每列支持独立宽度、最小宽度、表头对齐、单元格对齐、列宽拖拽、表头模板和单元格模板。

const options = {
  taskListTable: {
    tableWidth: 'auto',
    minTableWidth: 180,
    maxTableWidth: 720,
    columnResizable: true,
    headerStyle: {
      backgroundColor: '#eaf3f8',
      color: '#2f4858',
      fontWeight: '700'
    },
    columns: [
      { field: 'name', title: '资源', width: 160, minWidth: 120, tree: true },
      {
        field: 'stage',
        title: '工序',
        width: 90,
        renderHeader: () => '<strong>工序</strong>'
      },
      {
        title: '任务数',
        width: 72,
        align: 'right',
        headerAlign: 'right',
        valueGetter: ({ row }) => (row.tasks || []).length
      },
      {
        title: '状态',
        width: 96,
        headerStyle: { backgroundColor: '#dcecf4' },
        valueGetter: ({ row }) => row.status || '',
        renderCell: ({ value }) => `<span class="status-pill">${value || '-'}</span>`
      }
    ]
  }
}

树节点默认使用第一列 field: 'name' 作为树列,也可以显式设置 tree: true。如果自定义树单元格,需要给展开按钮加 data-vg-toggle

{
  field: 'name',
  title: '资源',
  tree: true,
  renderCell: ({ row, expanded }) => `
    <div class="resource-cell" style="padding-left:${row.level * 16}px">
      ${row.children ? `<button data-vg-toggle>${expanded ? '收起' : '展开'}</button>` : ''}
      <span>${row.name}</span>
    </div>
  `
}

时间轴刻度

时间轴由 timelineHeader.scales 决定,数组里每一项就是一行刻度。比如 15 分钟刻度只显示两行:天 + 15 分钟。

function formatMinute({ startDate }) {
  const hour = String(startDate.getHours()).padStart(2, '0')
  const minute = String(startDate.getMinutes()).padStart(2, '0')
  return `${hour}:${minute}`
}

const options = {
  timelineHeader: {
    backgroundColor: '#f7fbfd',
    style: {
      backgroundColor: '#f7fbfd',
      color: '#53666f'
    },
    scales: [
      {
        unit: 'day',
        step: 1,
        rowHeight: 24,
        style: { backgroundColor: '#eaf3f8', fontWeight: '700' }
      },
      {
        unit: 'minute',
        step: 15,
        colWidth: 48,
        rowHeight: 24,
        format: formatMinute
      }
    ]
  }
}

可配置的 unitminutehourdayweekmonthyear

const scalePresets = {
  hour: [
    { unit: 'day', step: 1, rowHeight: 24 },
    { unit: 'hour', step: 1, colWidth: 44, rowHeight: 24 }
  ],
  week: [
    { unit: 'month', step: 1, rowHeight: 24 },
    { unit: 'week', step: 1, colWidth: 180, rowHeight: 24 }
  ],
  month: [
    { unit: 'year', step: 1, rowHeight: 24 },
    { unit: 'month', step: 1, colWidth: 220, rowHeight: 24 }
  ]
}

gantt.setOptions({
  timelineHeader: {
    scales: scalePresets.week
  }
})

自定义刻度内容:

timelineHeader: {
  customLayout: ({ unit, major }) => `
    <div class="timeline-cell ${major ? 'is-major' : ''}">
      ${unit.label}
    </div>
  `,
  scales: [
    { unit: 'day', step: 1 },
    { unit: 'hour', step: 2, colWidth: 64 }
  ]
}

多行任务和自定义 TaskBar

一个资源行里可以放多条任务。通过 taskBar.lanes 定义泳道位置,任务记录上通过 lane 选择泳道。下面示例中第一行是计划任务,第二行是上料任务,第三行是下料任务。

const options = {
  rowHeight: 92,
  taskBar: {
    startDateField: 'startDate',
    endDateField: 'endDate',
    progressField: 'progress',
    laneField: 'lane',
    statusField: 'status',
    labelText: 'title',
    subLabelText: 'subtitle',
    lanes: [
      { key: 'plan', offset: 8, height: 58 },
      { key: 'load', offset: 70, height: 6 },
      { key: 'unload', offset: 82, height: 6 }
    ],
    customLayout: ({ task, progress }) => {
      if (task.logistics) {
        return `<div class="logistics logistics-${task.status}"></div>`
      }
      return `
        <div class="work-task work-task-${task.status || 'normal'}">
          <strong>${task.title || ''}</strong>
          <span>${task.subtitle || ''}</span>
          ${progress !== undefined ? `<i style="width:${progress}%"></i>` : ''}
        </div>
      `
    }
  },
  records: [
    {
      id: 'unit-1',
      name: '热处理炉 1',
      height: 92,
      tasks: [
        { id: 'wo-1', lane: 'plan', title: '计划工单', subtitle: 'A001', startDate: '2026-03-30T08:00', endDate: '2026-03-30T18:00', progress: 60 },
        { id: 'wo-1-load', lane: 'load', title: '上料', startDate: '2026-03-30T06:30', endDate: '2026-03-30T08:00', status: 'load-running', logistics: true },
        { id: 'wo-1-unload', lane: 'unload', title: '下料', startDate: '2026-03-30T18:00', endDate: '2026-03-30T19:00', status: 'unload-waiting', logistics: true }
      ]
    }
  ]
}

自定义模板中如果存在按钮、下拉等控件,并且不希望触发任务拖拽,给元素加 data-vg-no-drag

customLayout: ({ task }) => `
  <div class="work-task">
    <span>${task.title}</span>
    <button data-vg-no-drag>操作</button>
  </div>
`

任务交互、拖拽和 Tooltip

Tooltip 默认关闭。需要显示时配置 taskBar.tooltip: true 或传入对象。

const options = {
  taskBar: {
    draggable: ({ task }) => !task.locked && !task.logistics,
    dragStep: 15 * 60 * 1000,
    tooltip: {
      visible: true,
      offsetX: 12,
      offsetY: 12,
      customLayout: ({ task, startDate, endDate }) => `
        <div class="task-tooltip">
          <strong>${task.title}</strong>
          <span>${startDate.toLocaleString()} - ${endDate.toLocaleString()}</span>
        </div>
      `
    },
    onClick: ({ task, row }) => {
      console.log('click', task, row)
    },
    onContextMenu: ({ task, event }) => {
      console.log('context menu', task, event.clientX, event.clientY)
    },
    onMouseEnter: ({ task }) => {
      console.log('mouseenter', task.id)
    },
    onMouseLeave: ({ task }) => {
      console.log('mouseleave', task.id)
    },
    onDragStart: ({ task }) => {
      if (task.locked) return false
    },
    onDrag: ({ sourceTask, startDate, endDate }) => {
      console.log('dragging', sourceTask.id, startDate, endDate)
    },
    onDragEnd: ({ sourceTask, startDate, endDate }) => {
      console.log('drag end', sourceTask.id, startDate, endDate)
    }
  }
}

拖拽结束后组件会把源任务的开始和结束字段写回原始任务对象,字段名由 startDateFieldendDateField 决定。

树形数据和父节点任务条

records 支持 children。父节点未展开时,组件会基于所有子节点的主任务自动生成一条聚合任务条;父节点展开后,只显示子节点任务,父节点自己的聚合任务条不显示。

const options = {
  records: [
    {
      id: 'heat',
      name: '热处理',
      expanded: false,
      children: [
        {
          id: 'heat-1',
          name: '热处理炉 1',
          tasks: [
            { id: 'wo-1', lane: 'plan', title: '工单 1', startDate: '2026-03-30T08:00', endDate: '2026-03-30T12:00' }
          ]
        },
        {
          id: 'heat-2',
          name: '热处理炉 2',
          tasks: [
            { id: 'wo-2', lane: 'plan', title: '工单 2', startDate: '2026-03-30T13:00', endDate: '2026-03-30T18:00' }
          ]
        }
      ]
    }
  ],
  taskBar: {
    projectStyle: {
      barColor: '#dff4f1',
      borderColor: '#8bc7c0',
      cornerRadius: 2
    }
  }
}

背景区间、休息时间和标记线

grid.backgroundRanges 用于整张时间区域背景,比如休息、停机、冻结区;支持精确到分钟。grid.rowBackgroundRanges 用于某个资源行的局部背景。

const options = {
  grid: {
    backgroundColor: '#f7fbfb',
    alternatingBackgroundColor: '#f8fbfb',
    verticalLine: { lineColor: '#e8eeee' },
    horizontalLine: { lineColor: '#edf1f2' },
    backgroundRanges: [
      {
        id: 'rest-1',
        startDate: '2026-03-30T12:00:00',
        endDate: '2026-03-30T13:30:00',
        fill: '#f2f3f3',
        opacity: 1
      },
      {
        id: 'stop-1',
        startDate: '2026-03-30T19:00:00',
        endDate: '2026-03-31T05:00:00',
        fill: '#fdeeee',
        opacity: 1
      }
    ],
    rowBackgroundRanges: [
      {
        id: 'shift-unit-1',
        recordKey: 'unit-1',
        startDate: '2026-03-30T08:00:00',
        endDate: '2026-03-30T20:00:00',
        fill: '#ffe2a8',
        opacity: 0.8,
        offsetY: 8,
        height: 32
      }
    ]
  },
  markLine: [
    {
      date: '2026-03-30T12:00:00',
      content: '当前时间',
      style: { lineColor: '#35cce0', lineDash: [4, 4] },
      contentStyle: { color: '#1599aa' }
    }
  ]
}

依赖连接线

通过 dependency.links 定义任务依赖。fromto 都可以是单个 id 或 id 数组。默认 showLinks: false,即不常驻显示连接线;点击某个任务后只显示它所在的整条关联网络。点击空白区域会取消连接状态。

const options = {
  dependency: {
    showLinks: false,
    highlightConnected: true,
    dimOpacity: 0.18,
    linkLineStyle: {
      lineColor: '#168dff',
      lineWidth: 2
    },
    links: [
      {
        id: 'flow-1',
        type: 'finish_to_start',
        from: 'wo-1',
        to: ['wo-2', 'wo-3'],
        color: '#168dff'
      },
      {
        id: 'flow-2',
        type: 'start_to_start',
        from: 'wo-4',
        to: 'wo-5',
        dashed: true,
        linkLineStyle: { lineColor: '#40c51b' }
      }
    ]
  }
}

支持的连接类型:

| type | 说明 | | --- | --- | | finish_to_start | 从前置任务结束连到后置任务开始 | | start_to_start | 从前置任务开始连到后置任务开始 | | finish_to_finish | 从前置任务结束连到后置任务结束 | | start_to_finish | 从前置任务开始连到后置任务结束 |

动态更新

gantt.setOptions({
  minDate: '2026-03-30T00:00:00',
  maxDate: '2026-04-02T00:00:00',
  timelineHeader: {
    scales: [
      { unit: 'day', step: 1, rowHeight: 24 },
      { unit: 'hour', step: 4, colWidth: 72, rowHeight: 24 }
    ]
  }
})

销毁:

gantt.destroy()

完整 options 说明

顶层配置

| 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | records | GanttRecord[] | [] | 左侧表格和任务数据 | | recordKeyField | string | 'id' | 资源行唯一 key 字段 | | taskKeyField | string | 'id' | 任务唯一 key 字段 | | minDate | string \| number \| Date | 自动取最小任务开始时间 | 时间轴开始时间 | | maxDate | string \| number \| Date | 自动取最大任务结束时间 | 时间轴结束时间 | | rowHeight | number \| 'auto' | 78 | 默认行高。设置为 'auto' 时按当前行任务的 offsetY + height 自动撑开。大量自定义 task 时优先配置 record.heighttask.heightrowHeight: 'auto',可减少 foreignObject 测量 | | taskHeight | number | 36 | 默认任务条高度 | | headerRowHeight | number | 24 | 默认时间刻度行高 | | taskListTable | GanttTaskListTableOptions | 见下方 | 左侧表格配置 | | timelineHeader | GanttTimelineHeaderOptions | 见下方 | 顶部时间轴配置 | | taskBar | GanttTaskBarOptions | 见下方 | 任务条配置 | | dependency | GanttDependencyOptions | 见下方 | 依赖连接线配置 | | grid | GanttGridOptions | 见下方 | 时间区网格和背景配置 | | virtualScroll | { enabled?: boolean, bufferPx?: number, rowEnabled?: boolean, rowBufferPx?: number, patchRender?: boolean } | { enabled: false, bufferPx: 1200, rowEnabled: true, rowBufferPx: 4800, patchRender: false } | 虚拟渲染。开启后 x 轴只渲染视口附近时间内容,y 轴只渲染视口附近行;patchRender 可复用 layout 未变化的 task 节点,适合高密度横向滚动 | | loading | { enabled?: boolean, text?: string, className?: string, customLayout?: renderer, bodyRenderSlice?: boolean, bodyRenderSliceBudget?: number } | { enabled: false, text: '加载中...', bodyRenderSlice: true, bodyRenderSliceBudget: 8 } | setOptions 重渲染时显示加载层。customLayout 支持模板字符串自定义;开启 loading 时默认按帧分片追加 body SVG 节点,降低大刻度切换阻塞 | | scrollbar | { alwaysVisible?: boolean, width?: number, height?: number, dragRenderDelay?: number, dragRenderMaxWait?: number } | { alwaysVisible: false, width: 10, height: 10, dragRenderDelay: 80, dragRenderMaxWait: 260 } | 主滚动区滚动条配置。支持常显、设置滚动条宽高,以及自定义滚动条拖拽时虚拟渲染的空闲延迟和最大等待 | | performance | { enabled?: boolean, console?: boolean, onRender?: (payload) => void } | { enabled: false, console: false } | 性能日志配置。开启后可获取 body 渲染耗时、snapshot 耗时、可视任务数、连接线数和 SVG 节点数 | | filter | { text?: string, statuses?: string[], rowKeys?: id[], taskKeys?: id[], startDate?: time, endDate?: time, row?: fn, task?: fn } \| null | null | 行和任务筛选。筛选命中的行和任务会保留,任务筛选支持状态、时间范围和 predicate | | highlight | { rowKeys?: id[], taskKeys?: id[] } \| null | null | 行和任务高亮,可配合定位 API 使用 | | markLine | GanttMarkLine \| GanttMarkLine[] \| null | null | 标记线 | | onScroll | (payload) => void | null | 滚动回调,返回 scrollLeftscrollTop |

实例方法

| 方法 | 说明 | | --- | --- | | setOptions(options) | 增量更新配置 | | setFilter(filter) / clearFilter() | 设置或清空筛选 | | setHighlight(highlight) / clearHighlight() | 设置或清空行、任务高亮 | | scrollToRow(rowKey, options?) | 定位到资源行,options.align 支持 startcenterendnearest | | scrollToTask(taskKey, options?) | 定位到任务,默认会同步高亮任务和所在行 | | findTaskByKey(taskKey) | 从当前可见任务索引中查找任务 | | destroy() | 销毁实例并清理 DOM 与事件 |

records

interface GanttRecord {
  id?: string | number
  name?: string
  type?: string
  height?: number
  load?: number
  expanded?: boolean
  children?: GanttRecord[]
  tasks?: GanttTaskRecord[]
  [key: string]: unknown
}

children 表示树形子节点;expanded 控制初始展开状态;height 可单独覆盖当前行行高。顶层 rowHeight: 'auto' 时,没有显式 height 的行会基于当前行任务的 offsetY + height 自动计算高度,适合一个资源包含多组计划、上料、下料的场景。

tasks

interface GanttTaskRecord {
  id?: string | number
  title?: string
  subtitle?: string
  startDate?: string | number | Date
  endDate?: string | number | Date
  lane?: string
  status?: string
  height?: number
  offsetY?: number
  progress?: number
  locked?: boolean
  striped?: boolean
  draggable?: boolean
  milestones?: Array<{
    id?: string | number
    title?: string
    date?: string | number | Date
    width?: number
    height?: number
  }>
  [key: string]: unknown
}

任务字段名可以通过 taskBar.startDateFieldtaskBar.endDateFieldtaskBar.progressFieldtaskBar.laneFieldtaskBar.statusField 改掉。里程碑数组默认读取 task.milestones

taskListTable

| 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | tableWidth | 'auto' \| number | 'auto' | 左侧表格宽度,auto 时按列宽求和 | | minTableWidth | number | 120 | 左侧表格整体最小宽度 | | maxTableWidth | number | 640 | 左侧表格整体最大宽度 | | columnResizable | boolean | true | 是否允许拖拽调整列宽 | | rowDraggable | boolean \| function | false | 是否允许上下拖拽调整行顺序,默认关闭 | | onRowDragEnd | function | null | 行拖拽完成回调,返回 recordsourceIndextargetIndexrecords | | headerStyle | GanttTableHeaderStyle | null | 表头整体样式 | | columns | GanttTableColumn[] | [{ field: 'name', title: '工位', width: 170, tree: true }] | 表格列 | | renderHeader | renderer | null | 整体表头自定义渲染 | | renderCell | renderer | null | 全局单元格自定义渲染 |

GanttTableColumn

| 字段 | 说明 | | --- | --- | | field | 从 row 上读取的字段名 | | title | 表头文本 | | width / minWidth / maxWidth | 列宽配置 | | resizable | 当前列是否允许拖拽列宽 | | align | 单元格水平对齐:leftcenterrightstartend | | headerAlign | 表头水平对齐 | | headerStyle | 当前列表头样式,会覆盖 taskListTable.headerStyle | | tree | 是否作为树列 | | className | 追加到表头和单元格的 class | | valueGetter | 自定义单元格值 | | renderHeader | 当前列表头模板 | | renderCell | 当前列单元格模板 |

行拖拽默认可从行区域起拖。如果自定义单元格里提供 data-vg-row-drag-handle,则只有从该元素起拖才会触发行拖拽:

renderCell: ({ value }) => `
  <span data-vg-row-drag-handle>⠿</span>
  <span>${value}</span>
`

timelineHeader

| 字段 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | backgroundColor | string | '#fff' | 时间轴区域背景 | | colWidth | number | 56 | 默认基础刻度列宽 | | minLabelWidth | number | 0 | 最小刻度文案显示宽度。大于 0 时,刻度宽度低于该值只渲染空刻度,减少密集时间轴节点开销 | | style | GanttTimelineHeaderStyle | null | 时间刻度默认样式 | | scales | GanttTimelineScale[] | 天 + 2 小时 | 时间轴刻度行 | | customLayout | renderer | null | 全局刻度自定义模板 |

GanttTimelineScale

| 字段 | 说明 | | --- | --- | | unit | minutehourdayweekmonthyear | | step | 刻度步长,例如 minute + 15 表示 15 分钟 | | colWidth | 当前刻度作为基础刻度时的列宽 | | minLabelWidth | 当前刻度行的最小文案显示宽度,会覆盖 timelineHeader.minLabelWidth | | rowHeight | 当前刻度行高 | | startOfWeek | 周起始:mondaysunday | | visible | 是否显示当前刻度行 | | style | 当前刻度行样式 | | format | 自定义刻度文案,参数为完整 dateInfo | | customLayout | 当前刻度行自定义模板 |

format 参数:

{
  unit: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
  step: number
  scaleIndex: number
  dateIndex: number
  label: string
  title: string
  startDate: Date
  endDate: Date
  days: number
  x: number
  width: number
}

taskBar

| 字段 | 默认值 | 说明 | | --- | --- | --- | | tasksField | 'tasks' | row 上任务数组字段 | | startDateField | 'startDate' | 任务开始时间字段 | | endDateField | 'endDate' | 任务结束时间字段 | | progressField | 'progress' | 进度字段 | | laneField | 'lane' | 泳道字段 | | statusField | 'status' | 状态字段 | | milestoneField | 'milestones' | task 上里程碑数组字段 | | milestoneDateField | 'date' | 里程碑时间字段 | | labelText | 'title' | 默认任务标题字段或函数 | | subLabelText | 'subtitle' | 默认任务副标题字段或函数 | | barStyle | null | 普通任务默认样式,支持函数 | | projectStyle | null | 父节点聚合任务样式,支持函数 | | customLayout | null | 任务条自定义模板 | | denseRender | false | 高密度短任务批量渲染。开启后小于 maxTaskWidth 的任务会合并为少量 SVG path,适合只浏览密度的分钟级任务 | | milestoneStyle | null | 里程碑尺寸配置,支持函数 | | milestoneCustomLayout | null | 里程碑自定义模板,支持模板字符串 | | milestoneTooltip | false | 里程碑 tooltip,true 显示默认时间节点,也支持自定义模板 | | clip | true | 是否裁剪超出时间范围的任务 | | hoverBringToFront | false | 鼠标移入任务时是否把该任务提升到当前 SVG 图层最上方,并添加 vg-task-fo--hover 便于展示完整内容 | | draggable | false | 是否允许拖拽,默认不支持拖拽;只有配置为 true 或函数返回 true 才能拖拽 | | dragStep | 60000 | 拖拽吸附步长,单位毫秒 | | tooltip | false | Tooltip 配置,默认关闭 | | lanes | plan/load/unload | 行内多任务泳道 | | onClick | null | 任务点击 | | onContextMenu | null | 任务右键 | | onMouseEnter | null | 鼠标移入 | | onMouseLeave | null | 鼠标移出 | | onDragStart | null | 拖拽开始,返回 false 可阻止拖拽 | | onDrag | null | 拖拽中 | | onDragEnd | null | 拖拽结束 |

barStyle / projectStyle 支持:

{
  barColor?: string
  completedBarColor?: string
  height?: number
  width?: number
  cornerRadius?: number
  borderWidth?: number
  borderLineWidth?: number
  borderColor?: string
  minSize?: number
}

tooltip

taskBar: {
  tooltip: false
}
taskBar: {
  tooltip: true
}
taskBar: {
  tooltip: {
    visible: true,
    className: 'my-tooltip',
    offsetX: 12,
    offsetY: 12,
    showDelay: 0,
    customLayout: ({ task, startDate, endDate }) => `
      <div>${task.title} ${startDate.toLocaleString()} - ${endDate.toLocaleString()}</div>
    `
  }
}

dependency

| 字段 | 默认值 | 说明 | | --- | --- | --- | | links | [] | 依赖连接线数组 | | linkLineStyle | null | 全局连接线样式 | | showLinks | false | 是否默认显示全部连接线 | | highlightConnected | false | 显示连接线时是否弱化无关任务 | | dimOpacity | 0.18 | 无关任务透明度 | | lineMode | { pattern: 'solid', path: 'polyline' } | 连接线模式。pattern 支持 solid/dashed/dottedpath 支持 straight/polyline/curved/smoothstep/oblique | | linkCreatable | false | 是否显示任务左右连接原点。开启后仅支持右侧输出点拖到其他任务左侧输入点 | | linkCreateRules | { allowDuplicate: false } | 拖拽创建连接规则。支持限定输出端点、输入端点、指定 from/to 组合和自定义校验 | | linkConnector | { width: 14, height: 14 } | 连接点渲染配置。支持 customLayout/startLayout/finishLayout 模板字符串自定义 | | linkCreateDisabledTaskKeys | [] | 兼容字段,同时禁止指定任务作为输出和输入端点。推荐使用 linkCreateRules | | onLinkCreate | null | 拖拽创建连接回调,返回 linkfromTasktoTaskfromSidetoSide | | linkSelectable | false | 是否允许点击或右键选中连接线。选中后连接线会显示 active 样式 | | linkDeletable | false | 是否允许选中连接线后按 Delete/Backspace 删除 | | onLinkDelete | null | 删除连接线前回调,返回 false 可阻止内部删除 |

links

{
  id?: string | number
  type?: 'finish_to_start' | 'start_to_start' | 'finish_to_finish' | 'start_to_finish'
  from: string | number | Array<string | number>
  to: string | number | Array<string | number>
  color?: string
  dashed?: boolean
  linkLineStyle?: {
    lineColor?: string
    lineWidth?: number
    lineDash?: number[]
  }
}

linkCreateRules

{
  // 默认 false,同一个 from -> to 线路只能创建一次
  allowDuplicate?: boolean
  // 只有这些 task 可以作为右侧输出端点
  fromTaskKeys?: Array<string | number>
  // 只有这些 task 可以作为左侧输入端点
  toTaskKeys?: Array<string | number>
  // 禁止这些 task 作为右侧输出端点,不影响左侧输入端点
  disabledFromTaskKeys?: Array<string | number>
  // 禁止这些 task 作为左侧输入端点,不影响右侧输出端点
  disabledToTaskKeys?: Array<string | number>
  // 只允许指定 from -> to 组合
  pairs?: Array<{
    from: string | number | Array<string | number>
    to: string | number | Array<string | number>
  }>
  // 返回 false 时拒绝创建
  validate?: (context) => boolean
}

linkConnector

{
  width?: number
  height?: number
  size?: number
  customLayout?: (context) => string | Node
  startLayout?: (context) => string | Node
  finishLayout?: (context) => string | Node
}

grid

| 字段 | 默认值 | 说明 | | --- | --- | --- | | backgroundColor | '#f7fbfb' | 时间区底色 | | alternatingBackgroundColor | '#f8fbfb' | 按第一层刻度隔列背景 | | verticalLine | { lineColor: '#e8eeee' } | 竖向网格线,支持函数 | | horizontalLine | { lineColor: '#edf1f2' } | 横向网格线,支持函数 | | backgroundRanges | [] | 全局时间背景区间 | | rowBackgroundRanges | [] | 指定行背景区间 |

backgroundRanges

{
  id?: string | number
  startDate: string | number | Date
  endDate: string | number | Date
  color?: string
  fill?: string
  opacity?: number
}

rowBackgroundRanges 额外支持:

{
  recordKey: string | number
  height?: number
  offsetY?: number
}

markLine

{
  date: string | number | Date
  content?: string
  contentStyle?: {
    color?: string
    fontSize?: number
    fontWeight?: string
  }
  style?: {
    lineColor?: string
    lineWidth?: number
    lineDash?: number[]
  }
  position?: 'left' | 'right' | 'middle' | 'date'
  scrollToMarkLine?: boolean
}

renderer 返回值

所有 customLayoutrenderHeaderrenderCell 都支持返回:

Node | string | { rootContainer?: Node } | null | undefined

返回 string 时,组件内部会把字符串放入 <template> 并作为 HTML 片段解析。字符串模板适合可信的静态片段;如果拼接业务数据,调用方必须自行转义不可信内容。需要承载用户输入或外部数据时,优先返回 Node{ rootContainer }

本项目内 demo

当前项目只保留一个业务 demo:

src/views/WorkOrderStatusDemo.vue

路由:

#/work-order-status

构建

npm --prefix packages/gantt run build