mxGraph 是一个JS的Graph库,提供基础的API,并不是一个开箱即用的产品,它不同于一般的Chart库,虽然有很多相似的地方。包括以下特点:
包含的组件如下:
一般的Chart包括了饼图,线图等,但Graph意指所有的图形。它由节点和线组成,Graph中包含的各个元素都可以称为Cell,Cell可以是节点,线或者分组。Graph提供很广泛的显示元素,节点可以是shape,图形,动画,和浏览器中任何可视化的内容。
Graph支持拖动,克隆,改变大小或者重新resize,链接或者断开链接,也可以拖入外部图片,并且在交互方面提供了可编程的方式来增加灵活性。许多复杂的应用程序都依赖于服务器的相应来构造客户端的显示,同时交互的事件也会依赖于这种方式。尽管可以通过ajax的方式来支持,但是这样强依赖服务器端的交互并不适合强交互的应用,每次交互可能都需要花费0.2s的时间,这对于客户端的用户体验并不是很好。将所有的交互放在客户端,可以提供作为一个完整应用的体验,而不是仅仅是一个远程使用端,同时也支持离线应用。
Graph可以被画在任何一个应用程序中,这里涉及到一个布局计算问题,对于非编辑型的图表,这个应用程序仅处理布局算法进行展示,对于交互性的图表,那些可以被编辑的节点,要允许用户可以编辑,同时在编辑之后,还可以应用布局算法来重新计算布局的展现。算法的分析上决定了算法中的很多结构上的细节,比如两个节点间的最短路径等。
mGraph和其他框架整合非常简单,他只需要一个DIV,初次之外不会对界面的其他部门产生影响,它有自己的事件系统,页面的其他部门甚至可以有自己的事件系统,这些都无所谓的。
扩展mGraph遵循两个原则:
mxGraphModel模型描述了图形的结构,提供了改变和删除模型结构的方法,也提供了改变模型状态的方法,比如可见性,分组和样式等。尽管这些处理方法属于模型的职能,但这些方法在mxGraph上也都存在对应的公共接口,这是因为从业务上更好理解:”增加元素到图形中“而不是增加元素到图形模型中。因此在模型上的这些方法在mxGraph都会存在一份调用拷贝。尽管许多外部api的调用用的是mxGraph,但一定要记住,隐藏在下面的实际上是mxGraphModel。
mxGraph提供了一系列事务性的方法来对模型进行改变,比如下面的例子:
// Adds cells to the model in a single step
graph.getModel().beginUpdate();
try
{
var v1 = graph.addVertex(parent, null, 'Hello,', 20, 20, 80, 30);
var v2 = graph.addVertex(parent, null, 'World!', 200, 150, 80, 30);
var e1 = graph.addEdge(parent, null, '', v1, v2);
}
finally
{
// Updates the display
graph.getModel().endUpdate();
}
对graph的模型进行更改时,必须以beginUpdate开始,然后以endUpdate结束。最主要的方法包括:
mGraph同时支持子事务的更新,事务性的代码可以嵌套。在模型中存在一个计数器,当遇到一个beginUpdate时,会加1,当遇到endUpdate时会减1。当减到1的时候,count为0,整个模型的事务性代码完成提交并进行模型改变的事件性通知。这种方式带来的好处是可以对所有的更改只发送一个事件,也可以每次改变发送一个事件,对于undo的处理也更加的细分化。
在自动布局中,用户的改变会根据某种算法来重新排列,在begin&end之间的代码会被直接操纵在模型上,布局就可以一次性的操作模型的状态,可以减少重绘的过程。当endupdate调用的时候,模型改变的事件会被触发,此时在事件中就可以一次性的拿到所有模型改变的状态来进行处理。
下面是一系列的模型改变方法:
初次之外,还有两个重要的方法,下面两个方法都被包含在begin&update中。
mxCell是节点和线的通用类,他也像模型一样,提供了一个通用的操作方法。最大的不同是,使用模型的方法可以触发事件通知和undo操作,使用cell的方法不会记录这些内容。但是这对于一些可视化的行为,比如动画,鼠标操作等是非常有用的。作为一个通用的机制,建议统一使用model上的api,而不是cell中的api。
Sytles类似于CSS,他是一个hashtable结构,默认提供了defaultVertex和defaultEdge样式,可以对其进行修改。设置样式可以使用setStyle方法,也可以在insertVertex的时候插入样式。核心的方法包括:
var style = new Object();
style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
style[mxConstants.STYLE_OPACITY] = 50;
style[mxConstants.STYLE_FONTCOLOR]= '#774400';
graph.getStylesheet().putCellStyle('ROUNDED',style);
mxGeometry属性单独存放而不是存在mxGeometry的类中是因为线条也有几何属性,线条的宽度和高度经常被忽略,初次之外,还包括线上label的相对位置,线还有控制点的概念。
坐标在无关位置:
x和y是相对父容器的定位位置,这里不讨论parent和分组的概念,如果没有parent,x和y就是相对于整个graph的定位。
上图中可以看出,子节点相对于父节点的xy值。
而线条中的lable却是绝对定位的,xy分别到线中坐标的左上角。
坐标在相关位置:
如果相对模式下,xy是父节点的百分比。(0,0)和父容器左上角同源,(1,1)和父容器的右下角同源。这种方式可以同父元素的比例保持一个很好的固定大小比例关系。
线上的label是从线的中点开始定位的。x轴是从线开始的相对距离,y轴是线直角的相对距离。
UserObject就是存放在节点总的数据,支持从和服务器端进行交互。还有一个cellType的问题。可以存放任何的对象。
mxGraph中有一个分组的概念,其他的产品中叫做子图,从数据结构上来说,他通常包含了一个或者多个元素。分组有以下特点:
一个图中的节点不能太多,一个是性能问题,一个是用户的使用问题。
相关函数:
核心的api包括
有个概念是z-order,类似于中css中的在z-index. 核心的api包括:
通过分组和分层可以让你的图标从逻辑上更加简单。