【mxGraph】原始碼學習:(6)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】原始碼學習:(6)mxGraphModel
1. 概覽 mxGraphModel繼承自mxEventSource以實現graph model。graph model是負責儲存graph資料結構的包裝器。graph model充當事務包裝器,其中包含所有更改的事件通知,而cell包含用於更新實際資料結構的原
【mxGraph】原始碼學習:(5)mxGraph
由於mxGraph原始檔有一萬多行,且涉及很多其它原始檔,所以重點在於瞭解mxGraph的作用、結構以及定義了哪些方法 1. 概覽 1.1 作用 mxGraph繼承自mxEventSource以實現基於Web的圖形元件的功能性方面。要啟用平移和連線,使用se
【mxGraph】原始碼學習:(7)mxCell
1. 概覽 mxCell是graph model的元素。它們表示graph中的group、vertex和edge的狀態。 對於自定義屬性,建議使用XML節點作為cell的值。以下程式碼可用於建立具有XML節點的cell作為值: var doc = mxUtils
【mxGraph】原始碼學習:(2)mxClient
1. mxClient.js檔案 mxClient.js是客戶端的引導機制,此檔案include了執行mxGraph所需的所有原始檔,並載入了其依賴的資原始檔,以及配置了客戶端的語言。 意思就是隻要在需要使用mxGraph的地方用<script>標籤
【機器人學】機器人開源專案KDL原始碼學習:(6)笛卡爾空間軌跡規劃、圓弧過渡、姿態插值、梯形速度、pathlength
本文的內容是對另一篇文章(連結)的補充,對Trajectory_example.cpp涉及到的原理作一些簡單的講解,主要內容是: (1)機器人路徑規劃圓弧過渡的原理; (2)機器人路徑規劃梯形波的原理; (3)機器人末端姿態插值的方法(角-軸); (4)KDL
【機器人學】機器人開源專案KDL原始碼學習:(8)KDL的精髓
首先說一下我的心得: 1. 我認為KDL的精髓是Spatial Vector,結合C++等面向物件的語言可以寫出較好的軟體。 2. 直接閱讀KDL程式碼不適合初學者學習機械臂動力學。 3. 要學習機械臂動力學的話應首先閱讀使用3維向量推導公式的文獻,也就是線速度和角速度獨立分析
【機器人學】機器人開源專案KDL原始碼學習:(4)機械臂逆動力學的牛頓尤拉演算法
機械臂的逆動力學問題可以認為是:已知機械臂各個連桿的關節的運動(關節位移、關節速度和關節加速度),求產生這個加速度響應所需要的力/力矩。KDL提供了兩個求解逆動力學的求解器,其中一個是牛頓尤拉法,這個方法是最簡單和高效的方法。 牛頓尤拉法演算法可以分為三個步驟: step1:
【機器人學】機器人開源專案KDL原始碼學習:(7)examples中的CMakeList.txt檔案解讀
通過學習KDL開源專案的程式碼可以學習CMake構建程式的知識,現簡單介紹一下orocos_kinematics_dynamics-master\orocos_kinematics_dynamics-master\orocos_kdl\examples\CMakeList.txt檔案的指令。
【機器人學】機器人開源專案KDL原始碼學習:(5)KDL如何求解幾何雅克比矩陣
這篇文章試圖說清楚兩件事:1. 幾何雅克比矩陣的本質;2. KDL如何求解機械臂的幾何雅克比矩陣。 一、幾何雅克比矩陣的本質 機械臂的關節空間的速度可以對映到執行器末端在操作空間的速度,這種對映可以通過一個矩陣來描述,就是幾何雅克比矩陣,瞭解雅克比矩陣需要了解這種對映關係的本質,這
【機器人學】機器人開源專案KDL原始碼學習:(3)機器人操作空間路徑規劃(Path Planning)和軌跡規劃(Trajectory Planning)示例
很多同學會把路徑規劃(Path Planning)和軌跡規劃(Trajectory Planning)這兩個概念混淆,路徑規劃只是表示了機械臂末端在操作空間中的幾何資訊,比如從工作臺的一端(A點)沿直線移動到另一端(B點)。而軌跡規劃則加上了時間律,比如它要完成的任務是從A點開始到B點結束,中間
【轉】Nodejs學習筆記(一)--- 簡介及安裝Node.js開發環境
ack 目錄 javascrip 難度 時間 網站開發 clas jetbrains 常用 目錄 學習資料 簡介 安裝Node.js npm簡介 開發工具 Sublime Node.js開發環境配置 擴展:安裝多版本管理器 學習資料 1.深入淺出Node.j
【ADNI】資料預處理(6)ADNI_slice_dataloader ||| show image
ADNI Series 1、【ADNI】資料預處理(1)SPM,CAT12 2、【ADNI】資料預處理(2)獲取 subject slices 3、【ADNI】資料預處理(3)CNNs 4、【ADNI】資料預處理(4)Get top k slices according to CNN
【原創】VBA學習筆記(2)--例項,VBA刪除表中的空行
Sub 巨集1迴圈內刪列() '資料不規範,有的空行是4,有的是6,有的是1就不好處理了 For i = 15 To 100 Step 2 Rows(i).Delete Shift:=xlUp &nb
【原創】python學習筆記(10)--《笨辦法學python》字串處理
字串基本操作 (1) 字串+字串 (2)字串*數字 (3)字串+str(其他) # -*- coding:utf-8 -*- print ("test1") name1="alice" name2="bob" name_new=name1+name2 print
【整理】python學習筆記(5)-- pygame庫的函式和方法整理
PYGAME的方法和官方文件查詢 官方文件 http://www.pygame.org/docs/ 模組 簡介 pygame.BufferProxy An array protocol view
【原創】pygame學習筆記(4)----一個打飛機遊戲
根據資料學習,程式碼是在資料的基礎上,重新打的,有部分修改。 轉載資料來源:-will https://www.cnblogs.com/wuzhanpeng/p/4261015.html http://eyehere.net/2011/python-pygame-n
【原創】pygame學習筆記(3)--triviagame答題遊戲
一 容易出錯的地方 def _init_(self,name,score) 要記住, __init__ 前後都是兩個下劃線,而不只是1個下劃線 二 程式碼測試 顯示效果正常了,可以玩了 現在題目會迴圈玩 # -*- coding:utf
【原創】pygame學習筆記(2)----pie遊戲(需優化)
測試程式碼情況 (1)做到了弧形可以按出來 (2)數字的顯示正確 (3)出的一些低階錯誤 temp:\\pygame2.txt 這樣的錯誤, temp\\pygame2.txt 導致 這樣的錯誤,
【原創】pygame學習筆記(1)----基本的線,矩形,圓形,弧形繪製
PYgame的內容 (1)這個module很有意思 (2)書本至少來源於《Python遊戲程式設計入門》 (3)官方權威說明:https://www.pygame.org/docs/ 下面的嘗試把各種圖形在一個程式裡繪製 注意點: (1)特別注意,比如引
【原創】python學習筆記(5)--《笨辦法學python》,指令碼帶引數
一 指令碼檔案 (1) 簡單的說就是一段自己寫的,可執行的程式碼,否則會報錯 (2)簡單指令碼,直接 python xxx1.py (3)帶引數指令碼,需要 python xxx2.py argv1 argv2 argv3 根據指令碼引數的數量,