從0到1設計通用數據大屏搭建平臺

来源:https://www.cnblogs.com/vivotech/archive/2022/10/17/16785572.html
-Advertisement-
Play Games

基於可視化搭建的方式來實現通用數據大屏搭建的解決方案,通過對平臺能力的開發來講解可視化搭建的核心功能實現,幫助有需要的同學瞭解可視化搭建的整體架構設計流程。 ...


作者:vivo 互聯網大數據團隊- Wang Lei

一、前言

一直以來,許多產品平臺都在嘗試通過可視化搭建的手段來降低 GUI 應用的研發門檻,提高生產效率。隨著我們業務的發展,數據建設的完善,用戶對於數據可視化的訴求也日益增多,而數據大屏是數據可視化的其中一種展示方式,它作為大數據展示媒介的一種,被廣泛運用於各種會展、公司展廳、發佈會等。

相比於傳統手工定製的圖表與數據儀錶盤,通用大屏搭建平臺的出現,可以解決定製開發, 數據分散帶來的應用開發、數據維護成本高等問題,通過數據採集、清洗、分析到直觀實時的數據可視化展現,能夠多方位、多角度、全景展現各項指標,實時監控,動態一目瞭然。

本文將通過敏捷BI平臺的通用大屏搭建能力的實現方案,來講解一下通用可視化搭建平臺整體的設計思路。

二、快速瞭解可視化大屏

2.1 什麼是數據可視化

從技術層面上來講,最直觀的就是前端可視化框架:Echart、Antv、Chart.js、D3.js、Vega 等,這些庫都能幫我們快速把數據轉換成各種形式的可視化圖表。

圖片

業務層面來講, 其最主要的意義就在於通過數據 -> 圖表組合 -> 可視化頁面這一業務流程,來幫助用戶更加直觀整體的分析不同行業和場景的趨勢和規律。

圖片

所以在數據領域里,對於複雜難懂且體量龐大的數據而言,圖表的信息量要大得多,這也是數據可視化最根本的目的。

2.2 可視化大屏都有哪些部分

主要由 可視化組件 + 事件交互 + 坐標關係 組成,效果如下圖所示:

圖片

2.3 可視化大屏和常見的BI報表看板的區別

經常會有同學會問到,可視化大屏和BI報表看板的區別是什麼?

這裡簡單的做一下介紹:

  1. 大屏和報表看板都只是BI的其中一種展現方式,大屏更多是通過不同尺寸的顯示器硬體上進行投屏,而報表看板更多是在電腦端進行展示使用。

  2. 大屏更加註重數據動態變化 ,會有極強的視覺體驗和衝擊力,提供豐富的輪播動畫、表格滾動等動畫特效。而報表看板更註重互動式數據探索分析,例如上捲下鑽、排序、過濾、圖表切換、條件預警等。

三、設計思路

3.1 技術選型

  • 前端框架:React 全家桶(個人習慣)

  • 可視化框架:Echarts\DataV-React (封裝度高,json結構的配置項易拓展) D3.js(可視化元素粒度小、定製能力強)

  • 拖拽插件:dnd-kit (滿足樹狀結構視圖的跨組件拖拽)

  • 佈局插件:React-Grid-Layout(網格自由佈局,修改源碼,支持多個方向的拖拽,自由佈局、鎖定縮放比等)

3.2 架構設計

下圖是我們搭建平臺的整體架構設計:

圖片

整個大屏搭建平臺包含四個非常重要的子系統和模塊:

  • 可視化物料中心:是整個平臺最基礎的模塊,我們在開源的圖表庫和自主開發的可視化組件上面定義了一層標準的 DSL 協議,這個協議和接入 畫布編輯器 的協議是對應的,目前已經有 40+ 相關組件,組件數量還在不斷增長。

  • 畫布編輯器:是搭建平臺的核心與難點,支持頁面佈局配置、頁面交互配置和組件數據配置等功能,另外還支持代碼片段的配置,也可以稱得上是一個低代碼平臺。

  • 數據中心:是提供專門用於連接不同數據源的服務,例如直連 MySQL、ClickHouse、Elasticsearch、Presto 等,提供了大屏搭建所需要的原始數據。

  • 管理中心:是大屏的後臺運營管理模塊,包含了大屏模版管理、大屏發佈下線、訪問許可權等管理功能。

3.3 搭建流程

通過上面提到的大屏組成元素,我們可以分析總結出大屏搭建主流程如下圖所示:

圖片

四、核心功能實現

接下來我們會逐一對平臺幾個核心功能實現進行解析:

1、大屏自適應佈局

背景:解決頁面錯亂問題,實現多種解析度的大屏適配:

思考:首先我們想到的是移動端適配主流的 vh、vw、rem組合的方式以及 font.js+rem 等兩種方案。第一種方案主要是通過媒體查詢來定義父級大小,然後對組件的height、margin、padding等多種css屬性採用rem作為單位,繼承父級設置等單位(1vw),實現自適應適配,第二種方案是引用第三方腳本,通過在main.js中寫代碼計算,使用rem進行繼承,實現適配。

① vh、vw、rem組合

//vw vh單位 w3c的官方解釋 vw:1% of viewport’s width vh:1% of viewport’s height
//例如,設計稿的寬度為1920px,則1vw=19.2px,為了方便計算,我們將html元素的font-size大小設置為100px,也就是5.208vw=100px。
body,html {
     font-size:5.208vw
}

② font.js + rem

//監聽視窗的oversize事件,來動態計算根節點字體大小,再配合rem做適配
(function(doc, win) {
    const docEl = doc.documentElement
    const resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'
    const recalc = function() {
      let clientWidth = docEl.clientWidth
      if (!clientWidth) return
      docEl.style.fontSize = 100 * (clientWidth / 1920) + 'px'
    }
    if (!doc.addEventListener) return
    win.addEventListener(resizeEvt, recalc, false)
    doc.addEventListener('DOMContentLoaded', recalc, false)
})(document, window)

缺陷:當我們大屏裡面使用到的第三方插件,它的樣式使用的是px為單位時,例如 line-height 的設置為20px,此時就不能適應行高,就會出現重疊等錯亂問題。或者我們利用 postcss-px2rem 插件進行全局替換,但是在使用過程中,需要註意對已經處理過適配的插件,例如 Ant Design,否則引入的antd 控制項使用會出現樣式錯亂的問題

解決思路:採用了css3 的縮放 transform: scale(X,Y) 屬性,主要是通過監聽瀏覽器視窗的 onresize 事件,當視窗大小發生變化時,我們只需要根據大屏容器的實際寬高,去計算對應的放大縮小的比例,就可以實現佈局的自適應了,我們也提供了不同的佈局適應效果,例如等高縮放、等寬縮放、全屏鋪滿等,不同的縮放方式,決定了我們在計算寬高比例的優先順序。因此我們後面在做畫布的縮小功能,也可以直接使用這種方案來實現。

// 基於設置的設計稿尺寸 換算對應的寬高比
useEffect(() => {
    const wR = boxSize.width / viewWidth;
    const hR = boxSize.height / viewHeight;
 
    setBgScaleRatio(wR);
    setBgHeightScaleRatio(hR);
}, [boxSize, viewWidth, viewHeight]);
 
//根據等寬、等高、全屏等不同的縮放比例 計算scale值
const getScale = (proportion, x, y) => {
    if (proportion === 'radioWidth') {
        return `scaleX(${x})`
    }
    if (proportion === 'radioHeight') {
        return `scaleY(${y})`
    }
    return `scale(${x}, ${y})`
}

2、大屏組件通用開發流程設計

背景:隨著可視化組件的增多、新增組件流程繁瑣冗長,為了避免重覆的造輪子以及後續引入第三方組件,需要制定一套通用的組件開發流程:

設計思路:組件 = component 組件主體 + schema 組件配置協議層 + 組件定義層(類型、從屬關係、初始化寬高等)

① component 組件主體:

  • 可視化框架選型:行業主流可視化庫有 Echart、Antv、Chart.js、D3.js、Vega、DataV-React 基於可視化的通用性和定製性的需求,我們選擇了 Echart、DataV-React 作為基礎組件的開發框架,面對定製性要求更高的自定義組件,我們選擇了可視化粒度更小的 D3.js。

  • 封裝通用 Echarts 組件(初始化、事件註冊、實例註銷等):

// initialization echarts
const renderNewEcharts = () => {
    // 1. new echarts instance
    const echartObj = updateEChartsOption();
    // 2. bind events
    bindEvents(echartObj, onEvents || {});
    // 3. on chart ready
    if (typeof onChartReady === 'function') onChartReady(echartObj);
    // 4. on resize
    echartObj.resize();
};
 
