數據可視化平臺 vue+node+webpack+echarts+d3

前言

隨着公司的發展和進步,數據大屏的業務日益增長,公司目前的做法大致可以分爲兩種 人工標配 or 第三方工具 .
人工:很簡單,一個前端配備,熟練的 html + css + js 技能就完事了 ;
優點:開發靈活多變
不足:效率低,頁面複用度不高(幾乎爲0複用度),大量重複性工作,佔用前端開發時間 等

當然,也有人會說,目前比較主流的前端框架,像 Vue ,React 都是組件化,模塊兒化的工程,組件複用性很高,也對,這點毋庸置疑,但也改變不了大量重複性的工作和消耗前端資源的劣勢 ;甚至還有人會說,當組件封裝的夠多,質量夠好,工程架構的得體,就可以解決上述的缺點,很對 !這就是我要分享給大家的《可視化數據平臺》稍安勿躁 emmm ~ ~

第三方工具 :如:阿里雲的dataV , 百度的 Sugar 都是很優秀的工具平臺 ;
優點:組件豐富,功能強大,基本滿足大中小型企業對數據大屏的需求
不足:有沒有不足請大家去體驗一下 , 這裏我就不做過多的評價 重點是要RMB

OKey,綜上所述,隨着公司業務的增多 ,市場未來對數據可視化的需求,爲了降低開發成本,提高開發效率,降低開發難度,我們的 NTDVP《數據可視化平臺》就這樣誕生了,在這裏,我作爲主要開發人員來給大家分享一下平臺的具體實現 。

NTDVP - 簡單認識一下吧
在這裏插入圖片描述
在這裏插入圖片描述
NTDVP - 技術棧

Vue 2.6 + Webpack 3.6 + Node + eCharts + D3

這裏簡單講一下 Node 在項目裏的應用情況
1,通過 node 啓動 dev-server.js 文件,然後運行如下代碼(dev-server.js);
webpack-dev-server 主要是啓動了一個基於 expressHttp 服務器 ;這個Http服務器和 client (客戶機)使用了websocket通訊協議,原始文件作出改動後,webpack-dev-server會實時的編譯,實時編譯後的文件都保存到了內存當中 ;所以我們可以看到實時更新 。重點:基於啓動的http服務實時編譯工程

// dev-server.js 文件
var webpack = require('webpack')
var webpackDevServer = require('webpack-dev-server')
var webpackDevconfig = require("./webpack.dev.conf.js"); 
var opn = require('opn')
var port = process.env.PORT || config.dev.port

// api 
var apiServer = {
  setup: (app) => {
    // 具體接口就不做展示了
  }
}

webpackDevconfig.then(res => {
  var compiler = webpack(res);
  var server = new webpackDevServer(compiler, Object.assign(res.devServer, apiServer));

  server.listen(port, "0.0.0.0", function (error) {
    console.log(error);
  });
  opn("http://127.0.0.1:" + port) // 打開本地頁面
})

2,就比較明瞭了,主要寫一些接口,來實現平臺目錄和文件的保存,讀取,複製,刪除,修改等功能,後期有導入導出…目的是可以滿足本地部署和雲部署

NTDVP - 設計思路

整個工程結構在這裏不做分享,涉及到公司的產品代碼,我簡單說一下產品實現的思路和原理 ;
其實,以拖拉拽的方式做可視化頁面的產品有很多,原理也大同小異,無非就是擁有一個舞臺,一定數量的組件,然後組件通過配置二次加工後放進舞臺的過程,最後集成的舞臺就是我們想要的成品 ;

首先分析一下舞臺和組件的實現方式
舞臺

舞臺很簡單,就是一個容器 , 用來盛放拖拽出來的組件 , 當然這個舞臺可能有 寬,高,背景等配置屬性,適用於已知寬高的大屏 ;這其中也會有未知寬高的大屏,終端設備等,所以採用了自適應模式 ;那麼舞臺如何渲染組件的呢 ? 這裏使用到了 Vue.extends() 構造器 + document.createDocumentFragment()

1,對組件配置文件的信息讀取通過 Vue.extends() 構造器來渲染組件
2,使用原生Api Document.createDocumentFragment 文檔片段模擬虛擬dom做性能優化

# Vue-extends() 查看

