mxGraph 入门实例教程

mxGraph进阶 一 mxGraph教程-开发入门指南 阅读详情

 

可视化javascriptvue.js图

发布于 2019-03-14

Cover

在上一篇文章 《记一次绘图框架技术选型: jsPlumb VS mxGraph》 中,提到了我为什么要去学习 mxGraph。在入门时我遇到了以下几个问题

  • 官方文档偏向理论,没能较好地结合代码进行讲解
  • 虽然官方给出的例子很多,但没有说明阅读顺序,对刚入门的我不知道应该从哪开始阅读
  • 通过搜索引擎搜索 “mxGraph教程” 没能得到太大帮助

通过自己对着官方文档死磕了一段时间并在公司项目中进行实践后,慢慢开始掌握这个框架的使用。下面我就根据我的学习经验写一篇比较适合入门的文章。

官方列了比较多文档,其中下面这几份是比较有用的。

在看完我的文章后希望系统地学习 mxGraph 还是要去阅读这些文档的,现在可以暂时不看。因为刚开始就堆这么多理论性的东西,对入门没有好处。

这篇教程分为两部分,第一部分结合我写的一些例子讲解基础知识。第二部分则利用第一部分讲解的知识开发一个小项目 pokemon-diagram。本教程会使用到 ES6 语法,而第二部分的项目是用 Vue 写的。阅读本教程需要你掌握这两项预备知识。

引入

使用 script 引入

我们来分析一下官方的 HelloWorld 实例是怎样通过 script 标签引入 mxGraph 的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>

<body>
<div id="graphContainer"></div>
</body>

<script>
mxBasePath = '../src';
</script>

<script src="../src/js/mxClient.js"></script>
<script>
    // ......
</script>
</html>

首先要声名一个全局变量 mxBasePath 指向一个路径,然后引入 mxGraph。

2

mxBasePath 指向的路径作为 mxGraph 的静态资源路径。上图是 HelloWorld 项目的 mxBasePah,这些资源除了 js 目录 ,其他目录下的资源都是 mxGraph 运行过程中所需要的,所以要在引入 mxGraph 前先设置 mxBasePath。

3

再来看看 javascript 目录下有两个 mxClient.js 版本。 一个在 javascript/src/js/mxClient.js ,另一个在 javascript/mxClient.js,后者是前者打包后的版本,所以两者是可以替换使用的。如果你的项目是使用 script 标签引入 mxGraph,可以参考我这个库。

模块化引入

模块化引入可以参考 pokemon-diagram 的这个文件 static/mxgraph/index.js

/*** 引入 mxgraph ***/
// src/graph/index.js
import mx from 'mxgraph';

const mxgraph = mx({
  mxBasePath: '/static/mxgraph',
});

//fix 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;


/*** 在其他模块中使用 ***/
// src/graph/Graph.js
import mxgraph from './index';

const {
  mxGraph,
  mxVertexHandler,
  mxConstants,
  mxCellState,
  /*......*/
} = mxgraph;

这里有两点需要注意的

  • mx 方法传入的配置项 mxBasePath 指向的路径一定要是一个可以通过 url 访问的静态资源目录。举个例子,pokemon-diagram 的 static 目录是个静态资源目录,该目录下有 mxgraph/css/common.css这么个资源,通过http://localhost:7777 可以访问 pokemon-diagram 应用,那么通过 http://localhost:7777/static/mxgraph/css/common.css 也应该是可以访问 common.css 才对
  • 如果你是通过 script 标签引入 mxGraph,是不需要绑定全局变量那段代码的。模块化引入要使用这段代码是因为,mxGraph 这个框架有些代码是通过 window.mxXXX 对以上属性进行访问的,如果不做全局绑定使用起来会有点问题。这是官方一个未修复的 BUG,详情可以查阅上面代码注释的 issue

基础知识

这部分会使用到我自己编写的一些例子。大家可以先把代码下载下来,这些例子都是不需要使用 node 运行的,直接双击打开文件在浏览器运行即可。

Cell

Cell 在 mxGraph 中可以代表组(Group)、节点(Vertex)、边(Edge),mxCell 这个类封装了 Cell 的操作,本教程不涉及到组的内容。下文若出现 Cell 字眼可以当作 节点 或 边。

事务

官方的 HelloWorld 的例子向我们展示了如何将节点插入到画布。比较引人注意的是 beginUpdate 与 endUpdate 这两个方法,这两个方法在官方例子中出镜频率非常高,我们来了解一下他们是干嘛用的,嗯,真是只是了解一下就可以了,因为官方对两个方法的描述对入门者来说真的是比较晦涩难懂,而且我在实际开发中基本用不上这两个方法。可以等掌握这个框架基本使用后再回过头来研究。下面的描述来源这个文档,我来简单概括一下有关这两个方法的相关信息。

