echarts实现多层不等距x轴,支持框选缩放功能

//--------------初始数据部分--------------------
// 拼数据
let series: any = [];

// 存放多层x轴数据的series

const seriesextends: KeyValue[] = [];

// x轴的层数
const xlevel: number = details[0].xaxisValue.length;
// 折线图的个数
const yAxisLineNum: number = details[0].yaxisLine.length;
// 柱型图的个数
const yAxisBarNum: number = details[0].yaxisBar.length;
// 最多的x的值
const xNum: number = details.length;
// lenged中data的值
const yName: string[] = [];

// 初始化yAxisLineListObject的列表
let yAxisLineListObject = {

// yAxisLineValue1:['num1','num2','num3','num4']

};

for (let i: number = 0; i < yAxisLineNum; i++) {

const tempyaxislinevalue: string[] = [];
for (let j = 0; j < details.length; j++) {
  tempyaxislinevalue.push(details[j].yaxisLine[i].yvalue);
}
yAxisLineListObject = Object.assign({}, yAxisLineListObject, {
  [details[0].yaxisLine[i].yfield]: tempyaxislinevalue,
});

}
// console.log(yAxisLineListObject);

// 初始化yAxisBarListObject的列表
let yAxisBarListObject = {

// yAxisLineValue1:['num1','num2','num3','num4']

};
for (let i: number = 0; i < yAxisBarNum; i++) {

const tempyaxisbarvalue: string[] = [];
for (let j = 0; j < details.length; j++) {
  tempyaxisbarvalue.push(details[j].yaxisBar[i].yvalue);
}
yAxisBarListObject = Object.assign({}, yAxisBarListObject, {
  [details[0].yaxisBar[i].yfield]: tempyaxisbarvalue,
});

}
// console.log(yAxisBarListObject);

//向series里填充y的折线图数据
for (let i: number = 0; i < Object.keys(yAxisLineListObject).length; i++) {

yName.push(Object.keys(yAxisLineListObject)[i]);
series.push({
  data: Object.values(yAxisLineListObject)[i],
  type: 'line',
  name: Object.keys(yAxisLineListObject)[i],
  yAxisIndex: 0,
  // xAxisIndex: 0,
});

}

// console.log(series);

//向series里填充y的柱状图数据
for (let i: number = 0; i < Object.keys(yAxisBarListObject).length; i++) {

yName.push(Object.keys(yAxisBarListObject)[i]);
series.push({
  data: Object.values(yAxisBarListObject)[i],
  type: 'bar',
  name: Object.keys(yAxisBarListObject)[i],
  yAxisIndex: 1,
  // xAxisIndex: 1,
});

}

// 存放所有层维度数据的数组
const xAxisArray: any = [];

// 先按维度的层次拼接x的名字
const tempxaxisname = [];
for (let i: number = 0; i < details.length; i++) {

const tempxaxislevelname: string[] = [];
tempxaxislevelname.push(details[i].xaxisValue[0]);
for (let j: number = 1; j < xlevel; j++) {
  tempxaxislevelname.push(
    tempxaxislevelname[j - 1] + ',' + details[i].xaxisValue[j],
  );
}
tempxaxisname.push(tempxaxislevelname);

}

// console.log(tempxaxisname, '按层次拼接好的x的名字---------------');

// 设置x轴的数据
const xAxisData: any = [

// {value:星期1}

];

for (let i: number = 0; i < details.length; i++) {

xAxisData.push({
  ['value']: tempxaxisname[i][xlevel - 1],
  ['textStyle']: {
    ['fontSize']: 8,
  },
});

}

// 分维度取出x轴的名字数组
for (let i: number = 0; i < xlevel; i++) {

let tempxxaisvalue: KeyValue = {};
// 该层循环确定一个维度上的名称和所占的单元格的长度
for (let j = 0; j < details.length; j++) {
  if (
    Object.keys(tempxxaisvalue)[Object.keys(tempxxaisvalue).length - 1] ===
    tempxaxisname[j][i]
  ) {
    //如果和最后一位重复,则合并单元格,长度+1

    // console.log("重复,需要合并");
    const lastkey =
      Object.keys(tempxxaisvalue)[Object.keys(tempxxaisvalue).length - 1];
    // console.log(lastkey);
    tempxxaisvalue[lastkey]++;
  } else {
    // console.log("不重复,不需要合并");

    tempxxaisvalue = Object.assign({}, tempxxaisvalue, {
      [tempxaxisname[j][i]]: 1,
    });
  }
}
xAxisArray.push(tempxxaisvalue);

}
// 外层循环走完所有的维度都已经拼成了一个对象数组,对象里面分别包裹着每一层维度的名称和对应的长度,一个对象就是一个维度

