- A+
WEB组态可视化软件
1 B/S组态软件
它是一个独立的产品,包含编辑器(设计时)和运行环境(运行时)两大模块,我们将其命名为——WEB组态可视化软件(下称“组态软件”)。
2 组态概念
组态(Configure)的概念来自于20世纪70年代中期出现的第一代集散控制系统(Distributed Control System),可以理解为“配置”、“设定”、“设置”等,是指通过人机开发界面,用类似“搭积木”的简单方式来搭建软件功能,而不需要编写计算机程序。我们也可称之为“二次开发”,组态软件即为“二次开发平台”。
3 组态产品呈现
组态软件是个怎样的产品?
先做一个概述:组态软件通过浏览器操作组态工具、浏览组态画面,实现工程管理、组态编辑以及组态运行三大功能。通过实现图元组态、可视化图表组态、数据库组态的配置与关联,完成基于Web服务的实时数据监控与服务端的多用户访问等。
从用户操作与界面呈现的角度来说,组态软件采用标准HTML5技术,基于B/S架构进行开发,支持Web端呈现,在浏览器端即可完成便捷的人机交互,简单的拖拽即可完成可视化页面的编排设计。此外,由于组态软件功能较为复杂,为降低使用门槛,组态软件进行了模块集成化,旨在简化用户的操作步骤,提高用户的工作效率。
从软件架构来说,组态软件具备高度的开放性。随着应用场景的逐渐增加,软件必然需要进行功能扩展,因此,组态软件不仅支持多种数据接口,也提供了二次开发接口,可以由用户自行完成二次开发。组态软件在功能上集成了大量通用模块和个性化模块,以实现不同行业用户的需求。针对具体的用户,软件支持定制化模块的开发与配置,实现“即插即用“。
软件的运行逻辑并不复杂,除了基础的组态管理外,主要可分为组态编辑和组态运行两个部分。用户需要在组态编辑环境中使用组态软件提供的组态功能(图元、图表、数据库)进行组态设置、建立网络拓扑、绘制数据显示界面、配置各种系统参数(如数据采集频率)等;然后在组态运行环境中运行已经组态好的应用系统,包括数据实时监控、场景展示等。
两者之间的关系如图所示:
4 功能特点
- 基于html5,B/S架构
- 支持 2D、2.5D、3D多种呈现模式
- 可视化拖拽编辑、简单易用
- 支持云端/本地等部署方式,多终端使用
- 提供丰富的行业标准元器件图元库
- 提供行业模板和组件,支持自定义模板和图纸管理
- 提供定制开发服务
- 支持Http、WebSocket等主流协议,支持扩展更多协议
- 支持嵌入第三方系统或者集成平台,也可作为独立平台
- 具备延续性、可扩展性、封装性(易学易用)、通用性、开放性
- 周密的系统安全防范
软件主要功能模块有组态管理、组态编辑、组态运行三大模块:
- 组态管理
管理模块的详细功能与其他软件大同小异,系统管理通过分级权限保障系统的安全;工程管理则是对组态文件的建立、提交、删除、恢复等基本操作提供入口。
2. 组态编辑
本模块是组态软件的核心模块,软件绝大部分操作都在这一个模块里面进行。
主要操作对象有画布、图元、可视化图表以及数据库。针对画布与图元这类基础对象,软件提供诸如调整尺寸、属性、复制、粘贴、增删、合并、拆分、绑定跳转页面/事件等操作,搭建可视化页面的基础架构。
可视化图表是页面展示的主要形式,因此,除了针对图元的基本操作之外,软件还提供了样式设计、文本属性以及运行参数设置,确保图表在可视化页面的展示效果。
数据库作为系统的数据源,需要与组态形成关联,为组态提供数据。软件支持配置组态关联的数据库信息、绑定图元/可视化图表对应实时/历史数据源、设置图元/可视化图表数据源触发事件等功能。
- 组态运行
本模块将为各类应用场景提供实际的运行功能,具体如下所示:
- 解析组态画面编辑文件
- 绘制动态实时监控页面
- 关联图元及可视化图表数据源
- 可视化图表数据导出
- 网络通信检测
- 设置可视化图表运行参数
- 失效数据检测处理等
5 组态软件应用场景
组态软件的出现,为解决实际工程问题提供了一种崭新的方法,用户通过类似“搭积木”的简单方式来完成自己所需要的软件功能,不需要编辑计算机程序。组态软件能够很好地解决各类场景中存在的种种问题,使用户能根据自己的管理对象和管理目的的任意组态,完成最终的场景控制自动化、数据可视化。主要适应场景如下:
- 配电
- 工业(控制)
- 智能楼宇
- 变电站管理
- 电厂电气
- 配电室监控
- 冶金工艺流程控制
- 水力自动控制
- 石油智能控制系统等
6 经典的案例
6.1 某通信基站的组态可视化
本项目采用2.5D的形式进行可视化展示,2.5D技术使用三维建模方式,构建立体效果,同时增加了2D的光照和2D各种方法,系统的功能具有很好的延展性。系统在项目中可以进行数据结构更换、tips效果优化、选中效果、设备告警、油箱动态油量显示、油机开关机功能,支持自动布局多种布局方式,可进行接口对接,支持基站多设备的添加,设备基本信息的查看等功能。
7 具体实现
7.1 设计时
7.1.1 表单输入
基于HTML5进行表单输入,前端给ui打上id标签
<li data-cIndex='16'><img src="./images/icons/door.png" alt="WEB组态可视化软件(B/S)" class="CNicons" alt=""><a id="a_16" class=" controlName" group="">门禁</a></li> <tr id="tr_i_DoorState" style=" display:none;"> <td></td> <td class="txt i_attrName">门状态点</td> <td class="txt"> <input type="text" id="i_DoorState" name="DoorState" style="width:150px;"> </td> </tr> <tr id="tr_i_OpenStateValue" style=" display:none;"> <td></td> <td class="txt i_attrName">门打开值</td> <td class="txt"> <select id="i_OpenStateValue" name="openValue"> <option value="0">0</option> <option value="1">1</option> </select> </td> </tr> <tr id="tr_i_OpenDoorState" style=" display:none;"> <td></td> <td class="txt i_attrName">开门控制点</td> <td class="txt"> <input type="text" id="i_OpenDoorState" name="OpenDoorState" style="width:150px;"> </td> </tr> <tr id="tr_i_linkdeviceid" style=" display:none;"> <td></td> <td class="txt" id="td_i_linkdeviceid_tit">联动点</td> <td class="txt i_attrName"> <input id="i_linkdeviceid" class="input0" value="" style="width:150px;"> </td> </tr> <tr id="tr_i_CardReader" style=" display:none;"> <td></td> <td class="txt" id="td1">读头</td> <td class="txt i_attrName"> <input id="i_CardReader" name="CardReader" class="input0" value="" style="width:150px;"> </td> </tr>
7.1.2 js脚本
根据id,通过js来面向dom元素编程,如果时vue,angular,react则直接可绑定数据,面向数据编程。通过js来对拖动,点击,修改,保存等事件进行编程;
//门状态点 $('#i_DoorState').focus(function(){ var stateName = $(this).attr('name'); selectDevState(stateName); }); //门打开控制点 $('#i_OpenDoorState').focus(function(){ var stateName = $(this).attr('name'); selectDevState(stateName); }); //读头 $('#i_CardReader').focus(function(){ var stateName = $(this).attr('name'); selectDevState(stateName); });
else if(devIndex==16){//门禁 $('#tr_i_OpenStateValue').show(); $('#tr_i_DoorState').show(); $('#tr_i_OpenDoorState').show(); $('#tr_i_CardReader').show();
如,如下保存点击事件可保存配置属性成json,生成json文件或者post给后台服务加载到数据库。
$('#a_save').click(function(){ var row = $('#MonitoringSiteTable').datagri('getSelected'); if(row){ var devArr= $('.dev'); for(var i=0;i<devArr.length;i++){ if(devArr.eq(i).css('outline-style'!=='none'){ var upId = devArr.eq(i).attr('id'); switch(stateName){ case 'devname': $('#i_deviceid').val(rowdevname); deviced[upId].devname=rowdevname; if(deviced[upId].devIndex==8){ var txt = textShowMod(upId); var textID = 'p'+upI+'img'; $('#'+textID).text(txt)css({color:deviced[upId]fontColor}); textAlign(devId); }else if(deviced[upId]devIndex==14){ devArr.eq(i).find('span')text(row.devname).css{color:'#555'display:'inline-block'position:'absolute'bottom:'10px'}); }else if(deviced[upId]devIndex==5){ moniShowMode(upId); var textID = 'p'+upI+'img'; $('#'+textID).css{color:deviced[upId]fontColor}); }else if(deviced[upId]devIndex==15){ devArr.eq(i).find('span')text(row.devname).css{color:'#555'position:'absolute'bottom:'10px',left:'0px'}; } break; case 'OpenDoorState': $('#i_OpenDoorState').val(rowdevname); deviced[upId].OpenDoorState =row.devname; break; case 'DoorState': $('#i_DoorState').val(rowdevname); deviced[upId].DoorState = rowdevname; break; case 'CardReader': $('#i_CardReader').val(rowdevname); deviced[upId].CardReader =row.devname; break; case 'linkorgid': $('#i_linkorgid').val(roworgname); deviced[upId].linkorgid=roworgname; break;
7.2 运行时
7.2.1 前端给ui打上id标签
<div id="centerTabs" class="easyui-tabs" style="width:100%;height:100%;"> <div title="组态图设计" id="contentBox" data-options="closable:false" style="padding:4px;position:relative;"> <div id="resizeBox" style="position:relative;width:100%;height:100%;z-index:2;border:1px solid #ccc;overflow:hidden;" data-Box="bgBox"></div> </div> <div title="预览" data-options="closable:false" style="padding:4px;position:relative;" id="previewBox"> </div> </div>
7.2.2 js脚本
需要先从数据库或者*.json加载控件的配置数据,来展现完成的控件属性,然后去对应的后台接口,或者devicedata.json(后台服务生成),来更新当前设备的实时数据。
定时刷新设备实时数据,其余定时刷新实时数据的代码太长,这里不粘贴,自行补全。
//预览 $('#centerTabs').tabs({ onSelect:function(title,index){ if(title=="预览"){ preview(); }else if(title=="组态图设计"){ clearInterval(intervalId); if($('.video').length>0){ var video = $('.video').eq(0); $('#resizeBox').append(video); var devId = video.attr('id'); video.css('outline-style',deviced[devId].outlineStyle); if(video.css('outline-style')!=='none'){ $('#'+devId+'img').show(); } $('#'+devId).resizable({ disabled:false }); deviced[devId].ocx.DisConnectAllChannel(); }else if($('.chart').length>0){ var chart = $('.chart'); for(var j=0;j<chart.length;j++){ $('#resizeBox').append(chart.eq(j)); var devId = chart.eq(j).attr('id'); chart.eq(j).css('outline-style',deviced[devId].outlineStyle); $('#'+devId).resizable({ disabled:false }); } } $('#previewBox').empty(); for(var i in deviced){ if(deviced[i].devIndex==14){ deviced[i].option.series[0].data[0].value=50; deviced[i].Chart = echarts.init(document.getElementById(i+'img')); deviced[i].Chart .setOption(deviced[i].option,true); }else if(deviced[i].devIndex==15){ deviced[i].dial = new canvasPanel(); deviced[i].dial.bgColor = deviced[i].panelColor; deviced[i].dial.splitNum = deviced[i].lineValue; deviced[i].dial.MaxNum=parseInt(deviced[i].dmaxvalue); deviced[i].dial.MinNum = parseInt(deviced[i].dminvalue); deviced[i].dial.init(i+'img'); }else if(deviced[i].devIndex==24){ deviced[i].data = []; clearInterval(deviced[i].chartInterval); } } } } });
8 小结
- 设计时,根据配置属性,生成配置json文件,或者配置后台服务,通过webapi接口持久化配置到db;
- 运行时,从数据库或者配置文件来生成定制的控件,根据配置参数来加载实时json或者去实时接口ajax或者websocket拿数据;
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.cnblogs.com/JerryMouseLi/p/14082036.html