echarts 自定义配置信息

519 阅读7分钟

echarts 自定义配置信息

renderItem 函数提供了两个参数:

  • params:包含了当前数据信息和坐标系的信息。
  • api:是一些开发者可调用的方法集合。

一、前移半格

renderItem 实现

option = {
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value',
   
  },
  series: [
    {
      type: 'custom',
      renderItem:function(params, api){
      const xIndex = params.dataIndex;
      // 横线
      const horizontalPoint = api.coord([xIndex, api.value(0)]);
      // 竖线
      const verticalPoint = api.coord([xIndex, api.value(1)]);
      const halfWidth = api.size([1, 0])[0] * 0.5;
      const style = api.style({
        stroke: api.visual('color'),
        fill: undefined
      });

      const customObj = {
          type: 'group',
          children: [
              {
                  //横线
                  type: 'line',
                  shape: {
                      x1: horizontalPoint[0] - halfWidth,
                      y1: horizontalPoint[1],
                      x2: horizontalPoint[0] + halfWidth,
                      y2: horizontalPoint[1]
                  },
                  style: style
              },
              {
                  //竖线
                  type: 'line',
                  shape: {
                      x1: horizontalPoint[0] + halfWidth,
                      y1: horizontalPoint[1],
                      x2: verticalPoint[0] + halfWidth,
                      y2: verticalPoint[1]
                  },
                  style: style
              },


          ]
      }



       const pointDraw = {
          // 小圆点-在横线中间
          type: 'circle',
          x: horizontalPoint[0] + halfWidth,
          y: horizontalPoint[1],
          shape: {
              cx: horizontalPoint[0],
              cy: horizontalPoint[1],
              r: 2.2
          },
          style
      }

        // customObj.children.push(pointDraw)

       return customObj;

      },
     data:[[12, 80], [80, 14], [14, 14], [14, 8], [8]]
    }
  ]
};

效果:

image.png

补充

/** 
 * 自定义数据过滤
 * [12, 80, 14, 14, 8] 转成 [[12, 80], [80, 14], [14, 14], [14, 8], [8]]
 */
customDataFilter(data) {
    let arr = [];
    for (let i = 0; i < data.length; i++) {
        if (data[i + 1]) {
            arr.push(['', data[i], data[i + 1]]);
        } else {
            arr.push(['', data[i]]);
        }
    }
    return arr;
},

二、划分多区域

graphic 结合 renderItem 实现

/*
xAxis横坐标数据源
说明:上下限个数必须同横坐标一一对应
格式:[21, 43.5, 64, 84, 100]
*/
var xAxis = [21, 43.5, 64, 84, 100]

/*
seriesData上下限数据源
说明:二维数组,每组length必须相同,下限在前上限在后,必须一一对应
格式:[
[10, 10, 10, 10, 10, 20, 20, 20, 30, 30],//前5个为下限值,后5个为上限值
      [50, 50, 50, 50, 50, 70, 70, 70, 80, 80],
      [81, 81, 81, 81, 81, 92, 92, 92, 92, 92]
]


markLine 自定义标线
说明:自定义
格式:
 {
        symbol: 'none', //去掉箭头
        data: [
          // { type: 'average', name: 'Avg' },
          {
            yAxis: 20,
            symbol: 'circle',
            label: {
              position: 'middle',
              formatter: `装机容量(MW)`
            },
            lineStyle: {
              color: 'red',
              dashOffset: 5
              // type: 'solid'
            }
          }
        ]
      }
*/
var  seriesData = [
    [10, 10, 10, 10, 10, 20, 20, 20, 30, 30],
    [50, 50, 50, 50, 50, 70, 70, 70, 80, 80],
    [81, 81, 81, 81, 81, 92, 92, 92, 92, 92]
  ]