4_1

  • beginUpdate、endUpdate 用于创建一个事务,一次 beginUpdate 必须对应一次 endUpdate
  • 为了保证,假如 beginUpdate 执行失败,endUpdate 永远不会被调用,beginUpdate 一定要放到 try 块之外
  • 为了保证,假如 try 块内更新失败,endUpdate 也一定被调用,beginUpdate一定要放到 finally 块
  • 使用 beginUpdate 与 endUpdate 可提高更新视图性能,框架内部做撤消/重做管理也需要 beginUpdate、endUpdate

按照官方这个说明,如果我不需要撤消/重做功能,是不是可以不使用这两个方法呢。我试着把这两个方法从 HelloWorld 例子的代码中删掉,结果程序还是可以正常运行。

insertVertex

mxGraph.prototype.insertVertex = function(parent, id, value,
                                          x, y, width, height, style, relative) {

  // 设置 Cell 尺寸及位置信息
  var geometry = new mxGeometry(x, y, width, height);
  geometry.relative = (relative != null) ? relative : false;

  // 创建一个 Cell
  var vertex = new mxCell(value, geometry, style);
  // ...
  // 标识这个 Cell 是一个节点
  vertex.setVertex(true);
  // ...

  // 在画布上添加这个 Cell
  return this.addCell(vertex, parent);
};

上面是经简化后的 insertVertex 方法。 insertVertex 做了三件事,先是设置几何信息,然后创建一个节点,最后将这个节点添加到画布。insertEdge 与 insertVertex 类似,中间过程会调用 vertex.setEdge(true) 将 Cell 标记为边。从这里我们也可以得知无论节点还是边在 mxGraph 中都是由 mxCell 类表示,只是在该类内部标识当前 Cell 是 节点 还是 边。

mxGeometry

function mxGeometry(x,y,width,height){}

mxGeometry 类表示 Cell 的几何信息,宽高比较好理解,只对节点有意义,对边没意义。下面通过 02.geometry.html 这个例子说明如x、y的作用。

4

mxGeometry 还有一个很重要的布尔属性 relative,

  • relative 为 false 的节点,表示以画布左上角为基点进行定位,x、y 使用的是绝对单位

    上一小节提到 insertVertex 内部会创建 mxGeometry 类。使用 mxGraph.insertVertex 会创建一个 mxGeometry.relative 为 false 的节点,如 A 节点

  • relative 为 true 的节点,表示以父节点左上角为基点进行定位,x、y 使用的是相对单位

    使用 mxGraph.insertVertex 会创建一个 relative 为 false 的节点。如果你要将一个节点添加到另一个节点中需要在该方法调用的第9个参数传入 true,将 relative 设置为 true。这时子节点使用相对坐标系,以父节点左上角作为基点,x、y 取值范围都是 [-1,1]。如 C节点 相对 B节点定位。

6

  • relative 为 true 的边,x、y 用于定位 label

    使用 mxGraph.insertEdge 会创建一条 relative 为 true 的边。x、y 用于定位线条上的 label,x 取值范围是 [-1,1],-1 为起点,0 为中点,1 为终点。y 表示 label 在边的正交线上移到的距离。第三个例子能帮忙大家理解这种情况。
    7

    const e1 = graph.insertEdge(parent, null, '30%', v1, v2);
    e1.geometry.x = 1;
    e1.geometry.y = 100;

设置样式

8

由 03.stylesheet.html 这个例子我们得知 mxGraph 提供两种设置样式的方式。

第一种是设置全局样式。mxStylesheet 类用于管理图形样式,通过 graph.getStylesheet() 可以获取当前图形的 mxStylesheet 对象。mxStylesheet 对象的 styles 属性也是一个对象,该对象默认情况下包含两个对象defaultVertexStyle、defaultEdgeStyle,修改这两个对象里的样式属性对所有线条/节点都生效。

第二种是命名样式。先创建一个样式对象,然后使用 mxStylesheet.putCellStyle 方法为 mxStylesheet.styles 添加该样式对象并命名。在添加 Cell 的时候,将样式写在参数中。格式如下

[stylename;|key=value;]

分号前可以跟命名样式名称或者一个样式的 key、value 对。

ROUNDED 是一个内置的命名样式,对节点设置有圆角效果,对边设置则边的拐弯处为圆角。

例子中设置折线有一个需要注意的地方。

// 设置拖拽边的过程出现折线,默认为直线
graph.connectionHandler.createEdgeState = function () {
  const edge = this.createEdge();
  return new mxCellState(graph.view, edge, graph.getCellStyle(edge));
};

虽然调用 insertEdge 方法时已经设置了线条为折线,但是在拖拽边过程中依然是直线。上面这段代码重写了 createEdgeState 方法,将拖动中的边样式设置成与静态时的边样式一致,都是折线。

