基于 HTML5 Canvas 的 Web SCADA 组态电机控制面板

前言

HT For Web 提供完整的基于 HTML5 图形界面组件库。您能够轻松构建现代化的,跨桌面和移动终端的企业应用,无需担心跨平台兼容性,及触屏手势交互等棘手问题。也可用于快速建立和部署,高度可定制化,并具备强大交互功能的拓扑图形及表盘图表等应用。HT for Web 很是适用于实时监控系统的界面呈现,普遍应用于电信网络拓扑和设备管理,以及电力、燃气等工业自动化 ( HMI / SCADA ) 领域。HT for Web 还有提供了一套一套强大的基于 WebGL 技术的 3D 图形引擎,独特的 WebGL 层抽象,将 Model – View – Presenter ( MVP ) 的设计模型延伸应用到了 3D 图形领域。使用 HT for Web 您可更关注于业务逻辑功能,没必要将精力投入复杂 3D 渲染和数学等非业务核心的技术细节。( http://www.hightopo.comjson

做为刚入门的小白(你们能够叫我老郑),我尝试着一步一步的作这个面板,用这篇文章来记录本身的一些收获(毕竟我仍是个菜鸟)以及代码的实现,但愿可以帮到一些朋友。固然,若是有什么意见能够直接跟我说,你们一块儿交流才会进步!浏览器

效果图

代码实现

话很少说,上代码。总体是一个 2D 的面板,那么要引入咱们必须须要用到的 HT 核心库:ht.js 。网络

首先,要建立数据容器和拓扑图形组件。DateModel 做为承载 Data 数据的模型,管理着Data数据的增删以及变化事件派发, HT 框架全部组件都是经过绑定 DataModel,以不一样的形式呈现到用户界面;同时组件也会监听 DataModel 模型的变化事件, 实时同步更新界面数据信息,掌握了 DataModel 的操做就掌握了全部组件的模型驱动方式;拓扑图形组件 ht.graph.GraphView 是 HT 框架中 2D 功能最丰富的组件,其相关类库都在 ht.graph 包下。GraphView 具备基本图形的呈现和编辑、拓扑节点连线及自动布局功能。架构

var dataModel = new ht.DataModel();
var graphView = new ht.graph.GraphView(dataModel);

经过如下代码来进行一些基础操做上的设置:框架

// 禁止平移
graphView.setPannable(false);
// 将其重载为空函数,禁止滚动 graphView.handleScroll
= function() {};
// 禁用touch上双指操做缩放 graphView.handlePinch
= function() {};
// 禁止拓扑上框选操做 graphView.setRectSelectable(
false);
// 经过过滤器设置禁止拖动 graphView.setMovableFunc(
function(data) { return false; });
// 后将组件加入到指定的 DOM 元素底下,不指定则加入到 document.body 下 graphView.addToDOM(); window.addEventListener(
'resize', function(e) { graphView.fitContent(); }, false);

接下来经过请求把图纸(json 文件)的 url 写好拿到咱们精心设计的面板。先还原成 JSON 字符串,而后将其反序列化并加入 dataModal 而后就能够操做数据了。dom

var json = ht.Default.parse(text);
dataModel.deserialize(json);

而后,咱们来实现其中的一些小效果。第一,我想让 Alarm 的 4 个小灯每 2s 交替变化一次。那么,让我们来写一个函数来控制它们:编辑器

var flag = true;
setInterval(function () {
  changeAlarmColor(dataModel, 'Alarm1', flag);
  changeAlarmColor(dataModel, 'Alarm2', flag);
  changeAlarmColor(dataModel, 'Alarm3', flag);
  changeAlarmColor(dataModel, 'Alarm4', flag);
  flag = !flag;
}, 2000);
function changeAlarmColor(dataModel, tag, flag) {
    var tag = dataModel.getDataByTag(tag);
        if(flag) {
            tag.a('backgroundColor', 'rgb(138,40,18)');
            tag.a('progressiveColor', 'rgb(232,97,56)');
        } else {
            tag.a('backgroundColor', 'rgb(34,168,38)');
            tag.a('progressiveColor', 'rgb(82,222,133)');
        }
}

由于我以前在 2D 编辑器中已经对它们的 tag 和属性名进行了设置,因此我在这里直接经过寻找 tag 值来返回指定标示的 Data 对象。接着只须要改变它们的属性值就能够产生想要的效果了。(.a 是获取或设置 attr 属性的简写,仅有一个参数时至关于getAttr,有两个参数时至关于setAttr)怎么样,是否是很简单。同理,咱们再将 PUMP 中每一个部分的文字和颜色每 2.5s 变化一次。函数

setInterval(function () {
  changePumpState(dataModel, 'pump1');
  changePumpState(dataModel, 'pump2');
  changePumpState(dataModel, 'pump3');
}, 2500);
function changePumpState(dataModel, tag) {
  var tag = dataModel.getDataByTag(tag);
  var num = Math.floor(Math.random() * 3 + 1);
  tag.a('status', num);
}