//使用基礎 Vue 構造器,創建一個“子類”。參數是一個包含組件選項的對象。
//data 選項是特例,需要注意 - 在 Vue.extend() 中它必須是函數
<div id="mount-point"></div>
// 創建構造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 創建 Profile 實例,並掛載到一個元素上。
new Profile().$mount('#mount-point')
//結果如下:
<p>Walter White aka Heisenberg</p>

# Document.createDocumentFragment() 查看

let fragment = document.createDocumentFragment();
//fragment 是一個指向空DocumentFragment對象的引用。 有興趣的可以在控制檯實踐一下

DocumentFragments 是DOM節點。它們不是主DOM樹的一部分。通常的用例是創建文檔片段,將元素附加到文檔片段,然後將文檔片段附加到DOM樹。在DOM樹中,文檔片段被其所有的子元素所代替。

因爲文檔片段存在於內存中,並不在DOM樹中,所以將子元素插入到文檔片段時不會引起頁面迴流(對元素位置和幾何上的計算)。因此,使用文檔片段通常會帶來更好的性能。

組件

組件就相對比較複雜一點,由於我們的工程使用的 Vue 技術棧, 所以這裏使用的是字符串模板來動態的創建組件,如何創建呢 ? 每一個組件分別有三個文件(暫不考慮公共提取部分)

1,組件配置文件 - 相當於組件的父文件,通過對配置屬性的修改來渲染對應組件
2,組件文件 - 圖表及組件,根據父文件的屬性配置生成對應的組件
3,屬性配置文件 - 屬性樣式配置文件,也就是編輯頁面圖的右側屬性欄

看到這裏也許有的童鞋已經聯想到如何讓它們聯合工作了,其實就是採用簡單的發佈訂閱模式,不管是組件的拖動位置,大小變化還是右側欄的屬性值變化,都會觸發當前選中組件的更新,讓我們進一步剖析一下 ;

組件配置文件 - 樣例代碼 => 返回一個模板和最新屬性鍵值對

var handle = function (attr, info) {
    let attributes = {
        name: "BarAlien",
        infoId: info.id,
        zIndex: 1,
        top: 1,
        left: 10,
        width: 300,
        height: 200,
        title: "柱狀圖",
        remark: '', //圖表簡介
        chartCustomStyle: false, //開啓圖表自定義背景和邊框
        chartBackgroundColor: '', //圖表背景顏色
        chartBorderRadius: false, //圖表圓角
        borderWidth: 10, //圖表邊框寬度
        borderColor: '', //圖表邊框顏色
        shadowWidth: 0, //圖表陰影寬度
        ...... // 更多省略
    }

    // 合併屬性 
    Object.assign(attributes, attr)

    // 獲取 attr 屬性並傳入組件,組件通過props獲取    
    let stringAttr = getStringTypeAttr(attributes);

    //字符串模板操作
    let template = `<BarAlien ${stringAttr}/>`
    return { template, attributes }
}

export default handle;

組件 - 就簡單了, 通過父文件傳過來的參數, props 接收,渲染

屬性配置文件 - 樣例文件
這裏的右側屬性欄,相對來講比較麻煩,採用的是 Vue 的雙向綁定原理 ;
樣式則是通過配置的數組對象遍歷生成對應的屬性欄 ; 而屬性欄風格很多,輸入框,下拉框,單選,多選,開關,顏色,表格,自定義 等等分別是一個獨立的組件 ,提供單獨的事件監聽與廣播 ;

[{
    label: "開啓圖表自定義配色",
    bind: "openCustomColor",
    tipLink: "/docs/Chart-Common#圖表的自定義配色",
    tipText: "自定義配色說明",
    type: "switch"
}, {
    type: "color",
    bind: "textColor",
    format: "rgb",
    label: "文字顏色",
    visiblity: "openCustomColor",
    placement: "right-top-right-bottom"
}, {  
	type: "number",
    bind: "shadowBlur",
    visiblity: "openCustomShadow",
    label: "陰影模糊大小",
    min: 0
},{
    type: 'table',
    bind: "customColors",
    visiblity: "openCustomColor",
    label: "可增加多個配色項,依次對應各項顏色",
    addTipText: "新增配色項",
    controls: [{
        type: "color",
        label: "顏色",
        bind: "color",
        defaultValue: "#23b7e5",
        tdStyle: {
            minWidth: 100
        }
    }]
}]