查看样式效果小技巧

mxGraph 所有样式在这里可以查看,打开网站后可以看到以 STYLE_ 开头的是样式常量。但是这些样式常量并不能展示样式的效果。下面教大家一个查看样式效果的小技巧,使用 draw.io 或 GraphEditor (这两个应用都是使用 mxGraph 进行开发的) 的 Edit Style 功能可以查看当前 Cell 样式。

比如现在我想将边的样式设置成:折线、虚线、绿色、拐弯为圆角、粗3pt。在 Style 面板手动修改样式后,再点击 Edit Style 就可以看到对应的样式代码。

9

10

为了方便观察我手动格式化了样式,注意最后一行以 entry 或 exit 开头的样式代表的是边出口/入口的靶点坐标,下一小节会进行讲解。

靶点

关于如何设置靶点可以参考 04.anchors.html ,下面也是以这个 Demo 进行讲解两个用户操作的例子,对比不同的操作对于获取靶点信息的影响。

将鼠标悬浮中 A 节点中心,待节点高亮时连接到 B 节点的一个靶点上

11

12

然后将 A 节点拖拽到 B 节点右边

13

可以看到如果从图形中心拖出线条,这时边的出口值 exit 为空,只有入口值 entry。如果拖动节点 mxGraph 会智能地调整线条出口方向。如节点 A 的连接靶点原来是在右边,节点拖动到节点 B 右边后靶点也跟着发生了变化,跑到了左边,而节点 B 的连接靶点一直没变。

这次将鼠标悬浮到 A 节点的一个靶点,待靶点高亮时连接到 B 节点的一个靶点上

14

15

然后将 A 节点拖拽到 B 节点右边

16

可以看到这次所有值都有了,连接后拖动节点 A,连接靶点的位置也固定不变,mxGraph 不像第一个例子一样调整连接靶点位置。之所以产生这样的差异是因为第一个例子的边是从节点中心拖出的,并没有出口靶点的信息,而第二个例子则是明确地从一个靶点中拖出一条边。

面向对象编程

mxGraph 框架是使用面向对象的方式进行编写的,该框架所有类带 mx 前缀。在接下来的例子你会看到很多这种形式的方法重写(Overwrite)。

const oldBar =  mxFoo.prototype.bar;
mxFoo.prototype.bar = function (...args)=> {
   // .....
    oldBar.apply(this,args);
    // .....
};

节点组合

这一小节通过 05.consistuent.html 这个例子,讲解节点组合需要注意的地方。

组合节点后默认情况下,父节点是可折叠的,要关闭折叠功能需要将 foldingEnabled 设为 false。

graph.foldingEnabled = false;

如果希望在改变父节点尺寸时,子节点与父节点等比例缩放,需要开启 recursiveResize。

graph.recursiveResize = true;

下面是这个例子最重要的两段代码。

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

