Echarts 踩坑
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Echarts 踩坑相关的知识,希望对你有一定的参考价值。
参考技术A 导语:近日在项目中需要用到echarts图表,因为是第一次使用echarts图表画图,所以也遇到很多坑;特意整理总结了一下,希望对小伙伴有帮助1.tooltip(提示框) 提示框的样式数据和样式修改
因为项目中的图数据是区间的数据差,例如:'+99.9' = '+99' + '+95' ; [+99.9,+99,+95] = [5,3,2]
所以在'series':[
'type': 'bar',
'barWidth': this.bar_width,
'barGap': '-50%',
'stack': '指标范围',
'silent': true,
'name': '-95',
'data': this.sci.ciData['+95'],
'itemStyle':
'color': '#174496'
]中的数据都是区间,但是我们在提示框中数据肯定需要一个确切的数据,而不是一个区间的数据;但是我们tooltip 中默认的数据是从series中拿到的数据片段,所以这个时候我们需要将series中data进行改写
注意:series类目中没有加data属性的,在tooltip中是拿不到data的 数据,这个在后面legend可以用到;
2.因为我的需求是渲染不同的图表,所以我把图表做成了子组件,就会出现请求不同的数据会渲染不同的图表
大坑:只渲染第一个图表,但是父组件图表的数据已经拿到了,但是页面没有渲染
原因是子组件没有渲染DOM,也就是没有初始化,所以这个时候我们就要手动让每个子组件图表重新初始化一次,只需要在init中加入this.echart.resize
3.legend显示与series中显示不同的问题
官方给的是data默认取得是series.name或者是series.encode的seriesName,但是我们想要的legend并不需要series.name 如下图 红框:legend显示的图例;黄色框是series.name值,显然不同,所以我们需要设计;
首先我们在legend.data中声明我们想要的图例名
legend:
'data':[name:avg,name:n,name:95%,name:99%,name:99.9%]
如果series中有我们声明的name,如avg,n等就不需要重复声明,但是像95%,99%,99.9%没有声明的,我们需要在series中声明,但是不需要声明data属性
4.直角坐标轴Y轴, Y轴设置显示数据为百分比, 配置 yAxis属性中的 axisLabel 里的 formatter: 'value %' ,如果想Y轴不显示数据 formatter: function() return "" .
5.背景的网格线:配置 yAxis属性中的 splitLine是控制横向网格线的,lineStyle配置项可以控制线宽和颜色,color属性为数组,如果数组长度小于线的数量,则会循环该颜色数组,如果不想要网格线,可以通过show:false;或直接将颜色设置为透明
解决echarts使用renderItem自定义图表时的残影问题
公司有一个需求是绘制人员的排班任务甘特图,因为有大量自定义元素和复杂交互,在初版时采用dom+Virtual List的办法来做,显示和交互的效果都不错,但是一旦数据量大的时候,就算是Virtual List在滚动时都会很卡,于是就有了通过echarts使用canvas来绘制甘特图的想法,主要是通过echarts的renderItem自定义图表来展示,于是开始踩坑。
option
yAxis: {
type: \'value\'
}.
xAxis: {
type: \'time\'
}
series: [ { id: \'flightData\', type: \'custom\', renderItem: this.renderGanttItem, dimensions: [null, { type: \'time\' }, { type: \'time\' }, { type: \'ordinal\' }], encode: { x: [1, 2], y: 0, }, data: echarts.util.map(_missions, (item, index) => { let startTime = new Date(this.root.options.startTime) let endTime = new Date(this.root.options.endTime) return [index, startTime, endTime].concat(item); }), }, { type: \'custom\', renderItem: this.renderAxisLabelItem, dimensions: [null, { type: \'ordinal\' }], encode: { x: -1, // Then this series will not controlled by x. y: 0 }, data: echarts.util.map(_staffList, function (item, index) { return [index].concat(item); }), }
],
dataZoom:[
{
id: \'slider_x\',
type: \'slider\',
xAxisIndex: 0,
filterMode: \'none\',
height: 20,
bottom: 0,
start: this.zoom.x_left,
end: this.zoom.x_right,
handleIcon: dragIcon,
handleSize: \'80%\',
showDetail: false,
backgroundColor:\'#E4E7ED9E\',
throttle: 100
},
{
id: \'slider_y\',
type: \'slider\',
filterMode: \'weakFilter\',
fillerColor:\'#d2d9e4\',
yAxisIndex: 0,
zoomLock: true,
width: 20,
right: 0,
start: this.zoom.y_top,
end: this.zoom.y_bottom,
handleSize: 0,
showDetail: false,
backgroundColor:\'#E4E7ED9E\',
throttle: 100
},
{
type: \'inside\',
id: \'insideX\',
xAxisIndex: 0,
throttle: 100,
zoomOnMouseWheel: false,
moveOnMouseMove: true
},
{
type: \'inside\',
id: \'insideY\',
yAxisIndex: 0,
throttle: 100,
zoomOnMouseWheel: false,
moveOnMouseMove: true,
moveOnMouseWheel: true
}
]
在renderGanttItem方法里自定义绘制甘特图元素,因为每一行的元素非常多,所以只显示当前datazoom时间范围内元素。
// 计算视口内横向的显示图形 var slider_x = this.myChart.getModel().option.dataZoom.filter(it => it.id == "slider_x")[0] var sliderXLeft = new Date(slider_x.startValue) var sliderXRight = new Date(slider_x.endValue) // 根据视口的范围筛选元素 ...
这时候碰到问题:renderGanttItem返回的元素group数量是变化的,因为时间轴的移动,显示的元素在不停变化,元素数量当然在变化,echarts对于减少和新增的元素,在界面上会出现残影、动画跳动的问题。参考了文档严格定义了唯一的series-custom.renderItem.return_rect.id也不能解决。
解决办法一
通过设置series-custom.renderItem.return_rect.ignore,节点是否完全被忽略(既不渲染,也不响应事件)。当视口离开元素时,把元素的ignore设置为true,当元素一定出现添加和减少时,先 调用this.myChart.clear(),保证不会在renderItem中有元素增减。
这个办法有用,但是碰到每行元素很多的时候,就算时设置了ignore,也可以看到卡顿,没有canvas对比dom的流畅,只能修改dataZoom-slider.throttle增加节流来减少卡顿。
解决办法二
通过查看源码,看到这样一段注释:
// Usage: // (1) By default, `elOption.$mergeChildren` is `\'byIndex\'`, which indicates that // the existing children will not be removed, and enables the feature that // update some of the props of some of the children simply by construct // the returned children of `renderItem` like: // `var children = group.children = []; children[3] = {opacity: 0.5};` // (2) If `elOption.$mergeChildren` is `\'byName\'`, add/update/remove children // by child.name. But that might be lower performance. // (3) If `elOption.$mergeChildren` is `false`, the existing children will be // replaced totally. // (4) If `!elOption.children`, following the "merge" principle, nothing will happen. // // For implementation simpleness, do not provide a direct way to remove sinlge // child (otherwise the total indicies of the children array have to be modified). // User can remove a single child by set its `ignore` as `true` or replace // it by another element, where its `$merge` can be set as `true` if necessary.
在renderItem返回的group元素中设置$mergeChildren=\'byName\',并且给每一类元素设置一个name,这样每次都会根据name来更新元素
renderGanttItem = (params, api) => {
...
return {
type: \'group\',
name: \'gantt-group\',
id: categoryIndex,
info: {data:item},
children: allChildren,
$mergeChildren: \'byName\'
};
}
这样设置了以后,大量元素滚动也非常顺滑,解决问题
以上是关于Echarts 踩坑的主要内容,如果未能解决你的问题,请参考以下文章
在Vue项目中引入 ECharts 3D 路径图 Flights GL(需安装echartsecharts-gljQuery依赖,已踩坑)
vue父组件异步传递prop到子组件echarts画图问题踩坑总结