var colorArr = ['#ee6666', '#5470c6', '#91cc75', '#fac858', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#8f85f6']
var MyCubeRect = echarts.graphic.extendShape({
  shape: {
    x: 0,
    y: 0
  },
  buildPath: function (ctx, shape) {
    // const xAxis = vm.xAxis;
    const api = shape.api;
    //处理数据取出上限下限的值
    let yMinArr = [];
    let yMaxArr = [];
    for (let i = 0; i < xAxis.length; i++) {
      yMinArr.push(shape['yMin' + i]);
      yMaxArr.push(shape['yMax' + i]);
    }
    //坐标系列
    xAxis?.length &&
      xAxis.map((item, index) => {
        if (index === 0) {
          ctx.moveTo(api.coord([xAxis[index], yMinArr[index]])); //起始点
        }
        const yPoint = api.coord([xAxis[index], yMinArr[index]]);
        ctx.lineTo(yPoint[0], yPoint[1]); //1
      });
    xAxis?.length &&
      xAxis.map((item, index) => {
        const yPoint = api.coord([xAxis[xAxis.length - index - 1], yMaxArr[xAxis.length - index - 1]]);
        ctx.lineTo(yPoint[0], yPoint[1]); //1
      });
    ctx.closePath();
  }
});

echarts.graphic.registerShape('MyCubeRect', MyCubeRect);


var  option={
    xAxis: {
      name: '测试x',
      type: 'value'
    },
    yAxis: {
      name: '测试y',
      type: 'value'
    },
    series: [
      {
        type: 'custom',
        data: seriesData,
        // markLine: vm.markLine,
        renderItem: function (params, api) {
          console.log('params: ', params);
          let shapeObj = {};
          for (let i = 0; i < xAxis.length; i++) {
            shapeObj['yMin' + i] = api.value(i);
            shapeObj['yMax' + i] = api.value(i + xAxis.length);
          }
          return {
            type: 'group',
            children: [
              {
                type: 'MyCubeRect', // 自定义shape
                shape: {
                  api,
                  ...shapeObj
                },
                style: {
                  //边框颜色
                  stroke: 'rgba(255,255,255,1)',
                  fill: colorArr[params.dataIndex],
                  //平面颜色
                  // fill:{ //渐变
                  //     type: 'linear',
                  //     x: 0,
                  //     y: 0,
                  //     x2: 0,
                  //     y2: 1,
                  //     colorStops: [{
                  //         offset: 0, color: '#3F66EC' // 0% 处的颜色
                  //     }, {
                  //         offset: 1, color: '#8092D0' // 100% 处的颜色
                  //     }],
                  //     global: false // 缺省为 false
                  // },
                  //   fill: '#4067EB',
                  // text:seriesData[params.dataIndex],
                  // textPosition:[10,-20] //文字显示位置
                }
              }
            ]
          };
        }
      }
    ]
};

效果:

image.png

注意,这是5.0.0版本效果,其他版本请自测

三、柱状图 设置多个横坐标共用一个柱子

custom 结合 renderItem 实现

const data1 = [
  ['01月01日', 5, 30, 'a'],
  ['06月01日', 3, 10, 'b'],
  ['09月01日', 3, 37, 'c']
].map((item, index) => {
  return {
    value: item,
    itemStyle: {
      color: ['#66CCFF', '#ff6699', '#ccff99', '#bce9a6', '#8da2e4'][index]
    }
  };
});
const data2 = [
  ['01月01日', 5, 30, 'A'],
  ['06月01日', 3, 10, 'B'],
  ['09月01日', 3, 37, 'C']
].map((item, index) => {
  return {
    value: item,
    itemStyle: {
      color: ['#a4e0f7', '#ff9b9b', '#ffe68f', '#bce9a6', '#8da2e4'][index]
    }
  };
});
option = {
  title: {
    text: '百分比',
    left: 'center'
  },
  tooltip: {},
  xAxis: {
    type: 'category',
    boundaryGap: true,
    axisTick: {
      alignWithLabel: true
    },
    data: [
      '01月01日',
      '02月01日',
      '03月01日',
      '04月01日',
      '05月01日',
      '06月01日',
      '07月01日',
      '08月01日',
      '09月01日',
      '10月01日',
      '11月01日',
      '12月01日'
    ]
  },
  yAxis: {
    max: 100,
    min: 0,
    splitNumber: 20,
    axisLabel: {
      formatter: '{value} %'
    }
  },
  series: [
    {
      type: 'custom',
      renderItem: function (params, api) {
        var start = api.coord([api.value(0), api.value(2)]);
        var size = api.size([api.value(0), api.value(2)]);
        var width = params.coordSys.width / 12;
        return {
          type: 'rect',
          shape: {
            x: start[0],
            y: start[1],
            width: width * api.value(1),
            height: size[1]
          },
          style: api.style()
        };
      },
      label: {
        show: true,
        position: 'inside'
      },
      dimensions: ['起始日期', '结束日期', 'name'],
      encode: {
        x: 0,
        y: 2,
        tooltip: 2,
        itemName: 3
      },
      data: data1
    },
    {
      type: 'custom',
      renderItem: function (params, api) {
        var start = api.coord([api.value(0), 100]);
        var size = api.size([api.value(0), 100 - api.value(2)]);
        var width = params.coordSys.width / 12;
        return {
          type: 'rect',
          shape: {
            x: start[0],
            y: start[1],
            width: width * api.value(1),
            height: size[1]
          },
          style: api.style()
        };
      },
      label: {
        show: true,
        position: 'inside',
        color: '#000'
      },
      dimensions: ['起始日期', '结束日期', 'name'],
      encode: {
        x: 0,
        y: 2,
        tooltip: [0, 1, 2],
        itemName: 3
      },
      data: data2
    }
  ]
};

效果:

image.png

四、折线图比梯级图多一点

renderItem 实现

option = {
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
    boundaryGap:false
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [150, 230, 224, 218, 135],
      type: 'line'
    },
    {
      data: [[15, 23],[23,29], [29,21],[21]],
      type: 'custom',
      renderItem:function(params,api){
        const xIndex = params.dataIndex;
        const circleR = 3
        // 横线
        const horizontalPoint = api.coord([xIndex, api.value(0)]);
        
         // 竖线
        const verticalPoint = api.coord([xIndex, api.value(1)]);
        const lineWidth = api.size([1, 0])[0];
        const halfWidth = lineWidth*0.5;
        //
        const style = api.style({
        stroke: api.visual('color'),
        fill: undefined
      });
      
      const groupObj ={
         type: 'group',
          children: [
              {
                  //横线
                  type: 'line',
                  shape: {
                    x1:horizontalPoint[0], 
                    y1:horizontalPoint[1], 
                    x2:horizontalPoint[0]+halfWidth-circleR*0.5, 
                    y2:horizontalPoint[1]
                  },
                  style
              },
               {
                  //横线
                  type: 'line',
                  shape: {
                    x1:horizontalPoint[0]+halfWidth+circleR*0.5, 
                    y1:horizontalPoint[1], 
                    x2:horizontalPoint[0]+lineWidth, 
                    y2:horizontalPoint[1]
                  },
                  style
              },
              {
                  //竖线
                  type: 'line',
                  shape: {
                      x1: horizontalPoint[0]+lineWidth,
                      y1: horizontalPoint[1],
                      x2: horizontalPoint[0]+lineWidth,
                      y2: verticalPoint[1]
                  },
                  style
              },
              {
              // 小圆点-在横线中间
              type: 'circle',
              shape: {
                cx: horizontalPoint[0]+ halfWidth,
                cy: horizontalPoint[1],
                r: circleR
              },
              style
            }
          ]
      }
      
       return groupObj
      }
    },
    
  ]
};