到这里,细心的朋友可能看出我换了写法,用了一个 status 属性。由于咱们之后会遇到更多的属性须要根据需求同时变化,那么咱们逐一去操做会写出大量的代码。对比一下“笨方法”:布局

function changePumpState(dataModel, tag) {
  var tag = dataModel.getDataByTag(tag);
  var changeArr = [
    {
      instruction: 'Stopped',
      instructionColor: 'rgb(234,0,0)',
      backgroundColor: 'rgb(138,40,18)',
      progressiveColor: 'rgb(232,97,56)',
      status: 'FAULT'
    },
    {
      instruction: 'Need to Run',
      instructionColor: 'rgb(221,181,0)',
      backgroundColor: 'rgb(29,143,32)',
      progressiveColor: 'rgb(82,222,133)',
      status: 'NO FAULT'
    },
    {
      instruction: 'Running',
      instructionColor: 'rgb(92,137,34)',
      backgroundColor: 'rgb(29,143,32)',
      progressiveColor: 'rgb(82,222,133)',
      status: 'NO FAULT'
    }
  ];
  i = Math.floor(Math.random() * (changeArr.length - 1 + 1));
  tag.a('instruction', changeArr[i].instruction);
  tag.a('instructionColor', changeArr[i].instructionColor);
  tag.a('backgroundColor', changeArr[i].backgroundColor);
  tag.a('progressiveColor', changeArr[i].progressiveColor);
  tag.a('status', changeArr[i].status);
}

因此,我在图标里本身声明了一个属性,并经过改变 status 值来控制我在编辑器中绑定在一块儿的属性以达到同时变换。哦对了,你们在作点击图标产生变化的时候别忘记在 2D 编辑器中选中“可交互”!下面咱们再作一个 TANK 进度条每 3s 随机变化一次的动画效果。动画

  

setInterval(function () {
  var tag = dataModel.getDataByTag('tank');
  var num = Math.random() * 1;
  ht.Default.startAnim({
    duration: 500,
    action: function(v, t){
      tag.a('progress', num * v);
    }
  });
}, 3000);

这里咱们用到了动画。在 HT 的数据模型驱动图形组件的设计架构下,动画可理解为将某些属性由起始值逐渐变到目标值的过程, HT 提供了 ht.Default.startAnim 的动画函数。它支持 Frame-Based 和 Time-Based 两种方式的动画,Frame-Based方式是用户经过指定 frames 动画帧数,以及 interval 动画帧间隔参数控制动画效果。

我用的是 Time-Based 方式,该方式用户只须要指定 duration 的动画周期的毫秒数便可,HT 将在指定的时间周期内完成动画, 不一样于 Frame-Based 方式有明确固定的帧数,即 action 函数被调用多少次,Time-Based 方式帧数或 action 函数被调用次数取决于系统环境, 通常来讲系统配置更好的机器,更高效的浏览器则调用帧数越多,动画过程更平滑。因为 js 语言没法精确控制 interval 时间间隔, 采用 Frame-Based 不能精确控制动画时间周期,即便相同的 frames 和 interval 参数在不一样的环境,可能会出现动画周期差别较大的问题, 所以 HT 默认采用 Time-Based 的方式,若是不设置 duration 和 frames 参数,则 duration 参数将被系统自动设置为 ht.Default.animDuration 值。action 函数就是实现动画过程当中的属性变化(变化参数和进度)。

好了,若是大家还想改变其 HT 系统默认属性,能够经过全局的 htconfig 变量名指定,HT 系统只在初始化时读取 htconfig 的配置信息, 所以该属性必须在引入 ht.js 包以前初始化好,运行状态时修改 htconfig 变量不会再起做用。示例代码以下:

<script>
  htconfig = {
    Color: {
      label: '#000',
      labelSelect: '#FFF'
    },
    Default: {
      toolTipDelay: 100,
      toolTipContinual: true
    },
    Style: {
      'select.color': '#E74C3C',
      'select.width': 0// 去掉默认选中样式(绿框)
    }
  };
</script>
<script src="ht.js"></script>

总结

刚开始作的时候很费劲,以前没有接触过,不过用上编辑器以后发现一切都没有想象的那么难,虽然花了些时间,可是总的来讲收获仍是很大的,成长了不少,人都是要不断进步嘛~

经过这个 demo 的实现,你也将会慢慢联想到不少东西。互联网+ 的概念在新兴产业上可以很好地运营,同时在传统行业中利用得当一样可以产生很是大的效益,好比智慧城市建设,智慧能源管理,智慧工厂,甚至是地铁、隧道监管等等均可以结合互联网+ 的模式来运做,在必定程度上节省了很是多的人力和时间成本!

相关文章
相关标签/搜索