需求
做一个报警系统,需要绘制大量拓扑图,于是研究拓扑图编辑器,因为以前用过mxgraph,但研究的不深入,在探索过程中感谢部分掘友们的帮助回答,这里简单总结一下用到的api
最终确定技术方案,drawio编辑器+mxgraph库
drawio编辑器生成xml文件,但此时的xml文件需要通过解析,mxgraph才能渲染,drawio-tools是一个在线解析的工具,后面通过研究这个工具自己简单封装了一个简单的js,本地解析文件。同时x2js可用来xml和json文件的转换
相关技术栈
- mxgraph jgraph.github.io/mxgraph/ ——
- draw.io www.diagrams.net/
- drawio-tools jgraph.github.io/drawio-tool…
- pakojs
- x2js
引入方式
引入的public静态资源文件夹,考虑到demo中需要用到的 sharpjs,Graph.js 这是mxgraph官方编辑器对特色图形的一些初始化,在使用的时候我渲染也是参考使用的new Graph这个对象
* public\mxgraph
* mxgraph方法都被挂载到window上
mxgraph相关api
初始化mxGraph
var container = document.getElementById('graphContainer')
var graph = new mxGraph(container)
or
var graph = new Graph(container) //这也是我渲染使用的Graph对象,大部分api与mxgraph相同
设置默认themes
// 设置风格样式themes 根据mxgraph官方编辑器(http://jgraph.github.io/mxgraph/javascript/examples/grapheditor/www/index.html)的default.xml文件,以保持风格一致
const themsXml = mxUtils
.load('http://localhost:8080/mxgraph/default.xml')
.getXml()
new mxCodec().decode(themsXml.documentElement, graph.getStylesheet())
设置缩放拖动,放大放小
// 设置一些禁止缩放禁止拖动,放大放小
// 鼠标框选
new mxRubberband(graph);
// 开启可以拖拽建立关系,可以连线
graph.setConnectable(true);
// 开启方块上的文字编辑功能
graph.setCellsEditable(true);
// 启用对齐线帮助定位
mxGraphHandler.prototype.guidesEnabled = true;
// 选择基本元素开启
graph.setEnabled(true);
// 禁用浏览器默认的右键菜单栏
mxEvent.disableContextMenu(container);
// 只可预览不可选中拖动连接
graph.setEnabled(true);
// 禁止改变元素大小
graph.setCellsResizable(false);
// 容器大小自适应
graph.setResizeContainer(false);
// 可否重复连接
graph.setMultigraph(false);
// 放大
graph.zoomIn();
//缩小
graph.zoomOut();
//还原
graph.zoomActual();
//居中缩放
graph.centerZoom = true;
//画布
graph.allowAutoPanning = false
请求
同步
mxUtils.load(url)
异步
mxUtils.get(url)
mxUtils.post(url)
mxUtils.getAll(url)
读取xml,并渲染
// 读取xml,并渲染
var req = mxUtils.load('http://localhost:8080/mxgraph/xml.xml')
var xmlDoc = req.getXml()
var codec = new mxCodec(xmlDoc)
codec.decode(xmlDoc.documentElement, graph.getModel())
查看视图中图形的xml
var encoder = new mxCodec();
var node = encoder.encode(graph.getModel());
console.log(node)
获取每个cell
// 获取每个cell
const allCell = graph.getDefaultParent().children
mxCellTracker
该对象有很多功能,比如cell的高亮,cell的一些事件绑定
//高亮
var highlight = new mxCellTracker(this.graph, "red");
//任务节点的移入移出
var track = new mxCellTracker(this.graph);
track.mouseMove = function(sender, me){
}
整个画布的拖动 useLeftButtonForPanning
在mxgraph渲染中,当画图视图大于容器的时候,无论设置overflow:hidden,auto,即使设置setEnabled,画布拖动,画布显示都有明显的Bug。
同时mxgraph提供了panningHandler.useLeftButtonForPanning Api,该api可以使画布拖动正常。
this.graph.panningHandler.useLeftButtonForPanning = true;
this.graph.panningHandler.ignoreCell = true;
this.graph.container.style.cursor = 'move';
this.graph.setPanning(true);
Graph事件
Graph对象是mxgraph自己的官方编辑器demo中自己封装的对象,在处理事件的时候,本身又进行了封装,大部分与mxgraph相同
// 点击事件
this.graph.click = function(e) {
document.getElementById('graphContainer').oncontextmenu = function(e) {
//取消graphContainer容器默认的浏览器自带右键
return false;
};
if (e.state === undefined) {
return false
}
if (e.evt.button === 0) {
alert('左键点击')
} else {
alert('右键点击')
}
}
mxgraph添加常规事件
mxEvent对象下面下面有很多事件
// 点击事件
graph.addListener(mxEvent.CLICK, function (sender, evt) {
var cell = evt.getProperty('cell')
console.log(cell)
})
打印
mxgraph自带的打印事件,但我在使用中发现我在后期添加的告警图标等,没有被打印,后面自己写了个打印节点的utils
// sc比例
var sc = that.graph.getView().getScale();
// 视图
var preview = new mxPrintPreview(that.graph, sc);
preview.open();
添加图标
基础api
// 设置一个overlay图标
var overlay = new mxCellOverlay(new mxImage('images/add.png', 24, 24), 'Add outgoing');
overlay.cursor = 'hand';
// 添加告警图标 默认是一个warning 的gif,实现的闪烁效果
graph.setCellWarning(cell, 'Tooltip')
// 添加图标到cell上
graph.addCellOverlay(cell,overlay)
// 清楚图标
graph.removeCellOverlays(cell)
简单的封装
// 创建告警信息
createOverlay(image, tooltip) {
var overlay = new mxCellOverlay(image, tooltip);
overlay.addListener(mxEvent.CLICK, function(sender, evt) {
mxUtils.alert(tooltip);
});
return overlay;
},
// 新增告警信息
addOverlay(id, state) {
// 获取ID单元
var cell = this.graph.getModel().getCell(id);
// 修改有报警物体的样式
this.graph.setCellStyles(mxConstants.STYLE_STROKECOLOR, "#FF0000", [cell]);
this.graph.setCellStyles(mxConstants.STYLE_FONTCOLOR, "#FF0000", [cell]);
this.graph.setCellStyles(mxConstants.STYLE_IMAGE_BORDER, '#FF0000', [cell]);
// 添加告警
this.graph.addCellOverlay(cell, this.createOverlay(this.graph.warningImage, '状态: ' + state));
},
// 删除告警信息
delOverlay(id) {
// 获取ID单元
var cell = graph.getModel().getCell(id);
// 修改有报警物体的样式
this.graph.setCellStyles(mxConstants.STYLE_STROKECOLOR, "#CCCCCC", [cell]);
// 移除告警
this.graph.removeCellOverlays(cell);
}
this.addOverlay(cellItem.id, state.state)
节点操作新增删除
//删除节点
graph.removeCells()
//新增节点
graph.addCells()
draw.io编辑器
通过draw.io编辑器生成xml,此时xml需要解码
xml经过转码decode生成mxgraph可解析的文件 在线解码地址https://jgraph.github.io/drawio-tools/tools/convert.html
x2js工具库
可实现xml json的转换
pakojs
draw.io导出的图形库需要pakojs转码成mxgraph识别的xml文件
---drawDecode.js我根据drawio-tools在线地址,pakojs封装的用于本地解码js库
const pako = require('pako');
function decode(data) {
try {
var node = parseXml(data).documentElement;
if (node != null && node.nodeName == 'mxfile') {
var diagrams = node.getElementsByTagName('diagram');
if (diagrams.length > 0) {
data = getTextContent(diagrams[0]);
}
}
} catch (e) {
// ignore
}
try {
data = atob(data);
} catch (e) {
console.log(e);
alert('atob failed: ' + e);
return;
}
try {
data = pako.inflateRaw(Uint8Array.from(data, c => c.charCodeAt(0)), {
to: 'string'
});
} catch (e) {
console.log(e);
alert('inflateRaw failed: ' + e);
return;
}
try {
data = decodeURIComponent(data);
} catch (e) {
console.log(e);
alert('decodeURIComponent failed: ' + e);
return;
}
return data
};
function parseXml(xml) {
if (window.DOMParser) {
var parser = new DOMParser();
return parser.parseFromString(xml, 'text/xml');
} else {
var result = createXmlDocument();
result.async = 'false';
result.loadXML(xml);
return result;
}
};
function createXmlDocument() {
var doc = null;
if (document.implementation && document.implementation.createDocument) {
doc = document.implementation.createDocument('', '', null);
} else if (window.ActiveXObject) {
doc = new ActiveXObject('Microsoft.XMLDOM');
}
return doc;
};
function getTextContent(node) {
return (node != null) ? node[(node.textContent === undefined) ? 'text' : 'textContent'] : '';
};
export default decode
使用也很简单
var drawToMxgraph = drawDecode(mxUtils.load(`${process.env.BASE_URL}/mxgraph/draw.xml`).getText())
相关bug记录
Clipart图形库
draw.io与mxgrap关于Clipart图形库,默认的资源地址不同 导致渲染失败
draw.io: /img/clipart/Gear_128x128.png
mxgrap: /stencils/clipart/Gear_128x128.png
针对 "/img/clipart" nginx转发一次 或者 编辑器不使用此图形库