使用 Echarts 实现项目进度甘特图

您所在的位置:网站首页 里程碑进度表 使用 Echarts 实现项目进度甘特图

使用 Echarts 实现项目进度甘特图

2024-07-10 00:59| 来源: 网络整理| 查看: 265

 Echarts 功能十分强大,可以实现多种图表效果,下面简单介绍下最近使用 Eharts 实现的一个项目进度甘特图。

下面是实现的效果:

目录

一.概览 Echarts 基本内容

1.官网文档

2.查看示例

二.需求分析

1.数据系列(series)

2.标线 (markLine)

3.数据对象结构

4.“超时”、“按时”划分

三.引入并配置 Echarts

1.坑

2.具体操作

四.说明

一.概览 Echarts 基本内容 1.官网文档

首先基本的前端搭建必须的,然后应该大致浏览一下 Echarts 官网 文档 专题下的 教程 和 配置项手册,如果不是要实现特别复杂的效果和功能,这些内容基本就足够了。

2.查看示例

只看文字内容比较抽象,因为要做甘特图,可以先去 实例 中找一个甘特图研究下,看看别人是怎么实现的。你会发现Echarts官网好像只能在 实例 下找到官方示例图,别急,操作一番就可以看其他无私的贡献者发布的图表了。

点击官网页面右上角 “EN”,切换为英文版,

在 Get Started 下 点击 Gallery,

这样就能看到其他开发者贡献的 Demo 了,

点击 展开筛选,筛选你要找的图表类型。

下面这个图表(点击这里查看该图表Demo)和我们要实现的效果还是有几分类似的:

当然细节还得自己研究修改一下。

二.需求分析

从文章开头的图表效果来看,横坐标刻度值为时间,纵坐标为 “方案”、“纲要”、“成果” 三个项目阶段类目,每个阶段类目中包含按时完成(蓝色柱状图)和超时完成(红色柱状图)两种系列的数据,另外还有垂直于 x 时间坐标轴的 “计划开始时间”和“有效期”两条时间标线。结合查阅官网文档和demo,应该有以下初步结论:

1.数据系列(series)

每个阶段类目中实际应该有三种系列(series)的数据的,即应该有 开始时间、按时完成时间和超时完成时间三种系列,且三种系列的柱状图是堆叠在一起的。

2.标线 (markLine)

“计划开始时间” markLine 可以放在在 开始时间series 中,“有效期”markLine可以在 按时完成 或 超时完成 series 中。

3.数据对象结构

这里比较容易理解的传值结构,应该是传入 三个时间段 和 两个刻度值,类似下面这种结构:

