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依赖,已踩坑)

echarts自定义折线图横坐标时间间隔踩坑总结

vue父组件异步传递prop到子组件echarts画图问题踩坑总结

解决echarts使用renderItem自定义图表时的残影问题

vue踩坑之旅 -- computed watch

echarts关系图配置详解