mxGraph使用经验总结

mxGraph是一个支持多种语言(Java、JavaScript、PHP、.NET)的画图框架,所绘制的图形能够在主流浏览器以及原生应用上使用。
mxGraph官方资料全英文,网上有几篇mxGraph的教程,对于“入门”和“使用”讲解得比较详细。
因此这篇文章不是介绍如何画一个图形,写一个hello world,而是重点介绍学习mxGraph时以为比较重要的、难以理解的或者容易被忽略的知识点。
须要读者对mxGraph的文档有必定的了解或者使用mxGraph。css

mxGraph的使用场景

mxGraph的使用场景有4个:图形可视化、图形交互、图形布局、图形分析。html

图形可视化

图形可视化是mxGraph的主打功能,这个很好理解,就是把一些抽象的概念用图形来表示,好比常见的流程图、思惟导图、实体关系图等。
须要注意的是mxGraph所绘制的图主要是由“点”(也包括矩形、圆形这类基本形状)和“边”组成的,若是要用mxGraph来画蒙娜丽莎那就确定是不合适的。
下图是官方提供的一张样图。
做者猜想实现方式是用世界地图做为背景图片,而后在此之上绘制点和线。
为了验证猜想,访问了官方示例提供的网站,发现是一张jpg图片,并且没有连线。
多是后端生成导出的位图,或者源图片已经被网站替换了。前端

{% asset_img vis.png %}

图形交互

mxGraph除了绘制图形以外还提供了丰富的编辑功能,好比拖拽、选择、复制、调整大小等。
mxGraph甚至还专门提供了一个API类用来支持在线编辑器。
关于这一块我没有使用~git

{% asset_img interaction.png %}

图形布局

很是重要的一个功能,能自动排列图形元素。
mxGraph提供了多种布局方式,好比树形布局、栈式布局、圆形布局。
这一块后面重点介绍。github

{% asset_img layout.png %}

图形分析

支持图相关的算法分析,好比找出图中两个节点的最短路径。
关于这一块我没有使用~
不过我没有找到相关API,估计须要开发者本身实现相关算法。算法

{% asset_img analysis.png %}

小结

学习新技术或框架的时候首先须要弄清楚它是什么,能作什么。
若是和要实现的功能匹配再继续学习研究。数据库

mxGraph的绘图方式

前端绘制图形有3种方式:canvas

  1. HTML + CSS。
  2. canvas。
  3. svg。

HTML+ CSS

优势

  • 前端工程师最熟悉最经常使用的方式,开发起来很是简单。
  • 借助CSS3能够实现炫酷的动画效果。

缺点

  • 很是依赖浏览器环境,若是要迁移到原生应用上或者客户端就会比较麻烦。
  • HTML、CSS没有合适的模块机制,因此图形的复用也不方便。

canvas

canvas使用也比较普遍,好比百度的著名开源项目echarts就是经过canvas来绘制各类图形。后端

优势

  • 强大的API,能够实现复杂的图形和效果。
  • 渲染速度快,能够利用显卡加速。

缺点

  • 也很是依赖浏览器环境,并且低版本的浏览器不支持。
  • 代码逻辑比较复杂。
  • 不方便保存和导出。

svg

优势

  • 宽泛的运行环境。浏览器、绘图工具、编辑器里均可以正常显示。
  • 良好的可编辑性。svg能够在前端经过JavaScript修改,也能够经过后端语言修改,还可让设计师经过软件修改。
  • 使用简单。svg是xml的语法,没有复杂的逻辑,全都是配置出来
  • 矢量图。相对于位图,无分辨率要求,缩放清晰。

缺点

  • 复杂图形渲染速度较慢。

小结

mxGraph默认绘制的是svg图形(看API文档和源码发现也支持canvas),因此支持后端语言进行预渲染,同时也支持保存和导出,转化为位图也很是方便。
理解了这一点,对咱们了解mxGraph的功能特性,以及修改源代码都会有帮助。浏览器

mxGraph的核心概念cell

cell这个概念能够理解成为双向数据绑定中的数据模型,咱们须要修改图形的时候,应该经过mxGraph提供的API来修改mxCell实例的属性,而后mxGraph的绘图函数来根据数据模型来修改视图。
mxGraph的其余不少概念都是以cell做为基础的:样式、布局、内容文本、事件、位置......

误区

  1. 前面提到mxGraph的图形分为两类:vertex(点)和edge(边),但实际上它们都属于mxCell类的实例,只是一些属性值不一样而已。
  2. 官方文档提供的beginUpdateendUpdate函数,写法上和数据库的事务提交很像,也有文章说是进行批量处理,实际上只是为了不屡次触发而合并了change事件而已,若是不使用这两个函数不会对绘图结果产生什么影响。至于回滚什么的那是想多了。

mxGraph的布局算法