/** * 存储阶段进度的对象 */ var stageProgress = { // 方案 实际时间段 fangAnTimeBucket: ['2017-01-01', '2017-03-01'], // 纲要 实际时间段 gangYaoTimeBucket: ['2017-02-26', '2017-08-29'], // 成果 实际时间段 chengGuoTimeBucket: ['2017-08-29', '2017-12-06'], // 计划开始时间 scheduledStartTime: '2016-12-22', // 有效截止日期 validTime: '2017-05-10' };

4.“超时”、“按时”划分

这里要求三个阶段实际时间段的首尾可以不连续,即三个阶段之间没有影响,所以,是否超时就取决于 有效期 与 阶段实际时间段 之间的关系了。比如,有效期在阶段实际时间段开始和结束时间之间,那么该阶段是超时的,但是该阶段的柱状图应该是蓝色红色共存的;有效期在阶段实际时间段结束时间之后,那么该阶段按时完成,应该都是蓝色的;有效期在阶段实际时间段开始时间之前,那么该阶段超时完成,应该都是红色的。

其实主要是第四点需要计算一下,其他 参考一下 配置项手册基本没有太大问题。

三.引入并配置 Echarts 1.坑

用新不用旧,但是经过我的测试,Echarets4.x 透明堆叠不起效果,即设置了 series 为 bar ,且 开始时间、按时完成时间、按时完成时间 三个 series 设置了 相同的 stack 后,开始时间 柱状图并不能起到遮盖其他系列柱状图的效果,于是尝试使用3.x 版本,是可以起到柱条堆叠辅助隐藏的效果的。(请同学们注意!!!评论区的seuedu同学指出,在4.x版本中,series里配置z属性可以覆盖,但本人未进行验证,请大家自行验证下!!!)

若果需要兼容 IE8 的话,那么你需要定制下载  Echarts(我在实际测试中发现,这个定制下载即使选中 兼容IE8 ,下载下来的js仍让无法兼容 IE8,真的是让人脑壳痛)。

2.具体操作

在你的页面中,放置一个 div,作为放置图表的容器,需要为它指定宽高。

控制图表的 js 代码基本结构如下:

// 基于准备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('main')); // 指定图表的配置项和数据 var option = { title: { text: 'ECharts 入门示例' }, tooltip: {}, legend: { data:['销量'] }, xAxis: { data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"] }, yAxis: {}, series: [{ name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] }] }; // 使用刚指定的配置项和数据显示图表。 myChart.setOption(option);

下面是实现本文开头图表效果的 js,方法说明和需要注意的点基本都写在注释里了:

/** * 存储阶段进度时间段的对象 */ var stageProgress = { // // 方案 实际时间段 // fangAnTimeBucket: ['2017-01-01', '2017-03-01'], // // 纲要 实际时间段 // gangYaoTimeBucket: ['2017-02-26', '2017-08-29'], // // 成果 实际时间段 // chengGuoTimeBucket: ['2017-08-29', '2017-12-06'], // // 计划开始时间 // scheduledStartTime: '2016-12-22', // // 有效截止日期 // validTime: '2017-05-10' // // 方案 实际时间段 // fangAnTimeBucket: ['2017-01-01', '2017-01-20'], // // 纲要 实际时间段 // gangYaoTimeBucket: ['2017-02-07', '2017-02-28'], // // 成果 实际时间段 // chengGuoTimeBucket: ['2017-02-15', '2017-03-20'], // // 计划开始时间 // scheduledStartTime: '2017-01-01', // // 有效截止日期 // validTime: '2017-02-20' // 方案 实际时间段 fangAnTimeBucket: ['2017-11-23', '2017-11-28'], // 纲要 实际时间段 gangYaoTimeBucket: ['2017-11-25', '2017-11-30'], // 成果 实际时间段 chengGuoTimeBucket: ['2017-12-06', '2017-12-12'], // 计划开始时间 scheduledStartTime: '2017-11-23', // 有效截止日期 validTime: '2017-12-02' }; /** * 横坐标轴时间刻度可选值 * 这里 month和year 没有考虑平闰年之分 */ var timeInterval = { day: 3600 * 1000 * 24, month: 3600 * 1000 * 24 * 31, year: 3600 * 1000 * 24 * 31 * 12, }; /** * 时间坐标轴标签单位应该精确到哪一位 */ var xAxisLabelUnit = { year: false, month: false, day: false } /** * 获取合适的横坐标时间刻度间隔 */ function getProperTimeAxisInterval() { xAxisLabelUnit.year = false; xAxisLabelUnit.month = false; xAxisLabelUnit.day = false; var timeDataArray = getXAxisData(); var begin = getTimeMilliseconds(timeDataArray[timeDataArray.length - 1]); console.log("begin " + begin); var periodMillis = getTimeMilliseconds(timeDataArray[timeDataArray.length - 1]) - getTimeMilliseconds(timeDataArray[0]); console.log("periodMillis " + periodMillis); var years = periodMillis / timeInterval.year; console.log("years " + years); var months = periodMillis / timeInterval.month; console.log("months " + months); var days = periodMillis / timeInterval.day; console.log("days " + days); if (months = stageCompletionTimeMillis) { // 若有效期大于等于阶段完成时间,则阶段按时完成 return stageCompletionTimeStr; } } /** * 获取阶段内的超时完成时间(红色色柱状图值) * @param {Object} stage 阶段 * @param {Object} stateBeginTime * @param {Object} stateCompletionTime */ function getOverTimeCompletionTime(stage, stageBeginTimeStr, stageCompletionTimeStr) { var validTimeMillis = getTimeMilliseconds(stageProgress.validTime); var stageBeginTimeMillis = getTimeMilliseconds(stageBeginTimeStr); var stageCompletionTimeMillis = getTimeMilliseconds(stageCompletionTimeStr); if (validTimeMillis < stageCompletionTimeMillis) { // 阶段完成时间大于有效期,则将阶段完成时间作为超时时间返回 return stageCompletionTimeStr; } if (validTimeMillis >= stageCompletionTimeMillis) { // 阶段完成时间小于等于有效期,则阶段按时完成,超时时间应为'-' return '-'; } } /** * 根据时间字符串获取对应的毫秒值 * @param {Object} timeStr 时间字符串 */ function getTimeMilliseconds(timeStr) { return (new Date(timeStr)).getTime(); } /** *获取时间坐标轴的起始和结束值 */ function getProperTimeAxisBeginAndEndTime() { var xAxis = getXAxisData(); var begin = xAxis[0]; var end = xAxis[xAxis.length - 1]; var beginDate = new Date(begin); var endDate = new Date(end); if (xAxisLabelUnit.month) { beginDate.setDate(1); endDate.setMonth(endDate.getMonth() + 1); endDate.setDate(1); } else { var daysCount = getProperTimeAxisInterval() / timeInterval.day; console.log("daysCount " + daysCount); beginDate.setDate(beginDate.getDate() - daysCount); endDate.setDate(endDate.getDate() + daysCount); } var beArr = [formatDateToStr(beginDate), formatDateToStr(endDate)]; console.log("beArr " + beArr); return beArr; } 四.后续需求修改1

最近需求有修改,需要在 “方案”、“纲要”和“成果” 三个阶段的每个阶段都显示两个柱条,来显示对应阶段的实际用时和计划用时,在每个阶段中,实际用时柱条在上,计划用时柱条在下,突出对比效果,并且实际用时的柱条要可以显示蓝色(计划内用时)和红色(超时用时)两种颜色柱条的堆叠,同时移除之前的贯穿三个阶段的 “计划开始时间”和“有效期” markLine,最后修改成这个效果

这里需要修改的地方主要有:

去掉 markLine 配置。在 series 中,新增另一个 stack: '计划'来显示计划用时柱条。同时由于在一个阶段中已经有了一个新柱条可以显示某一阶段的计划完成时间,所以在实际完成时间的柱条上,不再需要显示计划完成时间了(对应之前进度图中的有效期),防止文字挤压。getProperTimeAxisInterval() 方法中 在总的时间跨度 = stageCompletionTimeMillis) { // 若有效期大于等于阶段完成时间,则阶段按时完成 return stageCompletionTimeStr; } } /** * 获取阶段内的超时完成时间(红色色柱状图值) * @param {Object} stage 阶段 * @param {Object} stateBeginTime * @param {Object} stateCompletionTime * @param{Object} stagePlanCompletionTimeStr 阶段计划完成时间 */ function getOverTimeCompletionTime(stage, stageBeginTimeStr, stageCompletionTimeStr, stagePlanCompletionTimeStr) { // var validTimeMillis = getTimeMilliseconds(stageProgress.validTime); var validTimeMillis = getTimeMilliseconds(stagePlanCompletionTimeStr); var stageBeginTimeMillis = getTimeMilliseconds(stageBeginTimeStr); var stageCompletionTimeMillis = getTimeMilliseconds(stageCompletionTimeStr); if(validTimeMillis < stageCompletionTimeMillis) { // 阶段完成时间大于有效期,则将阶段完成时间作为超时时间返回 return stageCompletionTimeStr; } if(validTimeMillis >= stageCompletionTimeMillis) { // 阶段完成时间小于等于有效期,则阶段按时完成,超时时间应为'-' return '-'; } } /** * 根据时间字符串获取对应的毫秒值 * @param {Object} timeStr 时间字符串 */ function getTimeMilliseconds(timeStr) { return(new Date(timeStr)).getTime(); } /** *获取时间坐标轴的起始和结束值 */ function getProperTimeAxisBeginAndEndTime() { var xAxis = getXAxisData(); var begin = xAxis[0]; var end = xAxis[xAxis.length - 1]; var beginDate = new Date(begin); var endDate = new Date(end); if(xAxisLabelUnit.month) { beginDate.setDate(1); endDate.setMonth(endDate.getMonth() + 1); endDate.setDate(1); } else { var daysCount = getProperTimeAxisInterval() / timeInterval.day; console.log("daysCount " + daysCount); beginDate.setDate(beginDate.getDate() - daysCount); endDate.setDate(endDate.getDate() + daysCount); } var beArr = [formatDateToStr(beginDate), formatDateToStr(endDate)]; console.log("beArr " + beArr); return beArr; }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3