NTDVP - 編輯(核心)
在這裏插入圖片描述
上圖可以看出來,整個編輯頁可以拆分爲四部分

  • 頂部 - 包含logo + 組件分類列表 + 舞臺操作
  • 左欄 - 當前舞臺組件管理 ,目前有刪除 ,後期考慮提供功能鍵對組件進行復制,層管理等
  • 右欄 - 核心位置之一,操作選中組件的所有配置項和動態數據(api , sql , ws 等方式 )以及體驗交互(聯動和下鑽), 支持自動刷新 等
  • 舞臺 - 中間的展示區,支持編輯佈局,拖拽組件,整體拖動,實時刷新,局部刷新,所見即所得

NTDVP - 遇到的問題及解決方案

整個初級階段,開發遇到的問題其實還是蠻多的,都在日常積累中一一擊破,這裏撿幾個記憶深刻的分享一下吧 ;

1,如何解析字符串 { key:function () {} , key2:function () {} } 實現組件自有函數
解決:acorn.js , 嘗試了多種方法,最終迫不得已使用了 acorn.js javascript 解析器
目標:解析如上字符串,獲取對應的函數的實體,進行二次編輯,保存回原函數,這裏小弟不才,沒能想到其它更好的方式,如有哪位大佬知道,評論告知,非常感謝

//項目中解析代碼
var ast = acorn.parse(res.data).body[0];
var nodeBinds = {};
for (let nb of ast.declarations[0].init.properties) {
	nodeBinds[nb.key.name] = res.data.substring(nb.value.body.start, nb.value.body.end);
}
//結果 nodeBinds[key] 就是上述字符串的第一個函數 key

2,舞臺跟預覽如何減少重排與重繪 , 如何提高渲染速度 , 如何確定頁面後處理執行時間
解決:
通過文檔片段Document.createDocumentFragment()模擬虛擬Dom來整合當前舞臺所有組件渲染 ,整合期間記錄通知數量,然後統計通知數量等於當前頁面所有組件length,則認爲整合完畢,最後掛載Dom,執行後處理 。

3,發佈訂閱模式,修改右側欄屬性頻率較高,組件渲染負擔重 ,如何處理

起初呢,我也考慮過是否做成手動渲染,就是在所有配置參數被設置完後,點擊按鈕渲染組件,後來發現雖然渲染性能大大提升,但是看不到實時效果,因爲大部分同事並不知道配置項的具體頁面效果,造成重複性的修改與點擊渲染 ,而且頁違背了我們想做一款實時圖形化編輯的平臺初衷 ;(放棄)
解決:
①,右側欄的廣播事件,發佈通知均使用防抖函數,組件響應以最後一次爲準,這個時間可配置,不同人體驗不同
②,組件渲染數據方面,採用必要條件同時滿足策略,如:普通折線圖,調試數據層,字段映射必須滿足x軸,y軸,data數據,均有值方可渲染,否則不做渲染動作
③,這裏的組件與右側欄屬性是訂閱模式,相互通知更新,渲染 ;並且組件與之對應的屬性有唯一infiId,不會影響舞臺上其它組件渲染與重繪 。

4,待整理 ,

NTDVP - 特色

  • 近百種豐富組件,拖拽式圖形化編輯,所見即所得
  • 自定義組件滿足私有定製化服務
  • 響應式,自適應,支持移動端
  • 多數據源支持 MySQL、SQL Server、Oracle 等數據源,本地 Excel 文件 或者 api 接口 ,ws 長連接
  • 靈活部署和發佈 支持雲部署,私有化部署, 本地部署

當然了,NTDVP 目前處於初級階段 ,零碎的功能點就不一一列出了,還有許多功能需要完善和添加 , 我們正在全力以赴 ,爭取做出來一款市場認可的可視化產品 。

NTDVP - 後續計劃

  • 豐富組件是必不可少的
  • 添加快速構建模板
  • 添加舞臺組件複製,粘貼
  • 權限管理,角色管理,想要做的太多,太多了,就不一一列舉了,emmm~~

總結
整個項目截至到現在,收貨滿滿,不論是對技術的提升還是場景的應用,甚至到對一個Web項目的架構理念都有了新的認識和理解。在這裏不做實質技術點的踩坑與分享,後續慢慢記錄。

結束語
未來是數字化時代,可視化會越來越重要,相信在未來的場景中,必將佔領一席之地 。

志同道合的朋友們,相信你們有更好的構建方案,分享出來的時候,希望我們可以再見面 ,謝謝閱讀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章