WebGL 3D 電信機架實戰之數據綁定

前言

在前端中,視圖層和數據層須要進行單向或者雙向數據綁定,你們都已經不陌生了,有時候 2D 作的比較順了以後,就會想要挑戰一下 3D,否則總以爲癢癢的。這個 3D 機架的 Demo 我以爲很是有表明性,首先,3D 機架用途很是廣,尤爲是在電信行業,就算不是機架,在好比工業方面 3D 模型以及數據綁定的應用也是很是普遍的,畢竟如今工業物聯網已是大趨勢了。前端

效果圖

圖片描述

上面動圖中,閃爍燈是在不斷變化的,因爲須要顯示的效果美觀一點,也實際一點,我截的圖仍是比較完整的,可是這個閃爍的部分有點看不清楚(cnblog 中放太明顯的外鏈容易被移出首頁啊!!!等會再發!)。node

代碼實現

雖然上面 gif 圖中顯示的一個是 2D 的一個是 3D 的,可是構建的步驟以及須要的內容是同樣的,因此本文只針對 3D 的模型進行代碼實現。json

場景搭建

搭建一個 3D 場景是很是快速的,只須要三行代碼:數組

dm = new ht.DataModel();//建立一個數據容器 數據容器也能夠經過 g3d.getDataModel() 獲取
g3d = new ht.graph3d.Graph3dView(dm);//建立一個 3D 場景,將數據容器做爲參數傳遞進去,這樣數據容器中的內容就能夠顯示在 3D 場景中了
g3d.addToDOM();//將 3D 場景添加到 body 體中

3D 機架模型構建

雖然能夠叫設計師直接給我一個 obj 格式的模型,可是我以爲這個比較簡答,仍是不要麻煩人家了。。。首先是建立一個六面體,模型上面的貼圖是我之前用的一個 json 格式的文件,用來做爲這個六面體的正面貼圖,這些部分都是寫在 json 文件裏面的,我先截取一小部分的 json 內容,而後用 js 代碼復現:dom

{
  "c": "ht.Node", //一個 ht.Node 類型的元素
  "i": 1277,//id
  "p": {//經過 set/get 來設置/獲取的元素的部分。如 setPosition/getPosition
    "tag": "service",//設置元素標籤 用來做爲惟一標識
    "image": "symbols/機櫃.json",//設置節點圖片
    "rotationX": 1.5708,//設置節點 X 軸旋轉角度
    "position": {//設置節點位置
      "x": 0,
      "y": 225
    },
    "anchor": {//設置節點錨點
      "x": 0.5,
      "y": 0.54
    },
    "anchorElevation": 1, //設置節點 y 軸錨點
    "width": 507,//設置節點寬度
    "height": 980, //設置節點長度
    "tall": 450, //設置節點高度
    "elevation": 451 //控制Node圖元中心位置所在3D座標系的y軸位置
  },
  "s": {//設置圖元的 style 樣式,HT 預約義的一些樣式屬性,經過 node.s('all.color') 獲取和設置節點的樣式
    "all.color": "#DDDDDD",  //設置節點六面顏色
    "top.image": "symbols/機櫃.json",//設置節點頂部圖片
    "front.visible": true, //設置節點正面是否可見
    "back.visible": true,
    "left.visible": true,
    "right.visible": true,
    "bottom.visible": true
  }
}

這部分的 json 內容大致上就是建立了一個 ht.Node 節點,而後對這個節點設置了一些屬性,包括節點座標,節點的大小,以及一些 style 樣式設置。異步

那麼,如何用代碼來建立這樣一個節點呢?函數

var node = new ht.Node();//建立一個 ht.Node 類型的節點
node.setTag('service'); //設置節點的標籤
node.setImage('symbols/機櫃.json'); //設置節點圖片
node.setRotationX(Math.PI/2);//設置節點x軸旋轉
node.setPosition(0, 225);//設置節點位置
node.setAnchor(0.5, 0.54);//設置節點錨點
node.setAnchorElevation(1);//設置節點y軸方向的錨點

node.setWidth(507);//設置節點的寬度
node.setHeight(980);//設置節點的長度
node.Tall(450);//設置節點的高度
node.setElevation(451);//控制Node圖元中心位置所在3D座標系的y軸位置

node.s({ //設置節點樣式
    'all.color': '#ddd', //六面顏色
    'top.image': 'symbols/機櫃.json', //節點頂部圖片
    'front.visible': true,//設置節點正面可見
    'back.visible': true,
    'left.visible': true,
    'right.visible': true,
    'bottom.visible': true
});

其實整個 json 就是由多個這種類型的圖元組合而成的。咱們來拆析一下,整個 3D 機架其實是由十個圖元組合而成的,第一個是總體的 3D 機櫃(也就是咱們上面 json 內容中建立的部分),剩下的九個都是須要動態變化閃爍燈的設備,也就是我紅框框起來的部分:spa

圖片描述

http://www.hightopo.com/demo/...
這些設備的建立方式跟上面的 3D 機架是相似的,只不過對應的節點尺寸小點,貼圖不同,座標不同罷了。可是下面的這九個節點的貼圖彷佛有點不同?上面有閃爍的燈,而且不止一盞!怎麼動態獲取他們呢?設計

矢量--數據綁定

不得不說到矢量這個概念。矢量在 HT for Web 中是矢量圖形的簡稱,常見的 png 和 jpg 這類的柵格位圖, 經過存儲每一個像素的顏色信息來描述圖形,這種方式的圖片在拉伸放大或縮小時會出現圖形模糊,線條變粗出現鋸齒等問題。 而矢量圖片經過點、線和多邊形來描述圖形,所以在無限放大和縮小圖片的狀況下依然能保持一致的精確度。3d

