1. 程式人生 > >基於 HTML5 Canvas 的樓宇自控系統

基於 HTML5 Canvas 的樓宇自控系統

前言

樓宇自控是指樓宇中電力裝置,如電梯、水泵、風機、空調等,其主要工作性質是強電驅動。通常這些裝置是開放性的工作狀態,也就是說沒有形成一個閉環迴路。只要接通電源,裝置就在工作,至於工作狀態、程序、能耗等,無法線上及時得到資料,更談不上合理使用和節約能源。現在樓宇自控是將上述的電器裝置進行線上監控,通過設定相應的感測器、行程開關、光電控制等,對裝置的工作狀態進行檢測,並通過線路返回控制機房的中心電腦,由電腦得出分析結果,再返回到裝置終端進行調解。

(具體效果請參考連結:http://www.hightopo.com/demo/building-automation-system/)

程式碼實現

首先第一步我們還是要對整個介面做一下基礎的設定:

gv.getSelectWidth = () => { return 0 } // 隱藏選中邊框
gv.setMovableFunc(() => { return false }) // 禁止圖元移動
gv.handleScroll = () => {} // 禁止滑鼠縮放
gv.handlePinch = () => {} // 禁止 touch 下雙指縮放
gv.setPannable(false) // 禁止平移
gv.setRectSelectable(false) // 禁止框選
gv.setScrollBarVisible(false) // 隱藏滾動條
window.document.oncontextmenu = () => { return false } // 全域性設定右鍵選單禁用

接下來就開始對面板進行封裝,實現每塊中包含的動畫效果,這些動效製作起來既簡單又能展現出整個系統的運動感,其實現的方式相仿,我就用一段例子來演示:

function chillerPanelAnim() {
  let num = []
  let n = []
  for (let i = 0; i < 10; i++) {
    if (i < 8) {
      num.push(Math.random() * 2)
    }
    else if (i === 8) {
      n.push(Math.random() * 40 + 60)
    }
    else {
      n.push(Math.random() * 31)
    }
  }
  let oldNumValue1 = chillerPanel.a('l1.l.clipPercentage')
  let oldNumValue2 = chillerPanel.a('l2.l.clipPercentage')
  let oldNumValue3 = chillerPanel.a('l3.l.clipPercentage')
  ht.Default.startAnim({
    duration: 2000,
    easing: (t) => { return t },
    action: (v, t) => {
      chillerPanel.a('l1.l.clipPercentage', oldNumValue1 + (num[0] - oldNumValue1) * v)
      chillerPanel.a('l2.l.clipPercentage', oldNumValue2 + (num[1] - oldNumValue2) * v)
      chillerPanel.a('l3.l.clipPercentage', oldNumValue3 + (num[2] - oldNumValue3) * v)
    },
    finishFunc: () => {
      setTimeout(() => {
        chillerPanelAnim()
      }, 2000)
    }
  })
}

關於動畫的方法大家可以理解為將某些屬性由起始值逐漸變到目標值的過程,HT 提供了 ht.Default.startAnim,它支援 Frame-Based 和 Time-Based 兩種方式的動畫,我使用 Time-Based 方式,優點在於只需要指定 duration 的動畫週期的毫秒數即可,HT 將在指定的時間週期內完成動畫,也就是說幀數或 action 函式被呼叫次數取決於系統環境,一般來說系統配置更好的機器,更高效的瀏覽器則呼叫幀數越多,動畫過程更平滑。避免了由於 js 語言無法精確控制 interval 時間間隔,可能會出現動畫週期差異較大的問題。這其中還有個 easing 屬性可以通過數學公式計算來配置動畫的 緩動效果,感興趣的朋友可以開啟來自己試著玩一玩。

2.5D 裝置的管道部分,我用排程的方式給大家介紹一下:

// 流動動畫
let flowTask = {
  interval: 10, action: (data) => { if (data.getDisplayName() === 'flow1') { data.s('shape.dash.offset', data.s('shape.dash.offset') + 1) } if (data.getDisplayName() === 'flow2') { data.s('shape.dash.offset', data.s('shape.dash.offset') - 1) } if (data.getDisplayName() === 'flow3') { data.s('shape.dash.offset', data.s('shape.dash.offset') + 5) } } }
dm.addScheduleTask(flowTask)

這也是一種實現動效的方式,它主要用於在指定的時間間隔進行函式回撥處理,常用於實現圖形的流動和閃爍等動畫效果。流程是先通過 DataModel 新增排程任務,DataModel 會在排程任務指定的時間間隔到達時,遍歷所有圖元回撥排程任務的 action 函式,可在該函式中傳入的 Data 圖元做相應的屬性修改以達到動畫效果。更多引數和設定可以參考 排程手冊。

我們還要注意最好給需要互動的圖元的滑鼠移入移出事件分別設定 view.setCursor('pointer') 和 view.setCursor('default') 來增強互動體驗感。同時,製作 2.5D 的圖元其實需要花費超出正常 2D 圖元數倍的工作量,除了要按照真實角度的透檢視去建模外,還需要把每個部分單獨製作。這就出現了有可能卡頓的問題,我們做的時候要注意用快取規則來優化效能,儘可能的把每個細節做好。cacheRule 就相當於都用同一個 image,預設規則時:圖示名 + 寬 + 高 + 縮放,如果規則判定一致,就會用同一張貼圖,如果有其他的需要影響,就多返回一些資訊,例如 data.a( 'color' ),這樣會額外判定他們這個屬性也是否一致,只有都一致的才會用同一張快取,不一致的話嘗試新建快取貼圖,比較適合靜態的。

總結

在二十一世紀的今天,隨著計算機技術和資訊科技突飛猛進的發展。對大樓內的各種裝置的狀態監視和測量不再是隨線式,而是採用掃描測量。智慧建築 (Intelligent Buildings) 是建築技術與網際網路技術相結合的產物,是資訊社會與經濟國際化的需要。今天我們打造的樓宇自動化控制系統 (BAS) 就屬於這其中的一類,還有通訊自動化系統 (CAS) 和辦公自動化系統 (OAS) 等組成。如今已經廣泛應用於各個領域,極大的提高了管理效率和能源的有效利用率以及裝置監測等智慧化為一體的作業系統。還有更多高大上的智慧作業系統在等待著我們推動社會資訊化的進步!

HT for Web :(http://www.hightopo.com/demos/cn-index.html)