視覺化佈局模組開發分享

劇中人發表於2018-10-08

在歷經兩年多的迭代後,Odeon大資料平臺在底層能力建設上已經相當豐滿。最近大半年來在資料視覺化方面也投入了很大的精力,目前自助 BI 產品也已經成功上線並穩定執行了一段時間,今天小劇就來分享下我們在資料視覺化中的一些經驗。

今天的分享主要圍繞 視覺化佈局模組 的一些工作,佈局模組是承載視覺化圖表的一塊畫布,是使用者用來組織業務邏輯的重要手段之一。先來體驗下 線上demo 或者看下面的效果圖:

圖一:視覺化佈局模組效果圖

效果圖

一、為什麼要開發視覺化佈局元件 ?

其實不管是在資料視覺化,還是在一些自助釋出的運營平臺,自助佈局一直是一個難以跳過的問題。在專案開始之初這個問題也同樣在困擾著我們,是我們開發幾套預置模版讓使用者挑選,還是開發一套讓使用者可拖拽配置的佈局模組?

前者實現上非常簡單,也很容易設計的非常精美,但是缺少了很多靈活性,很容易千篇一律。後者使用者在使用上自由度非常高,可以拖拽出更符合自己預期的介面,但是開發成本相對較高,並且想要達到穩定、易用、高輔助性卻比較難。

綜合考慮上面的這些問題,我們對制定的幾套方案均不滿意,最終還是決定自己動手實現一個可以輔助使用者進行拖拽佈局的元件。

二、我們是怎麼做的 ?

經過設計,我們對互動模型做了梳理,設計了卡片、圖表兩層結構。在此基礎上對資料模型做了整體設計,結合上面效果圖和 線上 demo 可以更加容易理解下面的劃分。

首先是區域性範圍內單例的 Map 類,用來描述整個 dashboard 佈局,以及其他資料儲存。

其次是 Widget 類,用來定義卡片資訊,包含卡片的尺寸、位置資訊,以及更詳細的卡片標題、卡片型別、腳註、圖表ID 等資訊。

最後是 Chart 類,用來定義圖表資訊。為了佈局與圖表模型分離,這裡的圖表資訊放置較少,僅僅儲存了必要的 id 等欄位,圖表本身實現由外部 slot 插槽來完成。

圖二:資料模型

資料模型

三、互動如何處理 ?

資料模型構建好了,接下來就是著手設計拖拽互動了。

出於響應式考慮,同時為了減少使用者操作的隨意性,在佈局設計上我們放棄了畫素單位,而是針對節點尺寸設計了虛擬的 12 柵格切分,在初始化、縮放、移動時都嚴格參照此柵格佈局。

為了保障使用者拖拽體驗的順暢,使佈局保持整齊,我們在遵循卡片自動調整邏輯的基礎上,設計了卡片的重繪流程,這一點在後面會有詳細的介紹。

為了提供更好的拖拽體驗,我們額外設計了虛擬卡片用來輔助使用者進行佈局,使用者隨時可以預覽鬆開滑鼠後卡片處在的位置及大小,效果如下圖陰影處所示。

圖三:拖拽預覽效果圖

輔助佈局

四、有哪些困難點 ?

有上面的資料模型設計,其實一大半的困難已經被解決了。難點主要體現在輔助佈局過程中易用性上的一些處理,總結下來有以下幾點。

1、碰撞檢測如何處理

其實單純的碰撞檢測是很容易解決的,畢竟所有卡片只是二維矩形而已,這一點並不是難事,困難的是碰撞後被接觸的卡片需要騰出位置進行讓位,我們需要找到所有被碰撞到的卡片,以及受此卡片影響的所有後續卡片,這是一個較為困難的點。

圖四:碰撞檢測佈局重繪過程

拖拽碰撞檢測

2、自動吸頂效果如何實現

在設計佈局的過程中,使用者可能會把卡片拖得七零八落,而且在上面提到的碰撞檢測的處理過程中,也會導致相鄰卡片受影響。初期的互動在體驗後發現,拖拽過程中使用者需要花很長時間來重新整理佈局,因此為了保證佈局排列緊密,必須要有一個方法,能夠將所有處於懸空狀態的卡片依序吸頂處理。

圖五:自動吸頂佈局重繪過程

拖拽碰撞檢測

五、如何處理這兩個問題 ?

上面提到的這兩個困難點,在移動、縮放這兩個拖拽互動中都存在,並且邏輯上是一致的,因此在拖拽佈局過程中我們抽象出了一套重繪邏輯,按順序整理如下:

  • 1、碰撞檢測,找出拖拽過程中與當前卡片相重疊的卡片,可能會多個卡片與之接觸;
  • 2、圈選影響範圍,也就是圖四左側所示,遞迴找到受碰撞的卡片影響的所有卡片,去重處理;
  • 3、臨時讓位,如圖四右側所示,所有將受影響的卡片做相同幅度向下移位處理,用來容納被拖拽的卡片;
  • 4、自動吸頂,圖五部分所示,需要自動處理所有卡片,邏輯是卡片上方如有可用空間,則自動吸附上去。

因為拖拽需要實時預覽效果,上面這四步重繪邏輯會被頻繁觸發。為了避免在佈局過程中反覆汙染真實的位置資料,我們為卡片位置我們引入了 previewOffset 欄位,用來存放預覽效果時的垂直偏移量。

可能會有同學會產生一個疑問:這裡是業務上的重繪邏輯,如此高密度的修改資料會不會在效能上表現比較差 ?

其實這個問題的解決得益於 Widget 類 的資料模型設計,在從碰撞檢測到自動吸頂等一系列處理過程中,被頻繁計算、修改的僅僅為相對單位的 position 物件,而介面佈局使用的是絕對單位的 screenPosition 物件。資料與表現是分離的,僅當一個重繪流程結束之後才去觸發 screenPosition 的更新,如此設計使得介面更新節奏更可控,介面更穩定,避免了視覺上卡片位置的閃爍的問題。

按照此重繪邏輯,既避免了 dom 層冗餘的重繪開銷,提高了整體效能,又在介面佈局的易用性上得到大大提升,操作體驗上也更加穩定、流暢。


本文主要從視覺化佈局模組的互動邏輯的設計上展開,並未涉及到具體程式碼實現,作為 Odeon 大資料平臺在視覺化佈局模組的一些思路,相信通過本文您已經有了初步的瞭解。

如果您對文中提到的碰撞檢測、讓位處理、吸頂效果以及輔助佈局中等具體實現細節感興趣,歡迎私下進行探討,可能的話我會另開一篇文章詳細展開來聊。


相關連結

來源:https://juejin.im/post/5bbb12c6f265da0ab228458f

相關文章