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" 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