效果就是这个效果,好不好看另说,反正基本功能是有了。可以根据后台传入的数据列表动态生成甘特图。
1.甘特图显示在数据列表下方
2.甘特图时间轴保持一致
回看上面的图确实有问题啊,每个项目进度条似乎都一样!
国家节假日和周末不显示颜色
说明:
1、要注意工作日(周一至周五)可能是国家节假日,周末可能补班
2、下面代码中都有注释,说的很详细了哦
前几天在网上百度了一圈,发现echarts都没有甘特图的官方实例,highcharts倒是有,不过那图不忍直视。
偶然间发现这个可以做甘特图,进官网一看发现图挺美观的,而且官方还提供了多种甘特图实例,还集成了不同的前端框架,真是天助我也!
FusionCharts官网:https://www.fusioncharts.com/
API:https://www.fusioncharts.com/dev/chart-attributes/
先在Vue项目中装插件
npm install fusioncharts vue-fusioncharts --save
// 必须引入 vue-fusioncharts 和 fusioncharts
import VueFusionCharts from 'vue-fusioncharts';
import FusionCharts from 'fusioncharts/core';
// 可选,引入扁平画主题
import FusionTheme from 'fusioncharts/themes/es/fusioncharts.theme.fusion'
/* 重点: 想显示图形,必须引入对应图形类型模块 */
//比如 想做个饼图,需要引入pie2d模块
import Pie2D from 'fusioncharts/viz/pie2d'
//我要做的是甘特图,那么我得引入gantt 不知道就去官方示例js代码的type中查看
import gantt from 'fusioncharts/viz/gantt'
/* 引入完成下一步就需要放入Vue中,如下 */
Vue.use(VueFusionCharts, FusionCharts,FusionTheme, Pie2D, gantt);// 添加多个类型图形,就在后面添加上
官方简单甘特图例子:https://www.fusioncharts.com/charts/gantt-charts/simple-gantt-chart?framework=vue
上面图中有不同前端框架使用的例子
官方提供的组件和数据
vue中的data数据
type: "gantt",
width: "100%",
// height: "30%", //高度
dataFormat: "json",
dataSource: {
chart: {
dateformat: "mm/dd/yyyy",
caption: "Event Planning Process",
theme: "fusion",
canvasborderalpha: "40",
ganttlinealpha: "50"
},
tasks: {
color: "#5D62B5",
task: [
{
start: "03/07/2018",
end: "03/17/2018"
},
{
start: "03/14/2018",
end: "03/28/2018"
},
{
start: "03/15/2018",
end: "03/31/2018"
},
{
start: "04/02/2018",
end: "04/12/2018"
},
{
start: "04/12/2018",
end: "04/30/2018"
},
{
start: "04/20/2018",
end: "05/06/2018"
},
{
start: "04/30/2018",
end: "05/10/2018"
},
{
start: "04/30/2018",
end: "05/25/2018"
},
{
start: "05/04/2018",
end: "06/05/2018"
}
]
},
processes: {
headertext: "Task",
headeralign: "left",
fontsize: "14",
isbold: "0",
align: "left",
process: [
{
label: "Define event goals"
},
{
label: "Source venue options"
},
{
label: "Finalize speaker reach out list"
},
{
label: "Compose sponsorship strategy"
},
{
label: "Reach out to sponsors"
},
{
label: "Create social media campaign"
},
{
label: "Reach out to blogs for backlinks"
},
{
label: "Optimize SEO ranking"
},
{
label: "Publish event lead up vlog series"
}
]
},
categories: [
{
category: [
{
start: "03/05/2018",
end: "03/31/2018",
label: "March"
},
{
start: "04/01/2018",
end: "04/30/2018",
label: "April"
},
{
start: "05/01/2018",
end: "05/31/2018",
label: "May"
},
{
start: "06/01/2018",
end: "06/10/2018",
label: "June"
}
]
},
{
category: [
{
start: "03/05/2018",
end: "03/11/2018",
label: "W 1"
},
{
start: "03/12/2018",
end: "03/18/2018",
label: "W 2"
},
{
start: "03/19/2018",
end: "03/25/2018",
label: "W 3"
},
{
start: "03/26/2018",
end: "04/01/2018",
label: "W 4"
},
{
start: "04/02/2018",
end: "04/08/2018",
label: "W 5"
},
{
start: "04/09/2018",
end: "04/15/2018",
label: "W 6"
},
{
start: "04/16/2018",
end: "04/22/2018",
label: "W 7"
},
{
start: "04/23/2018",
end: "04/29/2018",
label: "W 8"
},
{
start: "04/30/2018",
end: "05/06/2018",
label: "W 9"
},
{
start: "05/07/2018",
end: "05/13/2018",
label: "W 10"
},
{
start: "05/14/2018",
end: "05/20/2018",
label: "W 11"
},
{
start: "05/21/2018",
end: "05/27/2018",
label: "W 12"
},
{
start: "05/28/2018",
end: "06/03/2018",
label: "W 13"
},
{
start: "06/04/2018",
end: "06/10/2018",
label: "W 14"
}
]
}
]
}
引入了数据和组件,那么现在在Vue界面就可以看见图形了
基本介绍就是这样了,大家可以去试试了。
---------------分--------------------割-------------------线---------------
好,现在我来说说我的需求。现在页面的数据是写死的,不能动态变化,而且我需要的不止一个甘特图,有多少个项目就要显示几个图
首先,甘特图的显示是由官方主键来控制的,我的要求是根据项目数量动态生成多个图表。于是我在外层加了个v-for循环。
每一个图对应下方一个对象数据,我在方法里面组装好json数据,赋值给myChart,循环就ok了
myChart需要的基本格式如下
{
type: "gantt",
width: "100%",
height: "100%",
dataFormat: "json",
dataSource:{}
},
{
type: "gantt",
width: "100%",
height: "100%",
dataFormat: "json",
dataSource:{}
},
{
type: "gantt",
width: "100%",
height: "100%",
dataFormat: "json",
dataSource:{}
}
我贴出组装json数据的代码,有需要的小伙伴自行查看
具体内容在 chartsShow()方法里
data() {
return {
msgShow: true,
match: "",
pageSize: 0,
pageNumber: 0,
total: 0,
devProgress: "devProgress",
list: [],
myChart: [],
//2020年 周末补班日期
weekendWorkDateArr: [
// "2020-06-28", "2020-09-27", "2020-10-10"
],
//2020年 节假日
vacationArr: [
// "2020-06-25", "2020-06-26", "2020-06-27", "2020-10-01",
// "2020-10-02", "2020-10-03", "2020-10-04", "2020-10-05",
// "2020-10-06", "2020-10-07", "2020-10-08"
],
}
},
methods:{
// 日期,在原有日期基础上,增加days天数,默认增加1天
jiraAddDate(date, days) {
if (days === undefined || days === '') {
days = 1;
}
date = new Date(date);
date.setDate(date.getDate() + days);
var month = date.getMonth() + 1; //月份从0开始所以需要+1
var day = date.getDate();
return date.getFullYear() + '-' + this.getFormatDate(month) + '-' + this.getFormatDate(day);
},
// 日期 月份/天 的显示,如果是1位数,则在前面加上'0'
getFormatDate(arg) {
if (arg === undefined || arg === '') {
return '';
}
var re = arg + '';
if (re.length < 2) {
re = '0' + re;
}
return re;
},
/* 判断当天是否为周末 */
isWeekEnd(date) {
return "天一二三四五六".charAt(new Date(date).getDay()) === "天" || "天一二三四五六".charAt(new Date(date).getDay()) === "六";
},
/* 时间格式化 */
formatTime(dateVal) {
let year = dateVal.getFullYear(),
month = dateVal.getMonth() + 1,
day = dateVal.getDate();
if (month < 10) {
month = `0${month}`
}
if (day < 10) {
day = `0${day}`
}
return `${year}-${month}-${day}`
},
/* * 传入两个日期,得出范围内所有日期 传入yyyy-mm-dd 格式 */
generateFun(startTime, endTime) {
startTime = new Date(startTime);
endTime = new Date(endTime);
let timeStamp = Math.ceil((endTime.getTime() - startTime.getTime()) / (1000 * 60 * 60 * 24)),//判断两个日期相差多少天
timeArr = [];
for (let index = 1; index <= timeStamp; index++) {
const element = startTime.setTime((1000 * 60 * 60 * 24) + startTime.getTime());
timeArr.push(this.formatTime(new Date(element)))
}
return timeArr;
},
//计算日期天数差的函数,通用
dateDiff(firstDate, secondDate) {
firstDate = new Date(firstDate);
secondDate = new Date(secondDate);
var diff = Math.abs(firstDate.getTime() - secondDate.getTime());
return parseInt(diff / (1000 * 60 * 60 * 24));
},
//日期加减计算
addDate(date, days) {
var d = new Date(date);
d.setDate(d.getDate() + days);
var m = d.getMonth() + 1;
return d.getFullYear() + '-' + m + '-' + d.getDate();
},
//甘特图展示
chartsShow() {
let self = this;
var listArr = [];
var q = 0;
var tempListArr = [];
tempListArr = self.list;
for (var k = 0; k < tempListArr.length; k++) {
if (tempListArr[k].name.search("常规版本") !== -1) {//只需要常规版本
listArr[q++] = tempListArr[k];
}
}
var myChartArr = [];//定义空数组用来装每个图数据对象
var timeLineStart;
var timeLineEnd;//甘特图时间轴结束日期
for (let w = 0; w < listArr.length; w++) {
timeLineStart = listArr[w].starDate;
timeLineEnd = listArr[w].releaseDate;
break;
}
//甘特图时间轴开始日期
for (let e = 0; e < listArr.length; e++) {
if (new Date(listArr[e].starDate) <= new Date(timeLineStart)) {
timeLineStart = listArr[e].starDate;
}
if (new Date(listArr[e].releaseDate) >= new Date(timeLineEnd)) {
timeLineEnd = listArr[e].releaseDate;
}
}
var chartsStartTime = self.$options.methods.addDate(timeLineStart, -7);
var chartsEndTime = self.$options.methods.addDate(timeLineEnd, 1);
var days = self.$options.methods.dateDiff(chartsStartTime, chartsEndTime);//开始到结束总共多少天
for (var i = 0; i < listArr.length; i++) {
//这里存在问题 日期格式yyyy-mm-dd 月份和天数可能为单数
var starDate = listArr[i].starDate;//版本启动日期 需求结束时间
var frozenDate = listArr[i].frozenDate;//版本冻结日期
var releaseDate = listArr[i].releaseDate;//版本上线
var name = listArr[i].name;//版本名称,即甘特图名称
var categoriesArr = [];//甘特图dataSource下的categories数据数组
var taskArr = [];//甘特图dataSource下的tasks中task数组
var categoryArr = [];//甘特图dataSource下的categories中category数组
/* categoryArr 里面的时间要动态生成啊 且动态变化 */
for (var j = 0; j < days; j++) {
var time = self.$options.methods.addDate(chartsStartTime, j);
var labelTime = time.substring(5);// 将 yyyy-mm-dd 变为 mm-dd
//版本名称下方时间轴的日期显示
if (i === 0){
categoryArr.push({
"start":time,
"end":time,
"label":labelTime,
});
} else {
//第二个及以下的图不显示日期
categoryArr.push({
"start":time,
"end":time,
"label":" ",
});
}
}
categoriesArr.push({
"category":categoryArr,
});
let weekendWorkDateArr = self.weekendWorkDateArr;//周末补班日期
let vacationArr = self.vacationArr;//国家节假期
var demandDevEndTime = self.jiraAddDate(releaseDate, -1);
let tempDateArr = this.generateFun(starDate, demandDevEndTime);
/*-------------------------控制颜色显示----------------------------*/
//需求收集
taskArr.push({
"start":chartsStartTime,//需求收集开始时间 启动时间前7天
"end":self.$options.methods.addDate(starDate, -1),//需求收集结束时间
"color":"#409EFF",//显示颜色
"processid":"xqsj"
});
//版本启动
taskArr.push({
"start":self.$options.methods.addDate(starDate, -1),//版本启动时间
"end":starDate,//版本启动时间
"processid":"bbqd"
});
//循环每个日期 需求开发阶段
for (var v = 0; v < tempDateArr.length; v++) {
// 周末
if (self.isWeekEnd(tempDateArr[v])) {
if (weekendWorkDateArr !== 0) {
// 不是补班日期
if ( weekendWorkDateArr.indexOf(tempDateArr[v]) === -1 ) {
taskArr.push({
"start":self.$options.methods.addDate(tempDateArr[v], -1),
"end": tempDateArr[v],
"color":"#FFFFFF",
"processid":"xqkf"
});
} else {
// 是补班日期
taskArr.push({
"start":self.jiraAddDate(tempDateArr[v], -1),
"end": tempDateArr[v],
"color":"#41B883",
"processid":"xqkf"
});
}
} else {
//纯周末 没有补班日
taskArr.push({
"start":self.$options.methods.addDate(tempDateArr[v], -1),
"end":tempDateArr[v],
"color":"#FFFFFF",
"processid":"xqkf"
});
}
}
//是周一到周五
if (!self.isWeekEnd(tempDateArr[v])) {
//节假日不为空
if (vacationArr !== 0) {
// 不在国家节假日内 判断节假日数组中是否包含该日期
if (vacationArr.indexOf(tempDateArr[v]) === -1) {
taskArr.push({
"start":self.$options.methods.addDate(tempDateArr[v], -1),
"end":tempDateArr[v],
"color":"#41B883",
"processid":"xqkf"
});
} else {
// 在国家节假日内
taskArr.push({
"start":self.$options.methods.addDate(tempDateArr[v], -1),
"end":tempDateArr[v],
"color":"#FFFFFF",
"processid":"xqkf"
});
}
} else {
taskArr.push({
"start":self.$options.methods.addDate(tempDateArr[v], -1),
"end":tempDateArr[v],
"color":"#41B883",
"processid":"xqkf"
});
}
}
}
//需求冻结
taskArr.push({
"start":self.$options.methods.addDate(frozenDate, -1),//活动冻结期
"end":releaseDate,//活动冻结期结束时间(版本上线日期)
"color":"#E22018",//显示颜色
"processid":"xqdj"
});
//需求上线
taskArr.push({
"start":self.$options.methods.addDate(releaseDate, -1),//版本上线日期
"end":releaseDate,//版本上线日期
"color":"#FFD801",//显示颜色
"processid":"xqsx"
});
/*-------------------------控制颜色显示----------------------------*/
//甘特图需要的json数据格式
myChartArr.push({
"type":"gantt",//图类型
"width":"100%",//宽度
"dataFormat":"json",//数据格式
"dataSource":{
"categories":categoriesArr,//控制甘特图时间轴日期的显示
"processes":{
"width":"100%",
"headertext":"",
"headeralign":"left",
"fontsize":"14",
"align":"center",
"process":[
{ "label":"需求收集", "id":"xqsj" },
{ "label":"版本启动", "id":"bbqd" },
{ "label":"需求开发", "id":"xqkf" },
{ "label":"需求冻结", "id":"xqdj" },
{ "label":"需求上线", "id":"xqsx" }
],//图左侧5个子任务的名称
},
"tasks":{
"color":"#5D62B5",
"task":taskArr,//控制中间日期显示的范围、颜色
},
"chart":{
"dateformat":"yyyy-mm-dd",//时间格式
"caption":name,//版本名称,即甘特图名称
"theme":"fusion",
"canvasborderalpha":"40",
"ganttlinealpha":"50",
},
},//数据源
});
}
self.myChart = myChartArr;
}
}
1.直接把循环的主键拷贝到表格主键下方,对应的数据直接拷过来放到对应位置
2.时间轴:获取所有版本中的最早和最晚的日期
因为之前每个版本的图相对独立,日期获取的是当前版本的数据。现在我只想把时间轴变长一点,就先拿所有版本中的最早最晚的日期,然后获取总天数。这些数据在循环外面提前准备好,循环内部就直接拿来使用,这样就不用去拿对应版本的日期了。