公司有一个需求是绘制人员的排班任务甘特图,因为有大量自定义元素和复杂交互,在初版时采用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返回的元素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使用renderItem自定义图表时的残影问题
原文:https://www.cnblogs.com/mesopotamiaa/p/14813917.html