React 中如何使用 dhtmlxGantt 甘特图 function语法
官方文档 --建议翻墙食用
常用api
一列多行:级添加 render: 'split'
效果图
代码直接cv食用更佳
步骤 1
import { Button, Dropdown, Menu } from 'antd'
import React, { useEffect, useState } from 'react'
import Gantt from './Gantt/index'//步骤二的代码
function DHX() {
/**
* Year 年
* Quarter 月
* Days 日
* Hours 时
*
*/
const sum = [
{ name: '年', id: 'Year' },
{ name: '月', id: 'Quarter' },
{ name: '日', id: 'Days' },
{ name: '时', id: 'Hours' }
]
// const currentZoom = 'Hours'
const [currentZoom, setCurrentZoom] = useState<any>('Days') //缩放的状态
const [data, setData] = useState<any>({ data: [], links: [] }) //初始值为空
const [messages, setMessages] = useState<any>([
{ message: 'link create: 1648541366992 ( source: 1, target: 2 )' }
])
useEffect(() => {
api()
}, [])
const api = () => {
const list: any = {
/**
* links
*source
* target
* type 1首0尾
* parent: 1 属于谁
*/
data: [
//给父节点设置一个单独的状态 用于判断不可移动
{
id: 1,
text: '路飞一号', //名称
start_date: '2020-04-08', //日期
duration: 6, //天数
progress: 1, //控制完成百分比 范围0-1
color: 'red' //控制颜色
},
{
id: '1|0',
text: '路飞二号',
start_date: '2020-04-08',
duration: 2,
progress: 0.6,
parent: 1,
color: '#d9363e', //控制颜色
render: 'split' //添加同一行
},
{
id: '1|1',
text: '路飞二号的子1',
start_date: '2020-04-8',
duration: 2,
progress: 0.6,
parent: '1|0'
},
{
id: '1|2',
text: '路飞二号的子2',
start_date: '2020-04-10',
duration: 2,
progress: 0.6,
parent: '1|0'
},
{
id: '1|3',
text: '路飞二号的子3',
start_date: '2020-04-12',
duration: 2,
progress: 0.6,
parent: '1|0'
},
{
id: 3,
text: '路飞三号',
start_date: '2020-04-10',
duration: 3,
progress: 0.6,
parent: 1
},
{
id: 4,
text: '路飞四号',
start_date: '2020-04-12',
duration: 3,
progress: 0.6
}
],
/**
* id 唯一
* { id: 1, source: 2, target: 13, type: 0 },
* 2的尾部连接13
*/
links: [
{ id: 1, source: 1, target: 2, type: 0 },
{ id: 3, source: 2, target: 3, type: 0 }
]
}
setData(list)
}
const addMessage = (message: any) => {
const maxLogLength = 5
const newMessage = { message }
const messagesDome = [newMessage, ...messages]
if (messagesDome.length > maxLogLength) {
messagesDome.length = maxLogLength
}
setMessages(messagesDome)
}
//划过事件
const logDataUpdate = (type: any, action: any, item: any, id: any) => {
console.log('item', item)
// api()
}
const choose = (type: any) => {
setCurrentZoom(type)
}
const menu = (
<Menu>
{sum.map((item) => (
<>
<Menu.Item>
<div onClick={() => choose(item.id)} key={item.id}>
{item.name}
</div>
</Menu.Item>
</>
))}
</Menu>
)
return (
<div>
<div>
<div>
<Dropdown overlay={menu} placement="topRight" arrow>
<Button>缩放</Button>
</Dropdown>
</div>
<div className="gantt-container">
<Gantt
tasks={data}
zoom={currentZoom}
onDataUpdated={logDataUpdate}
/>
</div>
</div>
</div>
)
}
export default DHX
步骤2
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
import { gantt } from 'dhtmlx-gantt'
import React, { Component, useEffect, useState } from 'react'
function Gantt(props: any) {
const { zoom, tasks, onDataUpdated } = props
// const [type, setType] = useState(true)
const chartDom = document.getElementById('main') //获取id
// 参数设置
const initZoom = () => {
gantt.i18n.setLocale('cn') //设置中文
// gantt.config.readonly = true//只读
gantt.config.order_branch = true // 左侧可以拖动
gantt.config.sort = true //左侧点击表头排序
// gantt.config.drag_move = true //是否可以移动
// gantt.config.drag_progress = false //拖放进度
gantt.config.drag_resize = true //控制大小
gantt.ext.zoom.init({
levels: [
{
name: 'Hours',
scale_height: 60,
min_column_width: 30,
scales: [
{ unit: 'day', step: 1, format: '%d %M ' },
{ unit: 'hour', step: 1, format: '%H' }
]
},
{
name: 'Days',
scale_height: 60,
min_column_width: 70,
scales: [
// { unit: 'week', step: 1, format: '#%W' },
{ unit: 'day', step: 1, format: ' %M%d' }
]
},
{
name: 'Months',
scale_height: 60,
min_column_width: 70,
scales: [
{ unit: 'month', step: 1, format: '%F' },
{ unit: 'week', step: 1, format: '#%W' }
]
}
]
})
// 可以通过此控制 是否可以拖动
gantt.attachEvent(
'onBeforeTaskDrag',
function (id: any, mode: any, e: any) {
const task = gantt.getTask(id)
// console.log('onBeforeTaskDrag', id, mode, e, task)
console.log('task', task)
if (task.id === 1) {
return false
} else {
return true
}
}
)
//测试---------------------
gantt.config.fit_tasks = false
// 双击task时,弹出lightbox弹出框
gantt.attachEvent('onEmptyClick', function (e: any) {
console.log('我点击了空白')
})
//缩放
const zoomConfig = {
levels: [
{
name: 'Hours', //时
scale_height: 60,
min_column_width: 30,
scales: [
{ unit: 'day', step: 1, format: '%M %d ' },
{ unit: 'hour', step: 1, format: '%H' }
]
},
{
name: 'Days', //日
scale_height: 27,
min_column_width: 100,
scales: [{ unit: 'day', step: 1, format: ' %M %d' }]
},
{
name: 'Quarter', //月
height: 100,
min_column_width: 90,
scales: [{ unit: 'month', step: 1, format: '%M' }]
},
{
name: 'Year', //年
scale_height: 50,
min_column_width: 30,
scales: [{ unit: 'year', step: 1, format: '%Y' }]
}
]
}
gantt.ext.zoom.init(zoomConfig)
//测试结束---------------------
}
const setZoom = (value: any) => {
if (!gantt.$initialized) {
initZoom()
}
//缩放
gantt.ext.zoom.setLevel(value)
}
useEffect(() => {
setZoom(zoom)
}, [zoom])
useEffect(() => {
if (tasks) {
componentDidMount(tasks)
}
}, [tasks])
const initGanttDataProcessor = () => {
gantt.createDataProcessor((type: any, action: any, item: any, id: any) => {
return new Promise<void>((resolve, reject) => {
if (onDataUpdated) {
onDataUpdated(type, action, item, id)
}
return resolve()
})
})
}
const componentDidMount = (list: any) => {
gantt.config.date_format = '%Y-%m-%d %H:%i'
gantt.init(chartDom) //根据 id
initGanttDataProcessor()
gantt.parse(list) //渲染数据
}
return <div id="main" style={{ width: '100%', height: '100%' }}></div>
}
export default Gantt