echarts 自定义甘特图

效果

在这里插入图片描述
echarts 官网实例

思路

官网展示的甘特图,其实也是通过自定义type: 'custom'实现的。
在这里插入图片描述
1.grid,xAxis,yAxis属性可以根据你的业务需求进行样式调整。
2.tooltip,是可选的主要控制的是甘特图鼠标hover的提示文字。
3.series是核心代码。

实现

核心代码如下

      series: [
        {
          id: 'flightData',
          type: 'custom',
          renderItem: (params:any, api:any)=>{
            // seriesData 是每个甘特图段的数据值
            console.log(seriesData,'seriesData')
            let color = api.value(DIM_TIME_TASK) === currentTask ? currentColor : 'grey'
            // color 是根据我的业务需求进行的,单行甘特段颜色设置
            var categoryIndex = api.value(DIM_CATEGORY_INDEX);
            var timeArrival = api.coord([api.value(DIM_TIME_ARRIVAL), categoryIndex]); //单个段落起始值
            var timeDeparture = api.coord([api.value(DIM_TIME_DEPARTURE), categoryIndex]);//单个段落结束值
            var barLength = timeDeparture[0] - timeArrival[0] || 50;
            var barHeight = api.size([0, 1])[1] * HEIGHT_RATIO;
            var x = timeArrival[0];
            var y = timeArrival[1] - barHeight;
            var rectNormal = this.clipRectByRect(params, {
              x: x,
              y: y,
              width: barLength,
              height: barHeight,
            });
          console.log(rectNormal,'rectNormal')
            return {
              type: 'group',
              children: [
                {
                  type: 'rect',
                  shape: rectNormal,
                  style: api.style({                                 
                    fill: color,
                    textFill: '#fff',
                    text:aliasValue ? api.value(DIM_TIME_AlIAS)  + '' : api.value(DIM_TIME_TASK) + ''
                  })
                },
              ]
            };
          },
          encode: {
            x: [DIM_TIME_ARRIVAL, DIM_TIME_DEPARTURE],
            y: DIM_CATEGORY_INDEX,
            tooltip: [aliasValue ? DIM_TIME_AlIAS : DIM_TIME_TASK, DIM_TIME_ARRIVAL , DIM_TIME_DEPARTURE]  //此处控制tooltip展示的值
          },
          data:seriesData
        },
        {
          type: 'custom',
          renderItem: (params:any,api:any)=>{
            var interval = api.size([0,1])[1]
            var newY = api.coord([0, api.value(0)])[1];
            if (newY < params.coordSys.y + 5) {
              return;
            }
            return {
              type: 'group',
              position: [60, newY - interval/2 ],
              children: [
                {
                  type: 'text',
                  style: {
                    text:arrDataY[api.value(0)],
                    textAlign: 'center',
                    textFill: colorY,
                  }
                }
              ]
            };
          },
          encode: {
            x: -1,
            y: 0
          },
          data: arrDataY.map((it:any,i:number)=>i)
        }
      ]

先来看ganttItem的实现在这里插入图片描述

请仔细看seriseData的值,会发现下标为0,1名字都是demo,最后一项都是0,6,7都是demo14,最后一项都是5,那是因为是我将后台返回的数据进行了进行分组(分组方法下面会讲到)。

同时会按照分组后,为其添加下标,官网数据也是如此的,。

也就是说,如果想让甘特图一行显示多块儿,就要满足这两个数组会有同样的值(注意:这个值必须是数字,在canvas绘制并且会根据你的这个值进行排序绘画),这也就是为什么我的demo会显示在最下面第一行。

细心的同学也就会发现renderItem 其实是循环处理的seriesData,如上图我打印的4,0,1分别就对应了排序下标,开始时间,结束时间。

简而言之:就是将data数据组成 [ [单个甘特段开始值,单个甘特段结束值,当前甘特行在哪行显示的下标] ],其余的都可以不要

数组对象分组处理