// Redirects selection to parent
graph.selectCellForEvent = function (cell) {
  if (this.isPart(cell)) {
    mxGraph.prototype.selectCellForEvent.call(this, this.model.getParent(cell));
    return;
  }

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

这两个方法重写(Overwrite)了原方法,思路都是判断如果该节点是子节点则替换成父节点去执行剩下的逻辑。

getInitialCellForEvent 在鼠标按下(mousedown事件,不是click事件)时触发,如果注释掉这段代码,不使用父节点替换,当发生拖拽时子节点会被单独拖拽,不会与父节点联动。使用父节点替换后,原本子节点应该被拖拽,现在变成了父节点被拖拽,实现联动效果。

selectCellForEvent 其实是 getInitialCellForEvent 内部调用的一个方法。这个方法的作用是将 cell 设置为 selectionCell,设置后可通过 mxGraph.getSelectionCell 可获取得该节点。与 getInitialCellForEvent 同理,如果不使用父节点替换,则 mxGraph.getSelectionCell 获取到的会是子节点。项目实战我们会使用到 mxGraph.getSelectionCell 这个接口。

项目实战

这部分我主要挑一些这个项目比较重要的点进行讲解。

写一个节点组合

下面以项目的这个节点为例,讲解如何组合节点

17

const insertVertex = (dom) => {
  // ...
  const nodeRootVertex = new mxCell('鼠标双击输入', new mxGeometry(0, 0, 100, 135), `node;image=${src}`);
  nodeRootVertex.vertex = true;
  // ...
  
  const title = dom.getAttribute('alt');
  const titleVertex = graph.insertVertex(nodeRootVertex, null, title,
    0.1, 0.65, 80, 16,
    'constituent=1;whiteSpace=wrap;strokeColor=none;fillColor=none;fontColor=#e6a23c',
    true);
  titleVertex.setConnectable(false);

  const normalTypeVertex = graph.insertVertex(nodeRootVertex, null, null,
    0.05, 0.05, 19, 14,
    `normalType;constituent=1;fillColor=none;image=/static/images/normal-type/forest.png`,
    true);
  normalTypeVertex.setConnectable(false);
  // .....
};

单单 nodeRootVertex 就是长这个样子。通过设置自定义的 node 样式(见 Graph 类 _putVertexStyle 方法)与 image 属性设置图片路径配合完成。

18

因为默认情况下一个节点只能有一个文本区和一个图片区,要增加额外的文本和图片就需要组合节点。在 nodeRootVertex 上加上 titleVertex 文本节点和 normalTypeVertex 图片节点,最终达到这个效果。

19

有时需要为不同子节点设置不同的鼠标悬浮图标,如本项目鼠标悬浮到 normalTypeVertex 时鼠标变为手形,参考 AppCanvas.vue 的 setCursor 方法,重写 mxGraph.prototype.getCursorForCell 可以实现这个功能。

const setCursor = () => {
  const oldGetCursorForCell = mxGraph.prototype.getCursorForCell;
  graph.getCursorForCell = function (...args) {
    const [cell] = args;
    return cell.style.includes('normalType') ?
      'pointer' :
      oldGetCursorForCell.apply(this, args);
  };
};

编辑内容

下面这段代码是编辑内容比较常用的设置

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

默认情况下输入内容时如果按回车键内容会换行,但有些场景有禁止换行的需求,希望回车后完成输入,通过graph.setEnterStopsCellEditing(true) 设置可以满足需求。

重点说说 mxCellEditor.prototype.blurEnabled 这个属性,默认情况下如果用户在输入内容时鼠标点击了画布之外的不可聚焦区域(div、section、article等),节点内的编辑器是不会失焦的,这导致了 LABEL_CHANGED 事件不会被触发。但在实际项目开发中一般我们会期望,如果用户在输入内容时鼠标点击了画布之外的地方就应该算作完成一次输入,然后通过被触发的 LABEL_CHANGED 事件将修改后的内容同步到服务端。通过 mxCellEditor.prototype.blurEnabled = true 这行代码设置可以满足我们的需求。

可换行的 label

const titleVertex = graph.insertVertex(nodeRootVertex, null, title,
      0.1, 0.65, 80, 16,
      'constituent=1;whiteSpace=wrap;strokeColor=none;fillColor=none;fontColor=#e6a23c',
      true);

对于非输入的文本内容,默认情况下即便文本超出容器宽度也是不会换行的。我们项目中宽度为 80 的 titleVertex 正是这样一个例子。

20

要设置换行需要做两件事,第一是通过这行代码 mxGraph.setHtmlLabels(true),使用 html 渲染文本(mxGraph 默认使用 svg的text 标签渲染文本)。第二是像上面的 titleVertex 的样式设置一样,添加一句 whiteSpace=wrap。

21

Model

现在介绍一下 Model 这个概念,Model 是当前图形的数据结构化表示。mxGraphModel 封装了 Model 的相关操作。

你可以启动项目,画一个这样的图,然后点击输出XML。为了保的 xml 与下面的一致,需要先拖出智爷,再拖出超级皮卡丘,最后连接边。

22

控制台应该输出这样一份 xml

<mxGraphModel>
  <root>
    <mxCell id="0"/>
    <mxCell id="1" parent="0"/>
    <mxCell id="4" value="Hello" style="node;image=/static/images/ele/ele-005.png" vertex="1" data="{&quot;id&quot;:1,&quot;element&quot;:{&quot;id&quot;:1,&quot;icon&quot;:&quot;ele-005.png&quot;,&quot;title&quot;:&quot;智爷&quot;},&quot;normalType&quot;:&quot;water.png&quot;}" parent="1">
      <mxGeometry x="380" y="230" width="100" height="135" as="geometry"/>
    </mxCell>
    ........
  </root>
</mxGraphModel>

每一个 mxCell 节点都有 parent 属性指向父节点。我们对 value="Hello" 这个 mxCell 节点手动格式化。

<mxCell 
    id="4" 
    value="Hello" 
    style="node;image=/static/images/ele/ele-005.png" 
    vertex="1" 
    data="{&quot;id&quot;:1,&quot;element&quot;:{&quot;id&quot;:1,&quot;icon&quot;:&quot;ele-005.png&quot;,&quot;title&quot;:&quot;智爷&quot;},&quot;normalType&quot;:&quot;water.png&quot;}" 
    parent="1">
  <mxGeometry 
    x="380" 
    y="230" 
    width="100" 
    height="135" as="geometry"/>
</mxCell>

data 值是原对象经 JSON.stringify 得到的,经转义后就变成了上面的样子。控制台还打印了一个 mxGraphModel 对象,对比上面的 xml 与 下图的节点对象,可以发现它们只是同一个 Model 的不同表现形式,xml 正是将 mxGraph.model 格式化而成的。

23

事件

本项目监听事件写在 AppCanvas.vue 的 _listenEvent 方法,可以在这个方法了解一些常用的事件。下图来自 mxGraph 类的方法调用依赖图,我们可以从这里看出整个框架的事件流动。

24

监听事件

本项目的 _listenEvent 方法用到两个事件监听对象。

ADD_CELLS 与 CELLS_ADD 的区别

26

mxGraph 类有很多 XXX_CELLS、CELLS_XXXED 这种形式的事件,这部分我还没弄懂,下面仅以添加事件为例探讨这两类事件的区别。

  • 添加 Cell 的时候会触发两个事件 ADD_CELLS、CELLS_ADDED, 先触发 CELLS_ADDED 后触发 ADD_CELLS。
  • ADD_CELLS 在 addCells 方法中触发,而 CELLS_ADDED 在 cellsAdded 方法中触发。而对于 addCells与 cellsAdded 官方文档的说明并不能体现出两者的区别,再深究下去就要查阅源码了。按经验而言后触发的事件会携带更多的信息,所以平时开发我会监听 ADD_CELLS 事件。MOVE_CELLS、CELLS_MOVED、REMOVE_CELLS、CELLS_REMOVED 等事件与此类似。

监听 Cell 添加事件

从上面的方法调用依赖图中我们可以看到,insertVertex、insertEdge 最终都被当作 Cell 处理,在后续触发的事件也没有对 节点/边 进行区分,而是统一当作 Cell 事件。所以对于一个 Cell 添加事件,需要自己区别是添加了节点还是添加了边。

graph.addListener(mxEvent.CELLS_ADDED, (sender, evt) => {
  const cell = evt.properties.cells[0];
  if (graph.isPart(cell)) {
    return;
  }

  if (cell.vertex) {
    this.$message.info('添加了一个节点');
  } else if (cell.edge) {
    this.$message.info('添加了一条线');
  }
});

还有就是对于子节点添加到父节点的情况(如本项目将 titleVertex 、normalTypeVertex 添加到 nodeRootVertex)也是会触发 Cell 添加事件的。通常对于这些子节点不作处理,可以像 05.consistuent.html 一样用一个 isPart 判断过滤掉。

自定义事件

上面提到过 mxGraph 继承自 mxEventSource,调用父类的 fireEvent 可触发自定义事件。下面是一个简单的例子

mxGraph.addListener('自定义事件A',()=>{ 
  // do something .....
});
// 触发自定义事件
mxGraph.fireEvent(new mxEventObject('自定义事件A');

在本项目 Graph 类的 _configCustomEvent 方法我也实现了两个自定义事件。当边开始拖动时会触发 EDGE_START_MOVE 事件,当节点开始拖动时会触发 VERTEX_START_MOVE 事件。

导出图片

mxGraph 导出图片的思路是先在前端导出图形的 xml 及计算图形的宽高,然后将 xml、宽、高,这有三项数据发送给服务端,服务端也使用 mxGraph 提供的 API 将 xml 转换成图片。服务端如果是使用 Java 可以参考官方这个例子,下面主要介绍前端需要做的工作。

导出图片可以使用 mxImageExport 类,该类的文档有一段可以直接拿来使用的代码。

// ...
var xmlCanvas = new mxXmlCanvas2D(root);
var imgExport = new mxImageExport();
imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);

var bounds = graph.getGraphBounds();
var w = Math.ceil(bounds.x + bounds.width);
var h = Math.ceil(bounds.y + bounds.height);

var xml = mxUtils.getXml(root);
// ...

但这段代码会将整块画布截图,而不是以最左上角的元素及最右下角的元素作为边界截图。如果你有以元素作为边界的需求,则需要调用 xmlCanvas.translate 调整裁图边界。

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

完整截图代码可以参考本项目 Graph 类的 exportPicXML 方法。

如果节点像我的项目一样使用到图片,而导出来的图片的节点没有图片。可以从两个方向排查问题,先检查发送的 xml 里的图片路径是否是可访问的,如下面是项目“导出图片”功能打印的 xml 里的一个图片标签。

<image x="484" y="123" w="72" h="72" src="http://localhost:7777/static/images/ele/ele-005.png" aspect="0" flipH="0" flipV="0"/>

要保证 http://localhost:7777/static/images/ele/ele-005.png 是可访问的。如果图片路径没问题再检查一下使用的图片格式,本来我在公司项目中节点内使用的图片是 svg 格式,导出图片失败,可能是 mxGraph 不支持这个格式,后来换成 png 之后问题就解决了。

还有就是如果导出的图片里的节点的某些颜色跟设置的有差异,那可能是设置样式时写了3位数的颜色像 #fff,颜色一定要使用完整的6位,否则导出图片会有问题。

参考

【Mxgraph】Vue中使用mxgraph开发流程图工具 1.什么是mxgraph mxGraph是一个JavaScript图表库,可以快速创建交互式图形和图表应用程序,这些应用程序可以在其供应商支持的任何主要浏览器中运行。mxGraph 提供图形绘制、图形可视化、图形交互、图形布局、图形分析等能力, 适用于工作流程图、BPMN图、网络图、UML图、循环图、组织结构图、MindMap图、机架图、甘特图、信息图、平面图等绘制。 mxGraph在2005年创建,作为商业项目一直持续到2016年,2016年创建者以Apache 2.0开源协议在GitHub上公布源码。 阅读详情

相关推荐

【mxGraph】源码学习:(1)mxGraph库

基于 mxGraph 3.9.9 1. mxGraph简介 mxGraph是一个JavaScript图表库,可以快速创建交互式图形和图表应用程序,这些应用程序可以在其供应商支持的任何主要浏览器中运行。 mxGraph在2005年创建,作为商业项目一直持续到2016年,由于前端有很多新技术出现,所以mxGraph作为封装库的优势渐渐消失,最后创建者开明的以Apache 2.0开源协议在GitHu...

widiot的博客 5237

【亲测免费】 探索maxGraph:现代图表库的新选择

`maxGraph` 是一个用TypeScript编写的开源库,旨在展示和允许用户与矢量图进行交互。它提供了节点(也称为顶点)和边(连接节点的线或箭头)的基本组件。`maxGraph` 不仅支持基本的图表操作,如调整大小、移动和旋转节点,还特别强调自动布局算法和图论的应用。作为一个现代化的库,`maxGraph` 不需要第三方软件或插件,并且可以轻松集成到几乎任何JavaScript框架中。 #...

gitblog_00217的博客 762

基于 mxgraph 实现流程图

mxgraph 可以实现复杂的流程图绘制。mxGraph里的Graph指的是图论(Graph Theory)里的图而不是柱状图、饼图和甘特图等图(chart),因此想找这些图的读者可以结束阅读了。作为图论的图,它包含点和边,如下图所示。

小龙在线 1618

【亲测免费】 引领图形编程新时代:深入探索 maxGraph 开源库

在现代软件开发中,图形界面和数据可视化的重要性日益凸显。为了满足这一需求,一个强大的图形处理库——maxGraph 应运而生。作为 mxGraph 的继承者与革新者,maxGraph 不仅延续了其前辈的核心功能,还引入了许多激动人心的新特性,如 TypeScript 支持、模块化结构以及优化的性能表现。 maxGraph 是一款基于 TypeScript 编写的矢量图库,专注于提供节点(顶点)、...

gitblog_00039的博客 808

mxGraph进阶(一)mxGraph教程-开发入门指南

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mxGraph教程-开

mm2zzyzzp的博客 775

mxgraph-demo:使用 mxGraph 和 Convergence 进行协作图表编辑的演示

融合 mxGraph 演示 该项目演示了使用与集成的开源图表框架进行协作图表编辑。 此示例基于 mxGraph 附带的。 它已扩展并与 Convergence 集成,以提供实时编辑、共享光标、共享选择和视口感知。 该示例还利用 Convergence 为每个图表提供参与者列表和聊天室。 该项目使用lite-server来提供用于托管示例的最小 Web 服务器。 lite-server实例将node_modules目录和配置文件映射到运行示例的适当位置。 依赖关系 npm >= 7.0 节点 >= 14.0 mxGraph >= 4.2 收敛 >= 1.0.0-rc.11 运行演示 npm install 按照mxgraph.config.example.js文件中的说明创建配置文件。 npm start 打开浏览器访问http://localhost:4000

MxGraph从入门到精通之3:设置图形样式

文章目录设置节点样式创建指定样式的节点更新已有节点样式常用样式汇总shapefillColor 通过上一节 MxGraph从入门到精通之2:HelloWorld程序解析,我们已经知道通过MxGraph绘制图形的核心步骤,绘制出来的图形默认的样式如下: 我们可以在创建节点的时候通过参数来创建指定样式的节点或者调用graph的setCellStyle来更新节点的样式。 设置节点样式 创建指定样式的节点 在上一节中helloworld示例程序插入顶点的方法可以传入第八个参数,来指定创建出来的顶点的样式,如下:

祈晴小义 6030

ARS408毫米波雷达数据解析避坑指南:从硬件连接到Python处理

本文提供了ARS408毫米波雷达从硬件连接到Python数据处理的完整实战指南。针对串口通信不稳定、数据解析错误等常见问题,详细解析了硬件连接方案选择、串口数据高效读取策略、二进制协议解析的位操作技巧,并给出了坐标转换、目标跟踪及实时可视化的代码实现,帮助开发者快速搭建稳定的雷达数据处理流水线。

weixin_29091105的博客 149

Mxgraph 使用教程(3):本地引入mxgraph和 vue中引入mxgraph

1.本地引入mxgraph 第一步:下载mxgraph库 github地址:https://github.com/jgraph/mxgraph 第二步:clone项目 打开项目-》进入javascript 第三步:本地使用mxgraph 一个官方示例demo: <html> <head> <title>Hello, World! example for mxGraph</title> <!-- Sets the basepath for the

qq_43955202的博客 8168

解放双手:用KUKA示教器白键一键触发复杂工艺,自定义你的快捷指令

本文详细介绍了如何利用KUKA示教器的工艺白键功能,通过自定义快捷指令一键触发复杂工艺,显著提升自动化产线效率。文章涵盖UserTech技术栈解析、KRL脚本封装、人机交互视觉工程及工业实战策略,帮助工程师实现机械臂操作的高阶优化。

weixin_30379531的博客 432

ESP32-C61 eFuse控制器深度解析:寄存器架构与安全烧写实践

eFuse(电子熔丝)是嵌入式芯片实现硬件级不可逆配置与信任根构建的核心物理机制,其本质是通过电学编程固化关键安全参数。原理上依赖熔丝单元的单向导通/断开特性,结合Reed-Solomon纠错、多级写保护和时序可控编程,保障数据在宽温域与工艺偏差下的高可靠性。技术价值在于为Secure Boot、Flash加密、密钥隔离等安全功能提供可信锚点,支撑从启动到运行的全链路防护。典型应用场景涵盖物联网设备量产烧录、安全启动使能、MAC地址固化及抗DPA密码运算配置。本文聚焦ESP32-C61平台,深入解析其eFu

weixin_42589700的博客 123

mxgraph的艰难入门

前言 公司今年有个需求是希望前端能展现出大数据计算过程的拓扑图,最好还是能够动态展现。部门老大给我们推荐了mxgraph这个绘图js库,希望我们能够熟练掌握。于是我就先着手开始研究起来了。不过我现在对于mxgraph的掌握还非常的渣,这篇文章是记录到现在为止我的学习成果。 关于js绘图 绘图这块是前端的一个细分领域,是属于那种做的人不多,但深入下去很有前景的一个方向,当然也是一个比较难的方向。提...

weixin_34302561的博客 3257

ARM Cortex-M系列授权解析:从研发到量产的免费与付费之路

本文深入解析了ARM Cortex-M系列内核从研发到量产过程中的授权模式。研发阶段可利用ARM DesignStart等免费资源进行原型验证,但产品商业化量产则需支付授权费与版税。文章对比了采购商用MCU与自研芯片的成本差异,并探讨了RISC-V作为免费替代方案在IoT领域的应用前景与挑战,为开发者提供了清晰的选型指南。

weixin_29292431的博客 494

mxgraph + vue 入门 (概念篇)

本教程是基于mxgraph 3.9.12,mxgraph感觉在国内用的人比较少,百度上搜一圈都是一些简单的操作,稍微偏一些的操作或者问题都没有涉及,在官方example和官方API挣扎了几个月后终于有所感悟,于是写下这篇教程,一是方便后人,二是做为自己的记录。(mxgraph 和 vue的集成可以参考我另一篇博客。https://blog.youkuaiyun.com/dikentoujing99/artic...

懒牛不爱梳毛 2万+

Frigate进阶玩法:如何用MQTT和Python脚本扩展你的自定义目标检测算法

本文详细介绍了如何通过MQTT和Python脚本扩展Frigate的自定义目标检测算法,无需修改源码即可实现特殊场景(如工业设备异常、农业病虫害识别)的高效检测。文章涵盖Frigate配置、外部检测服务构建、高级集成技巧及性能优化实践,帮助开发者灵活扩展智能监控能力。

weixin_42662293的博客 350

Unreal5从入门到精通之一文搞懂Unreal的C++代码编译之谜

我们在开发Unreal项目时,如果时蓝图模板的项目,一般问题不大,因为当你修改完蓝图,点击编译Compile+保存Save,就可以继续开发了。这对于开发者来说也非常友好。但是,如果你使用的C++模板开发项目,代码编译一切都变得魔幻起来,IDE(VS/Rider)里面有编译,编辑器里面也有编译,有什么区别呢?我们来列举几个新手常碰到的问题。1.代码我明明新建了,编辑器里怎么看不到?2.昨天我新家的功能运行的好好的,今天怎么感觉还是老逻辑。或者昨天加的新代码,新蓝图不见了。

TxNet 1606

Mxgraph 使用教程(2):mxgraph常用方法介绍

1.mxgraph常用包(这个js类库被分成了8个包。) 1. 最上层的mxClient类包括或者动态导入了其他的包。当前的版本存储在maxClient.VERSION中。 2. mxEditor包提供了图表编辑器相关的类实现。入口函数式mxEditor。 3.view和model包实现了图表组件。他引用的mxGraphModel包含了mxCells和缓存了mxGraphView中的cells的状态。 4.mxCellRender基于mxStylesheet中的定义来渲染cells的外观。mxUndoMa

qq_43955202的博客 8544

【图像去噪】基于偏微分方程(PDE)实现图像去噪附matlab代码

在工程应用中,图像信息通过数字图像系统进行处理、存储和传输等加工变换时,由于不可避免地受到噪声干扰,使得原始图像信息产生偏差和失真,给图像的后续处理带来不便,进而影响人们对图像视觉特性的认知程度。因此,为了改善图像的质量效果,提高人们对图像视觉特性的认知度,对图像噪声进行有效去除,降低噪声对图像信息的干扰是很有必要的。近年来,基于偏微分方程( partial differential equation,PDE) ​的图像去噪方法在计算机视觉和图像处理等技术领域得到了广泛的重视,因为它在平滑噪声的同时,能够很

qq_59747472的博客 855

【mxGraph】源码学习:(5)mxGraph

由于mxGraph源文件有一万多行,且涉及很多其它源文件,所以会省略一些次要内容 1. 概览 mxGraph继承自mxEventSource以实现基于Web的图形组件。要激活平移和连接,请使用setPanning和setConnectable。对于橡皮带选择,您必须创建一个新的mxRubberband实例。默认情况下,以下侦听器添加到mouseListeners: tooltipHandle...

widiot的博客 8346

AI Agent开发大全第二十课-如何开发一个MCP(从0开发一个MCP Server)

大模型的MCP火了,可是无论是Claude官网本身自带Sample还是全网任何一本教程没有一个可以真正应用在生产环境中的。要么就是只能在本地以文件IO流的方式运行要么干脆连编译都出错,真正的mcp server和client是怎么编写的?如何运行在分布式环境?本教程就带大家真正从0开始以“AI计算食物热量“为例带大家真正学习mcp开发的全过程。

打造全国最全的AI Agent开发知识领域的博客 1802

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

MxGraph从入门到精通之4:布局

文章目录mxCircleLayout-圆形布局mxCompactTreeLayout-树状布局mxFastOrganicLayout-组织状布局 本文介绍MxGraph支持的几种常用布局方式。 mxCircleLayout-圆形布局 圆形布局不关注节点之间的连线,节点之间有没有连线不影响最终效果。 核心代码: for(let i=1; i< 10; i++){ graph.insertVertex(parent, null, 'Hello' + i, 0, 0, 80, 30); } let lay

祈晴小义 3361

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

MxGraph从入门到精通之5:在Vue项目中使用MxGraph

第一步:安装npm包 npm install mxgraph 第二步:在mxgraph.vue中使用mxgraph <template> <div> <div ref="graphContainer"> </div> </div> </template> <script> import mx from 'mxgraph' export default { name: 'Application

祈晴小义 3867

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

mxGraph 入门教程

客户端事件:mxGraph支持很多事件(如鼠标单击、双击、拖拽等)的处理,在客户端完成前台处理,减少后台交互数据,提升用户体验。数据绑定:mxGraph支持将数据绑定到图形元素上,以实现数据和图形之间的同步,并实时更新图形。打印:mxGraph包含了有用的打印功能,可让您生成高质量的打印输出,适合各种场合,如报告、演示文稿等。Views: 它们管理与绘制图形相关的所有信息,如滚动条、缩放级别、选择状态和当前显示的区域。Cells: 表示图形中的节点或连接线,并可以具有各种属性,例如标签、样式和几何位置。

X01动力装甲的专栏 954

mxgraph进阶(五)搭建mxGraph简单应用

mxgraph进阶(五)搭建mxGraph简单应用使用前准备  mxBasePath变量用来定义库资源的目录。这个变量必须在加载库前就定义好。    <script type="text/javascript">   mxBasePath = 'javascript/src/';   </script>  //mxClient.js包含该类库的全部所需代码。 <script

IT全栈 华强工作室 5万+

mxgraph

mxgraph浅入了解 参考文献:https://www.cnblogs.com/xuxg/articles/3246206.html 1.了解 (1)如何判断需要引入mxgraph产品:过程图、工作流和BPM的可视化图表、流程图、交通或水流量、 数据库和WWW的可视化、网络和电信显示、映射应用和地理信息系统、UML图、电子线路、金融、 超大规模集成电路和社会网络、数据挖掘、生化、生态循环、实体和因果关系和组织图表。 (2)如何选取自己需要mxgraph产品的哪一个库:mxGraph分为在客户端的.

IT博客技术分享 2534
上一篇: vue拖拉拽动态表单
下一篇: vue拖拉拽动态表单(转)
兀兀术
博客等级 码龄19年 25粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值