扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
mxGraph是一个支持多种语言(Java、JavaScript、PHP、.NET)的画图框架,所绘制的图形可以在主流浏览器以及原生应用上使用。
mxGraph官方资料全英文,网上有几篇mxGraph的教程,对于“入门”和“使用”讲解得比较详细。
所以这篇文章不是介绍如何画一个图形,写一个hello world,而是重点介绍学习mxGraph时觉得比较重要的、难以理解的或者容易被忽略的知识点。
需要读者对mxGraph的文档有一定的了解或者使用mxGraph。
mxGraph的使用场景有4个:图形可视化、图形交互、图形布局、图形分析。
图形可视化是mxGraph的主打功能,这个很好理解,就是把一些抽象的概念用图形来表示,比如常见的流程图、思维导图、实体关系图等。
需要注意的是mxGraph所绘制的图主要是由“点”(也包括矩形、圆形这类基本形状)和“边”组成的,如果要用mxGraph来画蒙娜丽莎那就肯定是不合适的。
下图是官方提供的一张样图。
作者猜测实现方式是用世界地图作为背景图片,然后在此之上绘制点和线。
为了验证猜测,访问了官方示例提供的网站,发现是一张jpg图片,而且没有连线。
可能是后端生成导出的位图,或者源图片已经被网站替换了。
mxGraph除了绘制图形之外还提供了丰富的编辑功能,比如拖拽、选择、复制、调整大小等。
mxGraph甚至还专门提供了一个API类用来支持在线编辑器。
关于这一块我没有使用~
非常重要的一个功能,能自动排列图形元素。
mxGraph提供了多种布局方式,比如树形布局、栈式布局、圆形布局。
这一块后面重点介绍。
图形分析
支持图相关的算法分析,比如找出图中两个节点的最短路径。
关于这一块我没有使用~
不过我没有找到相关API,估计需要开发者自己实现相关算法。
学习新技术或框架的时候首先需要弄清楚它是什么,能做什么。
如果和要实现的功能匹配再继续学习研究。
前端绘制图形有3种方式:
canvas使用也比较广泛,比如百度的著名开源项目echarts就是通过canvas来绘制各种图形。
mxGraph默认绘制的是svg图形(看API文档和源码发现也支持canvas),所以支持后端语言进行预渲染,同时也支持保存和导出,转化为位图也非常方便。
理解了这一点,对我们了解mxGraph的功能特性,以及修改源代码都会有帮助。
cell这个概念可以理解成为双向数据绑定中的数据模型,我们需要修改图形的时候,应该通过mxGraph提供的API来修改mxCell实例的属性,然后mxGraph的绘图函数来根据数据模型来修改视图。
mxGraph的其他很多概念都是以cell作为基础的:样式、布局、内容文本、事件、位置……
beginUpdate
和endUpdate
函数,写法上和数据库的事务提交很像,也有文章说是进行批量处理,实际上只是为了避免多次触发而合并了change事件而已,如果不使用这两个函数不会对绘图结果产生什么影响。至于回滚什么的那是想多了。不少开发者看到“算法”这个词就会犯怵,觉得很复杂、难以理解。
但其实mxGraph的布局算法并没有那么难以理解。
很多时候我们还需要对mxGraph绘制的图形进行定制化开发,主要为下面几点。
mxGraph对样式的支持是非常不完善的。
例如下面的代码是用来实现一个高亮样式的,如果支持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();
}
mxGraph一个强大之处是支持在svg中插入HTML元素,官方给出的examples中有个htmllabel.html实现了类似功能。
概括地说两步实现:
相关代码如下:
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;
//...
}
参考:
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流