Antv/s2 明细表 透视表实现和性能优化(一)

2023-10-08 19:45

本文主要是介绍Antv/s2 明细表 透视表实现和性能优化(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

        以我实际项目环境为准,vue+ts为技术框架,代码如果有什么不懂欢迎留言评论我会回复的

透视表

 定义文件

class PivotTableControl extends BaseControl {type = 'pivotTable';label = 'controls.chart.pivotTable';icon = 'tc-color-pivot-table';widget = () => ({...super.widget(),// 数据源表单relationForm: null,// 数据范围range: 'all',// 行维度xDimension: [],// 列维度yDimension: [],// 指标metrics: [],// 过滤filter: null,// 图表配置typeConfig: chartDefaultConfigs()[this.type],// 背景background: null,});
}

        不用关心BaseControl有什么,看看几个特有的属性:

        xDimension: 行维度

        yDimension: 列维度

        metrics:指标

维度和指标

        业务设计的概念,方便我们理解和开发。先看例子

        一个行维度,一个指标

        

        一个行维度,两个指标

        

        两个行维度,一个指标

        

        到这里,可以看到,行维度就是分组依据,而指标就是对应分组依据的值。

        两个行维度,一个指标

        

在透视表里的维度和指标

         维度(行):分类依据,在「透视表」中指代的是透视表的行数将会以该组件数据进行划分。(如:行维度使用了字段「成员名称」,成员中包含5个不同的字符,于是透视表将会拆分成5行,每一行的命名标题将以「成员名称」的各字符命名。)

        维度(列):跟行维度一样,也是分类依据,在「透视表」中指代的是透视表的列数将会以该组件数据进行划分。(如:列维度使用字段「性别」其中学科包含男女,于是透视表将会划分成2列,分别对应男、女。)

        指标:指标是对维度的量化。在透视表中,他是指代除「列表头」、「行表头」以外的单元格展示的数值,而该数值是从属于相应行和列维度的数据汇总结果(如某单元格的表示的是行为某个成员,列是语文科目的成绩,代表该成员的语文成绩。)

实例:这里是一行维度一指标

 两行维度一指标

一行维度一列维度一指标

两行维度一列维度一指标

搞个复杂点的!两行维度两列维度两指标

S2

        项目里用的功能有这三个

import { PivotSheet, S2Event} from '@antv/s2';

        PivotSheet是它的渲染表格组件,S2Event是事件列表

        S2的设计是把我们行列维度的划分放在了角头中,行头列头都是划分的数据。

S2-封装

      我们要先封装一个配置好的S2表格组件。

const s2OptionsDefault = {width: 0,height: 0,interaction: {resize: {cornerCellHorizontal: true, // 角头水平rowCellVertical: true, // 行头垂直colCellHorizontal: true, // 列头水平colCellVertical: true, // 列头垂直},hoverHighlight: false, // 不开启hover聚光灯效果, 提高性能hoverFocus: false,brushSelection: false,multiSelection: false,rangeSelection: false,enableCopy: true,},pagination: {pageSize: 100,},frozenRowHeader: true,style: {cellCfg: {height: 34,},colCfg: {height: 34,},},hierarchyType: 'grid',conditions: {},
};
const s2DataConfigDefault = {fields: {rows: [],columns: [],values: [],valueInCols: true,},meta: [],data: [],
};

        先写好自己想要的默认配置。创建一个代理类VirtualTableProxy 

export class VirtualTableProxy {#instance;#options;#dataConfig;// 实例get instance() {return this.#instance;}// 配置get options() {return this.#options;}// 数据get dataConfig() {return this.#dataConfig;}setOptions(path, value) {if (!this.#options || typeof path === 'object') {this.#options = path;} else {set(this.#options, path, value);}}setDataConfig(path, value) {if (!this.#dataConfig || typeof path === 'object') {this.#dataConfig = path;} else {set(this.#dataConfig, path, value);}}setInstance(instance) {this.#instance = instance;}
}

        这个类有什么用,我们后面讲

// s2-componentcreated() {// 初始化实例this.VT = new VirtualTableProxy();this.VT.setOptions(deepClone(s2OptionsDefault));this.VT.setDataConfig(deepClone(s2DataConfigDefault));
}

       render函数:

render() {return (<div><div id={this.componentId} class={this.$style.container}></div></div>);
}
componentId = `container_${this._uid}`;

        这里的uid你可以理解为组件的hash标识

        等待模板渲染后:

  mounted() {const container = document.getElementById(this.componentId);this.container = container;this.VT.setInstance(new PivotSheet(container, this.VT.options, this.VT.dataConfig),);}

        这里的setIntance只是把这个s2生成的表格实例存放到VirtualTableProxy 类里的私有属性而已

        注册S2事件监听

mounted() {....this.VT.instance.on(S2Event.DATA_CELL_CLICK, this.dataCellClick);this.VT.instance.on(S2Event.LAYOUT_AFTER_RENDER, () => {this.$emit('finishRender');});
}

            其实几乎就是把事件抛出去给外部处理,毕竟s2-component只是一个加载组件而已

            到这里,这个组件已经基本完成。我们做的只是创建一个代理类用来存储配置、表格实例,同时在组件上渲染了一个初始化的表格。那还差什么?数据注入。

        从外部调用S2-component

        index.vue调用s2-component

// 透视表组件主体文件 index.vue
<template><div><s2-componentref="virtualTableS2":fixed-header-y="widget.fixedY":fixed-header-x="widget.fixedX":field="field":relationFormFieldMap="relationFormFieldMap":total="total":totalText="totalText":metricsMaxValues="metricsMaxValues"@finishRender="finishRender"/></div>
</template>

        

created() {this.init();
}
init() {...// 转换数据结构const tableData = this.generateCommonData({cornerHeader: columnItem,colHeader: columnDimension,rowDimensionCategory: rowItem,metricsCategory: indicatorItem,rowHeader: rowDimension,dataCell: data,summaryResult: {rowSummary: result.summaryResult?.rowSummary || [],colSummary: result.summaryResult?.colSummary || [],},});...
}

        前面都是业务逻辑,将接口端的数据转换成S2表格支持的数据格式。like be...

                这个数据结构呢,类似于上文提到的s2DataConfigDefault。不出意外的话,tableData 将会覆盖原来的s2DataConfigDefault。

init() {// 避免Vue依赖收集this.data = new PivotTableProxy(tableData);
}
export class PivotTableProxy {#data;constructor(data) {this.#data = data;}get data() {return this.#data;}
}

        往下看,你会发现this.data被赋值了给一个类,而tableDate作为类的私有属性被储存起来。这里要引申一个概念,Vue的依赖收集。

Vue的依赖收集和性能问题-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_42274805/article/details/128685452?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169674882416800180624606%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=169674882416800180624606&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-128685452-null-null.nonecase&utm_term=%E4%BE%9D%E8%B5%96%E6%94%B6%E9%9B%86&spm=1018.2226.3001.4450        不懂可以看我这篇,这里为什么要绕开Vue的依赖收集呢。因为依赖收集需要对数据元进行递归绑定。当数据元数据量过大(例如明细表或透视表数十万条数据),会严重影响前端的性能效率。这么去藏值会让效率提升很多哦,特别是几十万条数据的情况下。但是,透视表的渲染将由前端自行控制,而不是由Vue框架的响应式决定。

init() {...// 接上文// 手动渲染透视表this.$nextTick(() => {this.$refs.virtualTableS2?.setData(this.data.data);});}

        看到这里,就该回去S2-component里补完数据注入逻辑啦

S2-封装-数据注入

        上面提到的setData方法。我们来看看怎么实现

 setData(pivotTableData) {const {fields: { rows, columns, values },meta,data,} = pivotTableData;// 配置this.pagination.total = this.total;this.VT.setOptions('frozenRowHeader', this.fixedHeaderY);this.VT.setOptions('style.cellCfg.height', this.field.widget.lineHeight);this.VT.setOptions('style.colCfg.height', this.field.widget.lineHeight);this.VT.setOptions('hierarchyType', this.field.widget.hierarchyType);// 数据this.VT.setDataConfig('fields.rows', rows);this.VT.setDataConfig('fields.columns', columns);this.VT.setDataConfig('fields.values', values);this.VT.setDataConfig('meta', meta);this.VT.setDataConfig('data', data);this.reRender();}

        操作很简单,根据数据去更改VT实例里的属性配置

  // 重新渲染S2reRender() {this.VT.instance.setOptions(this.VT.options);this.VT.instance.setDataCfg(this.VT.dataConfig);this.VT.instance.render(true);}

        上调用VT实例里的S2表格组件实例,填充配置和数据配置,并执行渲染。

        看到这里,大家应该知道为什么要设置VirtualTableProxy类了吧,一方面是为了绕开数据绑定,第二方面是为了把数据、配置、视图模块化。

性能对比

        上面提到过,绕过Vue的依赖收集会有巨大的性能提升。现在来看看效果:

        为了快速定位方法,我把上面的init改成testIn。打开浏览器的性能标签页,开始性能检测。

        这是绕过的:

 this.data = new PivotTableProxy(tableData);

       看到testin方法一共耗时1.03秒,其中this.generateCommonData占用了1.03秒,这个方法就是我们前端遍历转换数据的。

        这是没有绕过的:

this.data = tableData

         此时testin方法耗时了1.91秒,其中generateCommonData耗时仅1.08秒,与上面接近,那么多出来的800多毫秒,是黄色部分组成的。

        看到observer和defineReactive了吗?想到什么?Vue2的双向绑定啊!!Vue对data数据递归后逐个绑定观察者,上面的实验仅有124条数据,便要产生800毫秒的延迟!如果是124万条数据呢?不用怀疑,直接卡死!所以我们才要绕过Vue的依赖收集

这篇关于Antv/s2 明细表 透视表实现和性能优化(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/167605

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time