最近公司需要使用mxgraph,来进行流程图的开发,由于我是第一次接触这个库,所以踩到的坑还是挺多,最坑爹的网上关于这个库的资料实在是太少了,它的文档还是英文文档。所以开发起来还是有点痛苦的。
我们来看下以下部分需求:
这是PM要我做的流程图,这里我会拿部份的功能和大家分享。包括新建图形,删除节点图形,响应右键菜单事件…由于mxgraph的套路是很固定的,只要你GET到这几个部分再结合文档,就基本没有问题了。
一.创建项目
通过vue-cli创建项目,这里就不多说了…,这是我生成的项目目录。我进行了一个项目目录的修改,大家也可以参考一下。
vue.config.js配置
module.exports = {
publicPath: './',
outputDir: 'dist',
lintOnSave: true,
chainWebpack: (config) => {
config.module
.rule('')
.test(/mxClient\.js$/)
.use('exports-loader')
.loader('exports-loader?mxClient,mxToolbar,mxConnectionHandler,mxEllipse,mxConnectionConstraint,mxWindow,' +
'mxObjectCodec,mxGraphModel,mxActor,mxPopupMenu,mxShape,mxEventObject,mxGraph,mxPopupMenuHandler,mxPrintPreview,' +
'mxEventSource,mxRectangle,mxVertexHandler,mxMouseEvent,mxGraphView,mxCodecRegistry,mxImage,mxGeometry,' +
'mxRubberband,mxConstraintHandler,mxKeyHandler,mxDragSource,mxGraphModel,mxEvent,mxUtils,mxEvent,mxCodec,mxCell,' +
'mxConstants,mxPoint,mxGraphHandler,mxCylinder,mxCellRenderer,mxEvent,mxUndoManager')
.end()
}
}
package.json
{
"name": "workinteresting",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-vue": "^2.0.2",
"core-js": "^2.6.5",
"eslint-plugin-flow-vars": "^0.5.0",
"eslint-plugin-html": "^6.0.0",
"node-sass": "^4.12.0",
"popper.js": "^1.16.0",
"sass-loader": "^7.3.1",
"vue": "^2.6.10",
"vue-router": "^3.0.3",
"vuex": "^3.0.1",
"mxgraph": "^3.9.12"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.11.0",
"@vue/cli-plugin-eslint": "^3.11.0",
"@vue/cli-service": "^3.11.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.3",
"babel-preset-env": "^1.7.0",
"babel-preset-stage-0": "^6.24.1",
"eslint": "^5.16.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^3.0.2",
"eslint-plugin-vue": "^5.0.0",
"node-sass": "^4.9.0",
"sass-loader": "^7.1.0",
"vue-template-compiler": "^2.6.10",
"exports-loader": "^0.7.0",
"script-loader": "^0.7.2"
}
}
二.数据驱动生成图形
在项目开发的过程中,我使用了mxGraph踩了很多的坑,其中的一个大坑就是图形回显的问题,一开始我是采用官方推荐的xml形式,大致上就是前台生成一堆的xml,然后后台返回。这里的问题是什么呢?就是后台的小伙伴就会很繁琐,毕竟他们要从一大堆没有规律的xml抽取字段,然后写进数据库。所以,我就把数据格式修改为json格式,我个人认为这是使用mxGraph最为重要的一个东西。
首先我们就先约定好数据格式
graphData: [
{ type: "start", to: [], value: "hello", options: { x: 50, y: 120, width: 120, height: 60, style: "" } },
{ type: "end", to: [], value: "world", options: { x: 350, y: 120, width: 120, height: 60, style: "" } }
]
每一项的to作为一个数组,关联于它下面的一个节点,在Graph中:
createData () {
this.parent = this.graph.getDefaultParent();
this.graph.getModel().beginUpdate();
console.log(this.graphData);
try {
for (let i = 0; i < this.graphData.length; i++) {
let baseOptions = this.graphData[i].options;
let type = this.graphData[i].type || "";
let value = this.graphData[i].value || "";
let id = this.graphData[i].id || null;
let { x, y, width, height, style } = baseOptions;
let verter = this.graph.insertVertex(this.parent, id, value, x, y, width, height, style || "");
verter.type = type || "";
this.graphData[i].id = this.graphData[i].id ? this.graphData[i].id : verter.id;
this.graphData[i].to = this.graphData[i].to.length > 0 ? this.graphData[i].to : [];
}
let isHaveTo = this.graphData.some((v) => v.to.length > 0);
const cells = this.graph.getChildVertices(this.graph.getDefaultParent()); // 所有的图形
if (isHaveTo) {
for (let i = 0; i < this.graphData.length; i++) {
let arr = this.graphData[i].to;
let source = this.findCell(this.graphData[i].id);
if (arr instanceof Array && arr.length > 0) {
for (let i = 0; i < arr.length; i++) {
let target = this.findCell(arr[i]);
if (!source || !target) {
return;
}
this.graph.insertEdge(this.parent, null, "", source, target);
}
}
}
}
// console.log(cells);
this.$emit("initCell", cells);
} finally {
this.graph.getModel().endUpdate();
}
},
那么,如果一切顺利的话,则会出现以下的画面:
这种做法,有些麻烦的是,图形的宽度,大小,位置等的改变都需要实时反馈到graphData中一项,所幸的是在mxgraph这个库中,提供了这些api,下次我则会集中写这些api的功能和作用,包括复制,粘贴,全选,右键等等功能。
三.组件链接
组件的github链接mxGraph组件
这个组件库是我平时工作时候,碰到一些有意思的组件,我都会记录下来,也欢迎各位朋友star。