// console.log(
// xAxisArray,
// '要给多层x轴进行渲染的xAxisArray对象数据----------------',
// );

xAxisArray.reverse();

// 设置grid的值
const grid: any = [

{
  top: 100,
  bottom: (xlevel + 2) * 30,
},
{
  top: 100,
  bottom: (xlevel + 2) * 30,
},

];

// 设置多层的x轴,配置series,grid,xAxis,yAxis
const xAxisExtends: any = [];
const yAxisExtends: any = [];
for (let i: number = 0; i < xlevel; i++) {

grid.push({
  height: 30,
  bottom: (xlevel - i + 1) * 30,
  tooltip: {
    // show: false,
  },
});
xAxisExtends.push({
  type: 'category',
  gridIndex: i + 2,
  axisLine: { show: false },
  axisLabel: { show: false },
  axisTick: { show: false },
});
yAxisExtends.push({
  type: 'value',
  gridIndex: i + 2,
  axisLine: { show: false },
  axisLabel: { show: false },
  axisTick: { show: false },
});
// 当前该维度的名字字符串和对应的所占单元格长度的字符串
const tempsingleXAxisName: string[] = Object.keys(xAxisArray[i]);
const tempsingleXAxisLength: number[] = Object.values(xAxisArray[i]);
// console.log(xAxisArray);

// 依次填入该维度的所有出现的名称与匹配的所占单元格的长度
for (let j: number = 0; j < Object.keys(xAxisArray[i]).length; j++) {
  // 设置填充进bar中的name 的内容和样式,当长度大于当前bar的宽度时,以省略号显示
  let tempXAxisname: String = '';
  // tempsingleXAxisName[j].substring(tempsingleXAxisName[j].lastIndexOf(',')+1)为要展示的全部的字符串
  if (
    tempsingleXAxisName[j].substring(
      tempsingleXAxisName[j].lastIndexOf(',') + 1,
    ).length >
    (tempsingleXAxisLength[j] / xNum) * 100 - 1
  )
    tempXAxisname =
      tempsingleXAxisName[j]
        .substring(tempsingleXAxisName[j].lastIndexOf(',') + 1)
        .substring(0, Math.floor((tempsingleXAxisLength[j] / xNum) * 100)) +
      '..';
  else
    tempXAxisname = tempsingleXAxisName[j].substring(
      tempsingleXAxisName[j].lastIndexOf(',') + 1,
    );

  seriesextends.push({
    type: 'bar',
    barWidth: (tempsingleXAxisLength[j] / xNum) * 100 + '%',
    data: [{ name: tempXAxisname, value: 1 }],
    barGap: 0,
    label: {
      show: true,
      position: 'inside',
      formatter: '{b}',
      // offset: [0, 10],
    },
    itemStyle: {
      color: 'none',
      borderColor: '#000',
      borderWidth: 1,
    },
    animation: false,
    tooltip: {
      formatter: tempsingleXAxisName[j].substring(
        tempsingleXAxisName[j].lastIndexOf(',') + 1,
      ),
    },
    // barWidth:
    xAxisIndex: i + 2,
    yAxisIndex: i + 2,
  });
}
// console.log(series,'+++++++++++');

}

//------------------------------------------------------------------------------------------------------------------

//echarts 中 option设置
let option: EChartsOption;



option = {
  title: {
    text: titleinfo,
  },

  tooltip: {
    trigger: 'item',
    axisPointer: {
      type: 'shadow',
    },
  },
  grid: grid,
  legend: {
    data: yName,
  },
  xAxis: [
    {
      type: 'category',
      data: xAxisData,
      position: 'bottom',
      gridIndex: 0,
      nameTextStyle: {
        fontSize: 8,
      },
      axisTick: {
        length: 30,
        interval: 0,
      },
     
      axisLabel: { show: false },
    },
    {
      type: 'category',
      gridIndex: 0,
      data: xAxisData,
      axisLine: { show: false },
      axisLabel: { show: false },
      axisTick: { show: false },
    },

    // 下面都是多的x轴

    ...xAxisExtends,
  ],

  yAxis: [
    {
      type: 'value',
      name: '折线图数据',
      gridIndex: 0,
      min: 'dataMin',
      axisLabel: {
        formatter: function (value: number) {
          // console.log(value,'y轴的值');
          // console.log(value.toExponential(2),'处理后的y轴的值');

          return value.toExponential(1);
        },
      },
    },
    {
      type: 'value',
      name: '柱形图数据',
      gridIndex: 0,
      position: 'right',
      max: 'dataMax',
      min: 'dataMin',
      axisLabel: {
        formatter: function (value: number) {
          // console.log(value,'y轴的值');
          // console.log(value.toExponential(2),'处理后的y轴的值');

          return value.toExponential(1);
        },
      },
    },

    // 下面都是多的y轴
    ...yAxisExtends,
  ],

  series: [...series, ...seriesextends],

  toolbox: [
    {
      feature: {
        dataZoom: {
          show: true,
          // type: ['zoom'],
          yAxisIndex: false,
          xAxisIndex: 0,
        },
      },
      // right:-25
    },
  ],
};

