BI 數(shù)據(jù)可視化平臺建設(shè)(1)—交叉表組件演變實戰(zhàn)
一、背景
表格和表單在前端里面是最復雜的兩類需求,在BI工具平臺上,這2類組件需求更多,并且需要實現(xiàn)一些特有的交互展示。目前在敏捷BI平臺上進行報表配置,表格類組件的使用占比達到了1/3,在可視化組件庫里使用范圍很廣。為了滿足不同的數(shù)據(jù)分析場景,表格組件主要分為分組表、交叉表、明細表三種類型,其中又以交叉表功能最為豐富強大。隨著敏捷BI的業(yè)務(wù)的發(fā)展,交叉表組件也經(jīng)歷了多次設(shè)計改版以支持高性能的數(shù)據(jù)渲染和個性化的展示配置。
術(shù)語注解
- 【敏捷BI】
專為 vivo 生態(tài)用戶量身打造的 自助式 BI 平臺,提供從數(shù)據(jù)接入、數(shù)據(jù)準備、到數(shù)據(jù)分析、可視化應(yīng)用、數(shù)據(jù)管理的一站式數(shù)據(jù)解決方案,同Quick BI,F(xiàn)ineBI。 - 【圖表類型】
圖表是數(shù)據(jù)視覺化表示的特殊方式。表示數(shù)據(jù)的方法有很多,如使用不同的符號、形狀和排列,我們把這些稱之為圖表的類型。一些圖表類型你比較熟悉,如條形圖、餅圖、折線圖,但其他類型你可能就很少見了,如?;鶊D、樹圖、等值線圖的地圖。 - 【交互方式】
交互式可視化允許您修改,操作和探索計算機顯示的數(shù)據(jù)。絕大多數(shù)交互式可視化系統(tǒng)在計算機網(wǎng)絡(luò)上,但越來越多出現(xiàn)在平板電腦和智能手機上。相比之下,靜態(tài)可視化只顯示單一的、非交互數(shù)據(jù),它通常是為了打印和在屏幕上顯示。 - 【度量值】
表示數(shù)值的規(guī)模和范圍。度量通常以間隔表示(10、20、30等等),代表度數(shù)字的單位,如價格、距離、年,或百分比。 - 【指標】
同度量,表示具體某項值,單個值本身沒有任何業(yè)務(wù)意義,一般需要對應(yīng)的指標口徑解釋,才會具有業(yè)務(wù)價值。
二、交叉表介紹
交叉表(Cross Tabulations)是一種常用的由 行、列、匯總字段 三個元素組成分類匯總表格。利用交叉表查詢數(shù)據(jù)非常直觀明了,在進行數(shù)據(jù)分析中也被廣泛應(yīng)用。這里牽涉到另外一個概念即分組報表,分組報表是所有報表當中最普通,最常見的報表類型,也是所有報表工具都支持的一種報表格式。從一般概念上來講,分組報表就是只有縱向的分組,傳統(tǒng)的分組報表制作方式是把報表劃分為條帶狀,用戶根據(jù)一個數(shù)據(jù)綁定向?qū)е付ǚ纸M,匯總字段,生成標準的分組報表。交叉表有多列查詢能力、分類匯總、多角度排序、交互式分析等特性。
三、架構(gòu)演變歷程
為了提高交叉表的數(shù)據(jù)渲染性能和功能擴展能力,敏捷BI的表格組件經(jīng)歷了三次的設(shè)計升級。最開始用的jQuery拼接表格方式實現(xiàn),隨著組件化方案的推行,采用了組件化的方式實現(xiàn)升級,隨著業(yè)務(wù)的發(fā)展,用多維度、多指標交叉分析場景越來越多了,尤其是通過交叉表進行分析時,大數(shù)據(jù)量出現(xiàn)了渲染崩潰等問題,所以我們最后通過微前端方式實現(xiàn)。 下面我們從開發(fā)難度,性能,功能擴展性,學習成本等方面的調(diào)研來講解對底層表格的升級實踐。
3.1 V1版表格
敏捷BI平臺第一版表格,技術(shù)棧是基于jQuery+DIV的方式實現(xiàn)的。表格拼接屬于jQuery時代的常見開發(fā)風格,這種方式,代碼可維護性會非常差,很容易會出現(xiàn)標簽不匹配的情況,不帶縮進,調(diào)試起來也比較費勁。這個版本的表格組件支持的業(yè)務(wù)場景主要是數(shù)據(jù)的基本展現(xiàn),無法滿足用戶對表格的數(shù)據(jù)分析的需求。
架構(gòu)設(shè)計
圖片
// 簡單的拼接代碼demo
function createTable() {
var data = new Array();
data.push('<table border=1><tbody>');
for (var i = 0; i < 2000; i++) {
data.push('<tr>');
for (var j = 0; j < 5; j++) {
data.push('<td>' + i + ',' + j + '</td>');
}
data.push('</tr>');
}
data.push('</tbody><table>');
document.getElementById('table1').innerHTML = data.join('');
}
3.2 V2版表格
隨著系統(tǒng)整體架構(gòu)升級,前后端分離的推進,我們從原生的table組件遷移到Vue組件化上,開發(fā)了V2版表格組件。 平臺的整體架構(gòu)全面遷移到vue+ant-design-vue上面。
1. 功能拓展
鑒于ant-design-vue上正好有table組件,對此我們對比了antd的table組件和element的table組件。2 種表格對比來看,ant-design-vue參照ant.design的React版開發(fā)出來,配置相對element更豐富,考慮到本身復雜場景支持性,更適合深度定制,最終選擇了ant.design的vue版本。
V2版的表格主要支持這幾類場景配置(條件格式,合計行/列,單元格/行樣式/內(nèi)容定制等):
業(yè)務(wù)場景&具體實現(xiàn)
(1)數(shù)據(jù)展示
整體就是根據(jù)不同情況設(shè)置不同的column的字段,另外為了達到點擊交互下,能夠獲取業(yè)務(wù)的數(shù)據(jù),需要在column上掛一些冗余數(shù)據(jù),這樣會讓column的數(shù)據(jù)信息很龐大。
columns是一個tree結(jié)構(gòu),這里采用的是dfs遍歷,depth標識層級,item, itemType就是冗余的數(shù)據(jù)信息,在處理業(yè)務(wù)的時候會用到。
(2)數(shù)據(jù)排序
(3)數(shù)據(jù)過濾
(4)單元格自定義渲染
(5)多級表頭定制
這個實現(xiàn)難點主要在于把已有的列如何放到新增的表頭里,保持樹形children結(jié)構(gòu)具體實現(xiàn)代碼也比較復雜,總共80行。
圖片
(6)條件格式渲染(條形圖,熱力圖)
根據(jù)設(shè)定的條件,定制表格內(nèi)單元格內(nèi)容的樣式
(7)合計行/列配置
添加合計列和行,內(nèi)置min,max,avg,sum表達式,支持自定義簡易字段表達式運算這個功能難點在于合計列與行交叉的場景,也就是如何計算合計列的合計行。
2. 架構(gòu)設(shè)計
3. 渲染優(yōu)化
這個階段的交叉表,在功能上已經(jīng)能夠滿足絕大多數(shù)分析場景,但是一些數(shù)據(jù)量大的表格反饋渲染白屏時間過長,經(jīng)常會出現(xiàn)瀏覽器崩潰,表格的性能面臨新的挑戰(zhàn)。另外表格在渲染時,CPU會占滿,導致其他圖表也會卡住等待,形成假死的現(xiàn)象。我們通過分析大數(shù)據(jù)表格渲染流程,發(fā)現(xiàn)有30%的時間會花銷在數(shù)據(jù)適配,因此我們思考能不能把數(shù)據(jù)計算部分隔離出來,計算的時候,不阻塞渲染主進程,這樣的話,瀏覽器渲染就可以處理其他的渲染任務(wù)。在做性能優(yōu)化調(diào)研時,我們引入了service worker,worker在處理cpu密集型任務(wù)有獨特的優(yōu)勢,所以我們把數(shù)據(jù)預處理的過程交給了Worker。之前沒有使用worker時,我們前端邏輯會處理很多數(shù)據(jù)初始化和計算的操作,對于一個數(shù)據(jù)量很大的表格,會導致渲染卡頓2~3s,有些個別情況會導致瀏覽器崩潰的現(xiàn)象。
Worker原理和定義:
W3C 組織早在 2014 年 5 月就提出過 Service Worker 這樣的一個 HTML5 API ,主要用來做持久的離線緩存。service worker是瀏覽器的一個高級特性,本質(zhì)是一個web worker,是獨立于網(wǎng)頁運行的腳本。
web worker這個api被造出來時,就是為了解放主線程。因為,瀏覽器中的JavaScript都是運行在單一個線程上,隨著web業(yè)務(wù)變得越來越復雜,js中耗時間、耗資源的運算過程則會導致各種程度的性能問題。
而web worker由于獨立于主線程,則可以將一些復雜的邏輯交由它來去做,完成后再通過postMessage的方法告訴主線程。service worker則是web worker的升級版本,相較于后者,前者擁有了持久離線緩存的能力。
3.3 V3版表格
在開發(fā)V2表格時,我們意識到數(shù)據(jù)處理部分不應(yīng)該交給前端,列拼接上摻雜了太多的業(yè)務(wù)場景處理,另外渲染性能和崩潰問題急需解決,對此我們進行了V3版本迭代,提前對表格版本進行了技術(shù)升級,為之后的新一批列匯總行匯總,分組小計等高級交叉分析需求做好技術(shù)儲備。
1. 技術(shù)選型
我們對比了react,vue及canvas生態(tài)有代表性的表格組件。綜合三者優(yōu)劣勢最終確定了基于react的table組件。
S2:https://github.com/antvis/S2
ali-react-table:
https://github.com/alibaba/ali-react-table
vxe-table:
https://github.com/x-extends/vxe-table/tree/v2
vxe-table設(shè)計初衷是解決單元格編輯的問題,主要用于大量增刪改查的場景,性能不是它唯一的目標;S2是建立在電子表格需求上的,對篩選、排序、搜索、復制、框選、聚合分析都有訴求。
同時需要在大數(shù)據(jù)量下保持高性能,解決之前商業(yè)軟件版本實現(xiàn)的性能問題和拓展性問題,所以它覆蓋的場景更全更復雜,但是它的缺點就是定制型不強,不太適合我們自身的業(yè)務(wù)。
所以最終我們選擇了ali-react-table,它本身體積小,在基礎(chǔ)能力都滿足的情況下,擴展新功能也很容易,而且在大數(shù)據(jù)量渲染下有高性能的優(yōu)勢。
2. 架構(gòu)設(shè)計
后端接口返回數(shù)據(jù)和配置部分,基于渲染模型:左樹 + 上樹 => 表格,根據(jù)配置生成左樹leftTree和上樹topTree,構(gòu)造數(shù)據(jù)源,參照了ant-design的Table組件數(shù)據(jù)源構(gòu)造的流程,與自身的pipeline插件機制結(jié)合,實現(xiàn)了表格的交互操作(排序,篩選,分頁)。
由于本項目里接入了微前端架構(gòu),采用了loadApp的方式實現(xiàn)了異構(gòu)應(yīng)用混合開發(fā):
圖片
運作流程圖如下:
3. 升級實踐
(1)架構(gòu)升級:
(2)底層渲染:
虛擬滾動:長列表渲染受制于瀏覽器本身限制,在大量DOM下,會達到瀏覽器本身的渲染瓶頸,在這種情況下,虛擬滾動可以解決這種渲染問題,它是一種按需渲染的理念的體現(xiàn)。所以虛擬列表是一種根據(jù)滾動容器元素的可視區(qū)域來渲染長列表數(shù)據(jù)中某一個部分數(shù)據(jù)的技術(shù)。
大致原理如下圖:
我們發(fā)現(xiàn)長列表在展示時,用戶只會關(guān)注可視區(qū)域,其他非可視區(qū)域部分,我們可以把已經(jīng)渲染的DOM銷毀,不需要立即渲染的DOM延后。所以優(yōu)化策略就是只渲染可見區(qū)域的內(nèi)容。
在滾動事件觸發(fā)后,根據(jù)滾動 Offset 調(diào)整相應(yīng)渲染的內(nèi)容即可。在用戶看來,還是一個完整的長列表。這種懶加載的方式,和早期頁面圖片資源懶加載和非必須資源異步加載屬于同一種思路。
在新版版本里,ali-react-table自帶了虛擬滾動的特性,在大列表下,框架會自動開啟,可以明顯提升表格渲染性能和滾動的性能。
四、同類產(chǎn)品對比
4.1 技術(shù)架構(gòu)對比
1. Quick BI
① 架構(gòu)設(shè)計
② 技術(shù)實現(xiàn)
- 使用原生div和flex布局,不使用原生table表格
- 列寬,固定列,固定表頭等表格不好實現(xiàn)的問題,都易實現(xiàn),渲染性能也較好
- 有2個版本的表格,舊版表格使用table,在這種情況下,性能,復雜交互,分組都存在瓶頸,這一點和我們類似,新老版本的表格同時在線上應(yīng)用
- 虛擬滾動支持橫向,縱向滾動
③ 優(yōu)劣勢
- ali-react-table不維護了,源碼不太復雜,可以二次迭代開發(fā);基本滿足交叉表所有功能;大數(shù)據(jù)量下渲染高性能
- 接口數(shù)據(jù)略冗余
④ 備注
- 數(shù)據(jù)結(jié)構(gòu)明確行維、列維、指標列數(shù)據(jù);
- 數(shù)據(jù)匯總和小計是存放在后端
2. 敏捷BI
① 架構(gòu)設(shè)計
圖片
② 技術(shù)實現(xiàn)
- 使用table布局
- 使用position:sticky實現(xiàn)固定列;固定表頭使用獨立的單表頭表格模擬,這里需要強制table設(shè)置列寬,保證列對齊
- 支持橫向,縱向虛擬滾動,在10w列下依然可以正常渲染
- 在ali-react-table基礎(chǔ)上擴展了按維度合并,表頭篩選等feature
③ 優(yōu)劣勢
- flex布局靈活,不受表格本身布局限制,易實現(xiàn)固定列和表頭,列寬;canvas開發(fā)成本較高,bug不好調(diào)試
- 接口數(shù)據(jù)更精簡
④ 備注
- 數(shù)據(jù)結(jié)構(gòu)不明確,需要對二維數(shù)組轉(zhuǎn)換,存在一定的預處理邏輯;
- 數(shù)據(jù)結(jié)構(gòu)存在冗余現(xiàn)象
4.2 應(yīng)用場景對比
以實際測試為準
1. Quick BI
業(yè)務(wù)場景
(1)字段配置
- 行:數(shù)據(jù)集的維度字段拖拽到行選擇區(qū)
- 列:數(shù)據(jù)集里的維度或者度量字段拖拽到列選擇區(qū)
- 過濾器:數(shù)據(jù)集字段拖拽到過濾器選擇區(qū),對字段進行篩選
(2)樣式配置
- 標題與卡片:設(shè)置標題樣式
- 備注和尾注:設(shè)置圖表備注和尾注內(nèi)容
- 組件容器:設(shè)置內(nèi)邊距和背景色,圓角
- 展示型配置:設(shè)置主題,表頭樣式,內(nèi)容樣式,凍結(jié)列,序號等配置
- 功能型配置:條件格式配置,針對字段滿足特定條件下突出顯示配置的樣式
- 總計配置:支持列匯總和行匯總,行總計和行小計,列總計和列小計
(3)高級配置
- 聯(lián)動:圖表里的字段與其他圖標關(guān)聯(lián)
- 跳轉(zhuǎn):圖表字段跳轉(zhuǎn)傳值
技術(shù)實現(xiàn)
- 實現(xiàn)使用原生,未使用第三方庫
- 自定義主題使用主色編輯
- 拖拽方式交互
2. 網(wǎng)易有數(shù)
業(yè)務(wù)場景
- 沒有復雜的交叉表場景,只支持普通明細表
- 配置方式主要包括主題,表頭,內(nèi)容的字體樣式,背景,對齊等樣式
- 支持下鉆,字段跳轉(zhuǎn)
- 數(shù)據(jù)集字段支持維度層級和組的概念
- 沒有虛擬滾動
技術(shù)實現(xiàn)
- 內(nèi)部使用table表格實現(xiàn)
- 主題配置支持上傳主題json文件
3. 敏捷BI
(1)字段配置
- 行維:數(shù)據(jù)集維度字段放置區(qū)
- 列維:數(shù)據(jù)集維度字段放置區(qū)
- 指標:數(shù)據(jù)集指標字段
(2)圖表屬性和圖表樣式配置
- 支持條件格式,自定義代碼樣式嵌入,主題配置
(3)字段過濾
- 使用字段過濾數(shù)據(jù)
技術(shù)實現(xiàn)
- 最開始使用smooth-dnd庫,來實現(xiàn)從數(shù)據(jù)集字段拖拽到行列、指標區(qū)
- 因為smooth-dnd有性能問題,不再維護等問題,就廢棄掉了,使用原生的拖拽實現(xiàn)
- 主題使用在線代碼編輯主題,基于codemirror在線代碼,接入css variables,實時應(yīng)用,不需要刷新
4.3 部分核心代碼實現(xiàn)
應(yīng)用場景① :表頭篩選
代碼實現(xiàn)
應(yīng)用場景②:按維度合并
代碼實現(xiàn)
4.4 渲染性能對比
1. Quick BI
(1)數(shù)據(jù)量級 <50列
- 接口耗時300ms 接口大小<5kb
- 渲染耗時 < 1s
注:數(shù)據(jù)量不是很大的情況下,數(shù)據(jù)加載忽略不計,合入到數(shù)據(jù)渲染時間,差別不大
(2)數(shù)據(jù)量級 ≥ 200列
- 接口耗時1.88s 接口大小<10kb
- 表格渲染 < 3s
注:數(shù)據(jù)量很大的情況下,數(shù)據(jù)加載需要單獨計入時間
(3)數(shù)據(jù)量級 > 1W列
極端情況下,表格渲染崩潰
圖片
2. 敏捷BI
(1)數(shù)據(jù)量級 <50列
- 接口耗時250ms 接口大小~100kb
- 渲染耗時 < 1s
(2)數(shù)據(jù)量級 ≥ 200列
- 接口耗時300ms 接口大小~300kb
- 渲染耗時 <3s
(3)數(shù)據(jù)量級 > 1W列
- 接口耗時2s 數(shù)據(jù)大小2M
- 渲染耗時~10s
4.5 總結(jié)
網(wǎng)易有數(shù)表格組件較為簡單,只有簡單的數(shù)據(jù)展示和排序篩選,適用于明細數(shù)據(jù)展示場景。
Quick BI表格和敏捷BI在交互,可視化能力,業(yè)務(wù)場景上都保持著同樣的功能,底層實現(xiàn) Quick BI采用原生DIV+Flex布局模擬表格實現(xiàn),在渲染上比表格會有渲染的優(yōu)勢,這點是瀏覽器自身渲染機制決定,我們內(nèi)部實現(xiàn)需要滿足極端數(shù)據(jù)量下數(shù)據(jù)展示,所以特定做了橫向的虛擬列表優(yōu)化,這種場景看業(yè)務(wù)需求,否則表格會過于復雜,得不償失。
表格渲染性能基本與Quick BI性能相當,極端情況下,敏捷BI依舊可以正常渲染,這點優(yōu)于Quick BI。
五、規(guī)劃
- 數(shù)據(jù)預處理部分不由前端處理,交給后端,和后端協(xié)調(diào)好返回的數(shù)據(jù)結(jié)構(gòu),直接返回;
- 表格擴展的功能與表格耦合嚴重,表格渲染不夠純凈;
- 開發(fā)一個Headless UI,不依賴渲染框架,提供一個數(shù)據(jù)適配層,同時支持在Vue3生態(tài)上使用。