最近公司让学习了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>

图:

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

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

如下,左图可得右XML

(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();// 递归解析ElementElement 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();}// 递归解析ElementElement 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();// 递归解析ElementElement 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();// 创建DocumentBuilderDocumentBuilder builder = null;try {builder = factory.newDocumentBuilder();} catch (ParserConfigurationException e) {e.printStackTrace();}// 创建DocumentDocument 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();// 创建DocumentBuilderDocumentBuilder builder = null;try {builder = factory.newDocumentBuilder();} catch (ParserConfigurationException e) {e.printStackTrace();}// 创建DocumentDocument 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();// 创建DocumentBuilderDocumentBuilder builder = null;try {builder = factory.newDocumentBuilder();} catch (ParserConfigurationException e) {e.printStackTrace();}// 创建DocumentDocument 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")@ResponseBodyprotected 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 {//获取图的idString 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);//获取xmlString graphXml = DocumentUtil.getXmlStrByDocument(document);System.out.println(graphXml);JsonUtils.responseXml(StringEscapeHelper.encode(graphXml));}

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

var xml = '<diagram id="" tcn=""><mxGraphModel><root><Workflow value="Diagram" id="0"><mxCell/></Workflow><Layer value="Default Layer" id="1"><mxCell parent="0"/></Layer><mxCell id="2" value="Hello, World!" parent="1" vertex="1"><mxGeometry x="120" y="90" width="80" height="40" as="geometry"/></mxCell></root></mxGraphModel></diagram>';
var doc = mxUtils.parseXml(xml);
var codec = new mxCodec(doc);
codec.decode(doc.documentElement.firstChild, graph.getModel());

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

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

  

  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 parentthis.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 是 mxGraphHandlerlet 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 继承自 mxShaperes.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 pointsmxGraph.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 shapesmxShape.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

  2)在使用Vue的页面引入

import mxgraph from "../../graph/index";const {mxGraph,mxClient,mxDragSource,mxCell,mxRubberband,mxVertexHandler,mxConstants,mxCellState,mxPerimeter,mxCellEditor,mxGraphHandler,mxEvent,mxEdgeHandler,mxShape,mxConnectionConstraint,mxPoint,mxEventObject,mxCodec,mxObjectCodec,mxUtils,mxImageExport,mxXmlCanvas2D,mxClipboard,mxCodecRegistry
} = mxgraph;

  3)cnpm安装

    xnpm install mxgraph

注:其他的方式可能也能引入但是有些功能可能不能用,比如xml渲染的时候不出错但是也不显示

  4)关于节点样式的处理,拖拽生成图的处理,右键生成菜单,右键删除节点的功能如下

