基于mxGraph的组态设计器设计方案
2020-12-31孔晓阳代真虎
孔晓阳 代真虎
(上海宝信软件股份有限公司 上海:201900)
随着HTML5标准的发布,在Web浏览器前端可以完成的功能越来越多,其性能水平与CS架构的前端软件之间的差距在快速缩小。同时众多相关厂商先后发布基于H5标准的产品,一时间各种前端框架、前端解决方案百花齐放。传统工业监控组态软件大多基于CS架构搭建,此类软件与其他第三方系统集成、移动端集成以及多屏自适应等方面有诸多不便,难以适应目前工业互联网国家战略下对于工业领域IT系统的融合要求,各工业企业也急于寻找对自身监控类软件的改造升级路径。
组态设计器软件向来是工业SCADA系统的核心部件,是工业监控系统现场实施的重要工具。实现纯BS架构的组态设计器软件,将对工业监控领域的软件部署方式、实施方案等产生重大影响。首先,BS架构的组态设计器将大大减轻客户端部署的复杂度,用户只需要有浏览器便可以进行项目实施,也无需考虑客户端版本升级维护的问题;其次,基于H5标准和互联网最新技术构建的组态工具,可以满足工业互联网时代下的大规模、高强度的访问请求,方便支持横向扩展、系统高可用等特性;还有面对大融合的工业互联要求,BS架构的设计器能够与其他第三方系统、移动应用等进行快速集成。
本文介绍了一种基于mxGraph开源图形库的组态设计器工具的设计方案,通过该设计器工具用户可以所见即所得构建组态监控画面、创建可复用图元、与底层数采系统数据点绑定、编写业务逻辑脚本以及最终运行画面,满足了工业现场对BS架构的组态设计器软件的需求。
1 关键技术
1.1 mxGraph
mxGraph是一个基于SVG和HTML技术进行渲染的JavaScript图形库,通过它设计良好的API,可以进行图形绘制、与图形交互以及与图形相关常用操作。mxGraph提供了一套屏蔽不同浏览器差异的JavaScript库,通过进行完善的抽象和封装提供给用户一致的、简洁的API。mxGraph还提供一个设计器原型mxEditor,让使用者快速构建图形应用。本文介绍的设计方案便是基于mxEditor进行构建。mxGraph主要功能全部包含在一个JavaScript文件中,通过在HTML页面中引用该文件,便可以进行相关图形操作,结合与后端服务的通信实现数据联通、文件管理等功能,可以完成一个最简的图形绘制应用。图1是mxGraph全局架构图。
图1 mxGraph架构图
1.2 SVG
SVG是指Scalable Vector Graphics,即可缩放的矢量图形,用SVG描述的图形无论如何缩放都不会损失画质。它基于XML语言构建,通过描述性的语句来表述图形内容,与通常的位图有着本质的区别。SVG图形可以支持用户交互,基于浏览器用户事件可以完成众多交互相关功能;SVG直接支持HTML的DOM操作,可以通过JavaScript语言动态改变SVG内容;SVG自身提供动画操作元素,可以很方便完成动画过程。SVG对于JavaScript和DOM的支持,极大地扩展了其使用范围和灵活性,同时还可以搭配CSS样式表对SVG图形进行样式设置,更重要的是SVG标签支持自定义扩展属性,对于组态画面这样的复杂图形,通过扩展属性可以携带各种配置信息和数据信息,再结合JavaScript语言处理,便可基于此来实现前端组态画面数据刷新以及动画展示等功能。
2 组态设计器架构
2.1 整体流程
本文所实现的组态设计器为BS架构应用程序,基于mxGraph图形库的GraphEditor示例来搭建,该示例中包含了一个设计器的各项基本功能,并支持扩展。主要包括设计器页面框架、菜单栏、工具栏、元素边栏、元素上下文菜单、画面内部结构以及后台通信接口等。
设计器整体流程(见图2)描述如下:通过GraphEditor完成图形绘制生成内部的基于XML语法的画面表述文本,重写画面保存接口,将画面文本发送到后台服务进行画面内容保存和转换,画面转换主要是将内部表述形式的文本转换为基于SVG的形式,同时增加用户脚本等重要功能,最终方便前端浏览器运行态展示以及数据刷新。画面转换格式后,将画面内容进行后台存储,当后台服务接收到画面运行态加载请求后,将转换好格式的画面内容发送到前端,前端运行态对画面内容进行解析,主要对数据绑定、用户脚本进行提取,并根据配置内容进行画面数据刷新和接受用户事件。
图2 画面设计与运行流程
2.2 设计器搭建过程
mxGraph的GraphEditor示例是一个相对完整的前端设计器框架,通过将该示例文件夹拷贝到相应的Web工程中,并对后台对接服务进行相应调整,便可以初步运行起来。如果需要对后台对应的服务,比如画面保存服务、画面打开服务进行相应修改,则需要对与后台交互部分的逻辑进行调整;如果需要前端设计器功能、样式调整等,则需要对前端JavaScript、CSS等文件内容进行修改。
2.2.1 初始运行设计器
GraphEditor示例在mxGraph程序包中的/javascript/examples/grapheditor目录下,其中/java目录中是两个Java程序,分别负责启动一个HTTP服务以及一个画面打开服务,在本文方案中HTTP服务由Tomcat容器运行,画面打开、保存等后台服务参考GraphEditor的Java示例实现。
拷贝/javascript/examples/grapheditor/目录下的/www文件夹到Web工程下,并调整目录结构为需要的路径。本文方案中的设计器目录结构如图3所示。
图3 设计器目录结构
在/designer文件夹下的index.html文件为组态设计器入口,此时运行Tomcat容器加载Web工程后,通过浏览器访问/console/designer路径可以看到设计器初始运行成功,如果需要调整设计器界面的展示语言,可以通过修改mxLanguage=’zh’来指定使用中文,同时在/resources文件夹下增加grapheditor_zh.txt文件,内容可以参考/resources/grapheditor.txt文件。设计器初始界面如图4所示。
图4 设计器初始界面
2.2.2 调整后台交互
GraphEditor示例的后端交互请求主要有以下几种类型,包括画面新建、画面保存与画面打开,本文通过对前端设计器发出的请求进行复写,同时更改后台Java接口的实现方式,对原新建、保存等操作进行了重新编码,并新增画面导出、画面转换等后端接口。
以画面保存为例,其调用发起是在/js/EditorUI.js文件的EditorUi.prototype.save函数中,通过修改save函数的Ajax请求地址以及参数,可以将画面保存内容发送到后台服务中,从而实现自定义的画面保存功能。
为了更加丰富设计器功能,本文还对设计器画面提供画面导出、画面查错等功能,需要同时对前端设计器界面和后台服务进行调整。首先通过/js/Toolbar.js中添加工具栏中的按钮入口或者在/js/Menus.js中添加菜单入口,然后通过在/js/Actions.js中定义对应的action操作,从而实现设计器的自定义功能实现。图5是本文设计器的自定义工具栏。
图5 设计器工具栏
2.2.3 设计器样式调整
首先需要明确对于整体设计器的布局是通过/js/EditorUI.js文件来进行定义,该文件通过createDivs和createUI两个方法创建了整个设计器的样式内容,调整该方法中的div容器创建和相应UI组件,可以自定义设计器样式。本文中对于设计器右侧的Diagram容器、菜单容器以及左边栏容器都进行了相应的调整,图6为最终设计器界面。
图6 设计器界面样式
如果对于原有的div容器需要进行删除修改等操作,可以直接在createDivs方法中进行调整,在该方法中创建的div容器是各个UI控件的父容器。图7是createDivs方法截图。
图7 创建div容器
同时,本文设计器还对整体样式进行了调整,比如调整设计器整体色系、字体等。GraphEditor示例对于所有样式的定义都在/styles/grapheditor.css文件中,通过该文件可以查看设计器中已有UI控件的所有配置class、id信息,从而可以方便地进行样式调整,对于新增的UI控件,也可以自定义相关的class、标签样式等。
2.3 画面静态结构
由于组态画面在编辑状态和运行状态其功能有一定差异,比如编辑态需要能保留用户操作步骤以此进行撤销操作,而运行态则需要支持触发用户事件等,所以其各自状态下的表述形式也有所不同。编辑态内容以mxGraph图形库的文档结构为基础,其根元素为mxGraphModel,所有图形元素都是一个mxCell标签,在mxCell标签中通过parent属性表明父子关系,通过mxGeometry标签表明该元素的位置大小信息,其结构如图8所示。
图8 mxGraph文档基本结构
在组态画面搭建过程中的所有配置属性全部体现在该文档结构中,比如线条颜色、填充比例等,对于mxCell可以识别的属性内容,可以直接进行配置,如果不属于mxCell可识别的范围,比如图元闪烁频率、文本替换规则等,那么需要将这些自定义属性全部添加到style属性中,并通过配置界面来修改和展示这些内容。后续再次打开该画面内容时,需要对所有已配置属性进行解析,并回填到相应的属性配置界面中。基本的编辑态文档格式如图9所示。
图9 编辑态文档结构
事件处理是组态画面的重要功能,通过在编辑态定义画面元素与用户事件的关联关系以及处理函数,以此提供组态画面交互特性,而不仅仅只是简单的图形展示。用户事件处理内容并不与画面元素共同存储在同一文档中,这是因为mxGraph的文档格式并不支持JavaScript语言存储。所以当用户进行脚本编辑时,需要在设计器中缓存脚本内容,当画面进行保存时,将脚本内容与画面元素内容一并传递到后台进行处理。
画面脚本在编辑态以”元素唯一名称_事件=function(){}”的形式存储,经过后台解析后将具体元素的事件响应关联到该函数上,同时将所有用户脚本加入到页面