// bind the events
const bindEvents = (instance, events) => {
    const _bindEvent = (eventName, func) => {
       instance.on(eventName, (param) => {
           func(param, instance);
       });
    };
 
    // loop and bind
    for (const eventName in events) {
        if (Object.prototype.hasOwnProperty.call(events, eventName)) {
            _bindEvent(eventName, events[eventName]);
        }
    }
};
 
// dispose echarts and clear size-sensor
const dispose = () => {
    if ($chartEl.current) {
       clear($chartEl.current);
       // dispose echarts instance
       (echartsLib || echarts).dispose($chartEl.current);
    }
};
  • 封裝通用 DataV 組件(DataV-React、自定義等組件入口,統一負責配置、數據收集、監聽resize)

const DataV: React.FC<DataVProps> = (props) => {
    const { config } = props;
    const [renderCounter, setRenderCounter] = useState(0);
    const $dataVWarpEl = useRef(null);
    const $componentEl = useRef(null);
 
    useEffect(() => {
        // 綁定容器size監聽
        const resizefunc = debounce(() => {
            $componentEl.resize();
        }, 500)
       // fixme
       addResizeListener($dataVWarpEl.current, resizefunc);
       return () => {
           // 清除訂閱
           removeResizeListener($dataVWarpEl.current, resizefunc);
       };
    }, []);
 
    return (
        <DataVWarp ref={$dataVWarpEl}>
            <CompRender config={config} ref={$componentEl} />
        </DataVWarp>
    );
};

② schema 組件配置協議層 + 組件定義層(類型、從屬關係、初始化寬高等)

我們自定義了一套 schema 組件的DSL,結構協議層。通過DSL約定了組件的配置協議,包括組件的可編輯屬性、編輯類型、初始值等,之所以定義一致的協議層,主要是方便後期的組件擴展,配置後移。

圖片

  • JSON Schema設計:

{
    headerGroupName: '公共配置',                         //配置所屬類型
    headerGroupKey: 'widget',                           //配置所屬類型key值 相同的key值都歸屬一類
    name: '標題名稱',                                    //屬性名稱
    valueType: ['string'],                              //屬性值類型
    optionLabels: [],                                   //服務下拉列表、多選框等控制項的標簽名
    optionValues: [],                                   //服務下拉列表、多選框等控制項的標簽值
    tip: false,                                         //配置項的 Tooltip 註解
    ui: ['input'],                                      //使用的控制項類型
    class: false,                                       //控制項類名,定製控制項樣式
    css: { width: '50%'},                               //修改控制項樣式
    dependencies: ['widget,title.show,true'],           //屬性之間的聯動,規則['配置所屬類型, 屬性key, 屬性值']
    depContext: DepCommonShowState,                     //屬性之間的校驗回調方法
    compShow: ['line'],                                 //哪些組件可配置
    dataV: { key: 'title.text', value: '' },            //配置的key值和預設value值
},
  • 表單DSL設計:

圖片

收益:以上是我們定製的DSL結構協議層,用戶只需要填寫Excel表格,就可以實現動態表單的創建,實現組件配置項分類、配置復用、配置項之間聯動、屬性註釋等功能。目前屬性配置器已經支持了常用的15種的配置UI控制項,通過定製的DSL結構協議層,可以快速完成組件的配置界面初始化,為後續規劃的組件物料中心做準備。

3、拖拽器實現

背景:React-Grid-Layout 拖拽插件不支持自由佈局和組件不同緯度拖拽:

解決方案:通過分析源碼,對不同緯度的拖拽事件以及拖拽目標碰撞事件進行了重寫,並且也拓展了鎖定寬高比、旋轉透明度等功能。

源碼分析:

圖片

resize伸縮特性增強(優化),拖拽的同時,除了修改容器寬高外,也動態調整了組件的坐標位置。

// CSS Transforms support (default)
if (useCSSTransforms) {
    if (activeResize) {
        const { width, height, handle } = activeResize;
        const clonePos = { ...pos };
        if (["w", "nw", "sw"].includes(handle)) {
            clonePos.left -= clonePos.width - width;
        }
        if (["n", "nw", "ne"].includes(handle)) {
            clonePos.top -= clonePos.height - height;
        }
        style = setTransform(clonePos, this.props.angle);
    } else {
        style = setTransform(pos, this.props.angle);
    }
}

