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.length// 整合第二行X轴数据,并过滤重复label
chartGroups.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 = {} // 富文本样式,通过echarts的富文本设置第二行X轴居中
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.mzph.cn/diannao/62885.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

配置宝塔php curl 支持http/2 发送苹果apns消息推送

由于宝塔面板默认的php编译的curl未加入http2的支持&#xff0c;如果服务需要使用apns推送等需要http2.0的访问就会失败&#xff0c;所以重新编译php让其支持http2.0 编译方法&#xff1a; 一、安装nghttp2 git clone https://github.com/tatsuhiro-t/nghttp2.git cd nghttp…

记录一次网关异常

记一次网关异常 网关时不时就会出现下面的异常。关键是不知道什么时候就会报错&#xff0c;并且有时候就算什么都不操作&#xff0c;也会导致这个异常。 ERROR org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in schedul…

动态艺术:用Python将文字融入GIF动画

文章内容&#xff1a; 在数字媒体的多样化发展中&#xff0c;GIF动画作为一种流行的表达形式&#xff0c;常被用于广告、社交媒体和娱乐。本文通过一个具体的Python编程示例&#xff0c;展示了如何将文字以动态形式融入到GIF动画中&#xff0c;创造出具有视觉冲击力的动态艺术…

@antv/x6 再vue中 ,自定义图形,画流程图、数据建模、er图等图形

X6 是基于 HTML 和 SVG 的图编辑引擎&#xff0c;提供低成本的定制能力和开箱即用的内置扩展&#xff0c;方便我们快速搭建 DAG 图、ER 图、流程图、血缘图等应用。 最终效果图 1.安装 npm install antv/x6 --save //x6主要包 npm install antv/x6-vue-shape //使用vue组…

2.4特征预处理(机器学习)

2.4特征预处理 2.4.1 什么是特征预处理 通过 一些转换函数将特征数据转换成更加适合算法模型的特征数据过程。 1 包含内容 数值型数据的无量纲化&#xff1a; 归一化 标准化 2 特征预处理API sklearn.preprocessing 为什么要进行归一化/标准化&#xff1f; 特征的单…

前端、后端、测试?如何选择

目录 一、前端开发 &#xff08;一&#xff09;职业概述 &#xff08;二&#xff09;需学习的技术 二、后端开发 &#xff08;一&#xff09;职业概述 &#xff08;二&#xff09;需学习的技术 三、测试 &#xff08;一&#xff09;职业概述 &#xff08;二&#xff0…

AI - 谈谈RAG中的查询分析(2)

AI - 谈谈RAG中的查询分析&#xff08;2&#xff09; 大家好&#xff0c;RAG中的查询分析是比较有趣的一个点&#xff0c;内容丰富&#xff0c;并不是一句话能聊的清楚的。今天接着上一篇&#xff0c;继续探讨RAG中的查询分析&#xff0c;并在功能层面和代码层面持续改进。 功…

hadoop环境配置-创建hadoop用户+更新apt+安装SSH+配置Java环境

一、创建hadoop用户(在vm安装的ubantu上打开控制台) 1、sudo useradd -m hadoop -s /bin/bash &#xff08;创建hadoop用户&#xff09; 2、sudo passwd hadoop (设置密码) 3、sudo adduser hadoop sudo&#xff08;将新建的hadoop用户设置为管理员&#xff09; 执行如下图 将…

大数据新视界 -- Hive 数据湖架构中的角色与应用(上)(25 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

SpringMVC:参数传递之日期类型参数传递

环境准备和参数传递请见&#xff1a;SpringMVC参数传递环境准备 日期类型比较特殊&#xff0c;因为对于日期的格式有N多中输入方式&#xff0c;比如: 2088-08-182088/08/1808/18/2088… 针对这么多日期格式&#xff0c;SpringMVC该如何接收&#xff0c;它能很好的处理日期类…

jmeter如何导出中文版的测试报告?

文章目录 0、初始步骤&#xff1a;把报告模板换成中文形式1、首先添加一份聚合报告2、然后点开【聚合报告】3&#xff0c;生成报告3.1 选择【工具】-【generate HTML report】3.2 【generate HTML report】参数详解3.3 、最后点击 【generate report】直接生成。 声明&#xff…

基于IPD双轮驱动, 打破产品同质化竞争魔咒

在当今竞争激烈的商业环境中&#xff0c;产品同质化现象愈发严重&#xff0c;企业面临着巨大的挑战。如何在众多相似产品中脱颖而出&#xff0c;赢得客户的青睐并获取持续的竞争优势&#xff0c;成为企业亟待解决的关键问题。基于 IPD 双轮驱动的产品开发模式&#xff0c;为企业…

2.mysql 中一条更新语句的执行流程是怎样的呢?

前面我们系统了解了一个查询语句的执行流程&#xff0c;并介绍了执行过程中涉及的处理模块。 相信你还记得&#xff0c;一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块&#xff0c;最后到达存储引擎。 那么&#xff0c;一条更新语句的执行流程又…

【LeetCode每日一题】——204.计数质数

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时空频度】九【代码实现】十【提交结果】 一【题目类别】 数组 二【题目难度】 中等 三【题目编号】 204.计数质数 四【题目描述】 给定整数 n &…

【数据事务】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

【机器学习】机器学习的基本分类-监督学习-决策树-ID3 算法

ID3&#xff08;Iterative Dichotomiser 3&#xff09;是决策树的一种构造算法&#xff0c;由 Ross Quinlan 在 1986 年提出。它主要用于分类问题&#xff0c;通过信息增益选择特征来构建决策树。ID3 假设数据是离散型特征&#xff0c;且不支持连续型数据。 1. 核心思想 划分标…

JAVA |日常开发中读写XML详解

JAVA &#xff5c;日常开发中读写XML详解 前言一、XML 简介二、在 Java 中读取 XML2.1 使用 DOM&#xff08;Document Object Model&#xff09;方式读取 XML2.2 使用 SAX&#xff08;Simple API for XML&#xff09;方式读取 XML 三、在 Java 中写入 XML3.1 使用 DOM 方式写入…

ISAAC SIM踩坑记录--Omniverse Launcher添加代理

最近Omniverse Launcher不知道又抽什么疯&#xff0c;在Exchange界面安装各种软件都不成功&#xff0c;报错如下&#xff1a; FetchError: request to https://launcher-index-prod.s3.amazonaws.com/en/components.json failed, reason: Client network socket disconnected…

ECharts柱状图-交错正负轴标签,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个柱状图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供…

07《缓存》计算机组成与体系结构 系列课

目录 深入了解缓存内存 缓存的重要性 游戏中的存储需求与主内存 虚拟内存和按需分页 现代系统中的多级缓存 缓存级别的大小与速度 缓存相关的术语 缓存命中与未命中 页面命中与缺页 局部性原理 结语 深入了解缓存内存 大家好&#xff0c;欢迎来到今天的课程。上节课…