基于 H5 Canvas 实现楼宇自控系统
前言
楼宇自控是指楼宇中电力设备,如电梯、水泵、风机、空调等,其主要工作性质是强电驱动。通常这些设备是开放性的工作状态,也就是说没有形成一个闭环回路。只要接通电源,设备就在工作,至于工作状态、进程、能耗等,无法在线及时得到数据,更谈不上合理使用和节约能源。现在楼宇自控是将上述的电器设备进行在线监控,通过设置相应的传感器、行程开关、光电控制等,对设备的工作状态进行检测,并通过线路返回控制机房的中心电脑,由电脑得出分析结果,再返回到设备终端进行调解。
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) } }}
这也是一种实现动效的方式,它主要用于在指定的时间间隔进行函数回调处理,常用于实现图形的流动和闪烁等动画效果。流程是先通过 DataModel 添加调度任务,DataModel 会在调度任务指定的时间间隔到达时,遍历所有图元回调调度任务的 action 函数,可在该函数中传入的 Data 图元做相应的属性修改以达到动画效果。更多参数和设置可以参考