基於 HTML5 Canvas 的 3D 渲染引擎構建生產管控系統

前言

你們好,老鄭我又回來了。這一期爲你們帶來一個很是好玩的 demo,咱們製做一套本身的 3D 管道控制系統,運用了( http://www.hightopo.com )HT 的 Graph3dView 組件經過對 WebGL 底層技術的封裝,與 HT 其餘組件同樣,基於 HT 統一的 DataModel 數據模型來驅動圖形顯示。html

效果圖

此爲 2D 主界面:node

此爲 3D 界面的部分分段演示:瀏覽器

因爲 gif 上傳有大小限制,因此請你們務必去網頁感覺和體驗,雙擊進口閥開始。 ( 戳我進入!網絡

代碼實現

主要教你們的是一種流程動畫的製做方式,我用到包括動畫在內的多種方法,下面我聽我慢慢道來。因爲是 3D 界面,關於建立 3D 渲染引擎組件,可視化呈現數據模型的三維環境場景我以前有講過,就是 dataModel 和 graph3dView。(後面用簡寫的dm,gv代替)架構

咱們先對總體界面的基礎進行一下設置:函數

// 禁止拖動
gv.setMovableFunc(function() { return false })
// 設置眼睛
gv.setEye([-922, 1745, 4659]) // 設置中心點 gv.setCenter([98, 621, -318])

而後,把須要加動畫的閥都獲取到,咱們按照步驟依次來,以避免落下關鍵步:動畫

var a = dm.getDataByTag('進口電動球閥')
var b = dm.getDataByTag('旁通閥') var c = dm.getDataByTag('出口電動球閥') ... ...

能夠開始咱們的動畫設計了!我用的是 flyTo() 的方法,事實證實這種效果然的很不錯。咱們要事先準備好全部的動畫組並把它們串聯在一塊兒,我設計的開始演示是經過雙擊進口閥來控制。好比第一步,應該打開將進口球閥由遠程控制轉爲就地控制。因此,咱們要讓鏡頭從這裏開始:spa

gv.mi(function (e) {
    if (e.kind === 'doubleClickData') { if (e.data.getTag() === '進口電動球閥') { gv.flyTo(n, { animation : true, direction : [-200, 0, 0], distance : 100 }) anim1() } } })

注意 mi 是增長交互事件監聽器,addInteractorListener 的縮寫。設計

// 示例:
gv.mi(function (event) {
    // event 格式:
 { kind: 'clickData', // 事件類型 data: data, // 事件相關的數據元素 part: "part", // 事件的區域, icon、label 等 event: e // html 原生事件  } })

這裏面 n 就是第一步的那個按鈕,再介紹一下這個方法的相關參數:
flyTo : 相機看向具體的節點或者節點列表,參數 (target, options),其中
target : 一個節點 node 或者節點列表(Array)或者空(場景內的全部節點)
options : 可選屬性,格式爲對象({}),屬性包括有:
animation : 默認 false,是否啓用動畫,能夠設置爲 true 或者 false 或者 animation 動畫對象
center : 默認 undefined,新的場景 center 點,形如 [0,0,0](空的話,target 爲一個則看向 node 中心,target 爲列表則看向根據節點列表計算出來的中心)
direction : 默認 undefined,眼睛處於目標的方向(相對目標,受到目標自身旋轉影響),例如 [0,1,5] 在目標正面的斜向上
worldDirection : 默認 undefined,眼睛處於目標的方向(相對場景,不受目標旋轉影響),例如 [0,1,5] 在目標所在位置的斜向上
distance : 默認undefined(未定義的話則使用下面的 ratio 模式計算距離),浮點類型,表示眼睛跟中心的固定距離
ratio : 默認 0.8,浮點類型,表示眼睛跟中心的距離動態計算(例如 0.8 表示眼睛在上述方向上動態計算距離以將目標包圍盒的 8 個角所有適配到屏幕 80% 範圍內)3d

注意,direction跟worldDirection若是都不配置,則使用以前相機的角度保持不變化。

後面所有用到動畫,解釋一下。在 HT 的數據模型驅動圖形組件的設計架構下,動畫可理解爲將某些屬性由起始值逐漸變到目標值的過程, HT 提供了 ht.Default.startAnim 的動畫函數。它支持 Frame-Based 和 Time-Based 兩種方式的動畫,Frame-Based 方式是用戶經過指定 frames 動畫幀數,以及 interval 動畫幀間隔參數控制動畫效果。

我用的是 Time-Based 方式,該方式用戶只須要指定 duration 的動畫週期的毫秒數便可,HT 將在指定的時間週期內完成動畫, 不一樣於 Frame-Based 方式有明確固定的幀數,即 action 函數被調用多少次,Time-Based 方式幀數或 action 函數被調用次數取決於系統環境, 通常來講系統配置更好的機器,更高效的瀏覽器則調用幀數越多,動畫過程更平滑。因爲 js 語言沒法精確控制 interval 時間間隔, 採用 Frame-Based 不能精確控制動畫時間週期,即便相同的 frames 和 interval 參數在不一樣的環境,可能會出現動畫週期差別較大的問題, 所以 HT 默認採用 Time-Based 的方式,若是不設置 duration 和 frames 參數,則 duration 參數將被系統自動設置爲 ht.Default.animDuration 值。action 函數就是實現動畫過程當中的屬性變化(變化參數和進度)。

緊接着咱們要開始執行第一個動畫—— anim1() 了:

function anim1() {
    ht.Default.startAnim({
        duration: 2000, action: function (v, t) { // 讓旋鈕旋轉,改變其角度 r3 n.r3(n.r3()[0] - 0.02, n.r3()[1], n.r3()[2]) }, finishFunc: function () { // 動畫結束後調用的函數  gv.flyTo(a, { animation : true, direction : [-2000, 1000, 2000], distance : 1000 }) anim2() } }) }
...

能夠看到動畫結束後咱們再次用到 flyTo() 向下一個步驟開關去拉近,而後再次執行它的動畫,以此類推,關於一套清晰的操做流程的動畫實現指日可待!

當全部步驟結束後咱們應當將鏡頭拉回到最開始時的初始視角,因此咱們要注意一點,在最開始的時候提早把位置複製一下:

var oEye = ht.Default.clone(gv.getEye())
var oCenter = ht.Default.clone(gv.getCenter())

這樣,在最後一個 finishiFunc 中咱們還原位置:

gv.setEye(oEye)
gv.setCenter(oCenter)

最後,一個簡明的系統操做流程就作好了,想看不懂都難~

總結

HT For Web 提供完整的基於 HTML5 圖形界面組件庫。您能夠輕鬆構建現代化的,跨桌面和移動終端的企業應用,無需擔心跨平臺兼容性,及觸屏手勢交互等棘手問題。也可用於快速建立和部署,高度可定製化,並具備強大交互功能的拓撲圖形及錶盤圖表等應用。HT for Web 很是適用於實時監控系統的界面呈現,普遍應用於電信網絡拓撲和設備管理,以及電力、燃氣等工業自動化 ( HMI / SCADA ) 領域。

相關文章
相關標籤/搜索