从实际项目需求探索ECharts自定义组件

您所在的位置:网站首页 echart自定义按钮 从实际项目需求探索ECharts自定义组件

从实际项目需求探索ECharts自定义组件

2023-10-16 21:28| 来源: 网络整理| 查看: 265

1、需求

我们做的大数据项目为了给客户更好的展示数据内容,用到了很多图表来更直观的展示数据,其中有一个图表需要展示的数据为:频率范围以及时间段。

2、思路

刚开始的时候,我们画了一个草图,根据草图来制作ECharts图表,大致如下:

image-20220525000728881.png

仿照着草图做了后发现,其实这样展示的是不全面的,因为时间是个范围,这样只能展示某个时间,而不能很好的展示时间段之间的数据,于是经过我们再三思索,又花了第二个草图,大致如下:

image-20220525001003461.png

这个草图就可以很好的展示时间段与频率范围之间的关系了。

3、问题

但是当我利用现有的图表来绘制草图的时候,发现根本找不到哪个图表可以完整的来绘制我们想要的图表,经过我翻遍了ECharts图表所有实例后,找到了一个之前一直没接触过的"新东西" —— 自定义组件。

4、自定义组件 series-custom

自定义系列

自定义系列可以自定义系列中的图形元素渲染。从而能扩展出不同的图表。

同时,echarts 会统一管理图形的创建删除、动画、与其他组件(如 dataZoom、visualMap)的联动,使开发者不必纠结这些细节。

