mxGraph源码学习:mxGraphModel
Posted remo0x
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mxGraph源码学习:mxGraphModel相关的知识,希望对你有一定的参考价值。
1. 概览
mxGraphModel继承自mxEventSource以实现graph model。graph model是负责存储graph数据结构的包装器。graph model充当事务包装器,其中包含所有更改的事件通知,而cell包含用于更新实际数据结构的原子操作。
1.1 图层
模型中的cell层次结构必须具有顶级根cell,其中包含图层(通常是一个默认图层),而这些图层又包含图层的顶级cell。这意味着每个cell都包含在一个图层中。如果不需要图层,则应将所有新cell添加到默认图层。
图层可用于隐藏和显示cell组,或用于将cell组放置在显示中的其他cell之上。要识别图层,可以使用isLayer方法。如果给定cell的父级是模型的根,则返回true。
1.2 事件
有关详细信息,参阅事件部分。有一组新事件可用于跟踪事件发生的变化。这些事件称为初始beginUpdate的startEdit,为每个执行的更改执行,endEdit为endUpdate执行。执行的事件包含一个名为change的属性,表示执行后的更改。
1.3 编码模型
使用如下代码编码graph model,这将创建一个包含所有模型信息的XML节点:
var enc = new mxCodec();
var node = enc.encode(graph.getModel());
对于更改的编码,需要graph model监听器来编码来自给定更改数组的每个更改:
model.addListener(mxEvent.CHANGE, function(sender, evt)
var changes = evt.getProperty('edit').changes;
var nodes = [];
var codec = new mxCodec();
for (var i = 0; i < changes.length; i++)
nodes.push(codec.encode(changes[i]));
// do something with the nodes
);
对于解码和执行更改,编解码器需要一个查找功能,允许它按如下方式解析单元ID:
var codec = new mxCodec();
codec.lookup = function(id)
return model.getCell(id);
对于每个编码的变化(由节点表示),可以使用以下代码来执行解码并创建变更对象:
var changes = [];
var change = codec.decode(node);
change.model = model;
change.execute();
changes.push(change);
然后可以使用模型如下调度更改:
var edit = new mxUndoableEdit(model, false);
edit.changes = changes;
edit.notify = function()
edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
'edit', edit, 'changes', edit.changes));
edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
'edit', edit, 'changes', edit.changes));
model.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
model.fireEvent(new mxEventObject(mxEvent.CHANGE,
'edit', edit, 'changes', changes));
2. 构造
mxGraphModel的构造函数如下:
/**
* root - 表示根cell的mxCell
*/
function mxGraphModel(root)
this.currentEdit = this.createUndoableEdit();
if (root != null)
this.setRoot(root);
else
this.clear();
mxGraphModel与mxGraph一样,都是采用原型链方式继承自mxEventSource:
mxGraphModel.prototype = new mxEventSource();
mxGraphModel.prototype.constructor = mxGraphModel;
3. 原型属性
下面列举一些重要的原型属性:
// 保存根cell,而根cell又包含表示图层作为子cell的cell。也就是说,图中的实际元素应该存在于第三代cell中
mxGraphModel.prototype.root = null;
// 从id到cell的map
mxGraphModel.prototype.cells = null;
// 指定下一个被创建的id。初始值为0
mxGraphModel.prototype.nextId = 0;
// 保存当前事务的更改。如果事务已关闭,则使用createUndoableEdit为此变量创建新对象
mxGraphModel.prototype.currentEdit = null;
// 计算嵌套事务的深度。每次调用beginUpdate都会增加这个数字,每次调用endUpdate都会减少它
// 当计数器达到0时,事务将关闭并触发相应的事件。初始值为0
mxGraphModel.prototype.updateLevel = 0;
4. 原型方法
mxGraphModel中有许多原型方法和类,这里选择一些了解其联系及实现
4.1 创建根cell
创建根cell有两种方式,第一种就是在创建mxGraphModel时指定一个cell作为根cell,如果没有指定,则使用第二种方法,如下所示。
调用createRoot方法创建一个根cell,然后设置为当前model的根cell,并会触发根cell更改的事件:
/**
* 调用createRoot创建一个根cell
*/
mxGraphModel.prototype.clear = function ()
this.setRoot(this.createRoot());
;
/**
* 使用默认图层(第一个cell)创建新的根cell
*/
mxGraphModel.prototype.createRoot = function ()
var cell = new mxCell();
cell.insert(new mxCell());
return cell;
;
/**
* 使用mxRootChange设置模型的root,并将更改添加到当前事务。
* 这将重置模型中的所有数据结构,并且是清除现有模型的首选方法。返回新根。
*
* root - 根cell
*/
mxGraphModel.prototype.setRoot = function (root)
this.execute(new mxRootChange(this, root));
return root;
;
/**
* 如果需要,执行给定的编辑并触发事件。编辑对象需要一个被调用的执行函数。编辑将添加到beginUpdate
* 和endUpdate调用之间的currentEdit,以便在此执行是单个事务时触发事件,即如果没有调用
* endUpdate之前没有调用startUpdate调用。此实现在执行给定更改之前触发execute事件。
*
* change - 描述更改的对象。
*/
mxGraphModel.prototype.execute = function (change)
change.execute();
this.beginUpdate();
this.currentEdit.add(change);
this.fireEvent(new mxEventObject(mxEvent.EXECUTE, 'change', change));
// 新的全局执行事件
this.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
this.endUpdate();
;
设置新的根cell时,是通过创建一个新的mxRootChange来实现的:
/**
* 更改模型中的根的操作。
* 通过构造函数指定模型中根的更改。
*/
function mxRootChange(model, root)
this.model = model;
this.root = root;
this.previous = root;
/**
* 使用mxGraphModel.rootChanged执行根的更改
*/
mxRootChange.prototype.execute = function ()
this.root = this.previous;
this.previous = this.model.rootChanged(this.previous);
;
/**
* 内部回调以更改模型的根并更新内部数据结构,例如cells和nextId。返回先前的根。
*
* root - 根cell
*/
mxGraphModel.prototype.rootChanged = function (root)
var oldRoot = this.root;
this.root = root;
// 重置计数器和数据结构
this.nextId = 0;
this.cells = null;
this.cellAdded(root);
return oldRoot;
;
4.2 事务管理
mxGraphModel的事务管理简单而强大,主要通过beginUpdate和endUpdate实现:
/**
* 将updateLevel加1。事件通知排队,直到updateLevel使用endUpdate减到0。
*/
mxGraphModel.prototype.beginUpdate = function ()
this.updateLevel++;
this.fireEvent(new mxEventObject(mxEvent.BEGIN_UPDATE));
if (this.updateLevel === 1)
this.fireEvent(new mxEventObject(mxEvent.START_EDIT));
;
/**
* 将updateLevel减1,并在updateLevel减到0时触发undo事件。此函数通过调用currentEdit
* 上的notify方法间接触发change事件,然后使用createUndoableEdit创建新的currentEdit。
*
* 每次编辑时只会触发一次undo事件,而每当调用notify函数时,都会触发change事件,即在编辑的
* 撤消和重做时触发。
*/
mxGraphModel.prototype.endUpdate = function ()
this.updateLevel--;
if (this.updateLevel === 0)
this.fireEvent(new mxEventObject(mxEvent.END_EDIT));
if (!this.endingUpdate)
this.endingUpdate = this.updateLevel === 0;
this.fireEvent(new mxEventObject(mxEvent.END_UPDATE, 'edit', this.currentEdit));
try
if (this.endingUpdate && !this.currentEdit.isEmpty())
this.fireEvent(new mxEventObject(mxEvent.BEFORE_UNDO, 'edit', this.currentEdit));
var tmp = this.currentEdit;
this.currentEdit = this.createUndoableEdit();
tmp.notify();
this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', tmp));
finally
this.endingUpdate = false;
;
/**
* 创建一个新的mxUndoableEdit,它实现notify方法以通过mxUndoableEdit的源触发change和notify事件。
*
* significant - 可选布尔值,指定要创建的编辑是否重要。默认为true。
*/
mxGraphModel.prototype.createUndoableEdit = function (significant)
var edit = new mxUndoableEdit(this, (significant != null) ? significant : true);
edit.notify = function ()
// LATER: Remove changes property (deprecated)
edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
'edit', edit, 'changes', edit.changes));
edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
'edit', edit, 'changes', edit.changes));
;
return edit;
;
以上是关于mxGraph源码学习:mxGraphModel的主要内容,如果未能解决你的问题,请参考以下文章