智能監控的領域已經涉及到了各大領域,工控、電信、電力、軌道交通、航天航空等等,爲了減小人員的消耗,監控系統必不可少。以前我寫過一篇 2D 的智能地鐵監控系統廣受好評,忽然以爲,既然 2D 的這麼受歡迎,那麼 3D 的需求量確定也是很是大的,3D 畢竟比 2D 來講仍是更直觀一些,因而有了這個例子以及這篇文章。智能監控系統在 3D 中應用比較普遍的除了 3D 機房之外,我以爲就是樓宇的監控了,但是以前作了不少關於機房方面的 Demo,因此最終決定作 3D 樓宇監控系統。html
整個場景是由 3D 組件搭建而成,配合左側的 listView 列表組件,經過點擊這個 listView 列表組件中的各個項能夠自由切換各個監控樓層和樓宇的場景:前端
dm = new ht.DataModel(); g3d = new ht.graph3d.Graph3dView(dm); relativeLayout = new ht.ui.RelativeLayout();// 相對佈局器 可對界面進行佈局 var ht3dView = new ht.ui.HTView(g3d);// 放置 3d 組件 relativeLayout.addView(ht3dView, {// 給相對佈局器添加組件顯示,參數一爲組件名稱,參數二可設置寬高、對齊方式等屬性 width: 'match_parent', height: 'match_parent' }); var listView = window.list = new ht.ui.ListView();// 列表組件 for (var i = 1; i <= 15; i++) { var data = new ht.Data();// 建立節點 data.setName('樓層' + i);// 設置節點名稱 listView.dm().add(data);// 將節點添加進列表組件中 } relativeLayout.addView(listView, {// 將 listView 組件添加進佈局器中 align: 'left',// 設置對齊方式爲左對齊 vAlign: 'top',// 設置垂直對齊方式爲頂部對齊 marginTop: 120,// 設置外邊距頂部爲 120 像素 marginLeft: 60,// 設置外邊距左側爲 60 像素 width: 80,// 設置寬度爲 80 height: 480,// 設置高度爲 480 index: 100// 設置元素的堆疊順序 }); relativeLayout.addToDOM();// 將組件添加進 body 中
進入頁面顯示的就是整個城市的場景,經過 ht.Default.loadObj 方法加載 obj 模型:node
var loadCity = function(){ ht.Default.loadObj('obj/city.obj', 'obj/city.mtl', {// 加載模型 center: true,// 模型是否居中,默認爲false,設置爲true則會移動模型位置使其內容居中 cube: true,// 是否將模型縮放到單位1的尺寸範圍內,默認爲false prefix: 'obj/',// 圖片路徑前綴,即在map_kd值以前增長的前綴,若是是相對路徑則以加載obj的html頁面的路徑爲參考 shape3d: 'city',// 若是指定了shape3d名稱,則HT將自動將加載解析後的全部材質模型構建成數組的方式,以該名稱進行註冊 finishFunc: function(modelMap, array, rawS3){// 用於加載 obj 模型後的回調處理 city.rawS3 = rawS3;// 設置變量 city 對象的 rawS3 屬性 此函數中的 rawS3 屬性爲 obj 模型的原始大小 showCity();// 建立一個節點 設置節點的 shape3d 爲 city 顯示 city.obj 與 city.mtl 的內容 } }); }
工控樓層模型的加載也是相似,這裏就再也不贅述。json
直接將組件添加進場景中是不會有相關的操做的, 必需要監聽事件的觸發纔可進行後續的操做,這裏對數據選中容器中的選中變化事件進行監聽:數組
//列表點擊 listView.dm().sm().ms(function(e){// 監聽選中變化事件 if (e.kind === 'set') {// 設置監聽事件 showFloor();// 顯示樓層 } });
這裏爲了簡單就只設置了一個工控樓層的 obj 模型,經過調用不一樣的 obj 模型能夠顯示不一樣的工控樓層場景,也就是說咱們能夠本身經過 ht.Default.loadObj 方法加載模型,設置工控樓層模型的 shape3d 屬性,而後設置到節點的 shape3d 屬性上,便可修改;或者直接設置節點的 shape3d 屬性爲 json 格式的 obj 文件,這裏仍是採起第一種方式:緩存
var showFloor = function(){ g3d.setCenter([210, 0, 210]);// 設置 3d 組件的「中心」位置 dm.clear();// 清除數據容器中的全部節點 var rawS3 = floor.rawS3,// 獲取 obj 模型的原始大小 node = new ht.Node();// 建立一個新的節點 node.s({// 設置節點的樣式屬性 'shape3d': 'floor',// 此項設置的值爲 ht.Default.loadObj 中設置的 shape3d 屬性的值 'wf.visible': 'selected',// 設置選中節點時顯示節點外部的線框 '3d.selectable': false// 設置節點不可選中 }); node.s3(rawS3[0] / 10,rawS3[1]/ 10,rawS3[2] / 10);// 設置節點的大小爲原始大小的十分之一 node.p3(140, 0, 230);// 設置節點的位置 dm.add(node);// 將節點添加進數據容器中 // 添加四個「相機」的節點 createNode([0, 20, 0]); createNode([110, 20, 220]); createNode([330, 20, 420]); createNode([210, 20, 120]); createNode([420, 20, 120]); };
這裏順便說一下另外一種簡便的調用 obj 模型的方式,直接設置節點的 shape3d 屬性爲導入的 json 格式的文件:函數
var node = new ht.Node(); node.s("shape3d", "./symbols/city.json");
可是這個 json 的內容必需要有如下幾個元素:佈局
{ "modelType": "obj",// 必須設置此屬性爲 obj 格式 "obj": "./obj/city.obj",// 必須設置 obj 屬性 "mtl": "./obj/city.mtl"// 此項可寫可不寫,若是須要設置 obj 模型的樣式(如顏色等),則必須設置此項 }
可是這種模式不適用於這個場景,由於個人模型有些大,須要調用到 obj 模型的原始大小 rawS3 屬性除以必定比例後再顯示。性能
上面提到了 createNode 方法,這個方法主要是用來建立顯示爲「面片」類型的節點。所謂「面片」,即爲只有一個面。經過這種在一個面上顯示一張矢量圖的方式,結果會比在一個六面體上顯示一張圖的性能好,3D 場景簡單的時候可能看不出來效果,若是場景卡頓,立馬就能看出「面片」的優點了:ui
function createNode(p3, s3){ var node = new ht.Node();// 建立一個新的節點 node.p3(p3);// 設置節點的位置 // node.s3(s3); node.s({ 'shape3d': 'billboard',// 設置節點的 shape3d 類型爲 billboard 類型,顯示爲「面片」 'shape3d.image': './symbols/智能樓宇/camera.json',// 3d圖形總體貼圖 'shape3d.image.cache' : true,// 若是貼圖是矢量,是否緩存(緩存後性能會獲得提高) 'shape3d.autorotate': true,// 是否自動朝向相機 'shape3d.transparent': true,// 決定3d圖形是否透明 // 'shape3d.alwaysOnTop': true,// 是否老是在最前 'shape3d.fixSizeOnScreen': [ 38, 47 ]// 是否不管縮放遠近,在屏幕內呈現固定大小,值可爲true(使用圖片或矢量自身大小)/false, 也能夠是[100, 200](對應寬高) }); dm.add(node);// 將節點添加進數據容器中 g3d.invalidateShape3dCachedImage(node);// cache 的代價是,這裏須要更新 return node; }
而後我就在想,既然到了樓層的 3D 模型顯示,那麼怎麼返回?以哪一種方式返回最好?想來想去比較沒有違和感的仍是點擊列表組件比較好,就選中了列表組件的頂部:
listView.getView().addEventListener('click', function(e){// 監聽點擊事件 e.preventDefault();// 阻止默認操做 if (e.clientY - 120 < 50) { showCity();// 顯示初始 3D 樓宇場景 listView.dm().sm().cs();// 列表設置清除全部選中元素 } });
全部代碼結束!
這個 3D 智能樓宇監控系統很是的簡單,對於技術人員來講是徹底沒有挑戰性的,主要工做內容在美工上,這麼一來,若是要添加比較複雜的需求,技術人員就能夠全身心地投入到產品上,而不是一些繁瑣的 3D 模型的搭建了。總而言之,我以爲這個 Demo 很是具備表明性,因此想拿出來跟你們分享一下,一塊兒討論一下前端的趨勢所在。