带toolTip

option = {
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
    boundaryGap:false
  },
  tooltip:{},
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [150, 230, 224, 218, 135],
      type: 'line'
    },
    {
      // [15,23,29,21]===> [[15, 23],[23,29], [29,21],[21]]
      data: [[23,15],[29,23], [21,29],[21,21]],
      type: 'custom',
      renderItem:function(params,api){
        const xIndex = params.dataIndex;
        const circleR = 3
        // 横线
        const horizontalPoint = api.coord([xIndex, api.value(1)]);
        
         // 竖线
        const verticalPoint = api.coord([xIndex, api.value(0)]);
        const lineWidth = api.size([1, 0])[0];
        const halfWidth = lineWidth*0.5;
        //
        const style = api.style({
        stroke: api.visual('color'),
        fill: undefined
      });
      
      const groupObj ={
         type: 'group',
          children: [
              {
                  //横线
                  type: 'line',
                  shape: {
                    x1:horizontalPoint[0], 
                    y1:horizontalPoint[1], 
                    x2:horizontalPoint[0]+halfWidth-circleR*0.5, 
                    y2:horizontalPoint[1]
                  },
                  style
              },
               {
                  //横线
                  type: 'line',
                  shape: {
                    x1:horizontalPoint[0]+halfWidth+circleR*0.5, 
                    y1:horizontalPoint[1], 
                    x2:horizontalPoint[0]+lineWidth, 
                    y2:horizontalPoint[1]
                  },
                  style
              },
              {
                  //竖线
                  type: 'line',
                  shape: {
                      x1: horizontalPoint[0]+lineWidth,
                      y1: horizontalPoint[1],
                      x2: horizontalPoint[0]+lineWidth,
                      y2: verticalPoint[1]
                  },
                  style
              },
              {
              // 小圆点-在横线中间
              type: 'circle',
              shape: {
                cx: horizontalPoint[0]+ halfWidth,
                cy: horizontalPoint[1],
                r: circleR
              },
              style
            }
          ]
      }
      

       return groupObj
      }
    },
    
  ]
};

效果:

image.png

数据结构优化,不连接Null

