Echarts x轴数据分组,支持dataZoom 拖拽

573 阅读3分钟

拖拽前:

1733118366370.png

拖拽后:

1733118490677.png

试过三种方案:

一、用echart的grapic进行定位竖线和文字,在dataZoom存在的时候没有动态效果

二、采用多个X轴

三、采用echarts的 custom 自定义画线和文字

推荐custom模式(getXAxisParentSeries函数已封装好)

     let data = [
        { date: '2023-01', year: '2023', data: 2 },
        { date: '2023-02', year: '2023', data: 3 },
        { date: '2023-03', year: '2023', data: 4 },
        { date: '2023-04', year: '2023', data: 5 },
        { date: '2023-05', year: '2023', data: 3 },
        { date: '2023-07', year: '2023', data: 2 },
        { date: '2023-08', year: '2023', data: 4 },
        { date: '2023-09', year: '2023', data: 4 },
        { date: '2023-10', year: '2023', data: 6 },
        { date: '2023-11', year: '2023', data: 3 },
        { date: '2023-12', year: '2023', data: 4 },
        { date: '2024-01', year: '2024', data: 3 },
        { date: '2024-02', year: '2024', data: 2 },
        { date: '2024-03', year: '2024', data: 5 },
        { date: '2024-04', year: '2024', data: 5 },
        { date: '2024-05', year: '2024', data: 5 },
        { date: '2024-06', year: '2024', data: 6 },
      ]
    let yearSeries = getXAxisParentSeries(data, 'year')
    let opt = {
        //其他设置
        ...
    }
    opt.series.push(yearSeries)
    this.Chart.setOption(opt, { replaceMerge: ['series'] })
    

封装的工具函数

/**
* @description: 返回custom类型的series对象
*  { object[] } xData 上方data数组
*  { string } 数组中父级的key
* { lineHeight, lineStyle, textHeight, textStyle } 函数内画线和字体的样式
**/
export function getXAxisParentSeries(
  xData,
  key,
  { lineHeight, lineStyle, textHeight, textStyle } = { lineHeight: 160, lineStyle: {}, textHeight: 140, textStyle: {} }
) {
  const x2StartArr = countXAxisStartIndex(xData, key)
  const x2EndArr = countXAxisEndIndex(xData, key)
  return {
    type: 'custom',
    data: xData.map(item => ''),
    xAxisIndex: 0,
    z: 9,
    renderItem: (params, api) => {
      let idx = params.dataIndex
      let pointStart = api.coord([idx, 0])
      let point2 = api.coord([idx + 1, 0])
      let gap = (point2[0] - pointStart[0]) / 2
      let start = x2StartArr.find(item => item.value === idx)
      let end = x2EndArr.find(item => item.value === idx)
      let group = {
        id: `group_${key}_${idx}`,
        type: 'group',
        ignore: false,
        x: pointStart[0] - gap,
        y: pointStart[1],
        children: [],
      }
      // 所有左侧竖线
      if (start) {
        group.children.push({
          id: `line_${key}_${idx}`,
          type: 'line',
          shape: {
            x1: 0,
            y1: 0,
            x2: 0,
            y2: lineHeight || 160,
          },

          style: {
            lineWidth: 1,
            lineDash: 'solid',
            stroke: 'rgba(0, 0, 0, 0.35)',
            ...lineStyle,
          },
        })
      }
      if (start || end) {
        if (!end) {
          let arrIdx = x2StartArr.findIndex(item => item.name === start.name && item.value === start.value)
          end = x2EndArr[arrIdx]
        }
        if (!start) {
          let arrIdx = x2EndArr.findIndex(item => item.name === end.name && item.value === end.value)
          start = x2StartArr[arrIdx]
        }
        let pointStart = api.coord([start.value, 0])
        let pointEnd = api.coord([end.value, 0])
        let dataZoomStart = params.dataIndex - params.dataIndexInside
        let pointZoomStart = api.coord([dataZoomStart, 0])
        let dataZoomEnd = params.dataInsideLength - 1 - params.dataIndexInside + params.dataIndex
        let pointZoomEnd = api.coord([dataZoomEnd, 0])
        let name = start.name
        let middle = (pointEnd[0] - pointStart[0]) / 2 + pointStart[0]

        // 预防 start undefined情况
        group.x = pointStart[0] - gap

        // 间距太窄,文字竖向展示
        if (end.value - start.value < 1) {
          name = name.split('').join('\n')
        }
        if (middle <= pointZoomEnd[0] && middle >= pointZoomStart[0]) {
          group.children.push({
            id: `text_${key}_${idx}`,
            type: 'text',
            x: (pointEnd[0] - pointStart[0]) / 2 + gap,
            y: textHeight || 140,
            style: {
              text: name,
              textAlign: 'center',
              fill: '#333',
              ...textStyle,
            },
          })
        }
        // 最右侧竖线
        if (idx === xData.length - 1) {
          group.children.push({
            id: `line_${key}_${idx}`,
            type: 'line',
            shape: {
              x1: pointEnd[0] - pointStart[0] + 2 * gap,
              y1: 0,
              x2: pointEnd[0] - pointStart[0] + 2 * gap,
              y2: lineHeight || 160,
            },

            style: {
              lineWidth: 1,
              lineDash: 'solid',
              stroke: 'rgba(0, 0, 0, 0.35)',
              ...lineStyle,
            },
          })
        }
      }

      if (!group.children.length) {
        group.ignore = true
      }
      return group
    },
  }
}

  /**
 * @description: 计算第N层X轴重复字符串终止索引 n>1
 * @param { string[] } list 第n层x轴全部数据
 * @return  [{name: 2023, value:0, name: 2024, value: 12 }]
 */
export function countXAxisEndIndex(list, key) {
  const temp = []
  if (list.length) {
    let name = list[0][key]
    temp[0] = { name, value: 0 }
    for (let i = 1; i < list.length; i++) {
      if (name != list[i][key]) {
        name = list[i][key]
        temp.push({ name, value: i - 1 })
      }
      temp[temp.length - 1].value++
    }
  }
  let name = list[list.length - 1][key]
  if (name == temp[temp.length - 1].name) {
    temp[temp.length - 1].value = list.length - 1
  } else {
    temp.push({ name, value: list.length - 1 })
  }

  return temp
}
/**
 * @description: 计算第N层X轴重复字符串起始索引 n>1
 * @param { string[] } list 第n层x轴全部数据
 * @return [{name: 2023, value:11, name: 2024, value: 17 }]
 */
export function countXAxisStartIndex(list, key) {
  const temp = []
  if (list.length) {
    let name = list[0][key]
    temp[0] = { name, value: 0 }
    for (let i = 1; i < list.length; i++) {
      if (name != list[i][key]) {
        name = list[i][key]
        temp.push({ name, value: i })
      }
    }
  }
  return temp
}
  

多个X轴

参考:blog.csdn.net/qq_43225508…