美文网首页前端开发那些事儿
vue项目使用Echarts制作项目工期甘特图

vue项目使用Echarts制作项目工期甘特图

作者: 鹏多多 | 来源:发表于2021-06-28 10:21 被阅读0次

    1,前言


    项目迭代过程中,碰上一个需求,要求用甘特图的方式显示项目的工期进度,开完会我赶紧搜索一下甘特图是啥东东,大概了解之后,做出了如下样式

    Echarts版本4.5.0

    vue版本2.x

    甘特图

    2,布局和数据部分


    HTML部分

    <template>
        <div id="index">
            <div id="chart" />
        </div>
    </template>
    

    CSS部分

    <style lang="less" scoped>
    #chart{
        width: 100%;
        height: 500px;
        margin: 50px auto;
    }
    </style>
    

    data部分

    data() {
        return {
            chart: null, // chart实例
            chartData: [], // chart数据源
            startTime: '', // X轴起始时间
            endTime: '', // X轴终末时间
            yData: [], // Y轴项目类目
            dayTime: 3600 * 24 * 1000, // 一天的毫秒,因为01.01日-01.01日,也算一天
            initData: { // 可以认为是axios请求过来的数据res.data
                startTime: '2020-12-01', // X轴起始时间
                endTime: '2022-01-30', // X轴终末时间
                value: [
                  {
                    itemName: '项目一', // 项目名
                    value: [
                      0, // 索引
                      '2021-06-01', // 项目开始时间
                      '2021-08-30', // 项目结束时间
                      '2021-07-01', // 项目实际开始时间
                      '2021-07-28' // 项目实际结束时间
                    ]
                  },
                  {
                    itemName: '项目二',
                    value: [
                      1,
                      '2021-06-21',
                      '2021-07-21',
                      '2021-07-18',
                      '2021-08-10'
                    ]
                  },
                  {
                    itemName: '项目三',
                    value: [
                      2,
                      '2021-06-01',
                      '2021-06-22',
                      '2021-06-01',
                      '2021-06-22'
                    ]
                  },
                  {
                    itemName: '项目四',
                    value: [
                      3,
                      '2021-06-22',
                      '2021-06-30',
                      '2021-06-22',
                      '2021-07-05'
                    ]
                  },
                  {
                    itemName: '项目五',
                    value: [
                      4,
                      '2021-06-21',
                      '2021-07-06',
                      '2021-07-01',
                      '2021-07-30'
                    ]
                  },
                  {
                    itemName: '项目六',
                    value: [
                      5,
                      '2021-07-01',
                      '2021-07-21',
                      '2021-07-02',
                      '2021-07-30'
                    ]
                  },
                  {
                    itemName: '项目七',
                    value: [
                      6,
                      '2021-06-18',
                      '2021-09-30',
                      '2021-06-30',
                      '2021-10-10'
                    ]
                  }
                ]
              }
            }
        }
    

    3,制作甘特图


    由于是demo,所以用的自己的数据,首先给需要用到的变量赋值

    getData() {
        this.chartData = this.initData.value // chart的数据
        const arr = []
        this.chartData.forEach(item => {
          arr.push(item.itemName)
        })
        this.yData = arr // Y轴的类目标题
        this.startTime = this.initData.startTime // X轴开始值
        this.endTime = this.initData.endTime // X轴结束值
        this.setData()
    }
    

    赋值之后,根据值,定义初始参数配置

    setData() {
       const _this = this
       const param = {
         title: {
           text: '项目执行情况',
           left: 'center'
         },
         tooltip: {
           // 自定义提示信息
           // params为当前点击图形元素的数据信息的对象
           formatter(params) {
             // 计划开始时间
             let planStartDate = params[0].value[1]
             // 计划结束时间
             let planEndDate = params[0].value[2]
             // 实际开始时间
             let practiceStartDate = params[0].value[3]
             // 实际结束时间
             let practiceEndDate = params[0].value[4]
             // 项目周期(毫秒值):计划结束日期 - 计划开始日期
             // eslint-disable-next-line
             let projectCycle_millisecond = +Echarts.number.parseDate(params[0].value[2]) - +Echarts.number.parseDate(params[0].value[1])
             // 项目周期(天数)
             let projectCycle_days = projectCycle_millisecond / _this.dayTime + 1
             return params[0].name + '<br/>'
               + '计划开始时间:' + planStartDate + '<br/>'
               + '计划结束时间:' + planEndDate + '<br/>'
               + '项目周期:' + projectCycle_days + '天<br/>'
               + '实际开始时间:' + practiceStartDate + '<br/>'
               + '实际结束时间:' + practiceEndDate
           }
         },
         dataZoom: [
           {
             // 区域缩放组件的类型为滑块,默认作用在x轴上
             type: 'slider',
             // 区域缩放组件的过滤模式,weakFilter:在进行区域缩放时,允许图形的一部分在坐标系上(可见),另一部分在坐标系外(隐藏)
             filterMode: 'weakFilter',
             showDataShadow: false,
             top: 450,
             height: 10,
             // 区域缩放组件边框颜色
             borderColor: 'transparent',
             // 区域缩放组件边框背景
             backgroundColor: '#e2e2e2',
             // 区域缩放组件上的手柄的样式
             // eslint-disable-next-line
             handleIcon: 'M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z',
             // 手柄大小
             handleSize: 20,
             // 为手柄设置阴影效果
             handleStyle: {
               shadowBlur: 6,
               shadowOffsetX: 1,
               shadowOffsetY: 2,
               shadowColor: '#aaa'
             },
             labelFormatter: ''
           },
           {
             // 区域缩放组件的类型为内置在坐标系中,默认作用在x轴的坐标系中
             type: 'inside',
             // 区域缩放组件的过滤模式,weakFilter:在进行区域缩放时,允许图形的一部分在坐标系上(可见),另一部分在坐标系外(隐藏)
             filterMode: 'weakFilter'
           }
         ],
         // 图表底板
         grid: {
           height: 330,
           tooltip: {
             trigger: 'axis',
             axisPointer: {
               type: 'shadow'
             }
           }
         },
         xAxis: {
           // x轴类型为时间轴
           type: 'time',
           // 最小值
           min: _this.startTime,
           // 最大值
           max: _this.endTime,
           axisLabel: {
             // 强制显示所有标签
             interval: 0
           }
         },
         yAxis: {
           data: _this.yData
         },
         legend: {
           selectedMode: false,
           left: '70%',
           top: 10,
           data: ['计划工期', '实际工期']
         },
         series: [
           {
             type: 'custom',
             // 使用自定义的图形元素
             renderItem: _this.renderItem,
             name: '计划工期',
             itemStyle: {
               opacity: 0.7,
               color: '#409EFF'
             },
             encode: {
               // 将维度1和维度2的数据映射到x轴
               x: [1, 2],
               // 将维度0的数据映射到y轴
               y: 0
             },
             data: _this.chartData
           },
           // 没有给它设置data,只是为了通过这个系列,显示图例(legend)而已
           {
             type: 'custom',
             name: '实际工期',
             itemStyle: {
               color: '#F56C6C'
             }
           }
         ]
       }
       this.init(param)
     }
    

    上述参数配置中,还需定义一下自定义的图形绘制方法

    // params为data中的数据项的信息对象 api是可调用的方法集合,可以对data中的数据项进行操作
    renderItem(params, api) {
          // 取出data中数据项的第一个维度的值
          let categoryIndex = api.value(0)
          // ===============计划工期进度条
          // 计划开始日期(在屏幕上的像素值)
          // 将数据项中的数值对应的坐标系上的点,转换为屏幕上的像素值
          // 坐标系上的点:是数据项映射到坐标系的x轴和y轴后,对应的位置
          // 屏幕上的像素值:是坐标系上的点,在屏幕上的位置
          let planStartDate = api.coord([api.value(1), categoryIndex])
          // 计划结束日期(在屏幕上的像素值)
          let planEndDate = api.coord([api.value(2), categoryIndex])
          // 由于data.value中维度1和维度2的数据会被映射到x轴,而x轴的type为time,即时间轴,
          // 所以api.value(1)和api.value(2)获取到的值是将日期转换后的毫秒值
          // 设置图形的高度
          // 获得Y轴上数值范围为1的一段所对应的像素长度;这是官方文档的注释,对于api.size()方法,目前我还不是很理解;先做个标记??? 以后再说
          let height = api.size([0, 1])[1] * 0.4
          let width = planEndDate[0] - planStartDate[0]
          if (width <= 10) {
            width = 3
          }
          // 使用graphic图形元素组件,绘制矩形
          // clipRectByRect方法,在绘制矩形时,如果矩形大小超出了当前坐标系的包围盒,则裁剪这个矩形
          let rectShape1 = Echarts.graphic.clipRectByRect({
            // 矩形的位置
            x: planStartDate[0],
            y: planStartDate[1],
            // 矩形的宽高
            width,
            height
          },
          {
            // 当前坐标系的包围盒
            x: params.coordSys.x,
            y: params.coordSys.y,
            width: params.coordSys.width,
            height: params.coordSys.height
          })
          // ===============实际工期进度条
          let rectShape2 = null
          // 判断实际开始日期和结束日期是否为空
          if (api.value(3) !== '' && api.value(4) !== '') {
            // 实际开始日期(在屏幕上的像素值)
            let practiceStartDate = api.coord([api.value(3), categoryIndex])
            let practiceEndDate = api.coord([api.value(4), categoryIndex])
            let widthNum = practiceEndDate[0] - practiceStartDate[0]
            if (widthNum <= 5) {
              widthNum = 3
            }
            // 使用graphic图形元素组件,绘制矩形
            // clipRectByRect方法,在绘制矩形时,如果矩形大小超出了当前坐标系的包围盒,则裁剪这个矩形
            rectShape2 = Echarts.graphic.clipRectByRect({
              // 矩形的位置
              x: practiceStartDate[0],
              y: practiceStartDate[1],
              // 矩形的宽高
              width: widthNum,
              height
            }, {
              // 当前坐标系的包围盒
              x: params.coordSys.x,
              y: params.coordSys.y,
              width: params.coordSys.width,
              height: params.coordSys.height
            })
          }
          let lineObj = {}
          // 如果项目还没开始,那么只渲染计划工期的进度条
          if (rectShape2 === null) {
            // 设置绘制的矩形的元素定义
            lineObj = rectShape1 && {
              type: 'group',
              children: [
                {
                  // 类型为矩形
                  type: 'rect',
                  // 具体形状
                  shape: rectShape1,
                  // 样式
                  style: api.style({
                    fill: '#409EFF'
                  })
                }
              ]
            }
          } else {
            // 渲染计划工期和实际工期
            // 设置绘制的矩形的元素定义
            lineObj = rectShape1 && rectShape2 && {
              type: 'group',
              children: [
                {
                  // 类型为矩形
                  type: 'rect',
                  // 具体形状
                  shape: rectShape1,
                  // 样式
                  style: api.style({
                    fill: '#409EFF'
                  })
                },
                {
                  // 类型为矩形
                  type: 'rect',
                  // 具体形状
                  shape: rectShape2,
                  // 样式
                  style: api.style({
                    fill: '#F56C6C'
                  })
                }
              ]
            }
          }
          return lineObj
        }
    

    这些都ok,我们就可以初始化chart了

    init(param) {
        this.chart = Echarts.init(document.getElementById('chart'))
        this.chart.setOption(param)
     }
    

    大功告成


    如果看了觉得有帮助的,我是@鹏多多11997110103,欢迎 点赞 关注 评论;
    END

    往期文章

    个人主页

    相关文章

      网友评论

        本文标题:vue项目使用Echarts制作项目工期甘特图

        本文链接:https://www.haomeiwen.com/subject/vjcqultx.html