很多开发者看到“算法”这个词就会犯怵,以为很复杂、难以理解。
但其实mxGraph的布局算法并无那么难以理解。

  • 全部的布局算法类都是“继承”自基类mxGraphLayout,自定义了一些属性,同时实现API函数execute,mxGraph在绘制图形的时候会调用这个函数。
  • 布局算法只涉及到vertex(点)的操做,当vertex(点)被调整以后,mxGraph会自动调整它们之间edge(边)的关系,或是显示隐藏或是弯曲。
  • 若是须要绘制大量的图形容易形成性能问题,不该该在算法中实现这。而能够借助mxGraph提供的几种默认方式实现:1.折叠/展开;2. 钻取/弹出;3.分层过滤显示

mxGraph的定制化

不少时候咱们还须要对mxGraph绘制的图形进行定制化开发,主要为下面几点。

样式

mxGraph对样式的支持是很是不完善的。

  • 首先不支持使用css,。这样也就意味着没法使用样式继承,样式类这些特性了。
  • 修改的时候须要经过API函数,传入JSON对象。
  • mxGraph内部操做样式的时候并无使用defs标签来声明样式类,而是直接修改标签的style、fill这些属性。这样会致使不少重复样式代码,同时不方便样式覆盖。

例以下面的代码是用来实现一个高亮样式的,若是支持CSS样式类,咱们只须要写个高亮样式,增删类名便可。
可是mxgraph就比较麻烦,要写成对象,同时在取消高亮时要手动清除对应属性。

var common_highlight = {}
common_highlight[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD
var vertex_highlight = Object.assign({}, common_highlight)
vertex_highlight[mxConstants.STYLE_FILLCOLOR] = '#00ffff'
var edge_highlight = Object.assign({}, common_highlight)
edge_highlight[mxConstants.STYLE_STROKECOLOR] = '#00ffff'
if (hover) {
  if (!state.styleList) {
    if (state.cell.edge) {
      state.styleList = new mxStylesheetList(Object.assign({}, graph.getStylesheet().styles.defaultEdge, state.style));
    } else if (state.cell.vertex) {
      state.styleList = new mxStylesheetList(Object.assign({}, graph.getStylesheet().styles.defaultVertex,
        state.style));
    }
  }
  if (state.cell.vertex && state.cell.value) {
    state.styleList.add('highlight', vertex_highlight);
  }
  if (state.cell.edge) {
    state.styleList.add('highlight', edge_highlight);
  }

} else {
  state.styleList.remove('highlight');
}
state.style = state.styleList.get();
state.shape.apply(state);
state.shape.redraw();
if (state.text != null) {
  state.text.apply(state);
  state.text.redraw();
}

HTML元素

mxGraph一个强大之处是支持在svg中插入HTML元素,官方给出的examples中有个htmllabel.html实现了相似功能。
归纳地说两步实现:

  1. 在建立点的时候插入一个 UserObject 对象声明,代表此处能够插入DOM元素。
  2. 重载 convertValueToString 函数,返回DOM元素。

相关代码以下:

var obj = doc.createElement('UserObject');
obj.setAttribute('label', 'FASTQ files');
var v1 = graph.insertVertex(col[0], null, obj, 0, 0, width, height)
...
graph.convertValueToString = function (cell) {
  let div = document.createElement('div')
  ...
  return div;
}

mxGraph的边都是自动绘制的,API支持对边的样式修改,好比箭头、粗细等。
边绘制成折线的时候为两种形式,默认是经过贝塞尔曲线绘制成带圆角的折线,另外一种是直角折线。
mxGraph内部并无对这些边进行优化,若是布局不合理,交叉、穿过点的状况就会发生。
在开发中我对边的绘制方式进行了小小的修改,统一改成直接使用三次贝塞尔曲线链接,具体代码以下:

// shap/mxShap.js
mxShape.prototype.addPoints = function(c, pts, rounded, arcSize, close, exclude, initialMove)
{
    if (pts != null && pts.length > 0)
    {
        initialMove = (initialMove != null) ? initialMove : true;
        var pe = pts[pts.length - 1];
        
        // Adds virtual waypoint in the center between start and end point
        if (close && rounded)
        {
            pts = pts.slice();
            var p0 = pts[0];
            var wp = new mxPoint(pe.x + (p0.x - pe.x) / 2, pe.y + (p0.y - pe.y) / 2);
            pts.splice(0, 0, wp);
        }
    
        var pt = pts[0];
        var i = 1;
    
        // Draws the line segments
        if (initialMove)
        {
            c.moveTo(pt.x, pt.y);
        }
        else
        {
            c.lineTo(pt.x, pt.y);
    }
    const midX = pt.x / 2 + pe.x / 2
    // 调用内置函数绘制三次贝塞尔曲线
    c.curveTo(midX, pt.y, midX, pe.y, pe.x, pe.y)
    // 忽略后面绘制折线的代码
    return;
    //...
  }

参考:

相关文章
相关标签/搜索