export const getSeriesData = (arr:Array<any>,taskVal:string)=>{
    // arr 原始数据  taskVal 根据哪个字段进行分组 我是根据 task进行的分组
    let arrData:any = [];
    console.log(arr,'原始数据 两笔数据')
    // 第一步 query 数据整合
    arr.forEach((item:any)=>{
        let fieldList:any = []
        item.fields.forEach((it:any) => {
            fieldList.push({
                name:it.name,
                value:it.values.buffer
            })

        });     
        const fieldData = getFieldData(fieldList)
        arrData = arrData.concat(fieldData.newArr);
    })

    console.log(arrData,'将两笔数据进行整合')

    // 第二部 根据task进行分组处理
    var taskRather:any = []
    var taskArr:any = []
    for(let i = 0 ; i < arrData.length ; i ++){
        const arrDataInfo = arrData[i];
        if(!taskRather.find((it:string)=>it === arrDataInfo[taskVal])){
            // 不重复task
            taskArr.push({
                task:arrDataInfo[taskVal],
                children:[arrDataInfo]
            })
            taskRather.push(arrDataInfo[taskVal])
        }else{
            // 重复的task
            for(let j = 0 ; j < taskArr.length ; j ++){
                const taskInfo = taskArr[j];
                if(arrDataInfo[taskVal] === taskInfo.task){
                    taskInfo.children.push(arrDataInfo)
                }
            }
        }
    }
    
    console.log(taskArr,'分组后的数据')

    // 第三步生成对应的index,用于在panel显示 tips:必须判断children长度,进行newData添加
    let newData:any = [ ]
    for(let i = 0 ; i < taskArr.length ; i ++ ){
        const taskInfo = taskArr[i];
        if(taskInfo.children.length > 1){
            for(let j = 0 ; j < taskInfo.children.length; j ++){
                const data = taskInfo.children[j]
                data.group = i
                newData.push(Object.values(data))
            }
        }else{
            for(let j = 0 ; j < taskInfo.children.length; j ++){
                const data = taskInfo.children[j]
                data.group = i
                newData.push(Object.values(data))
            }
        }
    }

    console.log(newData,'最后组成的符合echarts的数据')
    return {
        arrData:newData,
        
    }
}
export const getFieldData = (arr:Array<any>)=>{
    let newArr:any = [];
    
    for(let i = 0 ; i < arr[0].value.length ; i ++){
        let obj:any = {}
        for(let j = 0 ; j < arr.length ; j ++){
         
            obj[arr[j].name] = arr[j].value[i]
        }
        newArr.push(obj)
    }
    return {newArr}
    
}

运行结果如下
在这里插入图片描述
在这里插入图片描述

y轴自定义的实现就相对简单些

在这里插入图片描述
arrDataY 就对应了每行的名字,data取下标就变成了[0,1,2,3,4,5]。

有个注意点是position: [60, newY - interval/2 ], 我对interval/2这样y轴的文字就会显示在每行的中间位置上,不/2就会在每行x轴显示。

yAxis的max属性 换成rrDataY.length 即可

    yAxis: {
      axisTick: { show: false },
      splitLine: { show: false},
      axisLine: { show: true },
      axisLabel: { show: true },
      min: 0,
      max:arrDataY.length
    },

总结

其实甘特图整个不是特别复杂,只需要组成echarts符合的数据就好,官网的功能更复杂所以看起来很复杂。

为方便理解:可以将下面testData进行替换GanttItem中的data值,就会很明显的理解了

const testData = [
  [
    '0',
    1496840400000,  //2017-6-7 21:0:0
    1496934000000,  //2017-6-8 23:0:0
  ],[
    '1',
    1496924700000,  //2017-6-8 20:25:0
    1496934000000, //2017-6-8 23:0:0
  ],[
    '1',
     1496840400000,  //2017-6-7 21:0:0
     1496878800000,  //2017-6-8 7:40:0
  ],[
    '2',
    1496916600000,  //2017-6-8 18:10:0
    1496934000000,//2017-6-8 23:0:0
  ]
]
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值