🙏向這次肺炎疫情中逝世的同胞表示哀悼。css
本文首發於政採雲前端團隊博客: 可視化搭建數據大屏系統的前端實現
隨着公司業務的發展,常常會收到一些數據大屏的需求。目前我司有兩種實現方案,一是人肉搭建,二是用阿里雲 DataV 搭建。html
人肉搭建,在本地腳手架開發環境中進行編碼,有大量的重複勞動,能力複用性差,佔用前端寶貴的開發時間。前端
DataV 功能強大,但須要付費使用,且好用的組件還要額外收費,不支持本地化部署,還須要維護兩套數倉。vue
綜上,若是此類大屏的需求較多,業務的重要性明顯,就須要考慮是否是須要本身開發一套搭建大屏的系統,用以下降開發複雜度,提高研發效率,下降成本。本文嘗試基於政採雲前端團隊的數據大屏搭建系統 Big 的拆解說明,爲你們提供一種此類系統的設計和實施方案。數據庫
Big 是基於政採雲前端搭建系統 魯班,和數據大屏組件庫,進行快速搭建數據大屏的可視化系統。npm
爲何叫 Big 呢? 打開百度翻譯,輸入 大屏
,英文翻譯是 Big screen
,四捨五入叫 Big
。json
數據大屏是用可視化的方式展現龐雜數據的產品,常常會用在會議展覽、業務監控、風險預警、地理信息分析等多種業務場景。下圖是阿里雲 DataV 的一個模板:api
從前端實現來看,大屏是由線圖、柱狀圖、餅圖、標題、背景、邊框等基本元素組成。實現思路是以這些基本元素爲組件,經過選擇組件、拖拽方式佈局,配置樣式、數據來源,將這些數據保存在數據庫中。展現頁面獲取依賴的組件、樣式和數據信息,呈現給用戶。數組
大屏按場景劃分,可分爲編輯和查看。服務器
編輯:指的是大屏製做者製做大屏。
查看:包含兩種狀況,大屏製做者預覽和實際用戶查看大屏。
編輯大屏是數據可視化系統核心,頁面佈局參考 DataV:
拆解爲 4 個部分:頂部、組件區、畫布、數據配置區。先講下設計思路,再依次分解各區。
頂部區域包含三部分:左側開關區、控制圖層、組件列表、數據配置區的顯示隱藏;中間是大屏的標題;右側是保存和預覽。
組件區分爲左側圖層(已添加的組件)和右側組件列表,具有添加組件、選擇操做圖層、分組對齊的功能。
圖層
組件列表
畫布用於實時展現大屏組件的位置、尺寸、屬性和數據修改後的效果。
位置和尺寸改變經過註冊組件 vue-draggable-resizable
的 drag
和 resize
方法,改變對應組件的屬性。組件採用絕對定位,拖動時修改 top 和 left 的值。
屬性改變經過修改對應組件的 props.models 的值修改。
數據分爲靜態數據和接口數據。啓用靜態數據時,數據從用戶填寫的數據獲取。不然組件 watch 接口 id ,每次改變時從新發送請求獲取數據。
畫布上邊和左邊是標尺,畫布縮放時標尺要跟隨變更。在標尺上移動時顯示一條移動的參考線。點擊時增長一條參考線。雙擊參考線刪除。標尺用 Canvas 畫出,旋轉 90 度可得到 Y 軸。
右下是縮放滑塊,方便用戶縮放查看。進入頁面默認縮放到可查看全屏大小。縮放實現使用 CSS3 的 transform: scale(${this.scale})
。
畫布上未選擇組件時,顯示頁面的基本配置,包括大屏的寬高、背景圖。
選擇組件後,高亮顯示當前組件,標識位置,右側數據配置區顯示組件 Schema 定義的配置項。
核心代碼
<div :class="['data-com', item.info.previewId === activePreviewId ? 'data-com-active' : '']" v-for="item in preCompList" :key="item.info.activePreviewId" > <vue-draggable-resizable :w="item.models.width || 100" :h="item.models.height || 100" :x="item.models.x || 0" :y="item.models.y || 0" :active="item.info.previewId === activePreviewId" @dragging="onDrag" @resizing="onResize" @activated=" () => { onCompActivated(item.info.previewId); } " :prevent-deactivation="true" > <navigator-line :x="item.models.x" :y="item.models.y" :scale="scale" /> <div :is="item.info.name" :models="item.models" :extraProps="extraProps"></div> </vue-draggable-resizable> </div>
vue-draggable-resizable 用於選擇組件、縮放組件大小,可參考官方文檔。這個組件不支持分組和多選對齊場景,須要定製開發。
navigator-line
顯示組件當前的標尺位置。這裏要注意避免由於畫布縮小致使座標看不清,除以縮放比例便可。
使用 Vue 動態組件 is 控制組件顯示。
數據配置區有 2 種狀況:
實現邏輯:根據當前用戶的選擇來動態渲染出組件的屬性編輯域,並回填屬性的初始值,從而達到良好的編輯交互效果。用戶拖拽組件時同步更新編輯域中的屬性值,在屬性編輯域修改屬性時通知大屏觸發組件的刷新動做,達到實時編輯的效果。
數據配置區界面由組件 Schema 定義,props 定義展現,models 表示默認數據,詳細介紹見下面 Schema。
編輯類型由 fileds 裏的 type 決定,實現 Input、Select、Image、Border 等各類類型組件,再利用 Vue 的動態組件 is 屬性來展現。
數據回傳:每一個子組件值的修改會通知父組件 <Setting />
更新回傳給父組件 App,這裏採用全量回傳,避免 App 對 models 查找更新數據。
查看是將數據庫裏保存的數據,配合組件渲染出來。實現原理是經過頁面 id 獲取組件、數據渲染。代碼以下:
<div class="preview"> <div class="layout"> <div : class="['preview-line', preComp.info.name + '-' + preComp.info.previewId]" v-for="(preComp, index) in preCompList" :key="preComp.info.previewId" :style="formatCompStyle(preComp, index)" > <div : is="preComp.info.name" :models="preComp.models" :isPreview="isPreview" :extraProps="extraProps"></div> </div> </div> </div>
須要注意大屏是全屏展現,根據大屏配置的屏幕寬高、背景圖、背景色設置 body 樣式,設置 <meta name="viewport" content="width=' + window.screen.width + '"/>
viewport 的 width 讓屏幕佔滿全屏,再監聽屏幕的變化設置壓縮比例。自適應關鍵代碼以下:
// 獲取設置的大屏寬高、背景圖、背景色 if (window.__INITIAL_STATE__) { const { width, height, backgroundImage, backgroundColor } = __INITIAL_STATE__.preview.pageConfig.models; window.scr = { width: width, height: height, backgroundImage: `url(${backgroundImage})`, backgroundColor: backgroundColor, }; } else { window.scr = { width: window.screen.width, height: window.screen.height, }; } // 全屏展現 function resizeFull() { if (!window.scr.height || !window.scr.width) return resizeFullBak(); var ratioX = $(window).width() / window.scr.width; var ratioY = $(window).height() / window.scr.height; $('body').css({ transform: "scale(" + ratioX + ", " + ratioY + ")", transformOrigin: "left top", backgroundSize: "100% 100%", }); } function resizeFullBak() { var ratioX = $(window).width() / $('body').width(); var ratioY = $(window).height() / $('body').height(); $('body').css({ transform: "scale(" + ratioX + ", " + ratioY + ")", transformOrigin: "left top", backgroundSize: "100% " + ratioY * 100 + "%", }); }
組件是整個大屏設計的基礎。組件由組件模板來初始化,模板提供了兩個主要功能,一是實現一個可開發的簡單 Demo,二是提供打包發佈功能。
模板代碼很簡單,經過傳入的 props 控制組件的展現和業務邏輯。組件自動安裝,這樣在異步加載組件的時候頁面能夠識別組件。重點講下組件的 Schema 設計。
schema.json 是用來定義組件的可編輯項和默認配置。決定組件哪些東西能夠配置,配置的形式是什麼樣子的(Input、Select 等有默認值)。因此 Schema 包含 props 和 models 兩個屬性。
props: 數組,每一個元素是 tab 的一項。info 是 tab 頭部信息,fields 是配置項。fields 的 name 對應 models 的屬性名,type 決定了配置的類型,title 是中文名。還能夠定義其餘屬性,好比下拉框選擇項、數字輸入框最大最小值等。
models: 默認數據,props.fileds
裏每一個 name
的默認值。
下面是一個簡單 Schema 的定義:
{ "props": [ { "info": { "title": "配置", "icon": "icon-setting" }, "fields": [ { "title": "組件寬度", "name": "width", "description": "組件寬度", "type": "number" }, { "title": "組件高度", "name": "height", "description": "組件高度", "type": "number" }, { "title": "x軸座標", "name": "x", "description": "組件x軸座標", "type": "number" }, { "title": "y軸座標", "name": "y", "description": "組件y軸座標", "type": "number" } ] } ], "models": { "width": 300, "height": 200, "x": 0, "y": 0 } }
大屏組件之間如何通訊? 要確保大屏組件能夠通訊。
採用事件中心來處理組件間的通訊。核心代碼以下:
// 全局事件中心 Vue.prototype.$eventBus = new Vue(); // 觸發, 在組件內部 this.$eventBus.$emit('eventName', '這裏傳值'); // 監聽, 獲取值 this.$eventBus.on('eventName', v => { console.log(v); }) // 組件通知父組件區劃變更或其餘變更 this.$eventBus.$emit('component__update-extraProps', { dist: '選擇的區劃' });
App 統一管理通訊對象 extraProps,以 props 形式注入到每一個組件。組件能夠監聽 extraProps
的屬性變化。
// 組件代碼 { ..., props: { extraProps: { type: Object, default: () => {} } }, computed: { dist() { return (this.extraProps && this.extraProps.dist) || ''; } }, watch: { dist(val, oldVal){ // 添加區劃改變時獲取新數據的邏輯 } } }
大屏數據須要作權限控制,有權限的人才能查看大屏,而魯班原來頁面訪問邏輯是沒有權限的。實現方案是編輯、預覽頁面調用的免登接口訪問中間 Server,中間 Server 實現登陸,去 Server 請求數據。用戶的查看頁面內嵌魯班 iframe,該地址由實際服務器提供並帶上權限 token。訪問該魯班地址時先去 Server 鑑權,有權限返回大屏頁面,不然返回 401。
Big 處於初級階段,還有好多地方須要完善:
DT 時代,數據可視化將會愈來愈重要。相信有愈來愈多的同窗會遇到大屏的場景。經過可視化搭建大屏系統,能夠賦能相關的業務方,讓非專業人士作出專業的大屏效果,同時知足公司的一些定製化需求。這裏作了一個比較淺的大屏構建方案,目前還在開發階段,但願拋磚引玉,有更多的可視化數據搭建方案分享出來,謝謝閱讀。
政採雲前端團隊(ZooTeam),一個年輕富有激情和創造力的前端團隊,隸屬於政採雲產品研發部,Base 在風景如畫的杭州。團隊現有 50 餘個前端小夥伴,平均年齡 27 歲,近 3 成是全棧工程師,妥妥的青年風暴團。成員構成既有來自於阿里、網易的「老」兵,也有浙大、中科大、杭電等校的應屆新人。團隊在平常的業務對接以外,還在物料體系、工程平臺、搭建平臺、性能體驗、雲端應用、數據分析及可視化等方向進行技術探索和實戰,推進並落地了一系列的內部技術產品,持續探索前端技術體系的新邊界。
若是你想改變一直被事折騰,但願開始能折騰事;若是你想改變一直被告誡須要多些想法,卻無從破局;若是你想改變你有能力去作成那個結果,卻不須要你;若是你想改變你想作成的事須要一個團隊去支撐,但沒你帶人的位置;若是你想改變既定的節奏,將會是「5 年工做時間 3 年工做經驗」;若是你想改變原本悟性不錯,但老是有那一層窗戶紙的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但願參與到隨着業務騰飛的過程,親手推進一個有着深刻的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我以爲咱們該聊聊。任什麼時候間,等着你寫點什麼,發給 ZooTeam@cai-inc.com