這些有點都是次要的,最重要的是這個矢量能夠進行數據綁定(這個數據綁定是綁定到節點中的),並且綁定方式很是容易!

矢量採用 json 格式描述,使用方式和普通的柵格位圖一致,經過 node.setImage('hightopo.json') 或者 node.setIcon('hightopo.json') 等設置到數據模型中。

矢量 json 描述必需包含 width、height 和 comps 參數信息:

  • width 矢量圖形的寬度
  • height 矢量圖形的高度
  • comps 矢量圖形的組件 Array 數組,每一個數組對象爲一個獨立的組件類型,數組的順序爲組件繪製前後順序

因爲這張圖繪製的仍是比較複雜的,因此我就將設置了數據綁定的矩形部分的矢量繪製代碼粘貼出來:

{
    "width": 48, //一個矢量圖標必備的寬度 矢量詳細內容請參考 HT for Web 矢量手冊
    "height": 262,//一個矢量圖標必備的高度
    "comps": [//一個矢量圖標必備的 Array 數組組件
        {//數組組件中的第一個元素
            "type": "rect",//類型爲矩形
            "background": {//設置矩形背景色
                "func": "attr@rectBg1", //HT 用一個帶func屬性的對象替換之前的參數值 這裏就是進行數據綁定的地方
                "value": "rgb(255,0,0)"//若是 func 值爲 undefined 或者 null 時,採用這個值
            },
            "shadow": true,//設置「陰影」
            "shadowColor": { //「陰影」顏色
                "func": "attr@shadowColor1", // 這邊將「陰影」也進行了數據綁定,爲的是可以實現燈「發光」的效果
                "value": "rgba(255,0,0,0.35)"//設置備選值
            },
            "shadowOffsetX": 0, //設置陰影橫軸偏移量
            "shadowOffsetY": 0,//設置陰影縱軸偏移量
            "rect": [//設置該組件的寬高以及座標
                4.38544,//x 軸座標
                23.52679,//y 軸座標
               14.46481, //width 組件寬度
               6.1554//height 組件高度
           ]
       }
    ]
}

由於一個矢量圖形中有 5 個「閃爍燈」,因此我添加了 5 個組件,也就是在 comps 參數裏面添加了五個元素,綁定的數據不一樣,爲了省事,我將綁定的數據名都設置爲「rectBg」後面加一個數字,這些數字依次遞增。

咱們就是將這樣一張矢量圖設置爲節點的 front.image 做爲節點正面顯示圖的:node.s('front.image', 'symbols/內部設備2.json')。

JSON 反序列化

會不會有人好奇 json 文件裏面的內容是如何轉換成 3D 模型的?

說實在的,步驟依然很簡單:

ht.Default.xhrLoad('scene/service3d.json', function(text) {//xhrLoad 函數是一個異步加載文件的函數
    dm.deserialize(text);//反序列化數據容器,解析用於生成對應的Data對象並添加到數據容器 這裏至關於把 json 文件中生成的 ht.Node 節點反序列化到數據容器中,這樣數據容器中就有這個節點了
});

因爲 xhrLoad 函數是一個異步加載函數,因此若是 dm 數據容器反序列化未完成就直接調用了其中的節點,那麼會形成數據獲取不到的結果,因此通常來講我是將一些邏輯代碼寫在這個函數內部,或者給邏輯代碼設置 timeout 錯開時間差。

首先,因爲數據都是存儲在 dm 數據容器中的(經過 dm.add(node) 添加的),因此咱們要獲取數據除了能夠經過 id、tag 等獨立的方式,還能夠經過遍歷數據容器來獲取多個元素:

var infos = [
    { shadowColor: 'shadowColor1', background: 'rectBg1' },
    { shadowColor: 'shadowColor2', background: 'rectBg2' },
    { shadowColor: 'shadowColor3', background: 'rectBg3' },
    { shadowColor: 'shadowColor4', background: 'rectBg4' },
    { shadowColor: 'shadowColor5', background: 'rectBg5' }
];
var len = infos.length; //獲取數組中的長度
var datas = dm.toDatas(function(d) { return d.getDisplayName() === 'device'; });//以過濾函數構建新的元素集合並返回(ht.List 數組類型)
setInterval(function() {
    datas.forEach(function(data) {
        var info = infos[Math.floor(Math.random() * len)];
        var shadowName = info.shadowColor;
        var bgName = info.background;

        if (data.a(shadowName) === 'rgba(255, 0, 0, 0.35)') {//若節點業務屬性「陰影」顏色爲紅色,則設置爲綠色
            data.a(shadowName, 'rgba(0, 255, 0, 0.35)');
        }
        else {//若節點業務屬性「陰影」顏色爲綠色,則設置爲紅色
            data.a(shadowName, 'rgba(255, 0, 0, 0.35)');
        }

        if (data.a(bgName) === 'rgb(255, 0, 0)') {//若節點業務屬性背景顏色爲紅色,則設置爲綠色
            data.a(bgName, 'rgb(0, 255, 0)');
        }
        else {//若節點業務屬性背景顏色爲綠色,則設置爲紅色
            data.a(bgName, 'rgb(255, 0, 0)');
        }
    });
}, 1000);

結束語

總體來講這個 Demo 仍是比較有價值的,一是快速實現了 3D 機櫃模型,二是對模型上的元素進行了數據綁定。只是想讓大家知道,清晰的圖片繪製沒有那麼難~ 3D 的世界沒有那麼難~ 數據綁定也沒有那麼難!我但願也能讓您發現這並非件難事。

相關文章
相關標籤/搜索