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 = https://www.it610.com/article/{}; // 该层循环确定一个维度上的名称和所占的单元格的长度 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 = https://www.it610.com/article/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 = https://www.it610.com/article/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 = https://www.it610.com/article/{}; // 该层循环确定一个维度上的名称和所占的单元格的长度 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 = https://www.it610.com/article/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', ], },

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

    推荐阅读