堆疊顯示,自由佈局(優化),通過控制佈局是否壓縮,動態調整拖拽目標的層級zIndex來實現多圖層組件操作交互和自由定位。

// 每次拖拽時zIndex要在當前最大zIndex基礎上 + 1,並返回給組件使用
const getAfterMaxZIndex = useCallback(i => {
    if (i === curDragItemI) {
        return;
    }
    setCurDragItemI(i);
    setMaxZIndex(maxZIndex => maxZIndex + 1);
    return maxZIndex;
}, []);

改造後效果展示

圖片

4、大屏狀態推送

背景:大屏的後期維護需要有版本發佈自更新以及大屏下線等需求,這個時候就需要有一套消息通知機制,通過命令來控制大屏的運行狀態。

解決方案:基於websocket通信機制,建立長鏈接,實現了心跳及重連機制,實時對上線發佈後的大屏進行更新或下線管理。

圖片

五、效果預覽

圖片

六、總結

本文通過可視化頁面搭建、no/low code 平臺、Schema 動態表單等技術思想來分析講解瞭如何去設計開發一個通用的數據大屏搭建平臺。

當前的設計方案基本滿足了數據大屏的核心能力搭建需求。如果想實現更富有展現力, 滿足更多場景的大屏搭建平臺, 我們還需要進一步提高平臺的擴展性和完善整體的物料生態, 具體規劃如下:

  • 豐富和拓展大屏組件&配置能力,覆蓋不同行業的可視化場景。

  • 可視化物料平臺的搭建,沉澱優秀的可視化組件、大屏模版素材。

  • 3D以及動效渲染引擎開發實現。

分享 vivo 互聯網技術乾貨與沙龍活動,推薦最新行業動態與熱門會議。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先依賴註入 懶得下載autofac了 直接用程式集進行批量註入 private static WebApplicationBuilder builder; internal static void Load(WebApplicationBuilder web) { builder = web; b ...
  • 前面簡單介紹了騰訊雲的由來和定義,本編介紹騰訊的簡單使用(我這個展示的是把最近寫的vs項目部署到雲服務中): 1、首先根據前面的定義註冊個騰訊雲賬戶,然後購買個雲伺服器,當然首次註冊的都有免費體驗資格,我這裡用到的是免費體驗輕量式伺服器: 進入購買然後開通就會顯示在你的輕量伺服器上,會根據你選的wi ...
  • 有這個想法的初衷 喜歡電子和DIY硬體的朋友對稚暉君應該都不陌生,他定期都會分享一些自己做的好玩的硬體,他之前做了一個ElectronBot桌面機器人我就很感興趣,所以就自己也做了一個。 起初我只是自己開發了一個叫電子腦殼的上位機軟體,大家在之前的博客里應該也有見到,是個用WinUI(WASDK)開 ...
  • 一、 先決條件 1.Azure Repos Git/Git和項目上傳 把本地的Net Core項目上傳至Azure Repos Git/Git 2.Docker Registry Service Connection/Azure subscription和Azure Container Regist ...
  • keepalived實現nginx負載均衡機高可用 環境說明: | 系統 | 主機名 | IP | 服務 | | | | | | | centos8 | master | 192.168.111.141 | nginxkeepalived | | centos8 | backup | 192.168 ...
  • 摘要:近日,華為雲GaussDB企業級分散式資料庫內核正式通過了全球知名獨立認證機構歐洲SGS Brightsight實驗室的安全評估,獲得全球權威信息技術安全性評估標準CC EAL4+級別認證。 本文分享自華為雲社區《中國首個,我們拿下了!業界最高級別!華為雲GaussDB資料庫榮獲國際CC EA ...
  • 摘要:本文主要描述下函數在滿足特征的前提下可以把函數屬性定義為下推屬性。 本文分享自華為雲社區《GaussDB(DWS)性能調優:函數下推》,作者:譡里個檔 。 DWS作為MPP架構的數倉產品,其性能優勢主要在分散式計算上。預設情況下,DWS為了保證結果的正確性,自定義函數預設屬性是不下推的,這會導 ...
  • 資料庫選型是一件很大的事情,也是一件很頭疼的事情。 很多企業並沒有資料庫的選型標準,或者並不瞭解業務需要什麼樣的資料庫。 很多企業的資料庫是開發說了算,熟悉什麼就用什麼,很多選型失誤,導致後期非常尷尬的局面。 那麼資料庫選型要註意什麼呢? 列舉一些例子,取自如下文檔 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...