vue甘特图gantt
vue做甘特图,先大致介绍下核心功能: (1)横轴、纵轴拖拽; (2)自定义监听点击事件(双击、右键等)(3)任务之间显示父子层级关系;(4)左侧列表信息,右侧时间轴表示任务;(5)每个任务可以订制样式,并且可以动态修改样式;(6)自定义时间粒度显示(小时、天、星期、月、年);(7)支持大批量数据渲染;(8) 支持同行多节点渲染;(9)支持选中,以及批量选中;(9)优秀的扩展性,支持第三方插件。等等还有其他的一些功能。这里先看一下效果图:
接下来会介绍用什么实现的,怎么使用,怎么添加拖拽、点击等各种功能,我以vue为例进行开发。
1、使用GSTC做甘特图开发
Git项目地址:https://github.com/neuronetio/gantt-schedule-timeline-calendar#weekendhighlight-plugin
官方vue实例:https://github.com/neuronetio/vue-gantt-schedule-timeline-calendar
npm指令: npm i gantt-schedule-timeline-calendar
官方做了 3 大主流框架的封装,具体看Git链接,这里我也附上了vue版本的 npm 包地址。
基本使用如下: ps:文章末尾我会贴一个完整的代码,如果是vue项目可以直接复制查看效果。下边这个是个极度阉割的。
<template>
<GSTC :config="config" />
</template>
<script>
import GSTC from "vue-gantt-schedule-timeline-calendar";
export default {
data(){
return {
config: {
height: 500,
list: {
rows: {
"1": { id: "1", order: '订单1', },
},
columns: {
data: {
id: { id: "id", data: "id", width: 50, header: { content: "序号" } },
}
}
},
chart: {
items: {
"1": { id: "1", rowId: "1", time: { start: new Date().getTime() + 1 * 24 * 60 * 60 * 1000, end: new Date().getTime() + 2 * 24 * 60 * 60 * 1000 } }
}
},
},
subs: []
}
},
beforeDestroy() { this.subs.forEach(unsub => unsub()); }
}
</script>
<style lang="less" scoped>
.wrapper .gantt-elastic__grid-line-time {
display: none;
}
</style>
基础使用已经贴代码了,不做赘述,不清楚的查看官方示例,接下来主要说核心功能如何配置,这方面官方描述的不是很清楚,但是Git的 issues 好多问题都关闭了,基本大部分问题都可以查到。
1、基础展示,左侧多列表格展示
这个主要配置config中的 list 属性,
rows 代表左侧表格的行属性,key值是每行的id,多个key就有多行,通常都以数字做key值, 内部 具体属性是列信息。比如 order label line 等都是列信息,这个会一一对应到指定列。
parentID 是父节点配置,一般配置了父节点,就会在 甘特图 中展示出父子层级来。
expanded 是展开属性,默认false,父子层级是合上的,折叠隐藏子节点。如果想默认展示需要每个节点都加上这个属性。
columns 代表左侧表格的列属性,key唯一就是列关键字。
data 属性,是列,可以有多个属性,每个代表一列
id 当前列的id
data 列标识,和rows中每行的数据的字段唯一对应,比如 order、line 等
isHTML 是否要展示HTML,默认false。 这个直接关系到content、html字段用哪个
width 当前列宽度
expander 是否显示层级,默认false不展示,设置为true,会展示出父子层级来,一般我们仅设置一列,当然设置多列也行。
header 配置表头内容的
content 表头想显示的内容
html 写HTML,用来订制表头样式的,内容就是HTML,行内css
percent 是左侧表格总宽度占甘特图的百分比,0就直接隐藏表格
minWidth:是左侧表格的最小宽度
list: {
rows: {
"1": {
id: "1",
order: '订单1',
label: "压缩机",
line: '线体1',
expanded: true
},
"3": {
id: "3",
order: '订单3',
label: "箱体",
line: '线体3',
parentId: '2',
}
},
columns: {
data: {
id: {
id: "id",
data: "id",
width: 50,
expander: true,
header: { content: "序号" }
},
order: {
id: "order",
data: "order",
header: { content: "生产订单" }
},
label: {
id: "label",
data: "label",
header: { content: "描述" }
}
}
}
}
2、右侧任务排列显示(包括订制样式)
这个主要配置config中的 chart 属性,
time 配置时间轴
from 左侧开始时间,填写毫秒数
to 右侧结束时间,填写毫秒数
zoom 显示层级,10-22,越大,时间粒度展示的越大,越小,显示越精细,最小到5分钟
items 任务快配置,注意这个可以同行若干任务展示
id 当前任务的id
rowId 左侧表格 rows 的id,通过这个关联,渲染到某一行
label 当前任务的名称,会默认展示在任务中
time 任务的开始、结束时间
start 开始时间,填写毫秒数
end 结束时间, 填写毫秒数
style 订制样式,是个对象,写过jsx写法,写过react 、vue jsx 的应该都不默认,这里举个简单的例子,订制任务div的背景色 圆角等样式 { background: 'red', borderRadius: '3px' }
chart: {
time: {
from: new Date().getTime() - 2 * 24 * 60 * 60 * 1000,
to: new Date().getTime() + 8 * 24 * 60 * 60 * 1000,
zoom: 22,
},
items: {
"1": {
id: "1",
rowId: "1",
label: "Item 1",
time: {
start: new Date().getTime() + 1 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 2 * 24 * 60 * 60 * 1000
},
style: { // 每个块的样式
background: 'blue'
}
},
"21": {
id: "21",
rowId: "2",
label: "Item 2-1",
time: {
start: new Date().getTime() + 2 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 3 * 24 * 60 * 60 * 1000
}
}
}
}
3、配置右侧横轴的时间显示
这个主要配置config中的 locale 属性,时间的语言环境配置,这里看文档详细些,下面只详说2个属性,
weekdays 配置 每周显示的文案 主要是做国际化用的
months 配置月的,也是做国际化的
locale: {
name: "zh",
Now: "Now",
weekdays:["周日","周一","周二","周三","周四","周五","周六"],
months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],
}
4、监听鼠标右击事件
这个主要配置config中的 actions 属性,他是对象,以下是他所有能监听dom,很多,这篇博客就只介绍人物块的事件监听,其他的不做一一赘述了
main
list
list-column
list-column-header
list-column-header-resizer
list-column-header-resizer-dots
list-column-row
list-column-row-expander
list-column-row-expander-toggle
list-toggle
chart
chart-calendar
chart-calendar-date
chart-timeline
chart-timeline-grid
chart-timeline-grid-row
chart-timeline-grid-row-block
chart-timeline-items
chart-timeline-items-row
chart-timeline-items-row-item
这个监听函数会接收2个参数,element 和 data ,一个是dom,另一个是 任务节点的数据。根据官方要求,监听函数必须返回一个对象,此对象必须包含 update destroy 2个方法,分别是位置更新和销毁时需要执行的方法。具体写法请见如下代码:
actions: {
'chart-timeline-items-row-item': [this.addListenClick] // 监听右击事件
} methods:{
addListenClick(element, data) {
const onClick = (e) => {
e.preventDefault()
// console.log(data)
this.modal = {
visible: true,
title: data.item.label,
data
}
return false
}
element.addEventListener('contextmenu', onClick);
return {
update(element, newData) {
data = newData;
},
destroy(element, data) {
element.removeEventListener('click', onClick);
}
};
},
closeModal() {
this.modal = {
visible: false,
title: '',
data: {}
}
}
},
5、任务的横轴、纵轴拖动
这个主要配置config中的 plugins 属性,
ItemMovement 插件,这个是官方开发的用来拖拽任务的插件。这个包的插件系统做的很好,官方提供了几种不错的插件,同时还支持其他的第三方插件,有兴趣的可以自己试试,这里先介绍拖拽插件,
moveable 拖拽的方向, x 支持横轴拖拽; y 支持纵轴拖拽; true 横轴、纵轴都可以拖拽; false 禁止拖拽
resizeable 是否可以拖拽,true开启拖拽
resizerContent 拖拽的图标,直接写HTML,可以自己定制拖拽图标的样式
collisionDetection: 拖拽过程中是否允许元素重叠, true 不允许重叠
ghostNode false 不展示重影节点
snapStart 拖拽开始时间点回调,这个比较机制特殊,拖拽位置的时候触发这个方法,参数接收开始时间 时间变化 当前节点数据,默认是毫秒级的刷新,会卡,我们做if判断1小时拖拽
snapEnd 拖拽结束时间点回调,这个是拖动任务块大小时触发,接收结束时间 时间段。用法同上。具体请看如下代码:
plugins: [
// 拖动 x 横向, y 纵向
ItemMovement({
moveable: 'x',
resizerContent: '<div class="resizer">-></div>',
ghostNode: false,
snapStart(time, diff, item) {
if(Math.abs(diff) > 14400000) {
return time + diff
}
return time
},
snapEnd(time, diff, item) {
if(Math.abs(diff) > 14400000) {
return time + diff
}
return time
}
})
]
6、选中任务
这个主要配置config中的 plugins 属性,
Selection插件,单个选中、批量选中插件。
grid 能否选中单元格
items 能否选中任务
rows 能否选中行
rectStyle 矩形样式
selected 选中的回调
deselected 取消选中的回调
canSelected 可选中的的回调,用来过滤哪些可以选中
canDeselected 可取消选中的回调,用来过滤哪些可以取消选中
plugins: [
Selection({
items: false,
rows: false,
grid: true,
rectStyle: { opacity: '0.0' },
canSelect(type, currentlySelecting) {
if (type === 'chart-timeline-grid-row-block') {
return currentlySelecting.filter(selected => {
if (!selected.row.canSelect) return false;
for (const item of selected.row._internal.items) {
if (
(item.time.start >= selected.time.leftGlobal && item.time.start <= selected.time.rightGlobal) ||
(item.time.end >= selected.time.leftGlobal && item.time.end <= selected.time.rightGlobal) ||
(item.time.start <= selected.time.leftGlobal && item.time.end >= selected.time.rightGlobal)
) {
return false;
}
}
return true;
});
}
return currentlySelecting;
},
canDeselect(type, currently, all) {
if (type === 'chart-timeline-grid-row-blocks') {
return all.selecting['chart-timeline-grid-row-blocks'].length ? [] : currently;
}
return [];
}
})
]
小结:
以上就是整个甘特图的使用了,这是我用过最符合项目需求的甘特图,他的开发团队也在持续的维护这个项目,很赞。
最后贴一段完整的 vue 示例代码:
<template>
<div class="wrapper">
<GSTC :config="config" />
<infor-modal
:visible="modal.visible"
:title="modal.title"
:dataSource="modal.data"
@handleModal="closeModal"
/>
</div>
</template> <script>
import GSTC from "vue-gantt-schedule-timeline-calendar";
import ItemMovement from "gantt-schedule-timeline-calendar/dist/ItemMovement.plugin.js"
import Selection from "gantt-schedule-timeline-calendar/dist/Selection.plugin.js"
import inforModal from "./inforModal" export default {
components:{
GSTC,
inforModal
},
props:{},
data(){
return {
config: {
height: 500,
list: {
// 行属性
rows: {
"1": {
id: "1",
order: '订单1',
label: "压缩机",
line: '线体1',
expanded: true
},
"3": {
id: "3",
order: '订单3',
label: "箱体",
line: '线体3',
parentId: '2',
},
"4": {
id: "4",
order: '订单4',
label: "空调总装",
line: '线体4',
},
"2": {
id: "2",
order: '订单2',
label: "门体",
parentId: '1',
line: '线体2',
expanded: true
},
"5": {
id: "5",
order: '订单5',
label: "冰箱总装",
line: '线体5',
},
"6": {
id: "6",
order: '订单6',
label: "洗衣机总装",
line: '线体6',
},
},
// 列定义
columns: {
data: {
id: {
id: "id",
data: "id",
width: 50,
header: {
content: "序号"
}
},
order: {
id: "order",
data: "order",
width: 120,
header: {
content: "生产订单"
}
},
label: {
id: "label",
data: "label",
width: 120,
expander: true,
header: {
content: "描述"
}
},
line: {
id: "line",
data: "line",
width: 120,
header: {
content: "线体"
}
},
}
}
},
chart: {
time: { // 时间轴开始截至,
from: new Date().getTime() - 2 * 24 * 60 * 60 * 1000,
to: new Date().getTime() + 8 * 24 * 60 * 60 * 1000,
zoom: 22, // 10-22 缩放,默认 Shift + 滚轮, 默认缩放展示时间粒度, 一共有 小时、天、周、月、年
},
items: {
"1": {
id: "1",
rowId: "1",
label: "Item 1",
time: {
start: new Date().getTime() + 1 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 2 * 24 * 60 * 60 * 1000
},
style: { // 每个块的样式
background: 'blue'
}
},
"21": {
id: "21",
rowId: "2",
label: "Item 2-1",
time: {
start: new Date().getTime() + 2 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 3 * 24 * 60 * 60 * 1000
}
},
"22": {
id: "22",
rowId: "2",
label: "Item 2-2",
time: {
start: new Date().getTime() + 3 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 4 * 24 * 60 * 60 * 1000
}
},
"3": {
id: "3",
rowId: "3",
label: "Item 3",
time: {
start: new Date().getTime() + 3 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 5 * 24 * 60 * 60 * 1000
}
},
"4": {
id: "4",
rowId: "4",
label: "Item 4",
time: {
start: new Date().getTime() + 2 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 5 * 24 * 60 * 60 * 1000
}
},
"5": {
id: "5",
rowId: "5",
label: "Item 5",
time: {
start: new Date().getTime() + 3 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 5 * 24 * 60 * 60 * 1000
}
},
"6": {
id: "6",
rowId: "6",
label: "Item 6",
time: {
start: new Date().getTime() + 5 * 24 * 60 * 60 * 1000,
end: new Date().getTime() + 6 * 24 * 60 * 60 * 1000
}
},
}
},
locale: {
name: "zh",
Now: "Now",
weekdays:["周日","周一","周二","周三","周四","周五","周六"],
months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],
},
actions: {
'chart-timeline-items-row-item': [this.addListenClick] // 监听右击事件
},
plugins: [
// 拖动 x 横向, y 纵向
ItemMovement({
moveable: 'x',
resizerContent: '<div class="resizer">-></div>',
ghostNode: false,
collisionDetection: false,
snapStart(time, diff, item) {
if(Math.abs(diff) > 14400000) {
return time + diff
}
return time
},
snapEnd(time, diff, item) {
if(Math.abs(diff) > 14400000) {
return time + diff
}
return time
}
}),
Selection({
items: false,
rows: false,
grid: true,
rectStyle: { opacity: '0.0' },
canSelect(type, currentlySelecting) {
if (type === 'chart-timeline-grid-row-block') {
return currentlySelecting.filter(selected => {
if (!selected.row.canSelect) return false;
for (const item of selected.row._internal.items) {
if (
(item.time.start >= selected.time.leftGlobal && item.time.start <= selected.time.rightGlobal) ||
(item.time.end >= selected.time.leftGlobal && item.time.end <= selected.time.rightGlobal) ||
(item.time.start <= selected.time.leftGlobal && item.time.end >= selected.time.rightGlobal)
) {
return false;
}
}
return true;
});
}
return currentlySelecting;
},
canDeselect(type, currently, all) {
if (type === 'chart-timeline-grid-row-blocks') {
return all.selecting['chart-timeline-grid-row-blocks'].length ? [] : currently;
}
return [];
}
})
]
},
modal: {
visible: false,
title: '',
data: {}
},
subs: []
}
},
watch:{},
computed:{},
methods:{
addListenClick(element, data) {
const onClick = (e) => {
e.preventDefault()
// console.log(data)
this.modal = {
visible: true,
title: data.item.label,
data
}
return false
}
element.addEventListener('contextmenu', onClick);
return {
update(element, newData) {
data = newData;
},
destroy(element, data) {
element.removeEventListener('click', onClick);
}
};
},
closeModal() {
this.modal = {
visible: false,
title: '',
data: {}
}
}
},
created(){},
mounted(){
},
beforeDestroy() {
this.subs.forEach(unsub => unsub());
}
}
</script>
<style lang="less" scoped>
.wrapper .gantt-elastic__grid-line-time {
display: none;
}
</style>
vue甘特图gantt的更多相关文章
- vue 甘特图简单制作
甘特图(Gantt chart)又称为横道图.条状图(Bar chart).其通过条状图来显示项目,进度,和其他时间相关的系统进展的内在关系随着时间进展的情况.以提出者亨利·L·甘特(Henrry L ...
- odoo10甘特图gantt view
odoo10中的gantt图示例 1.Gantt属性说明 甘特图视图的根元素是<gantt />,它没有子节点但可以采用以下属性: date_start (required) 提供每条记录 ...
- gantt甘特图可拖拽、编辑(vue、react都可用 highcharts)
前言 Excel功能强大,应用广泛.随着web应用的兴起和完善,用户的要求也越来越高.很多Excel的功能都搬到了sass里面.恨不得给他们做个Excel出来...程序员太难了... 去年我遇到了 ...
- Twproject Gantt开源甘特图功能扩展
1.Twproject Gantt甘特图介绍 Twproject Gantt 是一款基于 jQuery 开发的甘特图组件,也可以创建其它图表,例如任务树(Task Trees).内置编辑.缩放和 CS ...
- 一款开源且功能强大的C#甘特图控件.NET Winforms Gantt Chart Control
甘特图在项目管理中非常重要,甘特图的思想比较简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间.它直观地表明任务计划在什么时候进行,及实际进展与计划要求的对比.管理 ...
- Twproject Gantt – 开源的 JavaScript 甘特图组件
Twproject Gantt 是一款基于 jQuery 开发的甘特图组件,也可以创建其它图表,例如任务树(Task Trees).内置编辑.缩放和 CSS 皮肤等功能.更重要的是,它是免费开源的. ...
- 【转载】 JQuery.Gantt(甘特图) 开发指南
转载来自: http://www.cnblogs.com/liusuqi/archive/2013/06/09/3129293.html JQuery.Gantt是一个开源的基于JQuery库的用于实 ...
- JQuery.Gantt(甘特图)开发
一.简介 JQuery.Gantt是一个开源的基于JQuery库的用于实现甘特图效果的可扩展功能的JS组件库. 二.前端页面 2.1 资源引用 首先需要将下载到的源码中的CSS.IMG.JS等资源放入 ...
- 甘特图 (Gantt )的优缺点
时间管理 - 甘特图 (Gantt ) 优点:甘特图直观.简单.容易制作,便于理解,能很清晰地标识出直到每一项任务的起始与结束时间,一般适用比较简单的小型项目,可用于WBS的任何层次.进度控制.资源优 ...
随机推荐
- ES6常见面试题
1.es5和es6的区别,说一下你所知道的es6 ECMAScript5,即ES5,是ECMAScript的第五次修订,于2009年完成标准化 ECMAScript6,即ES6,是ECMAScript ...
- 9.4 Go 数据格式
9.4 Go 数据格式 1.1. msgpack格式 官方msgpack官网用一句话总结: It’s like JSON. but fast and small. 简单来讲,它的数据格式与json类似 ...
- rasdaman介绍及安装
一.分布式介绍 Rasdaman中的主节点称为Rasdaman的主机,它充当中央Rasdaman请求分派器并且控制所有服务器进程.Rasdaman管理器接收客户机请求并将这些请求分配给服务器进程.服务 ...
- js得到文件后缀
js得到文件后缀 http://www.cnblogs.com/lan0725/archive/2010/05/25/1873745.html function getFileExt(str) { ...
- Python 字符串内置函数(四)
# 4.类型判断# isalnum()函数检测字符串是否只由字母和数字组成.s = "this2009"; # 字符中没有空格print(s.isalnum()) # 结果:Tru ...
- Spring注入的对象到底是什么类型
开篇 之前,在用spring编码调试的时候,有时候发现被自动注入的对象是原始类的对象,有时候是代理类的对象,那什么时候注入的原始类对象呢,有什么时候注入的是代理类的对象呢?心里就留下了这个疑问.后来再 ...
- js操作html的基本方法
刚学了js操作html的基本方法,在写代码过程中,有很多格式不规范,忘记加双引号尤其重要,通常这 样的错误很容易范,并且这种错误很难找.随着代码学习量越来越多,很多写法容易搞混.今天记录一下,以便后期 ...
- 【Gabor】基于多尺度多方向Gabor融合+分块直方图的表情识别
Topic:表情识别Env: win10 + Pycharm2018 + Python3.6.8Date: 2019/6/23~25 by hw_Chen2018 ...
- [python爬虫]简单爬虫功能
在我们日常上网浏览网页的时候,经常会看到某个网站中一些好看的图片,它们可能存在在很多页面当中,我们就希望把这些图片保存下载,或者用户用来做桌面壁纸,或者用来做设计的素材. 我们最常规的做法就是通过鼠标 ...
- 如何开启远程桌面连接功能?windows的远程桌面连接功能使用步骤
由于远程桌面的诞生,为电脑工作者提供了极大的便利.首先,推荐1款比较适合服务器管理的远程桌面: 可以管理1000+服务器/vps的远程桌面:IIS7远程桌面管理 开启远程桌面功能步骤: 1.右键点击电 ...