前言
“網際網路+”思維讓資料的蒐集和獲取更加便捷,並且隨著大資料的深度開發和應用,資料分析預測對於提升使用者體驗有非常重要的價值,同時也為不同行業、不同領域的合作提供了更廣闊的空間。傳統的發電企業是一個資金、技術密集但又相對獨立封閉的行業,例如沙角A電廠,擁有優質的碼頭、安信檢修、車隊、技術人才等資源,未來是否能借助網際網路走出去,或者其他一些先進的管理、技術能否通過網際網路走進來互融都是可以探索的。工業網際網路的典型應用,也不都是在機器上,包括照明、智慧交通、智慧機器應用、工廠控制、廠房應用、狀態監控,以及其他農業、電力裝置上的應用,網際網路+的應用會越來越廣,傳統的電力企業還是需要跟緊步伐。
http://www.hightopo.com/demo/electric-bling/index.html
程式碼生成
向量建立
整個場景實際上是由一個 json 格式的檔案生成的,鑑於整個場景中重複的部分太多了,因此將這些部分單獨拿出來作為一個圖示進行重複利用,這邊說的“圖示”指的就是向量圖示,與工業中常用的 SVG 圖有點類似,在縮放的情況下圖形都不會失真。向量在 HT for Web 中是向量圖形的簡稱,常見的 png 和 jpg 這類的柵格點陣圖, 通過儲存每個畫素的顏色資訊來描述圖形,這種方式的圖片在拉伸放大或縮小時會出現圖形模糊,線條變粗出現鋸齒等問題。 而向量圖片通過點、線和多邊形來描述圖形,因此在無限放大和縮小圖片的情況下依然能保持一致的精確度。
在 HT 中所有能用柵格點陣圖的地方都可用向量圖形替代,例如 GraphView 元件上的圖元圖片,TreeView 和 TableView 上的圖示等, 甚至整個 HT 框架做出來的系統介面可以實現全向量化,這樣 GraphView 元件上的圖元縮放都不會失真,並且不再需要為 Retina 螢幕提供不同尺寸的圖片, 在 devicePixelRatio 多樣化的移動時代, 要實現完美的跨平臺,向量可能是的最低成本的解決方案。
在 HT 中,向量採用 JSON 格式描述,使用方式和普通的柵格點陣圖一致,通過設定節點的樣式屬性即可,如:node.setStyle('image', 'test.json')。
向量 json 描述必需包含 width、height 和 comps 引數資訊:
- width 向量圖形的寬度
- height 向量圖形的高度
- comps 向量圖形的元件 Array 陣列,每個陣列物件為一個獨立的元件型別,陣列的順序為元件繪製先後順序
同時可設定以下可選引數資訊:
- visible 是否可見,預設為 true
- opacity 透明度,預設為 1,可取值範圍 0~1
- color 染色顏色,設定上該顏色後向量內部繪製內容將會融合該染色值
- clip 用於裁剪繪製區域,可設定兩種型別:boolean
- boolean 型別,控制繪製時超出 width 和 height 區域的內容是否被裁剪,預設為 false 不裁剪
-
- - function 型別,可利用 canvas 畫筆繪製,實現自定義裁剪任意形狀的效果
那麼我們來看看這個圖示是怎麼用 HT 繪製的:
從圖片上可以看出來,這個圖示由一條直線、一個矩形以及一個箭頭組成,我們把這個圖示取名為 arrow:
ht.Default.setImage('arrow', {//註冊圖片 arrow "width": 60,//向量圖形的寬度 "height": 30,//向量圖形的高度 "comps": [//向量圖形的元件 Array 陣列,每個陣列物件為一個獨立的元件型別,陣列的順序為元件繪製先後順序 {//繪製直線部分 "type": "shape",//多邊形 "borderWidth": 1,//邊框寬度 "borderColor": "rgb(255,0,0)",//邊框顏色 "points": [//點資訊 points 以 [x1, y1, x2, y2, x3, y3, ...] 的方式儲存點座標 1.4262, 14.93626, 51.46768, 14.93626 ] }, {//繪製箭頭尖的部分 "type": "shape", "borderWidth": 1, "borderColor": "rgb(255,0,0)", "rotation": 4.71239,//旋轉 "points": [ 45.50336, 9.63425, 52.88591, 13.92955, 60.26846, 9.63425, 52.88591, 20.23827, 45.50336, 9.63425 ] }, {//繪製矩形部分 "type": "rect",//矩形 "background": {//背景顏色 "func": "attr@lightBg", "value": "rgb(255,0,0)" }, "borderColor": "#979797", "shadow": {//陰影 "func": "attr@shadow", "value": false }, "shadowColor": {//陰影顏色 "func": "attr@shadowColor", "value": "rgba(255,0,0,0.7)" }, "shadowBlur": 32,//陰影模糊 "shadowOffsetX": 0,//陰影橫偏移 "shadowOffsetY": 0,//陰影縱偏移 "rect": [//指定矩形的區域 [x, y, width, height] 起始位置的座標和矩形的大小值 11.44694, 10.43626, 30, 9 ] } ] });
每一個陣列物件中的基本型別與 style 的 shape 引數是完全一一對應, 只是將 style 中的名稱改成駱駝式命名法去掉了.
分隔符,查詢對應的 style 屬性請參考 HT for Web 風格手冊,有些後期新增的屬性可能在風格手冊中還沒有新增,大家只要知道這麼一個屬性就行了,一般看屬性名就知道這個屬性的功能了。
上面程式碼中有一段可能讓大家疑惑的點我沒有在程式碼中解釋,接下來我們著重來講一下這個部分的內容:資料繫結。從文章一開始的圖片我們知道,這個圖示中的矩形部分是會變顏色的。
資料繫結
資料繫結意味將 Data 圖元的資料模型資訊,與介面圖形的顏色、大小和角度等視覺化引數進行自動同步, HT 的預定義圖形元件預設就已與 DataModel 中的 Data 資料繫結,例如使用者修改 Node 的 position 位置值, 則 GraphView 和 Graph3dView 上的相應圖元位置會自動同步變化。
傳統的資料繫結有單向繫結和雙向繫結的概念,但 HT 系統的設計模式使得繫結更加簡化易於理解,HT 只有一個 DataModel 資料模型, 繫結 DataModel 的圖形元件並沒有元件內部的其他資料模型,所以元件都是如實根據 DataModel 來呈現介面效果,因此當使用者拖拽圖元移動時, 本質也是修改了資料模型中 Node 的 position 位置值,而該屬性變化觸發的事件通過模型再次派發到圖形元件,引發圖形元件根據新的模型資訊重新整理介面。
繫結的格式很簡單,只需將以前的引數值用一個帶 func 屬性的物件替換即可,func 的內容有以下幾種型別:
- function 型別,直接呼叫該函式,並傳入相關 Data 和 view 物件,由函式返回值決定引數值,即 func(data, view) 呼叫。
- string 型別:
- func@*** 開頭,則返回 data.getStyle(***) 值,其中 *** 代表 style 的屬性名
- attr@*** 開頭,則返回 data.getAttr(***) 值,其中 *** 代表 attr 的屬性名
- field@*** 開頭,則返回 data.*** 值,其中 *** 代表 data 的屬性名
- 如果不匹配以上情況,則直接將 string 型別作為 data 物件的函式名呼叫 data.***(view),返回值作為引數值
除了 func 屬性外,還可設定 value 屬性作為預設值,如果對應的 func 取得的值為 undefined 或 null 時,則會採用 value 屬性定義的預設值。 例如以下程式碼,如果對應的 Data 物件的 attr 屬性 lightBg 為 undefined 或 null 時,則會採用 rgb(255, 0, 0) 顏色:
"background": {//背景顏色 "func": "attr@lightBg",// 返回的是 getAttr('lightBg')的值 "value": "rgb(255,0,0)"//設定預設值 }
同理,上面程式碼中的 shadow 和 shadowColor 也都是以這種方式來進行資料繫結的,繫結的資料只與這個陣列物件部分有關,所以就算這個圖示是一張圖片,我們還是能單獨控制區域性改變顏色等等。想了解所有的 func 的使用可以參考這個例子http://www.hightopo.com/guide/guide/core/databinding/examples/example_piebinding.html,所有的型別都用上了,非常實用。
我在程式碼中就是通過控制這幾個繫結的屬性來改變這個陣列物件的顏色的,燈要閃爍,肯定會有“發光”的感覺才更真實,那麼這裡還需要解釋一個內容,shadow 這個屬性,解釋為陰影,什麼是陰影?比較好的一種解釋就是,在一個矩形框中,由矩形中心點觸發,由內至外顏色逐漸變淺,有一點像虛化,下面這張圖片就是陰影的展示:
搭建場景
接著是搭建場景,大家可以直接使用 lightBling/displays/電力 下的 大廈.json 檔案,在這個檔案中,我設定了部分的“箭頭”圖示的 tag 標籤。在 HT 中,一般建議 id 屬性由 HT 自動分配,使用者業務意義的唯一標示可存在 tag 屬性上,通過 Data#setTag(tag) 函式允許任意動態改變 tag 值, 通過 DataModel#getDataByTag(tag) 可查詢到對應的 Data 物件,並支援通過 DataModel#removeDataByTag(tag) 刪除 Data 物件。
不過我是直接在 json 中新增 “tag” 屬性,具體的 json 拓撲結構說明如下:
我們用到的 大廈.json,我拿一部分出來解析一下:
{ "c": "ht.Node",//類名,用來反序列化 "i": 274997,//id 值 "p": {//get/set 型別屬性 這裡面的所有屬性都可通過 get/set獲取和設定 "displayName": "燈-紅",//顯示名稱 "tag": "alarm",//標籤 可通過 getTag 和 setTag 來獲取和設定 "image": "symbols/隧道用圖示/交通燈/燈/燈-紅.json",//圖片 引用的路徑為相對路徑 這邊呼叫的“紅燈”圖示的 json 檔案 "position": {//座標 "x": 70.9971, "y": 47.78651 } }, "s": {//對應 setStyle 屬性 "2d.movable": false,//2d 下不可以動 若要開啟,直接設定 setStyle('2d.movable', true) 即可,下面同理 "2d.editable": false//2d 下不可編輯 } }
其實整個不需要動畫的部分都是 json 檔案中的內容,大家可以根據上面的 json 拓撲結構來解析圖紙的 json。那麼問題來了,如何在 GraphView 中載入圖紙的 json 檔案?HT 封裝了 ht.Defautl.xhrLoad 函式用來將對應的圖紙 json 載入到 GraphView 上,引數為 text 文字,需要通過 ht.Default.parse 轉義成 json:
ht.Default.xhrLoad('displays/電力/大廈.json', function(text){
var json = ht.Default.parse(text);
window.gv.dm().deserialize(json);//反序列化,並將反序列化的物件加入 DataModel
});
此時,DataModel 中的內容就是這個 json 檔案反序列化出來的所有圖元了,所以我們可以通過 DataModel 任意獲取和改變 json 中的圖元的樣式和屬性。其中,setAttr/getAttr 中的屬性我們必須先定義一下,不然 HT 又不知道這個節點是否有這個使用者自定義的屬性:
for(var i = 0; i < gv.dm().size(); i++){ var data = gv.dm().getDatas().get(i);//獲取 datamodel 中的對應 i 的節點 if(data.getTag()){//如果這個節點有設定 tag 值 data.a('shadow', false);//設定自定義屬性,並且給一個值 data.a('shadowColor', 'rgba(255,0,0,0.9)'); data.a('lightBg', 'rgb(255, 0, 0)'); data.a('alarmColor', 'red'); } }
這下我們就可以任意操作上面已經宣告過的屬性了,當然,HT 預設的屬性我們也能任意操作!我在 json 檔案中設定了幾個 tag 標籤,light1~light15 以及 alarm 標籤,我們可以通過 data.getTag() 來獲取這個節點對應的標籤名,或者通過 dataModel.getDataByTag(tagName) 已知標籤名來獲取對應節點。
燈閃爍動畫
動畫的部分 HT 有三種動畫的方式,針對的點不同,這裡我用到的是 schedule 主要用於在指定的時間間隔進行函式回撥處理。HT 中排程進行的流程是,先通過 DataModel 新增排程任務,DataModel 會在排程任務指定的時間間隔到達時, 遍歷 DataModel 所有圖元回撥排程任務的 action 函式,可在該函式中對傳入的 Data 圖元做相應的屬性修改以達到動畫效果。
以下是我例子中的動畫相關程式碼:
var blingTask = { interval: 1000,//間隔毫秒數 action: function(data){//間隔動作函式 if(data.getTag() === 'light1' || data.getTag() === 'light13' || data.getTag() === 'light5' || data.getTag() === 'light6' || data.getTag() === 'light10' || data.getTag() === 'light11' || data.getTag() === 'light12' || data.getTag() === 'light14' || data.getTag() === 'light15'){ if(data.a('lightBg') === 'rgb(255, 0, 0)'){//如果屬性lightBg值為這個,就做以下一系列的動作 data.a('lightBg', 'rgb(0, 255, 0)'); data.a('shadow', true); data.a('shadowColor', 'rgba(0, 255, 0, 0.9)'); }else if(data.a('lightBg') === 'rgb(0, 255, 0)'){ data.a('lightBg', 'rgb(255, 255, 0)'); data.a('shadow', true); data.a('shadowColor', 'rgba(255, 255, 0, 0.9)'); }else{ data.a('lightBg', 'rgb(255, 0, 0)'); data.a('shadow', true); data.a('shadowColor', 'rgba(255, 0, 0, 0.9)'); } }else if(data.getTag() === 'alarm'){ if(data.a('alarmColor') === 'red'){ data.a('alarmColor', 'rgb(0, 255, 0)'); }else{ data.a('alarmColor', 'red'); } } } }; window.gv.dm().addScheduleTask(blingTask);//新增動畫進 DataModel 中
其他部分我相信大家都能看得懂,實在不就去官網(或者這個連結也行,裡面還有常見問題)查查對應的文件,都寫得非常清楚。
現在工業網際網路運用到了我們城市以及工業建設的方方面面,不僅 2D 中能夠進行實時資料監控,3D 中也同樣可以進行資料的監測。比如:變壓器的資料監聽,智慧工業園。
https://hightopo.com/demo/intelligent-transformer/index.html