轉(zhuǎn)帖|對(duì)比評(píng)測|編輯:楊鵬連|2020-07-20 09:34:52.730|閱讀 523 次
概述:本文記錄了我是為何棄用 echarts,轉(zhuǎn)而改用 dhtmlxGantt 完成甘特圖的過程,對(duì)一些功能的具體配置進(jìn)行了詳細(xì)的介紹。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
dhtmlxGantt是用于跨瀏覽器和跨平臺(tái)應(yīng)用程序的功能齊全的Gantt圖表。可滿足項(xiàng)目管理應(yīng)用程序的所有需求,是最完善的甘特圖圖表庫。它允許你創(chuàng)建動(dòng)態(tài)甘特圖,并以一個(gè)方便的圖形化方式可視化項(xiàng)目進(jìn)度。有了dhtmlxGantt,你可以顯示活動(dòng)之間的依賴關(guān)系,顯示具有完成百分比陰影的當(dāng)前任務(wù)狀態(tài)以及組織活動(dòng)到樹結(jié)構(gòu)。
事情是這樣的
早些時(shí)候,我接到了一個(gè)需求,說要將項(xiàng)目里程碑用甘特圖展示,一臉懵逼的我先是搜一下什么是“甘特圖” :From 百度百科:甘特圖(Gantt chart)又稱為橫道圖、條狀圖(Bar chart)。其通過條狀圖來顯示項(xiàng)目,進(jìn)度,和其他時(shí)間相關(guān)的系統(tǒng)進(jìn)展的內(nèi)在關(guān)系隨著時(shí)間進(jìn)展的情況。
配合圖片感受 :
在 github 上一搜,甘特圖組件不算多,由于時(shí)間緊急,當(dāng)時(shí)還沒發(fā)現(xiàn)只有413個(gè) 的真命天子(dhtmlxGantt),僅試用了前面4款 比較多的:
結(jié)果均是以失敗告終(不符合業(yè)務(wù)需求,改造難度大)。
調(diào)整一下心情,重新踏上甘特圖組件調(diào)研之路 ,終于,被我發(fā)現(xiàn)了 Top 5 : Best free jQuery and JavaScript Dynamic Gantt Charts for web applications 這個(gè)網(wǎng)站,真命天子 dhtmlxGantt 排名TOP1,于是我開始對(duì)其進(jìn)行了試用及研究。
經(jīng)過一番折騰,終于做出了符合業(yè)務(wù)方需求的甘特圖 :
有一說一,與 echarts 模擬的甘特圖一比,dhtmlxGantt 確實(shí)功能強(qiáng)大了許多,除了能實(shí)現(xiàn)對(duì)重要日期(如今日/項(xiàng)目開始時(shí)間/項(xiàng)目結(jié)束時(shí)間等)進(jìn)行標(biāo)示、tooltip、里程碑狀態(tài)區(qū)分等功能之外,最重要的是可以實(shí)現(xiàn)按時(shí)/日/月/年的切換。
由于 dhtmlxGantt 有免費(fèi)版和付費(fèi)版,一開始試用也不知道成不成功,所以我下載了免費(fèi)版的源碼進(jìn)行了一番研究,幸好最后的結(jié)果也是可以通過一些配置來實(shí)現(xiàn)需求,下面將介紹怎么實(shí)現(xiàn)。
通過配置 dhtmlxGantt 實(shí)現(xiàn)的功能
在 react 項(xiàng)目中使用
dhtmlxGantt 在 github 提供了在 Vue.js/Angular/React 項(xiàng)目中的使用方法入口,本文將對(duì)如何在 react 項(xiàng)目中使用進(jìn)行介紹(經(jīng)實(shí)踐)。
下載命令:
yarn add dhtmlx-gantt 復(fù)制代碼在組件中使用:
import 'dhtmlx-gantt'; import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'; import 'dhtmlx-gantt/codebase/ext/dhtmlxgantt_marker.js'; import 'dhtmlx-gantt/codebase/ext/dhtmlxgantt_tooltip.js'; import 'dhtmlx-gantt/codebase/locale/locale_cn.js'; import * as React from 'react'; import { getGanttConfigByZoomValue } from '../../utils/milestone.lib'; import Toolbar from './components/Toolbar'; import * as styles from './index.module.less'; export default class Gantt extends React.Component根據(jù) setConfig 和 setZoom 方法可以看到,我們可以通過對(duì) gantt 實(shí)例進(jìn)行操作來實(shí)現(xiàn)不同的功能。{ state = { currentZoom: 'Days', // 默認(rèn)按日維度展示 isMount: false, }; private ganttContainer: any; componentWillReceiveProps (nextProps: any) { this.generateGantt(); this.setState({ isMount: true }); } handleZoomChange = (zoom: string) => { this.setState({ currentZoom: zoom }, () => { this.generateGantt(); }); } async generateGantt () { const { ganttData } = this.props; if (this.state.isMount) { // 若不加判斷,首次使用會(huì)報(bào)錯(cuò) gantt.clearAll(); // 移除所有任務(wù),否則更新時(shí)任務(wù)會(huì)疊加 } this.setConfig(); // 添加配置 gantt.init(this.ganttContainer); // 初始化 dhtmlxGantt 到 ganttContainer 容器中 gantt.parse(ganttData); // 將數(shù)據(jù)注入到甘特圖 } setConfig () { ... } setZoom (value: string) { gantt.config = { ...gantt.config, ...getGanttConfigByZoomValue(value), // 根據(jù)維度展示不同的日期格式 }; } renderContent () { const { currentZoom } = this.state; return ( { this.ganttContainer = input; }} style={{ width: '100%', height: '100%' }} />); } render () { return ({this.renderContent()}); } } 復(fù)制代碼
只讀模式
在初始化 dhtmlxGantt 之前,通過將 gantt.config.readonly 設(shè)置為 true 來限制甘特圖為只讀模式:
gantt.config.readonly = true; gantt.init(this.ganttContainer); 復(fù)制代碼可以看到,盡管設(shè)置了只讀模式,表格行被選中后無法取消選中,同時(shí),表格列最右邊仍有?號(hào)按鈕,雖然點(diǎn)了沒有反應(yīng):
解決表格行被選中后無法取消選中的問題,可以通過以下設(shè)置即可解決:
gantt.config.readonly = true; // 開啟只讀模式 select_task: false, // 禁止任務(wù)被選中, gantt.init(this.ganttContainer); 復(fù)制代碼至于表格列最右邊仍有?號(hào)按鈕的問題,可以通過自定義表格列來解決 。
自定義表格列
表格列設(shè)置如下:
gantt.config.columns = [ { name: 'text', label: '里程碑節(jié)點(diǎn)', width: 280, template: function (obj: any) { return `節(jié)點(diǎn):${obj.text}`; // 通過 template 回調(diào)可以指定返回內(nèi)容值 }, }, ]; gantt.init(this.ganttContainer); 復(fù)制代碼結(jié)果如下:
自定義tooltip
如果我們要自定義鼠標(biāo)移動(dòng)到任務(wù)上的 tooltip 提示,非常重要的一點(diǎn)是需要引入 dhtmlxgantt_tooltip.js,才可以使用通過 gantt.attachEvent 方法添加 tooltip,然后可以開始進(jìn)行自定義:
// 自定義tooltip內(nèi)容 gantt.templates.tooltip_text = function (start: Date, end: Date, task: any) { const t = gantt; const output = `里程碑:${task.text} 狀態(tài):${ MILESTONE_STATE_MAP[task.state] } 計(jì)劃開始時(shí)間:${t.templates.tooltip_date_format( start, )} 計(jì)劃結(jié)束時(shí)間:${t.templates.tooltip_date_format(end)}`; return output; }, // 添加tooltip gantt.attachEvent('onGanttReady', function () { var tooltips = gantt.ext.tooltips; tooltips.tooltip.setViewport((gantt as any).$task_data); }); 復(fù)制代碼
當(dāng)鼠標(biāo)移動(dòng)到項(xiàng)目上是,可以看到我們自定義的 tooltip 內(nèi)容:
展示今日、項(xiàng)目開始和結(jié)束標(biāo)示線
與 tooltip 功能類似,如果需要使用標(biāo)示線的功能,需要引入 dhtmlxgantt_marker.js,這樣才能通過 gantt.addMarker 方法為一些重要日期的增加標(biāo)示:
const { online_date, offline_date } = this.props; // 今日紅線 let today = new Date(`${getEndOfDate()}`); // getEndOfDate 為獲取今天結(jié)束時(shí)間的方法 gantt.addMarker({ start_date: today, css: 'today', text: '今日', }); // 項(xiàng)目開始時(shí)間 if (online_date) { gantt.addMarker({ start_date: online_date, css: 'projectStartDate', text: '項(xiàng)目開始', }); } // 項(xiàng)目結(jié)束時(shí)間 if (offline_date) { gantt.addMarker({ start_date: offline_date, css: 'projectEndDate', text: '項(xiàng)目結(jié)束', }); } 復(fù)制代碼
需要注意 ??:除了今日標(biāo)示線已經(jīng)有默認(rèn)樣式以外,新增加的標(biāo)示線需要指定css類名來增加樣式:
.projectStartDate, .projectEndDate { background: #00bcd4; } 復(fù)制代碼
結(jié)果:
自定義任務(wù)顏色
可以通過設(shè)置 gantt.templates.task_class 實(shí)現(xiàn)任務(wù)顏色自定義:task_class: function (start: Date, end: Date, task: any) { return `milestone-${task.state}`; // task.state值為default/unfinished/finished/canceled其中一種 }, 復(fù)制代碼
css:
.milestone-default { border: none; background: rgba(0, 0, 0, 0.45); } .milestone-unfinished { border: none; background: #5692f0; } .milestone-finished { border: none; background: #84bd54; } .milestone-canceled { border: none; background: #da645d; } 復(fù)制代碼
高亮周末日期顏色
由于公司周末不上班 ,可以將周末日期顏色進(jìn)行高亮:
// 突出周末顏色 (gantt.templates as any).timeline_cell_class = function (item: any, date: Date): string { if (date.getDay() === 0 || date.getDay() === 6) { return 'weekend'; } return ''; }; 復(fù)制代碼
結(jié)果:
可以看到,由于按月和按年視圖展示,會(huì)用當(dāng)前列的時(shí)間去做計(jì)算,這樣會(huì)導(dǎo)致整周/整月都被高亮,這明顯不是我們想要的結(jié)果,那就改造一下吧:
// 突出周末顏色 const disableHighlight = this.state.currentZoom === 'Years' || this.state.currentZoom === 'Months'; (gantt.templates as any).timeline_cell_class = function (item: any, date: Date): string { if (!disableHighlight && (date.getDay() === 0 || date.getDay() === 6)) { return 'weekend'; } return ''; }; 復(fù)制代碼
可以看到,三月這一列變正常了:
切換視圖
切換視圖的 Toolbar 組件在文檔中有詳細(xì)介紹,這里就不進(jìn)行復(fù)述了,核心是getGanttConfigByZoomValue方法,用于設(shè)置不同視圖的具體時(shí)間格式,代碼如下:export function getGanttConfigByZoomValue (value: string) { switch (value) { case 'Hours': return { scale_unit: 'day', scale_height: 50, min_column_width: 30, date_scale: '%Y-%m-%d', subscales: [ { unit: 'hour', step: 1, date: '%H', }, ], }; case 'Days': return { scale_unit: 'week', scale_height: 50, min_column_width: 70, date_scale: '%Y年 %W周', subscales: [ { unit: 'day', step: 1, date: '%m-%d', }, ], }; case 'Months': return { scale_unit: 'month', scale_height: 50, min_column_width: 70, date_scale: '%Y-%m', subscales: [ { unit: 'week', step: 1, date: '%W周', }, ], }; case 'Years': return { scale_unit: 'year', scale_height: 50, min_column_width: 70, date_scale: '%Y年', subscales: [ { unit: 'month', step: 1, date: '%M', }, ], }; default: return {}; } } 復(fù)制代碼
通過上面介紹的配置,即可實(shí)現(xiàn)符合業(yè)務(wù)方需求的甘特圖 :
總結(jié)
本文記錄了我是為何棄用 echarts,轉(zhuǎn)而改用 dhtmlxGantt 完成甘特圖的過程,對(duì)一些功能的具體配置進(jìn)行了詳細(xì)的介紹。
通過這次的需求我學(xué)到了很多,有時(shí)候應(yīng)該轉(zhuǎn)換思路,先找找有沒有現(xiàn)成的開源庫,看看在原來已有的功能基礎(chǔ)上,能如何進(jìn)行改造使其滿足需求,這樣能避免走很多彎路。正如牛頓所說:“如果說我看得比別人更遠(yuǎn)些,那是因?yàn)槲艺驹诰奕说募绨蛏稀!?br />如果您有興趣在Salesforce應(yīng)用程序中實(shí)現(xiàn)我們的甘特圖庫,請(qǐng)隨時(shí)與我們聯(lián)系以獲取所有詳細(xì)信息和實(shí)時(shí)演示。
關(guān)產(chǎn)品推薦:
VARCHART XGantt:支持ActiveX、.Net等平臺(tái)的C#甘特圖控件
AnyGantt:構(gòu)建復(fù)雜且內(nèi)容豐富的甘特圖的理想工具
jQuery Gantt Package:基于HTML5 / jQuery的跨平臺(tái)jQuery Gantt包
phGantt Time Package:對(duì)任務(wù)和時(shí)間的分配管理的甘特圖
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自: