最近公司让学习了mxgraph,简单总结一下

(1)mxGraph学习路径

  1)API:http://jgraph.github.io/mxgraph/docs/js-api/files/index-txt.html

  2)demo:http://jgraph.github.io/mxgraph/javascript/index.html

(2)最简单的例子(helloword)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
    <style>
    html, body {
        height: 100%;
    }

    #graphContainer {
        position: relative;
        overflow: hidden;
        width: 100%;
        height: 100%;
        background: url('./images/grid.gif');
        cursor: default;
    }
    </style>
</head>

<body onload="main(document.getElementById('graphContainer'))">
<div id="graphContainer"></div>
</body>

<script>
const mxBasePath = '../static/mxgraph';
</script>

<script src="../mxClient.js"></script>
<script>
function main(container) {
  // 禁用鼠标右键
  mxEvent.disableContextMenu(container);
  const graph = new mxGraph(container);
  // 设置这个属性后节点之间才可以连接
  graph.setConnectable(true);
  // 开启区域选择
  new mxRubberband(graph);

  const parent = graph.getDefaultParent();
  graph.getModel().beginUpdate();
  try {
  const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);//创建第一个节点
  const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);//创建第二个节点
  const e1 = graph.insertEdge(parent, null, '30%', v1, v2);//创建连线
  } finally {
      graph.getModel().endUpdate();
  }
}
</script>
</html>

 图:

mxgraph初体验

(3)mxGraph将图转换成xml字符串

var graph = new mxGraph(container);
var xml = mxUtils.getXml(new mxCodec().encode(graph.getModel())) ;
console.log(xml)

如下,左图可得右XML

mxgraph初体验mxgraph初体验

(4)Java后台解析xml

package org.sxdata.jingwei.util.transUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author sonyan
 * @version 2019年8月14日 下午3:09:15
 * @desc
 */
public class DocumentUtil {
    private static String xmlStr = "";
    private static List<Map<String, Object>> nodeMapList = new ArrayList<Map<String, Object>>();

    /**
     * 将指定的document解析成xml字符串
     * @param doc
     * @return
     */
    public static String getXmlStrByDocument(Document doc) {
        xmlStr = "";
        // 根节点名称
        String rootName = doc.getDocumentElement().getTagName();
        // 递归解析Element
        Element element = doc.getDocumentElement();
        return getElementStr(element);
    }
    
    
    /**
     * 将指定的节点解析成xml字符串
     * @param element
     * @return
     */
    public static String getElementStr(Element element) {
        String TagName = element.getTagName();
        boolean flag = true;

        xmlStr = xmlStr + "<" + TagName;
        NamedNodeMap attris = element.getAttributes();
        for (int i = 0; i < attris.getLength(); i++) {
            Attr attr = (Attr) attris.item(i);
            xmlStr = xmlStr + " " + attr.getName() + "=\"" + attr.getValue() + "\"";
        }
        xmlStr = xmlStr + ">" ;

        NodeList nodeList = element.getChildNodes();
        Node childNode;
        for (int temp = 0; temp < nodeList.getLength(); temp++) {
            childNode = nodeList.item(temp);
            // 判断是否属于节点
            if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                // 判断是否还有子节点
                getElementStr((Element) childNode);
                if (childNode.getNodeType() != Node.COMMENT_NODE) {
                    xmlStr = xmlStr + childNode.getTextContent();
                }
            }
        }
        xmlStr = xmlStr + "</" + element.getTagName() + ">";
        return xmlStr;
    }

    /**
     * 解析节点
     * @param element
     * @param graphId 所属图的id
     */
    public static void parseElement(Element element, String graphId) {
        NodeList nodeList = element.getChildNodes();
        Node childNode;
        for (int temp = 0; temp < nodeList.getLength(); temp++) {

            childNode = nodeList.item(temp);
            String id= getUUID32();
            String nodeId = getNodeAttrValue(childNode, "id");
            if (!"0".equals(nodeId) && !"1".equals(nodeId) && "mxCell".equals(childNode.getNodeName())) {
                System.out.println(childNode.getNodeName());
                System.out.println("graphid:" + graphId);
                System.out.println("nodeId:" + getNodeAttrValue(childNode, "id"));
                System.out.println("parent:" + getNodeAttrValue(childNode, "parent"));
                System.out.println("value:" + getNodeAttrValue(childNode, "value"));
                System.out.println("source:" + getNodeAttrValue(childNode, "source"));
                System.out.println("target:" + getNodeAttrValue(childNode, "target"));
                System.out.println("vertex:" + getNodeAttrValue(childNode, "vertex"));
                System.out.println("edge:" + getNodeAttrValue(childNode, "edge"));
                parseElement2((Element) childNode, nodeId,graphId);
                System.out.println("****end*****");
                Map<String, Object> node = new HashMap<String, Object>();
                node.put("id", id);
                node.put("nodeId", nodeId);
                node.put("graphId", graphId);
                node.put("parent", getNodeAttrValue(childNode, "parent"));
                node.put("nodeValue", getNodeAttrValue(childNode, "value"));
                node.put("source", getNodeAttrValue(childNode, "source"));
                node.put("target", getNodeAttrValue(childNode, "target"));
                node.put("edge", getNodeAttrValue(childNode, "edge"));
                node.put("vertex", getNodeAttrValue(childNode, "vertex"));
                node.put("style", getNodeAttrValue(childNode, "style"));
                node.put("ass", getNodeAttrValue(childNode, "as"));
                node.put("nodeName", childNode.getNodeName());
                nodeMapList.add(node);
            }

            // 判断是否属于节点
            if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                // 判断是否还有子节点
                parseElement((Element) childNode, graphId);
            }
        }
    }

    /**
     * 解析mxGeometry节点
     * @param element 
     * @param parentId 
     * @param graphId
     */
    private static void parseElement2(Element element, String parentId, String graphId) {
        NodeList nodeList = element.getChildNodes();
        Node childNode;

        for (int temp = 0; temp < nodeList.getLength(); temp++) {
            childNode = nodeList.item(temp);
            String nodeName = childNode.getNodeName();
            if ("mxGeometry".equals(nodeName)) {

                String nodeId = getNodeAttrValue(childNode, "id");
                String id = getUUID32();

                System.out.println("--name:" + nodeName);
                System.out.println("--height:" + getNodeAttrValue(childNode, "height"));
                System.out.println("--width:" + getNodeAttrValue(childNode, "height"));
                System.out.println("--x:" + getNodeAttrValue(childNode, "x"));
                System.out.println("--y:" + getNodeAttrValue(childNode, "y"));
                System.out.println("--as:" + getNodeAttrValue(childNode, "as"));
                System.out.println("--relative:" + getNodeAttrValue(childNode, "relative"));

                Map<String, Object> node = new HashMap<String, Object>();
                node.put("id", id);
                node.put("nodeId", nodeId);
                node.put("parent", parentId);
                node.put("nodeName", childNode.getNodeName());
                node.put("height", getNodeAttrValue(childNode, "height"));
                node.put("width", getNodeAttrValue(childNode, "width"));
                node.put("x", getNodeAttrValue(childNode, "x"));
                node.put("y", getNodeAttrValue(childNode, "y"));
                node.put("ass", getNodeAttrValue(childNode, "as"));
                node.put("relative", getNodeAttrValue(childNode, "relative"));
                node.put("graphId",graphId);
                node.put("style", getNodeAttrValue(childNode, "style"));
                // node.put("value", getNodeAttrValue(childNode, "value"));
                // node.put("source", getNodeAttrValue(childNode, "source"));
                // node.put("target", getNodeAttrValue(childNode, "target"));
                // node.put("edge", getNodeAttrValue(childNode, "edge"));
                // node.put("vertex", getNodeAttrValue(childNode, "vertex"));
                nodeMapList.add(node);

                // 判断是否属于节点
                if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                    // 判断是否还有子节点
                    parseElement((Element) childNode, "");
                }
            }
        }

    }

    /**
     * 获取指定节点的指定属性的值
     * @param node
     * @param attrName
     * @return
     */
    public static String getNodeAttrValue(Node node, String attrName) {
        NamedNodeMap attr = node.getAttributes();
        if (attr != null) {
            Node attrNode = attr.getNamedItem(attrName);
            if (attrNode != null) {
                return attrNode.getNodeValue();
            }
        }
        return "";

    }

    /**
     * 获取指定的document对象中要保存的节点对象
     * @param doc
     * @return
     */
    public static List<Map<String, Object>> parseDocument(Document doc) {
        String id ="6ed10c4036f245b8bf78e1141d85e23b";// doc.getDocumentElement().getAttribute("id");
        if ("".equals(id)) {
            id = getUUID32();
        }
        // 递归解析Element
        Element element = doc.getDocumentElement();
        nodeMapList.clear();
        parseElement(element, id);
        return nodeMapList;
    }

    /**
     * 根据图的id获取图的xml字符串
     * @param graphId
     * @return
     */
    public static String getXmlByGraphId(String graphId){
        xmlStr = "";
        // 根节点名称
        /*String rootName = doc.getDocumentElement().getTagName();
        // 递归解析Element
        Element element = doc.getDocumentElement();*/
        return getElementStr(null);
        
    }
    
    
    /**
     * 生成32位主键
     * @return
     */
    public static String getUUID32() {
        return UUID.randomUUID().toString().replace("-", "").toLowerCase();
    }
    
    
    public static Document createDocument() {
        // 初始化xml解析工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        // 创建DocumentBuilder
        DocumentBuilder builder = null;
        try {
            builder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }

        // 创建Document
        Document doc = builder.newDocument();

        // standalone用来表示该文件是否呼叫其它外部的文件。若值是 ”yes” 表示没有呼叫外部文件
        doc.setXmlStandalone(true);

        // 创建一个根节点
        // 说明:
        // doc.createElement("元素名")、element.setAttribute("属性名","属性值")、element.setTextContent("标签间内容")
        Element diagram = doc.createElement("diagram");
        diagram.setAttribute("id", "");
        diagram.setAttribute("tcn", "");

        // 创建根节点第一个子节点
        Element mxGraphModel = doc.createElement("mxGraphModel");
        diagram.appendChild(mxGraphModel);

        Element root = doc.createElement("root");
        mxGraphModel.appendChild(root);

        Element mxCell1 = doc.createElement("mxCell");
        mxCell1.setAttribute("id", "0");
        root.appendChild(mxCell1);

        Element mxCell2 = doc.createElement("mxCell");
        mxCell2.setAttribute("id", "1");
        mxCell2.setAttribute("parent", "0");
        root.appendChild(mxCell2);
        
        
        //根据图的id获取图中节点
        
        /*Element mxCell3 = doc.createElement("mxCell");
        mxCell3.setAttribute("id", "2");
        mxCell3.setAttribute("parent", "1");
        mxCell3.setAttribute("vertex", "1");
        mxCell3.setAttribute("value", "songyan");
        root.appendChild(mxCell3);

        Element mxGeometry = doc.createElement("mxGeometry");
        mxGeometry.setAttribute("x", "20");
        mxGeometry.setAttribute("y", "20");
        mxGeometry.setAttribute("width", "80");
        mxGeometry.setAttribute("height", "30");
        mxGeometry.setAttribute("as", "geometry");
        mxCell3.appendChild(mxGeometry);*/
        
        // 添加根节点
        doc.appendChild(diagram);

        return doc;
    }
    
    /**
     * 根据图的id获取document对象
     * @param graphId 图的id
     * @return
     */
    public static Document getDocumentByGraphId(String graphId) {
        // 初始化xml解析工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        // 创建DocumentBuilder
        DocumentBuilder builder = null;
        try {
            builder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }

        // 创建Document
        Document doc = builder.newDocument();

        // standalone用来表示该文件是否呼叫其它外部的文件。若值是 ”yes” 表示没有呼叫外部文件
        doc.setXmlStandalone(true);

        // 创建一个根节点
        // 说明:
        // doc.createElement("元素名")、element.setAttribute("属性名","属性值")、element.setTextContent("标签间内容")
        Element diagram = doc.createElement("diagram");
        diagram.setAttribute("id", "");
        diagram.setAttribute("tcn", "");

        // 创建根节点第一个子节点
        Element mxGraphModel = doc.createElement("mxGraphModel");
        diagram.appendChild(mxGraphModel);

        Element root = doc.createElement("root");
        mxGraphModel.appendChild(root);

        Element mxCell1 = doc.createElement("mxCell");
        mxCell1.setAttribute("id", "0");
        root.appendChild(mxCell1);

        Element mxCell2 = doc.createElement("mxCell");
        mxCell2.setAttribute("id", "1");
        mxCell2.setAttribute("parent", "0");
        root.appendChild(mxCell2);
        
        
        //根据图的id获取图中节点
        //List<Map<String,Object>> transList = trans
        
        
        // 添加根节点
        doc.appendChild(diagram);

        return doc;
    }


    
    
    public static void main(String[] args) {
        Document document= createDocument();
        System.out.println(getXmlStrByDocument(document));
    }


    public static Document getDocument(List<Map<String, Object>> newNodeList,String graphId) {
        // 初始化xml解析工厂
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

                // 创建DocumentBuilder
                DocumentBuilder builder = null;
                try {
                    builder = factory.newDocumentBuilder();
                } catch (ParserConfigurationException e) {
                    e.printStackTrace();
                }

                // 创建Document
                Document doc = builder.newDocument();

                // standalone用来表示该文件是否呼叫其它外部的文件。若值是 ”yes” 表示没有呼叫外部文件
                doc.setXmlStandalone(true);

                // 创建一个根节点
                // 说明:
                // doc.createElement("元素名")、element.setAttribute("属性名","属性值")、element.setTextContent("标签间内容")
                Element diagram = doc.createElement("diagram");
                diagram.setAttribute("id", graphId);
                diagram.setAttribute("tcn", "");

                // 创建根节点第一个子节点
                Element mxGraphModel = doc.createElement("mxGraphModel");
                diagram.appendChild(mxGraphModel);

                Element root = doc.createElement("root");
                mxGraphModel.appendChild(root);

                Element mxCell1 = doc.createElement("mxCell");
                mxCell1.setAttribute("id", "0");
                root.appendChild(mxCell1);

                Element mxCell2 = doc.createElement("mxCell");
                mxCell2.setAttribute("id", "1");
                mxCell2.setAttribute("parent", "0");
                root.appendChild(mxCell2);
                
                for (Map<String, Object> node : newNodeList) {
                    handleNode(root,doc,node);
                }
                
                // 添加根节点
                doc.appendChild(diagram);

                return doc;
    }


    private static void handleNode(Element root, Document doc, Map<String, Object> node) {
        Element mxCell = doc.createElement((String) node.get("nodeName"));
        Object as = node.get("as");
        Object width = node.get("width");
        Object x = node.get("x");
        Object y = node.get("y");
        Object style = node.get("style");
        Object nodeId = node.get("nodeId");
        Object height = node.get("height");
        Object parent = node.get("parent");
        Object relative = node.get("relative");
        Object vertex = node.get("vertex");

        Object value = node.get("value");
        Object edge = node.get("edge");
        Object source = node.get("source");
        Object target = node.get("target");
            
        if(value!=null && !"".equals(value)){
            mxCell.setAttribute("value", (String) value);
        }
        if(edge!=null && !"".equals(edge)){
            mxCell.setAttribute("edge", (String) edge);
        }
        if(source!=null && !"".equals(source)){
            mxCell.setAttribute("source", (String) source);
        }
        if(target!=null && !"".equals(target)){
            mxCell.setAttribute("target", (String) target);
        }
        if(as!=null && !"".equals(as)){
            mxCell.setAttribute("as", (String) as);
        }
        if(width!=null && !"".equals(width)){
            mxCell.setAttribute("width", (String) width);
        }
        if(x!=null && !"".equals(x)){
            mxCell.setAttribute("x", (String) x);
        }
        
        if(y!=null && !"".equals(y)){
            mxCell.setAttribute("y", (String) y);
        }
        if(style!=null && !"".equals(style)){
            mxCell.setAttribute("style", (String) style);
        }
        if(nodeId!=null && !"".equals(nodeId)){
            mxCell.setAttribute("id", (String) nodeId);
        }
        if(parent!=null && !"".equals(parent)){
            mxCell.setAttribute("parent", (String) parent);
        }
        if(height!=null && !"".equals(height)){
            mxCell.setAttribute("height", (String) height);
        }
        if(relative!=null && !"".equals(relative)){
            mxCell.setAttribute("relative", (String) relative);
        }
        if(vertex!=null && !"".equals(vertex)){
            mxCell.setAttribute("vertex", (String) vertex);
        }
        root.appendChild(mxCell);
        
        Object child =  node.get("child");
        if(child!=null){
            List<Map<String, Object>> childNodeList = (List<Map<String, Object>>) child;
            for (Map<String, Object> map : childNodeList) {
                handleNode(mxCell, doc, map); 
            }
        }
        
    }

}

 这个是我写的一个工具类,包括解析xml的方法,也有些封装成xml的方法。

下面是解析xml并将其保存到数据库的方法

 @RequestMapping(value="/save2")
    @ResponseBody
    protected void save2(HttpServletResponse response,HttpServletRequest request,@RequestParam String graphXml) throws Exception{
        String xml = StringEscapeHelper.decode(graphXml);
        System.out.println(xml);
        
        Document current = mxXmlUtils.parseXml(xml);
        String graphId = "6ed10c4036f245b8bf78e1141d85e23b";//current.getDocumentElement().getAttribute("id");
        System.out.println("graphId:"+graphId);
        transService.deleteGraphById(graphId);
        List<Map<String, Object>> nodeMapList = DocumentUtil.parseDocument(current);
        for (Map<String, Object> trans : nodeMapList) {
            System.out.println(trans);
            transService.insert(trans);
        }
        try{
            PrintWriter out=response.getWriter();
            String result="songyan";
            out.write(result);
            out.flush();
            out.close();
        }catch (Exception e){
            e.printStackTrace();
            throw new Exception(e.getMessage());
        }
    }

 

 这里我是给每个图一个唯一的id,每次保存的时候都把之前的节点信息删除掉,再根据解析出来的节点信息,保存节点。

(5)节点信息封装成mxgraph可以解析的xml

下面是从数据库读取节点信息,并将其转换成xml的方法:

@ResponseBody
    @RequestMapping(method = RequestMethod.POST, value = "/open")
    protected void open(HttpServletRequest request) throws Exception {
        //获取图的id
        String graphId = request.getParameter("graphId");
        System.out.println("graphId::"+graphId);
        //获取节点对象
        List<Map<String,Object>> nodeList = transService.getTransListByGraphId(graphId);
        List<Map<String,Object>> newNodeList = new ArrayList<Map<String,Object>>();
        for (Map<String, Object> node : nodeList) {
            Map nodeMap = node;
            String nodeId = (String) node.get("nodeId");
            //查询子节点
            List<Map<String,Object>> childNodeList = getChildNodes(graphId,nodeId);
            if(childNodeList!=null && childNodeList.size()!=0){
                nodeMap.put("child", childNodeList);
                newNodeList.add(nodeMap);
            }
            
        }
        
        System.out.println(newNodeList);
        //获取图的document对象
        Document document = DocumentUtil.getDocument(newNodeList,graphId);
        
        //获取xml
        String graphXml = DocumentUtil.getXmlStrByDocument(document);
        System.out.println(graphXml);
        JsonUtils.responseXml(StringEscapeHelper.encode(graphXml));
    }

 

(6)页面渲染xml,回显成图(普通的html,js中显示正常,集成到VUE里面之后发现不报错,也不显示,针对VUE的处理会在下面说明)

var xml = '<diagram >;
var doc = mxUtils.parseXml(xml);
var codec = new mxCodec(doc);
codec.decode(doc.documentElement.firstChild, graph.getModel());

mxgraph初体验

(7)Vue引入mxGraph(引入的方法很重要)

  1)在项目的src目录下创建文件夹magraph,在mxgraph文件夹创建index.js,Graph.js两个文件

  mxgraph初体验

  index.js内容:

import mx from 'mxgraph'
const mxgraph = mx({
  mxBasePath: '/static/mxgraph'
})
// decode bug https://github.com/jgraph/mxgraph/issues/49
window.mxGraph = mxgraph.mxGraph
window.mxGraphModel = mxgraph.mxGraphModel
window.mxEditor = mxgraph.mxEditor
window.mxGeometry = mxgraph.mxGeometry
window.mxDefaultKeyHandler = mxgraph.mxDefaultKeyHandler
window.mxDefaultPopupMenu = mxgraph.mxDefaultPopupMenu
window.mxStylesheet = mxgraph.mxStylesheet
window.mxDefaultToolbar = mxgraph.mxDefaultToolbar
export default mxgraph

 

  Graph.js内容:

import mxgraph from './index';
import _ from 'lodash';

const {
  mxGraph,
  mxVertexHandler,
  mxConstants,
  mxCellState,
  mxPerimeter,
  mxCellEditor,
  mxGraphHandler,
  mxEvent,
  mxEdgeHandler,
  mxShape,
  mxConnectionConstraint,
  mxPoint,
  mxEventObject,
  mxCodec,
  mxObjectCodec,
  mxUtils,
  mxImageExport,
  mxXmlCanvas2D,
  mxCodecRegistry,
} = mxgraph;

Object.assign(mxEvent, {
  EDGE_START_MOVE: 'edgeStartMove',
  VERTEX_START_MOVE: 'vertexStartMove',
});

let pokeElementIdSeed = 0;

// export class PokeElement {
//   constructor(element) {
//     this.id = pokeElementIdSeed;
//     pokeElementIdSeed++;
//     this.element = element;
//     this.normalType = '';
//   }
// }

export class Graph extends mxGraph {
  static getStyleDict(cell) {
    return _.compact(cell.getStyle().split(';'))
      .reduce((acc, item) => {
        const [key, value] = item.split('=');
        acc[key] = value;
        return acc;
      }, {});
  }

  static convertStyleToString(styleDict) {
    const style = Object.entries(styleDict)
      .map(([key, value]) => `${key}=${value}`)
      .join(';')
      .replace(/=undefined/g, '');
    return `${style};`;
  }

  static getCellPosition(cell) {
    return _.pick(cell.getGeometry(), ['x', 'y']);
  }

  constructor(container) {
    super(container);
    this._init();
  }

  _init() {
    this._setDefaultConfig();
    this._configConstituent();
    this._putVertexStyle();
    this._setDefaultEdgeStyle();
    this._setAnchors();
    this._configCustomEvent();
    // this._configCoder();
  }

  _configConstituent() {
    // Redirects selection to parent
    this.selectCellForEvent = (...args) => {
      const [cell] = args;
      if (this.isPart(cell)) {
        args[0] = this.model.getParent(cell);
        mxGraph.prototype.selectCellForEvent.call(this, args);
        return;
      }

      mxGraph.prototype.selectCellForEvent.apply(this, args);
    };

    /**
     * Redirects start drag to parent.
     */
    const graphHandlerGetInitialCellForEvent = mxGraphHandler.prototype.getInitialCellForEvent;
    mxGraphHandler.prototype.getInitialCellForEvent = function getInitialCellForEvent(...args) {
      // this 是 mxGraphHandler
      let cell = graphHandlerGetInitialCellForEvent.apply(this, args);
      if (this.graph.isPart(cell)) {
        cell = this.graph.getModel().getParent(cell);
      }

      return cell;
    };
  }

  _setDefaultConfig() {
    this.setConnectable(true);
    mxEvent.disableContextMenu(this.container);

    // 固定节点大小
    this.setCellsResizable(false);

    // 编辑时按回车键不换行,而是完成输入
    this.setEnterStopsCellEditing(true);
    // 编辑时按 escape 后完成输入
    mxCellEditor.prototype.escapeCancelsEditing = false;
    // 失焦时完成输入
    mxCellEditor.prototype.blurEnabled = true;

    // 禁止节点折叠
    this.foldingEnabled = false;
    // 文本包裹效果必须开启此配置
    this.setHtmlLabels(true);

    // 拖拽过程对齐线
    mxGraphHandler.prototype.guidesEnabled = true;

    // 禁止游离线条
    this.setDisconnectOnMove(false);
    this.setAllowDanglingEdges(false);
    mxGraph.prototype.isCellMovable = cell => !cell.edge;

    // 禁止调整线条弯曲度
    this.setCellsBendable(false);

    // 禁止从将label从线条上拖离
    mxGraph.prototype.edgeLabelsMovable = false;
  }

  _putVertexStyle() {
    const normalTypeStyle = {
      [mxConstants.STYLE_SHAPE]: mxConstants.SHAPE_IMAGE,
      [mxConstants.STYLE_PERIMETER]: mxPerimeter.RectanglePerimeter,
    };
    this.getStylesheet().putCellStyle('normalType', normalTypeStyle);

    const nodeStyle = {
      // 图片样式参考这个例子
      // https://github.com/jinzhanye/mxgraph-demos/blob/master/src/06.image.html
      [mxConstants.STYLE_SHAPE]: mxConstants.SHAPE_LABEL,
      [mxConstants.STYLE_PERIMETER]: mxPerimeter.RectanglePerimeter,
      [mxConstants.STYLE_ROUNDED]: true,
      [mxConstants.STYLE_ARCSIZE]: 6, // 设置圆角程度

      [mxConstants.STYLE_STROKECOLOR]: '#333333',
      [mxConstants.STYLE_FONTCOLOR]: '#333333',
      [mxConstants.STYLE_FILLCOLOR]: '#ffffff',
      //
      [mxConstants.STYLE_LABEL_BACKGROUNDCOLOR]: 'none',

      [mxConstants.STYLE_ALIGN]: mxConstants.ALIGN_CENTER,
      [mxConstants.STYLE_VERTICAL_ALIGN]: mxConstants.ALIGN_TOP,
      [mxConstants.STYLE_IMAGE_ALIGN]: mxConstants.ALIGN_CENTER,
      [mxConstants.STYLE_IMAGE_VERTICAL_ALIGN]: mxConstants.ALIGN_TOP,

      [mxConstants.STYLE_IMAGE_WIDTH]: '72',
      [mxConstants.STYLE_IMAGE_HEIGHT]: '72',
      [mxConstants.STYLE_SPACING_TOP]: '100',
      [mxConstants.STYLE_SPACING]: '8',
    };
    this.getStylesheet().putCellStyle('node', nodeStyle);

    // 设置选中状态节点的边角为圆角,默认是直角
    const oldCreateSelectionShape = mxVertexHandler.prototype.createSelectionShape;
    mxVertexHandler.prototype.createSelectionShape = function createSelectionShape(...args) {
      const res = oldCreateSelectionShape.apply(this, args);
      res.isRounded = true;
      // style 属性来自 mxShape , mxRectangle 继承自 mxShape
      res.style = {
        arcSize: 6,
      };
      return res;
    };
  }

  _setDefaultEdgeStyle() {
    const style = this.getStylesheet().getDefaultEdgeStyle();
    Object.assign(style, {
      [mxConstants.STYLE_ROUNDED]: true, // 设置线条拐弯处为圆角
      [mxConstants.STYLE_STROKEWIDTH]: '2',
      [mxConstants.STYLE_STROKECOLOR]: '#333333',
      [mxConstants.STYLE_EDGE]: mxConstants.EDGESTYLE_ORTHOGONAL,
      [mxConstants.STYLE_FONTCOLOR]: '#33333',
      [mxConstants.STYLE_LABEL_BACKGROUNDCOLOR]: '#ffa94d',
    });
    // 设置拖拽线的过程出现折线,默认为直线
    this.connectionHandler.createEdgeState = () => {
      const edge = this.createEdge();
      return new mxCellState(this.view, edge, this.getCellStyle(edge));
    };
  }

  _setAnchors() {
    // 禁止从节点中心拖拽出线条
    this.connectionHandler.isConnectableCell = () => false;
    mxEdgeHandler.prototype.isConnectableCell = () => false;

    // Overridden to define per-shape connection points
    mxGraph.prototype.getAllConnectionConstraints = (terminal) => {
      if (terminal != null && terminal.shape != null) {
        if (terminal.shape.stencil != null) {
          if (terminal.shape.stencil != null) {
            return terminal.shape.stencil.constraints;
          }
        } else if (terminal.shape.constraints != null) {
          return terminal.shape.constraints;
        }
      }

      return null;
    };

    // Defines the default constraints for all shapes
    mxShape.prototype.constraints = [
      new mxConnectionConstraint(new mxPoint(0, 0), true),
      new mxConnectionConstraint(new mxPoint(0, 1), true),
      new mxConnectionConstraint(new mxPoint(1, 0), true),
      new mxConnectionConstraint(new mxPoint(1, 1), true),
      new mxConnectionConstraint(new mxPoint(0.25, 0), true),
      new mxConnectionConstraint(new mxPoint(0.5, 0), true),
      new mxConnectionConstraint(new mxPoint(0.75, 0), true),
      new mxConnectionConstraint(new mxPoint(0, 0.25), true),
      new mxConnectionConstraint(new mxPoint(0, 0.5), true),
      new mxConnectionConstraint(new mxPoint(0, 0.75), true),
      new mxConnectionConstraint(new mxPoint(1, 0.25), true),
      new mxConnectionConstraint(new mxPoint(1, 0.5), true),
      new mxConnectionConstraint(new mxPoint(1, 0.75), true),
      new mxConnectionConstraint(new mxPoint(0.25, 1), true),
      new mxConnectionConstraint(new mxPoint(0.5, 1), true),
      new mxConnectionConstraint(new mxPoint(0.75, 1), true)];
  }

  _configCustomEvent() {
    const graph = this;
    const oldStart = mxEdgeHandler.prototype.start;
    mxEdgeHandler.prototype.start = function start(...args) {
      oldStart.apply(this, args);
      graph.fireEvent(new mxEventObject(mxEvent.EDGE_START_MOVE,
        'edge', this.state.cell,
        'source', this.isSource,
      ));
    };


    const oldCreatePreviewShape = mxGraphHandler.prototype.createPreviewShape;
    mxGraphHandler.prototype.createPreviewShape = function createPreviewShape(...args) {
      graph.fireEvent(new mxEventObject(mxEvent.VERTEX_START_MOVE));
      return oldCreatePreviewShape.apply(this, args);
    };
  }


  _configCoder() {
    const codec = new mxObjectCodec(new PokeElement());

    codec.encode = function (enc, obj) {
      const node = enc.document.createElement('PokeElement');
      mxUtils.setTextContent(node, JSON.stringify(obj));

      return node;
    };

    codec.decode = function (dec, node, into) {
      const obj = JSON.parse(mxUtils.getTextContent(node));
      obj.constructor = PokeElement;

      return obj;
    };

    mxCodecRegistry.register(codec);
  }

  getDom(cell) {
    const state = this.view.getState(cell);
    return state.shape.node;
  }

  setStyle(cell, key, value) {
    const styleDict = Graph.getStyleDict(cell);
    styleDict[key] = value;
    const style = Graph.convertStyleToString(styleDict);
    this.getModel().setStyle(cell, style);
  }

  isPart(cell) {
    const state = this.view.getState(cell);
    const style = (state != null) ? state.style : this.getCellStyle(cell);
    return style.constituent === 1;
  }

  deleteSubtree(cell) {
    const cells = [];
    this.traverse(cell, true, (vertex) => {
      cells.push(vertex);
      return true;
    });
    this.removeCells(cells);
  }


  _restoreModel() {
    Object.values(this.getModel().cells)
      .forEach(cell => {
        if (cell.vertex && cell.data) {
          cell.data = JSON.parse(cell.data);
        }
      });
  }

  // 将 data 变为字符串,否则还原时会报错
  _getExportModel() {
    const model = _.cloneDeep(this.getModel());
    Object.values(model.cells)
      .forEach(cell => {
        if (cell.vertex && cell.data) {
          cell.data = JSON.stringify(cell.data);
        }
      });
    return model;
  }

  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();
  }

  exportModelXML() {
    const enc = new mxCodec(mxUtils.createXmlDocument());
    const node = enc.encode(this._getExportModel());
    return mxUtils.getPrettyXml(node);
  }

  exportPicXML() {
    const xmlDoc = mxUtils.createXmlDocument();
    const root = xmlDoc.createElement('output');
    xmlDoc.appendChild(root);

    const { scale } = this.view;
    // 这个项目画布边宽为0,可以自行进行调整
    const border = 0;

    const bounds = this.getGraphBounds();
    const xmlCanvas = new mxXmlCanvas2D(root);
    xmlCanvas.translate(
      Math.floor((border / scale - bounds.x) / scale),
      Math.floor((border / scale - bounds.y) / scale),
    );
    xmlCanvas.scale(1);

    const imgExport = new mxImageExport();
    imgExport.drawState(this.getView().getState(this.model.root), xmlCanvas);

    const w = Math.ceil(bounds.width * scale / scale + 2 * border);
    const h = Math.ceil(bounds.height * scale / scale + 2 * border);

    const xml = mxUtils.getPrettyXml(root);

    return {
      xml,
      w,
      h,
    };
  }
}

let graph = {};

export const destroyGraph = () => {
  graph.destroy();
  graph = {};
};

export const genGraph = (container) => {
  graph = new Graph(container);
  return graph;
};

export const getGraph = () => graph;
View Code

相关文章:

  • 2021-10-18
  • 2021-07-03
  • 2021-05-07
  • 2022-01-10
  • 2021-04-27
  • 2021-06-27
猜你喜欢
  • 2021-08-16
  • 2021-11-30
  • 2021-11-30
  • 2021-11-30
  • 2021-12-05
  • 2021-11-23
  • 2021-10-11
相关资源
相似解决方案