解决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返回的元素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'
    };

}
复制代码

这样设置了以后,大量元素滚动也非常顺滑,解决问题

posted @   索美不达米亚  阅读(2000)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示