import * as echarts from 'echarts' export default { props: { data: { default: null }, type: { default: 'noOccupy' }, eId: { default: 'chart' } }, data() { return { myChart: null, // 声明图表初始化内容 echartData: { grid: { top: '10%', left: '13%', right: '7%', bottom: '24%' }, xAxis: { type: 'value', name: '频率', nameLocation: 'center', nameGap: 30, // 清除横线 splitLine: false, axisLine: { show: true, lineStyle: { color: 'white' } }, axisTick: { show: true } }, yAxis: { name: `时\n间`, type: 'category', nameLocation: 'center', nameTextStyle: { align: 'center' }, nameGap: 90, nameRotate: 360, axisLabel: { formatter: val => val.slice(5, 16) }, axisTick: { alignWithLabel: true }, axisLine: { lineStyle: { color: 'white' } } }, // 缩放组件,时间多的时候y轴内容会很小,所以y轴也加了一个 dataZoom: [ { type: 'slider', show: true, height: 10, bottom: 10, // 设置这个就可以和图表绑定,实现缩放,0为第一个图表,基本只有一个 xAxisIndex: 0, borderColor: 'transparent', handleColor: '#aab6c6', realtime: true, start: 0, end: 100, textStyle: { color: '#fff' } }, { type: 'inside', realtime: true }, { type: 'slider', show: true, width: 10, height: 285, right: 20, bottom: 20, // 设置这个就可以和图表绑定,实现缩放,0为第一个图表,基本只有一个 yAxisIndex: 0, borderColor: 'transparent', handleColor: '#aab6c6', realtime: true, start: 0, end: 100, textStyle: { color: '#fff' } } ], series: [ { // 设置当前图表为自定义图表 type: 'custom', // 开发者自定义渲染逻辑(renderItem 函数) renderItem: this.renderItem, // 给组件分配维度数据 encode: { y: [5, 4], x: [2, 0] } } ] } } }, watch: { data(val) { this.setData(val) } }, mounted() { this.initChart() }, methods: { initChart() { this.myChart = echarts.init(document.getElementById(this.eId)) this.myChart.setOption(this.echartData) if (this.data) { this.setData(this.data) } }, setData(data) { const frees = [] data.forEach(itm => { const { freeList, occupyList, ...times } = itm freeList.forEach(i => frees.push({ ...i, ...times })) }) const seriesData = frees this.myChart.setOption({ series: [ { data: seriesData.map(itm => Object.values(itm)) } ] }) }, // renderItem 函数提供了两个参数: // params:包含了当前数据信息和坐标系的信息。 // api:是一些开发者可调用的方法集合。 renderItem(_, api) { // api.value(...),意思是取出 dataItem 中的数值。 // 例如 api.value(0) 表示取出当前 dataItem 中第一个维度的数值。 // 所以说自义定图表的单个data数据只能为一维数组。 var endIndex = api.value(5) // api.coord(...),意思是进行坐标转换计算。 // 例如 var start = api.coord([api.value(0), endIndex]) 表示 data 中的数值转换成坐标系上的点。 // 左下角点的位置 var start = api.coord([api.value(2), endIndex]) // api.size(...) 函数,表示得到坐标系上一段数值范围对应的长度。 // api.value(0) - api.value(2)计算图形宽度 // 高度默认为一个间距 var size = api.size([api.value(0) - api.value(2), endIndex]) return { type: 'rect', // 自定义形状 - 矩形 shape: { // 初始点的坐标 x: start[0], y: start[1], // 形状宽度 width: size[0], // 形状高度 height: size[1] }, // 图形样式 style: api.style({ fill: 'blue' }) } } } } .chart-layout { width: 800px; height: 350px; margin: 0 auto; background-color: darkgray; } .chart { width: 100%; height: 100%; padding: 0vw 1vw 1.5vw; box-sizing: border-box; }

效果如下:

image-20220525153317798.png

5、”聪明“的甲方

当做完这个功能以后,甲方又提要求了,不仅要显示时间段对应的频率范围,还要有一个占用度,用来表示当前频段范围占用了频率的百分比。

6、CSS百分比背景颜色?

我的想法是,可以设置css背景色百分比渲染dom,我翻过了css关于背景色的属性,好吧~,并没有找到相对应的属性,只好再次翻找自定义图表相关的属性了。

7、自定义组件组

然后我发现了这个,renderItem的type属性有个‘group’,可以返回一组图形。

image-20220525134223239.png

那么,这个属性可以帮我们实现想要的需求嘛?

是可以的,我们可以创建两个相同高度自定义图形,第一个图形宽度为全宽度只设置其边框,内容设为透明,而第二个图形设置其内容颜色,但宽度要和占用比相乘。两个图形合并,就可以达到我们想要的样子了。

import * as echarts from 'echarts' export default { props: { data: { default: null }, type: { default: 'noOccupy' }, eId: { default: 'chart' } }, data() { return { myChart: null, echartData: { grid: { top: '10%', left: '13%', right: '7%', bottom: '24%' }, xAxis: { type: 'value', name: '频率(MHz)', nameLocation: 'center', nameGap: 30, // 清除横线 splitLine: false, axisLine: { show: true, lineStyle: { color: 'white' } }, axisTick: { show: true } }, yAxis: { name: `时\n间`, type: 'category', nameLocation: 'center', nameTextStyle: { align: 'center' }, nameGap: 90, nameRotate: 360, axisLabel: { formatter: val => val.slice(5, 16) }, axisTick: { alignWithLabel: true }, axisLine: { lineStyle: { color: 'white' } } }, dataZoom: [ { type: 'slider', show: true, height: 10, bottom: 10, xAxisIndex: 0, borderColor: 'transparent', handleColor: '#aab6c6', realtime: true, start: 0, end: 100, textStyle: { color: '#fff' } }, { type: 'inside', realtime: true }, { type: 'slider', show: true, width: 10, height: 285, right: 20, bottom: 20, yAxisIndex: 0, borderColor: 'transparent', handleColor: '#aab6c6', realtime: true, start: 0, end: 100, textStyle: { color: '#fff' } } ], series: [ { type: 'custom', renderItem: this.renderItem, encode: { y: [5, 4], x: [2, 0] } } ] } } }, watch: { data(val) { this.setData(val) } }, mounted() { this.initChart() }, methods: { initChart() { this.myChart = echarts.init(document.getElementById(this.eId)) this.myChart.setOption(this.echartData) if (this.data) { this.setData(this.data) } }, setData(data) { const frees = [] data.forEach(itm => { const { freeList, occupyList, ...times } = itm freeList.forEach(i => frees.push({ ...i, ...times })) }) const seriesData = frees this.myChart.setOption({ series: [ { data: seriesData.map(itm => Object.values(itm)) } ] }) }, renderItem(_, api) { var endIndex = api.value(5) var start = api.coord([api.value(2), endIndex]) var size = api.size([api.value(0) - api.value(2), endIndex]) var occupy = api.value(1) return { type: 'group', children: [ { type: 'rect', shape: { x: start[0], y: start[1], width: size[0] * occupy, height: size[1] }, style: api.style({ fill: 'blue' }) }, { type: 'rect', shape: { x: start[0], y: start[1], width: size[0], height: size[1] }, style: api.style({ fill: 'rgba(255, 255, 255, 0.1)', lineWidth: 1, stroke: 'witer' }) }] } } } } .chart-layout { width: 800px; height: 350px; margin: 0 auto; background-color: darkgray; } .chart { width: 100%; height: 100%; padding: 0vw 1vw 1.5vw; box-sizing: border-box; }

效果如下:

image-20220525153251457.png

我们的功能就完美的实现啦~


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3