当前位置: 首页 > news >正文

echarts的双X轴,父级居中的相关配置

前言:折腾了一个星期,在最后一天中午,都快要放弃了,后来坚持下来,才有下面结果。

这个效果就相当是复合表头,第一行是子级,第二行是父级。
子级是奇数个时,父级label居中很简单,但是,当子级是偶数个的时候,父级就很难居中

如图:
在这里插入图片描述

直接把以下源码,复制到这个链接去打开看效果:
链接:https://echarts.apache.org/examples/zh/editor.html?c=bar-simple
查看效果,注意设置宽度boxW

const boxW = 547;
const boxH = 803;
const grid = { left: '10%', right: '10%', bottom: '40%', top: '10%' }// canvas的宽高
const canvasW = boxW * (1 - parseInt(grid.left) / 100 - parseInt(grid.right) / 100)
const canvasH = boxH * (1 - parseInt(grid.top) / 100 - parseInt(grid.bottom) / 100)const seriesData = [{data: [120, 200, 150, 80, 70, 110, 130, 120, 200, 150, 80, 70, 110, 130],type: 'bar'},{data: [120, 200, 150, 80, 70, 110, 130, 120, 200, 150, 80, 70, 110, 130],type: 'bar'},{data: [120, 200, 150, 80, 70, 110, 130, 120, 200, 150, 80, 70, 110, 130],type: 'line'}
]const textStr1 = '第一组123456'
const textStr2 = '第二组第二组第二组第二组1'
const textStr3 = '第三组哈'
const textStr4 = '第四组第四组第四组第四组123456'
const textStr5 = '第五组'
const chartGroups = [{grouplabel: textStr1,xAxis_datas: [textStr1, textStr1]},{grouplabel: textStr2,xAxis_datas: [textStr2, textStr2, textStr2]},{grouplabel: textStr3,xAxis_datas: [textStr3, textStr3]},{grouplabel: textStr4,xAxis_datas: [textStr4, textStr4, textStr4, textStr4, textStr4]},{grouplabel: textStr5,xAxis_datas: [textStr5, textStr5]},
]
const xAxisData = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', '日', 'Mon1', 'Tue1', 'Wed1', 'Thu1', 'Fri1', 'Sat1', '日1']
let item2DataArr = [] // x轴的第二行数据
const isShowLabelArr = [] // x轴的第二行 label的显示与隐藏规则
const axisTickArr = [] // 刻度线的显示与隐藏规则
const isExistObj = []
const isExistObj1 = []
const xObj = {}// 计算x轴的第二行,单元格label的显示与隐藏
chartGroups.forEach(gItem => {const datas = gItem.xAxis_datas || []const grouplabel = gItem.grouplabelconst len = datas.lengthdatas.forEach((o, i) => {const isEsist = isExistObj1.some(v => v === grouplabel)// debugger// 是否显示的设置if (!isEsist) {if (len % 2 === 0) { // 当前分组,有偶数个子级const index = len / 2 - 1if (index === i) {// debuggerisExistObj1.push(grouplabel)isShowLabelArr.push(1) // 1显示,0不显示(标签文字,刻度线)} else {isShowLabelArr.push(0) // 1显示,0不显示(标签文字,刻度线)}} else { // 当前分组,有奇数个子级let index = Math.ceil(len / 2) - 1if (index === i) {isExistObj1.push(grouplabel)isShowLabelArr.push(1) // 1显示,0不显示(标签文字,刻度线)} else {isShowLabelArr.push(0) // 1显示,0不显示(标签文字,刻度线)}}} else {isShowLabelArr.push(0) // 1显示,0不显示(标签文字,刻度线)}})})// 计算x轴的第二行,单元格刻度线的显示与隐藏
chartGroups.forEach(gItem => {const datas = gItem.xAxis_datas || []const grouplabel = gItem.grouplabeldatas.forEach((o, i) => {item2DataArr.push(grouplabel)const isEsist = isExistObj.some(v => v === grouplabel)// 是否显示的设置if (!isEsist) {isExistObj.push(grouplabel)axisTickArr.push(1) // 1显示,0不显示(标签文字,刻度线} else {axisTickArr.push(0) // 1显示,0不显示(标签文字,刻度线)}})
})// 每一柱子的宽度
const itemW = canvasW / item2DataArr.lengthchartGroups.forEach((item, i) => {const len = item.xAxis_datas.length// debuggerconst centerNum = Math.floor(len / 2) // 当前组的中心const isOdd = len % 2 === 0xObj[item.grouplabel] = {canvasW: boxW,canvasH: boxH,itemW,text: item.grouplabel,isOdd: isOdd ? '奇数个' : '偶数个',count: len, // 子级个数(x轴第一行个数)tdCountW: (len * itemW).toFixed(2) // 合并单元格的总宽度}
})// console.log('itemW', itemW)
let richObj = {}
let axisLabelFormat = []
const spaceW = 4 // 1个空格字符站4px
const perFontW = 12 // 1个字符的宽度12px
let isExistArr = []
let context = null// 第二行的文字长度区分奇数和偶数,并根据复合单元格宽度,适配文字最大长度
item2DataArr.forEach((k, index) => {const isTrue = isShowLabelArr[index]const o = xObj[k]let txt = o.textif (isTrue) { // 显示的才处理const isEsist = isExistArr.some(val1 => val1 === k)// 计算文字的总宽度const contextObj = measureTextWidth({ cxt: context, text: k });if (!context) {context = contextObj.context}o.txtW = contextObj.strWidth; // 文字的总宽度// debuggerif (o.count % 2 === 0 && !isEsist) { //偶数,需要计算中心位置let txtAlign = 'left'let paddingArr = [0, 0, 0, 0]isExistArr.push(k)o.halfW = (o.tdCountW - o.txtW) / 2 // 文字在复合单元格中的中心点o.centerNum = Math.abs(itemW / 2 - o.halfW) // 一个单元格相对文字中心的中心点o.spaceNum = Math.floor(o.centerNum % spaceW) // 计算把字符从单元格中心移到复合表头中心,需要多少个空字符const disAllItemW = o.txtW - o.tdCountWconst disItemW = o.txtW - itemW// debuggerif (disAllItemW > 0) { // 字的长度大于整个复合单元格的宽度txtAlign = 'center'paddingArr = [0, 0, 0, itemW]// debuggertxt = fixTxtMaxWidth({ item: o, context, perFontW }) // 字数长度大于复合单元格宽度(适配复合单元格的宽度,最多能显示多少个字符)// console.log('\n\n********', txt, 'paddingArr', paddingArr)} else if (disItemW > 0) { // 字的长度大于1个单元格的宽度txtAlign = 'center'txt = k// debuggerpaddingArr = [0, 0, 0, itemW]// console.log('\n\n----------', o.count, o.text, 'paddingArr', paddingArr)} else { // 字的长度小于1个单元格的宽度,则需要通过添加空字符来占位txtAlign = 'left'txt = fixTxtMinWidth({ item: o, context }) // 子级个数为偶数,且父级字数长度过小,通过给父级label加空格,把label居中显示// debugger}axisLabelFormat.push(`{${index}|${txt}}`)richObj[index] = {width: 0.5,height: 16,color: '#f00',padding: paddingArr,// backgroundColor: '#bbb',align: txtAlign}} else { // 奇数,直接显示中间的即可// debuggerif (k) {txt = fixTxtMaxWidth({ item: o, context, perFontW }) // 字数长度大于复合单元格宽度(适配复合单元格的宽度,最多能显示多少个字符)}axisLabelFormat.push(`{${index}|${txt}}`)richObj[index] = {height: 16}}} else {axisLabelFormat.push(`{${index}|${txt}}`)richObj[index] = {height: 16}}})console.log(' ')
console.log('itemW', itemW)
console.log('item2DataArr', item2DataArr)
console.log('isShowLabelArr', isShowLabelArr)
console.log('axisTickArr', axisTickArr)// console.log('canvasW', canvasW)
// console.log('canvasH', canvasH)console.log('xObj', xObj)
console.log('axisLabelFormat', axisLabelFormat)
console.log('richObj', richObj)
console.log(' ')// 字数长度大于复合单元格宽度(适配复合单元格的宽度,最多能显示多少个字符)
function fixTxtMaxWidth ({ item, context, perFontW }) {// console.log('\n\nfixTxtMaxWidth111');let txt = item.textlet txtLen = item.txtWconst countW = item.tdCountW - perFontW // 超出最大宽度,要裁剪,然后添加省略号let symbol = ''// debuggerwhile (txtLen > countW) {txt = txt.substring(0, txt.length - 1)// debuggerconst txtObj = measureTextWidth({ cxt: context, text: txt }); // 文字的总宽度txtLen = txtObj.strWidthconsole.log('\nwhile:', txt, txtLen, item.tdCountW)symbol = '...'}txt += symbolreturn txt
}// 通过canvas计算文字宽度
function measureTextWidth ({ cxt, text, fontSize, fontFamily }) {fontSize = fontSize || 12;fontFamily = fontFamily || 'Arial';let context = cxtif (!context) {// 创建一个canvas元素const canvas = document.createElement('canvas');context = canvas.getContext('2d');}// 设置文本样式context.font = `${fontSize}px ${fontFamily}`;// 测量文本宽度const metrics = context.measureText(text);// console.log(text, metrics.width);return {strWidth: metrics.width,context}
}// 子级个数为偶数,且父级字数长度过小,通过给父级label加空格,把label居中显示
function fixTxtMinWidth ({ item, context, dividendNum = 2 }) {let txt = item.textlet txtLen = item.txtWconst countW = itemW / dividendNum// debuggerwhile (txtLen < countW) {txt = ' ' + txtconst txtObj = measureTextWidth({ cxt: context, text: txt }); // 文字的总宽度txtLen = txtObj.strWidth.toFixed(2)// debuggerconsole.log('fixTxtMinWidth111:', item.txtW, txtLen, itemW, ', tdCountW=', item.tdCountW, txt)}return txt
}option = {grid,// 组件离容器下侧的距离,值可以是像 20 这样的具体像素值,也可以是像 '20%' 这样相对于容器高宽的百分比xAxis: [{type: 'category',axisLabel: {interval: 0,rotate: 0// 倾斜角度},axisTick: {show: true,length: 30,},// 是否显示坐标轴刻度data: xAxisData},// ******************************************************************************************************************************// 这个是X轴第二行,相当父级{type: 'category',axisLabel: { // 坐标轴文本标签align: 'center',formatter (value, index) {let val1 = axisLabelFormat[index]return val1 // 返回真,就会显示label},interval: function (index, value) {const val1 = isShowLabelArr[index]// 根据子级个数动态调整间隔, false则不显示return val1;},rich: richObj},position: 'bottom',// 很重要,如果没有这个设置,默认第二个x轴就会在图表的顶部offset: 30,// X 轴相对于默认位置的偏移,在相同的 position 上有多个 X 轴的时候有用axisTick: { // 刻度线show: true,length: 30,interval: function (index, value) {const val1 = axisTickArr[index]// 根据子级个数动态调整间隔return val1;}},// 是否显示坐标轴刻度axisLine: { // 是否显示坐标轴轴线show: true,onZeroAxisIndex: 2},data: item2DataArr},// ******************************************************************************************************************************// 这个设置只是在底部绘制一条线{type: 'category',position: 'bottom',// 很重要,如果没有这个设置,默认第二个x轴就会在图表的顶部offset: 60,// X 轴相对于默认位置的偏移,在相同的 position 上有多个 X 轴的时候有用axisLine: { // 是否显示坐标轴轴线show: true,onZeroAxisIndex: 2},data: []}],yAxis: [{name: '人数',type: 'value'},// {//   name: '年龄',//   type: 'value'// }],series: seriesData
};

后记:记录这一刻的不易,同时希望能帮到有需要的人,觉得不错可以收藏!


http://www.mrgr.cn/news/78882.html

相关文章:

  • AlmaLinux8.10安装samba实现与Windows文件共享
  • 手机租赁系统开发全攻略 创新服务助力企业智能转型
  • Spring Boot开发——整合MyBatis的几种SQL写法
  • 2024信创数据库TOP30之华为Gauss DB
  • Docker和Docker Compose部署方式的区别以及各自适用的场景(ChatGPT-4o回答)
  • spring boot3.3.5 logback-spring.xml 配置
  • IDEA 配置鼠标悬浮后显示方法注释 javaDoc
  • EasyMedia播放rtsprtmp视频流(flvhls)
  • 运输层总结
  • Win10+Ubuntu20.04双系统重装Ubuntu22.04单系统
  • Hive学习基本概念
  • 在全志 T113-S3 开发板上运行 AWTK
  • Rust : 生成日历管理markdown文件的小工具
  • 人体热释电传感器
  • 从最浅层剖析C语言————第六节(深入了解数组传参、嵌套调用以及链式访问)
  • 2024.12.2工作复盘
  • yolov10 获取误检,漏检
  • shell编程(4)脚本与用户交互以及if条件判断
  • 初识一维和二维数组
  • 编译器优化技术
  • AI-学习路线图-PyTorch
  • NuHertz/HFSS: 使用矩形、径向和阻抗短截线的平面 LPF 切比雪夫-II 实现
  • 公专业务能力
  • 【C语言】结构体(二)
  • Hot100 - 二叉树的中序遍历
  • 利用市场分析工具对特定国家的产品市场情况进行深入分析的全面指南