//---------------------------------------------------------------------------------------------------------------------------------------------------------

//缩放的监听,控制多层x轴的变化
myChart.on('datazoom', (params: any) => {

  // console.log(xAxisData, 'on监听里面的xAxisData----------');
  let slicestart: number = 0;
  let sliceend: number = 0;
  //回退到最初始的状态时
  if (params.batch[0].start === 0) {
    slicestart = 0;
    sliceend = details.length - 1;
  }
  // 有startValue值的时候(常规缩放)
  else if (params.batch[0].startValue) {
    slicestart = params.batch[0].startValue;
    sliceend = params.batch[0].endValue;
  }

  setdatazoom(slicestart, sliceend);
});

function setdatazoom(slicestart: number, sliceend: number) {

  
  const slicelength: number = sliceend - slicestart + 1;
  // 缩放之后的x轴的更新的data
  const sliceXAXisData = xAxisData.slice(slicestart, sliceend + 1);
  // console.log(
  //   sliceXAXisData,
  //   'sliceXAXisData+++++缩放时候的x轴的data数据+',
  // );
 

  
  
  // 存放所有层维度数据的数组
  const slicexAxisArray: any = [];

  // 先按维度的层次拼接x的名字
  const slicetempxaxisname = [];
  for (let i: number = slicestart; i < sliceend + 1; i++) {
    const tempxaxislevelname: string[] = [];
    tempxaxislevelname.push(details[i].xaxisValue[0]);
    for (let j: number = 1; j < xlevel; j++) {
      tempxaxislevelname.push(
        tempxaxislevelname[j - 1] + ',' + details[i].xaxisValue[j],
      );
    }
    slicetempxaxisname.push(tempxaxislevelname);
  }

  // console.log(
  //   slicetempxaxisname,
  //   '缩放后按层次拼接好的x的名字---------------',
  // );

  // 分维度取出x轴的名字数组
  for (let i: number = 0; i < xlevel; i++) {
    let tempxxaisvalue: KeyValue = {};
    // 该层循环确定一个维度上的名称和所占的单元格的长度
    for (let j: number = 0; j < slicetempxaxisname.length; j++) {
      if (
        Object.keys(tempxxaisvalue)[
          Object.keys(tempxxaisvalue).length - 1
        ] === slicetempxaxisname[j][i]
      ) {
        //如果和最后一位重复,则合并单元格,长度+1

        // console.log("重复,需要合并");
        const lastkey =
          Object.keys(tempxxaisvalue)[
            Object.keys(tempxxaisvalue).length - 1
          ];
        // console.log(lastkey);
        tempxxaisvalue[lastkey]++;
      } else {
        // console.log("不重复,不需要合并");

        tempxxaisvalue = Object.assign({}, tempxxaisvalue, {
          [slicetempxaxisname[j][i]]: 1,
        });
      }
    }
    slicexAxisArray.push(tempxxaisvalue);
  }
  //    外层循环走完所有的维度都已经拼成了一个对象数组,对象里面分别包裹着每一层维度的名称和对应的长度,一个对象就是一个维度

  // console.log(
  //   slicexAxisArray,
  //   '缩放时要给多层x轴进行渲染的xAxisArray对象数据----------------',
  // );

  slicexAxisArray.reverse();

  const sliceseriesextends = [];

  for (let i: number = 0; i < xlevel; i++) {
    // 当前该维度的名字字符串和对应的所占单元格长度的字符串
    const slicetempsingleXAxisName: string[] = Object.keys(
      slicexAxisArray[i],
    );
    const slicetempsingleXAxisLength: number[] = Object.values(
      slicexAxisArray[i],
    );
    // console.log(slicetempsingleXAxisName,'datazoomtempsingleXAxisName..................');
    // console.log(slicetempsingleXAxisLength,'datazoomtempsingleXAxisLength..................');

    // 依次填入该维度的所有出现的名称与匹配的所占单元格的长度
    for (
      let j: number = 0;
      j < Object.keys(slicexAxisArray[i]).length;
      j++
    ) {
      // 设置填充进bar中的name 的内容和样式,当长度大于当前bar的宽度时,以省略号显示
      let slicetempXAxisname: String = '';
      //slicetempsingleXAxisName[j].substring(slicetempsingleXAxisName[j].lastIndexOf(',')+1)为要展示的全部的字符串
      if (
        slicetempsingleXAxisName[j].substring(
          slicetempsingleXAxisName[j].lastIndexOf(',') + 1,
        ).length >
        (slicetempsingleXAxisLength[j] / slicelength) * 100 - 1
      ) {
        slicetempXAxisname =
          slicetempsingleXAxisName[j]
            .substring(slicetempsingleXAxisName[j].lastIndexOf(',') + 1)
            .substring(
              0,
              Math.floor(
                (slicetempsingleXAxisLength[j] / slicelength) * 100,
              ),
            ) + '..';
      } else
        slicetempXAxisname = slicetempsingleXAxisName[j].substring(
          slicetempsingleXAxisName[j].lastIndexOf(',') + 1,
        );

      sliceseriesextends.push({
        type: 'bar',
        barWidth: (slicetempsingleXAxisLength[j] / slicelength) * 100 + '%',
        data: [{ name: slicetempXAxisname, value: 1 }],
        barGap: 0,
        label: {
          show: true,
          position: 'inside',
          formatter: '{b}',
          // offset: [0, 10],
        },
        itemStyle: {
          color: 'none',
          borderColor: '#000',
          borderWidth: 1,
        },
        animation: false,
        tooltip: {
          formatter: slicetempsingleXAxisName[j].substring(
            slicetempsingleXAxisName[j].lastIndexOf(',') + 1,
          ),
        },
        // barWidth:
        xAxisIndex: i + 2,
        yAxisIndex: i + 2,
      });
    }
  }
  // console.log(sliceseriesextends, 'sliceseriesextends+++++++++++');

  

  myChart.setOption(
    {
      series: [...series, ...sliceseriesextends],
      yAxis: [
        {
          type: 'value',
          name: '折线图数据',
          gridIndex: 0,
          min: 'dataMin',
          max: 'dataMax',
          axisLabel: {
            formatter: function (value: number) {
              // console.log(value,'y轴的值');
              // console.log(value.toExponential(2),'处理后的y轴的值');

              return value.toExponential(1);
            },
          },
        },
        {
          type: 'value',
          name: '柱形图数据',
          gridIndex: 0,
          position: 'right',
          max: 'dataMax',
          min: 'dataMin',
          axisLabel: {
            formatter: function (value: number) {
              // console.log(value,'y轴的值');
              // console.log(value.toExponential(2),'处理后的y轴的值');

              return value.toExponential(1);
            },
          },
        },

        // 下面都是多的y轴
        ...yAxisExtends,
      ],

      
    },
    {
      replaceMerge: ['series', 'yAxis'], // 替换合并series,默认普通合并
    },
  );
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//原始数据details的格式
details: [

    {
      yaxisBar: [
        {
          yfield: 'firstPassCPU',
          yvalue: '1E-14',
        },
        {
          yfield: 'firstPassCPK',
          yvalue: '-1E-14',
        },
      ],
      yaxisLine: [
        {
          yfield: 'firstPassCP',
          yvalue: '0',
        },
      ],
      xaxisValue: [
        '20211023',
        'AGD142M208-D001',
        '1000:GSM824_Idle_Current',
      ],
    },
    {
      yaxisBar: [
        {
          yfield: 'firstPassCPU',
          yvalue: '8E-15',
        },
        {
          yfield: 'firstPassCPK',
          yvalue: '-8E-15',
        },
      ],
      yaxisLine: [
        {
          yfield: 'firstPassCP',
          yvalue: '0',
        },
      ],
      xaxisValue: [
        '20211023',
        'AGD142M208-D001',
        '1001:GSM824_Max_Pout_0dBm_Drive',
      ],
    },

}

你可能感兴趣的:(前端typescript)