// 从第二个点开始画,后往前画
// const yData = [15,123,209,21]
const yData = [null,15,123,209,35]
option = {
  tooltip:{
     trigger:'axis'
  },
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
    boundaryGap:false
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [150, 230, 224, 218, 135],
      type: 'line'
    },
    {
      data: yData,
      type: 'custom',
      tooltip:{},
      renderItem:function(params,api){
        const xIndex = params.dataIndex;
        if(xIndex ===0) return
        const circleR = 2.2
        // 横线
        const horizontalPoint = api.coord([xIndex, api.value(1)]);
        // 竖线
        const verticalPoint = api.coord([xIndex, yData[xIndex+1]]);
        
        const lineWidth = api.size([1, 0])[0];
        //
        const style = api.style({
        stroke: api.visual('color'),
        fill: undefined
      });
      
      const groupObj ={
         type: 'group',
          children: []
      }
      
      // 横线
      if((api.value(1) || api.value(1) ===0) ){
        groupObj.children.push(   
             {
                  //横线
                  type: 'line',
                  shape: {
                    x1:horizontalPoint[0] - circleR, 
                    y1:horizontalPoint[1], 
                    x2:horizontalPoint[0] - lineWidth, 
                    y2:horizontalPoint[1]
                  },
                  style
              },
             {
              // 小圆点-在横线末端
              type: 'circle',
              shape: {
                cx: horizontalPoint[0],
                cy: horizontalPoint[1],
                r: circleR
              },
              style
            })
      }

      // 竖线
      if((yData[xIndex+1] || yData[xIndex+1] ===0) ){
         groupObj.children.push( 
              {
                  type: 'line',
                  shape: {
                      x1: horizontalPoint[0],
                      y1: yData[xIndex+1]>yData[xIndex]?horizontalPoint[1]- circleR:horizontalPoint[1]+ circleR,
                      x2: horizontalPoint[0],
                      y2: verticalPoint[1]
                  },
                  style
              }
              )
      }
      
       return groupObj
      }
    },
    
  ]
};



五、自定义阶梯图填充颜色

renderItem 实现

// 从第二个点开始画,后往前画
// const yData = [15,123,209,21]
const yData = [null,15,123,209,35]
option = {
  tooltip:{
     trigger:'axis'
  },
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
    boundaryGap:false
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [150, 230, 224, 218, 135],
      type: 'line'
    },
    {
      data: yData,
      type: 'custom',
      tooltip:{},
      renderItem:function(params,api){
        const xIndex = params.dataIndex;
        // if(xIndex ===0) return
        const circleR = 2.2
        // 横线
        const horizontalPoint = api.coord([xIndex, api.value(1)]);
        // 竖线
        const verticalPoint = api.coord([xIndex, yData[xIndex+1]]);
        
        const lineWidth = api.size([1, 0])[0];
        //
        const style = api.style({
        stroke: api.visual('color'),
        fill: undefined,
      });
      
      const groupObj ={
         type: 'group',
          children: []
      }
      
      // 横线
      if((api.value(1) || api.value(1) ===0) ){
        groupObj.children.push(   
             {
                  //横线
                  type: 'line',
                  shape: {
                    x1:horizontalPoint[0] - circleR, 
                    y1:horizontalPoint[1], 
                    x2:horizontalPoint[0] - lineWidth, 
                    y2:horizontalPoint[1]
                  },
                  style
              },
             {
              // 小圆点-在横线末端
              type: 'circle',
              shape: {
                cx: horizontalPoint[0],
                cy: horizontalPoint[1],
                r: circleR
              },
              style
            })
      }

      // 竖线
      if((yData[xIndex+1] || yData[xIndex+1] ===0) ){
         groupObj.children.push( 
              {
                  type: 'line',
                  // areaStyle: {},
                  shape: {
                      x1: horizontalPoint[0],
                      y1: yData[xIndex+1]>yData[xIndex]?horizontalPoint[1]- circleR:horizontalPoint[1]+ circleR,
                      x2: horizontalPoint[0],
                      y2: verticalPoint[1]
                  },
                  style
              }
              )
      }
      
      let fillFlag=true
      if(fillFlag){
        groupObj.children.push(
          {
            type:'rect',
            shape:{
              x: horizontalPoint[0],
              y: verticalPoint[1],
              width:lineWidth,
              height:api.size([1, yData[xIndex+1]])[1]
            },
            style:{
                stroke:'red',
                lineWidth:0,
                fill: api.visual('color')
            },
          }  
        )
      }
      
       return groupObj
      }
    },
    
  ]
};

效果如下:

image.png

小圆点在线段中间的算法

     // 横线
      if((api.value(1) || api.value(1) ===0) ){
        groupObj.children.push(   
            {
                  //横线
                  type: 'line',
                  shape: {
                    x1:horizontalPoint[0] - circleR - halfWidth, 
                    y1:horizontalPoint[1], 
                    x2:horizontalPoint[0] - lineWidth, 
                    y2:horizontalPoint[1]
                  },
                  style
              },
            {
              // 小圆点-在横线中间
              type: 'circle',
              shape: {
                cx: horizontalPoint[0]- halfWidth,
                cy: horizontalPoint[1],
                r: circleR
              },
              style
            },
            {
                  //横线
                  type: 'line',
                  shape: {
                    x1:horizontalPoint[0], 
                    y1:horizontalPoint[1], 
                    x2:horizontalPoint[0] - halfWidth +circleR, 
                    y2:horizontalPoint[1]
                  },
                  style
              },
            )
      }