最近需要开发一款营销流程图项目,需要各种节点流程任务的拖拽跑出数据结果,需要用到节点的增删改查,插销删除流程测试执行各种操作,于是发现了mxgraph这款插件。
mxGraph是一款基于web的绘制流程图的javascript库工具
英文官方网站:http://jgraph.github.io/mxgraph/docs/js-api/files/index-txt.html
gitDemo地址:https://github.com/jgraph/mxgraph2
- npm可以直接安装
npm install mxgraph
- 通过类的方式可以直接引入
方式一:
//生成绘制图区域
graph = new Graph(container);
//生成右上角预览鹰眼图
outline = new mxOutline(graph, this.$refs.graphOutline);
方式二:
this.editor = new mxEditor()
this.graph = this.editor.graph
this.editor.setGraphContainer(this.$refs.graph_container);
但是两种方式有哪些区别呢?
区别就是文章开头提到的那些,mxEditor集成了好些方便的功能。
首先,方式二创建的graph,默认禁用了部分浏览器默认事件,比如鼠标右击弹出框事件;默认添加了鼠标右击拖动事件,按下鼠标右键拖动可以移动graph图层;还有全选等操作,非常方便。
其次,在actions方面,方式二已经预先注册好了大量现成的actions,直接通过action名称调用即可。
// 页面放大
// 方式一: 直接调用原始的页面放大方法
this.graph.zoomIn()
//方式二: 通过事先注册好的行为name调用执行
this。editor.execute('zoomIn')
mxEditor类的源码如下:
function mxEditor(config)
{
this.actions = [];
this.addActions();
...
}
mxEditor的构造函数中有一个actions数组,和addActions方法,即通过addActions方法预先注册好各种行为,最后添加到actions中
mxEditor.prototype.addActions = function ()
{
this.addAction('save', function(editor)
{
editor.save();
});
this.addAction('print', function(editor)
{
var preview = new mxPrintPreview(editor.graph, 1);
preview.open();
});
// 行为过多,省略
...
}
// addAction方法
mxEditor.prototype.addAction = function (actionname, funct)
{
// 将行为和行为的名称添加到数组
this.actions[actionname] = funct;
};
// 预先注册的行为:
[ save、print、show、exportImage、refresh、cut、copy、paste、delete、group、ungroup、
removeFromParent、undo、redo、zoomIn、zoomOut、actualSize、fit、showProperties、
selectAll、selectNone、selectVertices、selectEdges、edit、toBack、toFront、enterGroup、
exitGroup、home、selectPrevious、selectNext、selectParent、selectChild、collapse、
collapseAll、expand、expandAll、bold、italic、underline、alignCellsLeft、
alignCellsCenter、alignCellsRight、alignCellsTop、alignCellsMiddle、alignCellsBottom、
alignFontLeft、alignFontCenter、alignFontRight、alignFontTop、alignFontMiddle、
alignFontBottom、zoom、toggleTasks、toggleHelp、toggleOutline、toggleConsole ]
mxEditor其他的方法,如createLayoutManager、getTitle、showOutline等方法…
- 设置画布的背景图片
const url = 'https://cdn.pixabay.com/photo/2016/02/19/11/25/business.jpg'
const img = new mxImage(url, 400, 400)
graph.setBackgroundImage(img);
- 设置节点的样式
const style = {
[mxConstants.STYLE_SHAPE]: mxConstants.SHAPE_IMAGE,
[mxConstants.STYLE_PERIMETER]: mxPerimeter.RectanglePerimeter,
[mxConstants.STYLE_IMAGE]: "/assets/img/logo.png",
[mxConstants.STYLE_IMAGE_WIDTH]: 45,
[mxConstants.STYLE_IMAGE_HEIGHT]: 45,
[mxConstants.STYLE_SPACING_TOP]: 8,
[mxConstants.STYLE_VERTICAL_ALIGN]: mxConstants.ALIGN_TOP, // 文字垂直对齐
[mxConstants.STYLE_FONTCOLOR]:"red",
[mxConstants.STYLE_VERTICAL_LABEL_POSITION]: mxConstants.ALIGN_BOTTOM,
};
let parent = graph.getDefaultParent();
graph.getModel().beginUpdate();
graph.getStylesheet().putCellStyle('myStyle', style);
- 新建插入节点(insertVertex)
try {
let nodeRootVertex = graph.insertVertex(
parent, //父元素
null,
title, //节点名
resData.x, //x坐标
resData.y, //y坐标
45, //宽
45, //高
myStyle //插入的样式
);
nodeRootVertex.vertex = true;
// 自定义的业务数据放在 data 属性
let data = {
id: resData.id,
element,
};
// nodeRootVertex.data = JSON.stringify(data);
nodeRootVertex.data = new graph.CustomData(data);
this.initNodeData[resData.id] = nodeRootVertex;
return nodeRootVertex;
} finally {
// Updates the display
graph.getModel().endUpdate();
}
- 新建插入线(insertVertex)
// –在调用开始/结束更新中,创建并插入一条新的连线到模型中。
mxGraph.insertEdge(parent, id, value, source, target, style)
- 删除
if (!graph.isSelectionEmpty()) {
if (!_.isEmpty(this.selectVertex)) {
//调用封装的方法
graph.deleteSubtree(this.selectVertex);
} else {
//删除连接线条
graph.removeCells([this.selectEdge]);
}
}
//graph删除的公共方法
deleteSubtree(cell) {
const cells = [];
this.traverse(cell, true, (vertex) => {
cells.push(vertex);
return true;
});
this.removeCells(cells);
}
- 一些限制的方法
graph.setAllowLoops(true);//允许连接的目标和源是同一元素
graph.setMultigraph(false);//重复连接
//禁用浏览器默认的右键菜单栏
mxEvent.disableContextMenu(container)
//自定义设置右键菜单
graph.popupMenuHandler.factoryMethod = (menu, cell, evt) => {
return this.createPopupMenu(menu, cell, evt);
};
createPopupMenu(menu, cell, evt){
...
menu.addItem('复制', '', () => {
this.copy();
});
menu.addSeparator();
...
}
graph.setCellsResizeable(false);//固定节点大小
graph.setHtmlLabels(true);// Label 将显示 Html 格式的 Value
graph.setVertexLabelsMovable(true);// 允许移动 Vertex 的 Label
new mxRubberband(this);//可框选
graph.setCellsResizable(false);// 禁止改变元素大小
graph.setResizeContainer(true);// 容器大小自适应
graph.getView().updateStyle = true;// 动态改变样式
graph.setConnectable(true);// 开启可以拖拽建立关系
graph.orderCells(true);//使线在所有元素的底下
graph.clearSelection();//取消选中的元素
graph.selectEdges();//选中所有的线
graph.setCellsEditable(false);// 开启方块上的文字编辑功能
// 启用对齐线帮助定位
mxGraphHandler.prototype.guidesEnabled = true;
graph.setEnabled(true);// 选择基本元素开启
graph.scrollCellToVisible(cell, true);//显示节点到最中央
graph.setTooltips(true);// 节点悬浮提示信息
// 自定义悬浮提示
// 注:(不自定义getTooltipForCell方法,则tooltip默认为cell的value值)
graph.getTooltipForCell = function (cell) {
if (cell.isVertex()) {
} else {
}
return `${cell.value}`;
};
graph.setCellsMovable(false);//是否可移动
// 禁用移动功能,鼠标指针还是显示移动指标
mxGraphHandler.prototype.setMoveEnabled(false)
graph.setCellsLocked(false)//锁
graph.setEnabled(false)//禁用
graph.setConnectable(false)//Cell 是否可连线
// 是否可以移动连线,重新连接其他cell,主要用来展现中用
graph.setCellsLocked(true);
- 保存xml文件导出
exportFile(isSave) {
if (isSave) {
//保存数据
const model = graph._getExportModel();
console.log(model);
this.$message.success('保存成功!');
} else {
//保存xml格式方便回显
const xml = graph.exportModelXML();
const blob = new Blob([xml], { type: 'text/plain;charset=utf-8' });
FileSaver.saveAs(blob, 'pocket_monster.xml');
}
},
//graph.exportModelXML()方法
exportModelXML() {
const enc = new mxCodec(mxUtils.createXmlDocument());
const node = enc.encode(this._getExportModel());
return mxUtils.getPrettyXml(node);
}
- 接收导入的xml格式的文本回显
importModelXML(xmlTxt) {
this.getModel()
.beginUpdate();
try {
const doc = mxUtils.parseXml(xmlTxt);
const root = doc.documentElement;
const dec = new mxCodec(root.ownerDocument);
dec.decode(root, this.getModel());
} finally {
this.getModel()
.endUpdate();
}
this._restoreModel();
}
//页面回显
let xml = `... `
graph.importModelXML(xml);
- 获取选择的cell节点信息
//获取画布上的所有信息
graph.getDefaultParent();
//始终从选择的mxcells返回数组的第一个数据
graph.getSelectionCell();
//获取所有被选择的元素
graph.getSelectionCells();
//返回所选择所有cells的所有信息
graph.getSelectionModel();
- 监听事件
graph.addMouseListener({
mouseMove: (sender, me) => {
// marker.process(me);
},
mouseDown: () => {},
mouseUp: (sender, me) => {
//鼠标拖动完节点触发的事件,用于校验连线规则
_getEdgeValidationError();
},
});
//连接节点事件
graph.addListener(mxEvent.CELL_CONNECTED,this.eventConnectCellsHandler);
//移动节点事件
graph.addListener(mxEvent.CELLS_MOVED, this.eventMoveCellsHandler);
//删除节点事件
graph.addListener(mxEvent.CELLS_REMOVED, this.eventDeleteCellsHandler);
// 双击事件
graph.addListener(mxEvent.DOUBLE_CLICK, this.eventDoubleClickCellHandler);
//选中节点-线条事件
const mxGraphSelectionModel = graph.getSelectionModel();
mxGraphSelectionModel.addListener(
mxEvent.CHANGE,
this.eventChangeSelectionCellHandler
);
- 软件包类的概述
mxEditor:编辑器包提供实现图编辑器所需的类。 该软件包的主要类
mxGraphView:视图和模型包实现了由mxGraph表示的图形组件。
它引用了一个包含mxCells的mxGraphModel,并在mxGraphView中缓存了单元的状态。
mxCellRenderer:根据mxStyle表中定义的外观,使用mxCellRenderer绘制单元格。
mxUndoManager:撤消历史记录在mxUndoManager中实现。
mxCellOverlay:要在图形上显示图标,可以使用mxCellOverlay;
处理程序(event):布局和形状包分别包含事件侦听器,布局算法和形状。
mxRubber:图形事件侦听器包括用于橡皮筋选择的mxRubber条; mxTooltipHandler:用于工具提示;
mxGraphHandler:用于基本单元格修改; mxCompactTreeLayout:实现树布局算法;
mxShape:形状包装提供各种形状。 它们是mxShape的子类。 mxClipboard:复制和粘贴;
mxConstants:用于拖放;
事件:有三种不同类型的事件,即本机DOM事件,在mxEventSource中触发的mxEvent对象和在mxGraph中触发的mxMouse事件。
mxEvent:提供了一些用于处理本机事件的辅助方法。
它还负责DOM节点和JavaScript事件处理程序之间的解析周期,这可能导致IE6中的内存泄漏。
mxEventSource:mxGraph中的大多数自定义事件都是使用mxEventSource实现的。
它的侦听器是一个获取发送者和mxEventObject的函数。
此外,mxGraph类触发使用鼠标侦听器处理的特殊mxMouse事件,该事件是提供鼠标按下,鼠标移动和鼠标按下方法的对象。使用mxEventSource.fireEvent触发mxEventSource中的事件。
使用mxEventSource.addListener和mxEventSource.removeListener可以添加和删除侦听器。
使用mxGraph.fireMouse事件在mxGraph中触发mxMouse事件。使用mxGraph.addMouseListener和mxGraph.removeMouseListener分别添加和删除侦听器。