<template><el-container style="height: 500px; border: 1px solid #eee"><el-aside width="200px" style="background-color: rgb(238, 241, 246)"><el-header style="text-align: center; font-size: 16px;" class="left_header"><b>转换管理</b></el-header><el-menu :default-openeds="['1']"><el-submenu index="1"><template slot="title"><i class="el-icon-menu"></i>输入</template><el-menu-item-group><el-menu-item><span id="in1" class="itemstyle"></span><spanunselectable="on"qtip="从一个微软的Excel文件里读取数据. 兼容Excel 95, 97 and 2000."id="extdd-81">Excel输入</span></el-menu-item><el-menu-item><span id="in2" class="itemstyle"></span><spanunselectable="on"qtip="从一个文本文件(几种格式)里读取数据{0}这些数据可以被传递到下一个步骤里..."id="extdd-84">文本文件输入</span></el-menu-item><el-menu-item><span id="in3" class="itemstyle"></span><span unselectable="on" qtip="产生一些空记录或相等的行." id="extdd-87">生成记录</span></el-menu-item><el-menu-item><span id="in4" class="itemstyle"></span><span unselectable="on" qtip="Generate random value" id="extdd-90">生成随机数</span></el-menu-item><el-menu-item><span id="in5" class="itemstyle"></span><spanunselectable="on"qtip="Enter rows of static data in a grid, usually for testing, reference or demo purpose"id="extdd-93">自定义常量数据</span></el-menu-item><el-menu-item><span id="in6" class="itemstyle"></span><span unselectable="on" qtip="获取系统信息,例如时间、日期." id="extdd-96">获取系统信息</span></el-menu-item><el-menu-item><span id="in7" class="itemstyle"></span><span unselectable="on" qtip="从数据库表里读取信息." id="extdd-99">表输入</span></el-menu-item></el-menu-item-group></el-submenu><el-submenu index="2"><template slot="title"><i class="el-icon-menu"></i>输出</template><el-menu-item-group><el-menu-item><span id="out1"></span><spanunselectable="on"qtip="Stores records into an Excel (XLS) document with formatting information."id="extdd-102">Excel输出</span></el-menu-item><el-menu-item><span id="out2"></span><spanunselectable="on"qtip="Output SQL INSERT statements to file"id="extdd-105">SQL 文件输出</span></el-menu-item><el-menu-item><span id="out3"></span><span unselectable="on" qtip="基于关键字删除记录" id="extdd-108">删除</span></el-menu-item><el-menu-item><span id="out4"></span><span unselectable="on" qtip="基于关键字更新或插入记录到数据库." id="extdd-90">插入 / 更新</span></el-menu-item><el-menu-item><span id="out5"></span><spanunselectable="on"qtip="This step perform insert/update/delete in one go based on the value of a field. "id="extdd-93">数据同步</span></el-menu-item><el-menu-item><span id="out6"></span><span unselectable="on" qtip="写记录到一个文本文件." id="extdd-96">文本文件输出</span></el-menu-item><el-menu-item><span id="out7"></span><span unselectable="on" qtip="基于关键字更新记录到数据库" id="extdd-99">更新</span></el-menu-item><el-menu-item><span id="out8"></span><span unselectable="on" qtip="写信息到一个数据库表" id="extdd-102">表输出</span></el-menu-item></el-menu-item-group></el-submenu><el-submenu index="3"><template slot="title"><i class="el-icon-menu"></i>转换</template><el-menu-item-group><el-menu-item><span id="trans1"></span><spanunselectable="on"qtip="Maps values of a certain field from one value to another"id="extdd-105">值映射</span></el-menu-item><el-menu-item><span id="trans2"></span><spanunselectable="on"qtip="Denormalises rows by looking up key-value pairs and by assigning them to new fields in the输出 rows.{0}This method aggregates and needs the输入 rows to be sorted on the grouping fields"id="extdd-108">列转行</span></el-menu-item><el-menu-item><span id="trans3"></span><span unselectable="on" qtip="Strings cut (substring)." id="extdd-111">剪切字符串</span></el-menu-item><el-menu-item><span id="trans4"></span><spanunselectable="on"qtip="去除重复的记录行,保持记录唯一{0}这个仅仅基于一个已经排好序的输入.{1}如果输入没有排序, 仅仅两个连续的记录行被正确处理."id="extdd-114">去除重复记录</span></el-menu-item><el-menu-item><span id="trans5"></span><span unselectable="on" qtip="给记录增加一到多个常量" id="extdd-117">增加常量</span></el-menu-item><el-menu-item><span id="trans6"></span><span unselectable="on" qtip="从序列获取下一个值" id="extdd-120">增加序列</span></el-menu-item><el-menu-item><span id="trans7"></span><spanunselectable="on"qtip="Add a checksum column for each input row"id="extdd-123">增加校验列</span></el-menu-item><el-menu-item><span id="trans8"></span><spanunselectable="on"qtip="选择或移除记录里的字。{0}此外,可以设置字段的元数据: 类型, 长度和精度."id="extdd-126">字段选择</span></el-menu-item><el-menu-item><span id="trans9"></span><spanunselectable="on"qtip="Replace all occurences a word in a string with another word."id="extdd-129">字符串替换</span></el-menu-item><el-menu-item><span id="trans10"></span><span unselectable="on" qtip="基于字段值把记录排序(升序或降序)" id="extdd-132">排序记录</span></el-menu-item><el-menu-item><span id="trans11"></span><spanunselectable="on"qtip="Flattens consequetive rows based on the order in which they appear in the输入 stream"id="extdd-135">行扁平化</span></el-menu-item><el-menu-item><span id="trans12"></span><spanunselectable="on"qtip="De-normalised information can be normalised using this step type."id="extdd-138">行转列</span></el-menu-item></el-menu-item-group></el-submenu><el-submenu index="4"><template slot="title"><i class="el-icon-menu"></i>脚本</template><el-menu-item-group><el-menu-item><span id="scp1"></span><spanunselectable="on"qtip="This is a modified plugin for the Scripting Values with improved interface and performance.
Written &amp; donated to open source by Martin Lange, Proconis : http://www.proconis.de"id="extdd-81">JavaScript代码</span></el-menu-item><el-menu-item><span id="scp2"></span><span unselectable="on" qtip="执行一个SQL脚本, 另外,可以使用输入的记录作为参数" id="extdd-84">执行SQL脚本</span></el-menu-item></el-menu-item-group></el-submenu></el-menu></el-aside><el-container><el-header style="text-align: left; font-size: 12px" class="right_header"><el-button type="primary" @click="clearGraph">清空</el-button><el-button type="primary" @click="lookXML">查看xml</el-button><el-button type="primary" @click="save">保存</el-button></el-header><el-main><div ref="graph_container" id="right"></div></el-main></el-container></el-container><!-- <div ref="graph_container"></div> -->
</template><script>
import mxgraph from "../../graph/index";const {mxGraph,mxClient,mxDragSource,mxCell,mxRubberband,mxVertexHandler,mxConstants,mxCellState,mxPerimeter,mxCellEditor,mxGraphHandler,mxEvent,mxEdgeHandler,mxShape,mxConnectionConstraint,mxPoint,mxEventObject,mxCodec,mxObjectCodec,mxUtils,mxImageExport,mxXmlCanvas2D,mxClipboard,mxCodecRegistry
} = mxgraph;import api from "@/utils/api";
export default {data() {return {graph: null,undoMng: null};},name: "HelloWorld",props: {// msg: String
  },created() {},methods: {save() {var xml ='<diagram id="" tcn="">' +mxUtils.getXml(new mxCodec().encode(this.graph.getModel())) +"</diagram>";api("appserver/getAppServer", "post", { gid: "01" }).then(response => {console.log("response");consoele.log(response);/*  this.temp.name = response.namethis.temp.details = response.detailsthis.temp.iconurl = response.iconurlthis.temp.operateType = 'U'this.temp.flowtype = response.flowtypethis.imageUrl = response.iconshowurl */// this.isLoading = false
        }).catch(() => {//this.isLoading = false
        });},clearGraph(graph) {alert("clear");this.undoMng.undo();this.undoMng.redo();},createDragSource(graph) {//创建输入拖动源var in1 = this.createDragImage(graph,"in1","./images/XLI.png","EXCEL输入");var in2 = this.createDragImage(graph,"in2","./images/TFI.png","文本文件输入");var in3 = this.createDragImage(graph,"in3","./images/GEN.png","生成记录");var in4 = this.createDragImage(graph,"in4","./images/RVA.png","生成随机数");var in5 = this.createDragImage(graph,"in5","./images/GNR.png","自定义常量数据");var in6 = this.createDragImage(graph,"in6","./images/SYS.png","获取系统信息");var in7 = this.createDragImage(graph,"in7","./images/TIP.png","表输入");//创建输出拖动源var out1 = this.createDragImage(graph,"out1","./images/XLO.png","Excel输出");var out2 = this.createDragImage(graph,"out2","./images/SFO.png","SQL 文件输出");var out3 = this.createDragImage(graph,"out3","./images/Delete.png","删除");var out4 = this.createDragImage(graph,"out4","./images/INU.png","插入 / 更新");var out5 = this.createDragImage(graph,"out5","./images/SAM.png","数据同步");var out6 = this.createDragImage(graph,"out6","./images/TFO.png","文本文件输出");var out7 = this.createDragImage(graph,"out7","./images/UPD.png","更新");var out8 = this.createDragImage(graph,"out8","./images/TOP.png","表输出");//创建转换拖动源var trans1 = this.createDragImage(graph,"trans1","./images/VMAP.png","值映射");var trans2 = this.createDragImage(graph,"trans2","./images/UNP.png","列转行");var trans3 = this.createDragImage(graph,"trans3","./images/SRC.png","剪切字符串");var trans4 = this.createDragImage(graph,"trans4","./images/UNQ.png","去除重复记录");var trans5 = this.createDragImage(graph,"trans5","./images/CST.png","增加常量");var trans6 = this.createDragImage(graph,"trans6","./images/SEQ.png","增加序列");var trans7 = this.createDragImage(graph,"trans7","./images/CSM.png","增加校验列");var trans8 = this.createDragImage(graph,"trans8","./images/SEL.png","字段选择");var trans9 = this.createDragImage(graph,"trans9","./images/RST.png","字符串替换");var trans10 = this.createDragImage(graph,"trans10","./images/SRT.png","排序记录");var trans11 = this.createDragImage(graph,"trans11","./images/FLA.png","行扁平化");var trans12 = this.createDragImage(graph,"trans12","./images/NRM.png","行转列");//创建脚本拖动源var scp1 = this.createDragImage(graph,"scp1","./images/SCR_mod.png","scp1");var scp2 = this.createDragImage(graph,"scp2","./images/SQL.png","scp2");},paseXML(graph) {var xml ='<mxGraphModel> <root> <mxCell id="0"/> <mxCell id="1" parent="0"/> <mxCell id="2" value="EXCEL输入" style="in1" vertex="1" parent="1"> <mxGeometry x="100" y="110" width="50" height="50" as="geometry"/> </mxCell> <mxCell id="3" value="文本文件输入" style="in2" vertex="1" parent="1"> <mxGeometry x="380" y="130" width="50" height="50" as="geometry"/> </mxCell> <mxCell id="4" value="生成随机数" style="in4" vertex="1" parent="1"> <mxGeometry x="210" y="350" width="50" height="50" as="geometry"/> </mxCell> <mxCell id="6" edge="1" parent="1" source="2" target="4"> <mxGeometry relative="1" as="geometry"/> </mxCell> <mxCell id="7" edge="1" parent="1" source="4" target="3"> <mxGeometry relative="1" as="geometry"/> </mxCell> </root> </mxGraphModel>';var doc = mxUtils.parseXml(xml);var codec = new mxCodec(doc);codec.decode(doc.documentElement, graph.getModel());},RightMenu(graph) {var container = document.getElementById("right");//禁用浏览器自带的右键事件
      mxEvent.disableContextMenu(container);// 使用本地函数安装弹出菜单处理程序graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) {return createPopupMenu(graph, menu, cell, evt);};//创建右键的菜单function createPopupMenu(graph, menu, cell, evt) {if (cell != null) {menu.addItem("复制步骤", "", function() {var cells = new Array();cells = graph.getSelectionCells();console.log("graph");console.log(graph);console.log("cells");console.log(cells);console.log("mxClipboard", mxClipboard);mxClipboard.copy(graph, cells);});}menu.addSeparator();menu.addItem("删除步骤", "", function() {var cells = new Array();cells = graph.getSelectionCells();graph.removeCells(cells);});}},lookXML() {var encoder = new mxCodec();var node = encoder.encode(this.graph.getModel());const h = this.$createElement;this.$msgbox({title: "xml",message: h("p", null, [h("div",{style:"overflow-y:auto; overflow-x:auto; width:400px; max-height:400px;"},mxUtils.getPrettyXml(node))]),showCancelButton: true,confirmButtonText: "确定",cancelButtonText: "取消"});},getStyle(graph, url, styleName) {// 声明一个objectvar style = {};// 克隆一个objectstyle = mxUtils.clone(style);style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_LABEL; // 不设置这个属性 背景图片不出来// 边框颜色style[mxConstants.STYLE_STROKECOLOR] = "#15428b";//圆角style[mxConstants.STYLE_ROUNDED] = "1";// 边框大小style[mxConstants.STYLE_STROKEWIDTH] = "0.5px";// 字体颜色style[mxConstants.STYLE_FONTCOLOR] = "#000";// 文字水平方式style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_right;// 文字垂直对齐style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP;// 字体大小style[mxConstants.STYLE_FONTSIZE] = 14;style[mxConstants.STYLE_FILLCOLOR] = "transparent";// 底图水平对齐style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_LEFT;// 底图垂直对齐style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP;// 图片路径//style[mxConstants.STYLE_IMAGE] = 'images/icons48/gear.png';style[mxConstants.STYLE_IMAGE] = url; //'./images/i_assignedSlave.png';// 背景图片宽style[mxConstants.STYLE_IMAGE_WIDTH] = 40;// 背景图片高style[mxConstants.STYLE_IMAGE_HEIGHT] = 40;// 上间距设置// 即使下边定义了全局设置,但这里单独设置上边间距仍单独有效// style[mxConstants.STYLE_SPACING_TOP] = 'spacingTop';// 四边间距设置style[mxConstants.STYLE_SPACING] = 1;style[mxConstants.STYLE_VERTICAL_LABEL_POSITION] =mxConstants.ALIGN_BOTTOM;graph.getStylesheet().putCellStyle(styleName, style);},createDragImage(graph, id, image, text) {var img = mxUtils.createImage(image);img.style.width = "30px";img.style.height = "30px";img.style.margin = "0px";document.getElementById(id).appendChild(img);var style = this.getStyle(graph, image, id);// 检查图形中是否包含对应的elt节点function containsElt(graph, elt) {while (elt != null) {if (elt == graph.container) {return true;}elt = elt.parentNode;}return false;}// 在给定的位置插入一个元素var funct1 = function(graph, evt, target, x, y) {/* var prefix = '';prefix =     prefix+'verticalLabelPosition=bottom;verticalAlign=top;STYLE_STROKEWIDTH=1px;'; */var cell = new mxCell(text, new mxGeometry(0, 0, 50, 50), id);cell.vertex = true;var cells = graph.importCells([cell], x, y, target); //插入元素、位置、大小
        console.log(cells.getStyle);};// 禁用IE浏览器中的DnD功能(这是为了跨浏览器平台而设计的,见下文)if (mxClient.IS_IE) {mxEvent.addListener(img, "dragstart", function(evt) {evt.returnValue = false;});}// 创建拖动源的预览var dragElt = document.createElement("div");dragElt.style.border = "dashed black 1px";dragElt.style.width = "120px";dragElt.style.height = "40px";// 在点击拖动源图标时提供预览。 预览是提供的仅仅是拖动源的图片// 只有拖动源到容器内时才会显示元素的坐标预览var ds = mxUtils.makeDraggable(img,graph,funct1,dragElt,null,null,graph.autoscroll,true);//从拖动源拖动时显示导航线。//注意,对图形中已存在的元素拖动时显示导航线不在本方法约束范围。ds.isGuidesEnabled = function() {return graph.graphHandler.guidesEnabled;};//从拖动源拖动元素到图形以外的区域时,显示拖动源图片预览ds.createDragElement = mxDragSource.prototype.createDragElement;}},// /item1
  mounted() {var graph = new mxGraph(this.$refs.graph_container);graph.setConnectable(true);new mxRubberband(graph);var parent = graph.getDefaultParent();this.graph = graph;//创建拖拽源this.createDragSource(graph);//页面初始化this.paseXML(graph);//右键菜单定义this.RightMenu(graph);}
};
</script><style scoped>
.left_header {font-weight: 500;margin: 0 auto;padding: 15px;
}
.right_header {margin: auto 0;background-color: #e9edf1;padding: 10px;padding-left: 15px;
}
#right {height: 100%;position: relative;overflow: hidden;width: 100%;height: 100%;background: url("/images/grid.gif");cursor: default;
}.el-menu-item-group__title {padding: 0px 0 7px 20px;line-height: normal;font-size: 12px;color: #909399;
}
</style>

View Code

效果图

转载于:https://www.cnblogs.com/excellencesy/p/11385806.html

mxgraph初体验相关推荐

  1. 苹果电脑安装python3密码_mac系统安装Python3初体验

    前沿 对于iOS开发不要随便拆卸系统自带的Python,因为有很多 library 还是使用 Python2.7. 1 安装Xcode 1.1 App Store 搜索Xcode 并安装 1.2 安装 ...

  2. MapReduce编程初体验

    需求:在给定的文本文件中统计输出每一个单词出现的总次数 第一步: 准备一个aaa.txt文本文档 第二步: 在文本文档中随便写入一些测试数据,这里我写入的是 hello,world,hadoop he ...

  3. 小程序 缩放_缩放流星应用程序的初体验

    小程序 缩放 by Elie Steinbock 埃莉·斯坦博克(Elie Steinbock) 缩放流星应用程序的初体验 (First Experiences Scaling a Meteor Ap ...

  4. wxWidgets刚開始学习的人导引(3)——wxWidgets应用程序初体验

    wxWidgets刚開始学习的人导引全文件夹   PDF版及附件下载 1 前言 2 下载.安装wxWidgets 3 wxWidgets应用程序初体验 4 wxWidgets学习资料及利用方法指导 5 ...

  5. 用鸿蒙跑了个 “hello world”!鸿蒙开发初体验

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源 | https://my.oschina.net/u ...

  6. Windows Embedded Standard开发初体验(二)

    支持Silverlight的Windows Embedded Standard 好了,完成安装之后,我们就可以来做Windows Embedded Standard的第一个操作系统镜像了.在开始菜单中 ...

  7. 深度探索Hyperledger技术与应用之超级账本初体验(附部署代码)

    2019独角兽企业重金招聘Python工程师标准>>> 本章零基础地介绍了如何快速体验超级账本搭建的区块链网络,我们先绕过了比较复杂的初始化配置,用官方提供的fabric-sampl ...

  8. Spring环境搭建,IoC容器初体验~

    由于最近的任务是关于IoC配置文件格式的转换,所以需要从Spring的IoC容器开始学起,今天根据网上的介绍搭建了Spring环境,并对其IoC容器进行了初体验.文章中涉及到的软件以及推荐的一本关于S ...

  9. 来自新手Banana Pi香蕉派初体验

    2019独角兽企业重金招聘Python工程师标准>>> 一.前言 一段时间来对有强大的技术支持和完善的社区的Raspberry Pi很感兴趣,本想入一片学习学习,但转念一想Raspb ...

最新文章

  1. 031_spark架构原理
  2. http经典书籍--http权威指南
  3. Google Drive客户端
  4. mysql技术分享-- 视图是什么
  5. [转帖]关于Linux下的icotl函数
  6. 获得手机屏幕相关参数
  7. html特殊符号sm,以前搜集的一些资料—html中的特殊字符(2)
  8. rust进水器怎么用_RO反渗透净水器的正确使用方式 你都Get了吗?
  9. 计算机中的cmd是什么意思,计算机中的cmd是什么意思,全称是什么
  10. 中介者模式:还记得你到单位入职的第一天吗?你有没有遇到文中‘王二’的事呢?
  11. 2018的趋势与展望(下)——记罗振宇“时间的朋友2017”跨年演讲
  12. 解决Upload to dev failed. Could not resolve file “sftp://xxx.xxx.xxx.xxx:22/“. (Request failed)
  13. 赛码网在线考试无法使用外接摄像头解决方案
  14. html安全区怎么设置,[GEE引擎]自定义安全区形状的设置方法
  15. 服务器显示doorstall,杀戮空间2服务器插件AdminCmdsV2.0.6设置说明
  16. Excel公式向导,不会函数也可以单条件求平均值
  17. C51单片机的电子时钟(数码管显示)
  18. Windows live Writer 发布博文
  19. 43、在java中一个类被声明为final类型,表示了什么意思?
  20. video标签的全部配置

热门文章

  1. 机器学习笔记09:支持向量机(二)-核函数(Kernels)
  2. idea单测覆盖率不显示的问题
  3. 冯·诺依曼结构:现代计算机的诞生
  4. 会议及作用篇--项目管理(十六)
  5. ElasticSearch:为中文分词器增加对英文的支持(让中文分词器可以处理中英文混合文档)(转)
  6. android 获取默认字体,Android默认字体
  7. [Eclipse]GEF入门系列(三、应用实例)
  8. Alpha版本——展示博客【第二组】
  9. linux uac 设备,USB Audio Class (UAC) 分析
  10. 静态路由 动态路由 默认路由 默认网关