欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

再战mxgraph和draw.io:使用经验分享与回顾

最编程 2024-08-07 11:53:18
...

需求

做一个报警系统,需要绘制大量拓扑图,于是研究拓扑图编辑器,因为以前用过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转发一次 或者 编辑器不使用此图形库

推荐阅读