接着學習 kityminder, 前面其實沒看完 kity, 大體瞭解以後, 咱們先看看 minder 部分, 二者結合起來學更好些. css
下載 kityminder-core (按文檔說只含核心部分), 從 git-hub, 創建起開發/構造環境, 打開網頁 dev.html 看
果真能出來腦圖了, 真不錯! 因而從 dev.html 網頁開始, 其先加載 kity.js, 而後經過 seajs 加載 kityminder
各個 js 模塊. 前述咱們分別簡單瞭解過 kity, seajs, 這裏就略過, 直接去 kityminder src 目錄找. html
因而找到 src/kityminder.js, 代碼大體是:
define( ... // seajs 要求的格式, CMD 規範.
kityminder = {
許多許多 module = require('...xxx.js')
}
註解說順序是有講究的 (有依賴關係的), 因此咱們也大體按照順序(大體)瞭解下各個 module. node
== core/utils.js == git
提供一組函數, 常見的如 extend, each, trim, clone 等就略了.
另有 uuid(group): 負責爲指定 group 生成下一個可用 id. 估計爲每種 svg 元素生成 id.
guid(): 生成一個相似於(像) guid 的長的隨機字符串?
咱們實驗一下, 在瀏覽器 console 輸入:
var utils = seajs.require('core/utils.js')
utils.guid() --> 打印出 `azzsqpc8jm68' (隨機的), 再來一個: `azzsqq169tz4', 前幾個字符老是 azzsq, 不太滿意吧... 數組
comparePlainObject(a,b): 比較兩個 plain 對象是否等價? 方法是用將兩個對象用 JSON 字符串化, 而後
比較兩個字符串... 我試驗了一下, 這兩個 plain-object 不等價:
var a = {x:1, y:2}, b = {y:2, x:1};
utils.comparePlainObject(a, b) --> false! 因此不要弄太刁鑽的對象...... 瀏覽器
剩下的看着也不是很重要, 暫時略... 架構
== kityminder.Minder (core/minder.js) == app
註釋說暴露在 window 上的惟一變量. 應該就是 window.km 對象. 異步
定義爲 Minder = kity.createClass(..., ctor) svg
其中這裏 ctor 不是很複雜, 也沒有別的方法, 估計會在別的模塊 extend 方法到 minder 類.
在 ctor 中使用了 initHooks[] 機制, 對每一個註冊的 init-hook 用 this 產生調用.
彷佛還有 event 機制, 在 ctor 最後使用 fire() 觸發 'finishInitHook' 事件.
可是我沒看到 Minder 類從其它類派生(這裏沒看到), 以及混入別的mixin, 那麼哪裏來的 event 機制?
也許後續的模塊 mixin 的...?
== Command (core/command.js) ==
按照架構文檔說明, abstract Command 表示一條在 KityMinder 上執行的命令.
var Command = createClass(..., {
execute: 子類必須實現.
(optional) revert: 子類可選實現, 估計用於實現 undo.
set/get ContentChanged: 設置/獲取(內容變動)狀態
set/get SelectionChanged: 相似...
以及其它幾個可選重載的函數.
});
能夠認爲這是一個接口定義: ICommand.
而後向 Minder 類擴展了幾個方法:
_getCommand(name): 獲取維護在 _commands{} 中的命令. 裏面有一堆各類命令(對象).
_queryCommand(n, t, a): 看起來像先得到 cmd, 而後調用其(可選的) query+t 方法 ...?
我找了一個 move 方法看, 裏面有 queryState, queryValue 方法... 經過這種方法調用?
queryCommandState(): 至關於調用 cmd.queryState() ...?
queryCommandValue(): 至關於 cmd.queryValue() ... 用 _queryCommand() 方法實現的.
execCommand(name): 執行指定命令.
特點是有防止重入(?), 調用命令前產生事件 `beforeExecCommand', `preExecCommand',
執行以後產生事件 `execCommand', 'contentchange'? 等.
== Node (core/node.js) ==
Node/MinderNode 表示一個腦圖節點. (這裏節點的概念是什麼呢? 一個文本框就是一個節點吧?)
var MinderNode = createClass(..., {
ctor: 建立一個遊離的腦圖節點. 看到裏面設置的數據有:
parent: 估計是父節點. 根節點的 parent=null.
children: 顧名思義, 此節點的子節點, 是一個數組.
root: 多是此圖的根節點, 若是本身是 root, 則就指向本身.
data: 某些內部數據? ctor 中看到有 guid, created(time). 可是在 DOM 中未看到? 也許被後續覆蓋了?
initContainer(): 設置一個 rc, 是一個 Group 對象. 後面看 Group 時再理解.
這裏 rc 彷佛是 RenderContainer 的縮寫, 不是 rect...
isRoot(), getRoot(), isLeaf(), getParent(), getSiblings() 等比較簡單, 就略了.
有些函數的實現看着有點那個...
getData(), setData(): 獲取/設置 this.data 中的值.
getText(), setText(): 獲取/設置節點文本.
preTraverse(): 先序(前序?)遍歷當前節點樹. 含遞歸.
postTraverse(): 後序遍歷, 遞歸的. 這裏後序遍歷指先遍歷全部子元素, 再訪問本身.
traverse(): 即後序遍歷.
大量樹有關獲取信息, 維護的函數先略了, 總之和 DOM 樹有點像就是了.
clone(): 克隆一個節點(含全部子節點).
compareTo(other): 比較 this vs. other, 用前面的 comparePlainObject()...
getMinder(): 每一個 node 都屬於且只屬於一個 minder. 新建的估計爲 null?
});
實驗: 在 console 中輸入 var node = km.getRoot() 估計獲得根節點, 類型就是 MinderNode.
向 Minder 類擴展了很多方法: {
get/setRoot(): 獲取/設置根 node.
getAllNode(), getNodeById(), create/remove/appendNode(), ... 看名字就差很少了, 略.
}
== core/option.js: 提供腦圖選項支持 ==
註冊一個 init-hook: 爲 minder 添加一個屬性 this._defaultOption={}
向 Minder 類擴展了方法: {
get/set[Default]Option() ... 看名字也就差很少了.
}
這個類這麼小, 是否有必要單獨弄一個...?
== core/animate.js 動畫控制 ==
註冊 init-hook: 根據選項 使能/禁用 animate. 這裏依賴先有 option.js 部分.
擴展 Minder 類方法 enable/disable Animation(). 簡單略.
這個類叫動畫控制, 不如叫動畫選項...
== MinderEvent(core/event.js): 表示一個腦圖中發生的事件 ==
定義類 MinderEvent = createClass(..., {
ctor(): 構造, 複雜參數先略, 可能有些事件是從 kity Event 派生的.
getPosition(): 獲取事件發生的座標?
getTargetNode(), stopPropagation(), preventDefault() ... 看起來像 DOM 事件模式.
});
使用註冊 init-hook 的方法初始化 _initEvents().
向 Minder 類擴展: {
_initEvents(), _resetEvents(): 略.
_bindEvents(): 綁定不少事件, 有 click,dblclick, mousedown, contextmenu, mouseup, mousemove
mouseover, mousewheel, DOMMousScroll (各類鼠標事件), touchxxx(觸摸屏事件), dragxxx(拖放事件)
以及整個窗口的 resize 事件. 經過一個屬性 _firePharse bind(), 稍後瞭解.
dispatchKeyEvent(): 派發鍵盤事件. 注意上面的綁定不含鍵盤事件, 也許綁定到整個頁面?
_firePharse(e): 建立 MinderEvent() 包裝原生 DOM 事件 e;
產生 before+e, pre+e, e, after+e 事件調用序列. 看到要建立大量事件對象, 我擔憂是否有必要...
_interactChange(e): 彷佛是異步觸發一個 'interactchange' 事件. 估計是當前不方便馬上執行, 須要
在下一個空閒(timeout) 時間執行.
_listen(): 註冊指定類型的(腦圖)事件的回調(偵聽).
_fire(): 根據腦圖事件類型, 找到註冊的回調函數(數組), 產生回調. (有些 status, propagation 部分暫略).
on(), off(), fire(): 事件相關別名/包裝.
}
這裏也回答了前面的問題, 即 Minder 的 event 從哪裏來的問題.
== core/compatibility.js ==
處理腦圖數據從低版本到當前版本升級.
== core/keymap.js ==
鍵的名字(如 Escape) 到值(如=27) 的映射表的創建.
== core/shortcut.js 快捷鍵支持 ==
向 MinderEvent 擴展 isShortcutKey() 方法: 其根據 metakey? 判斷是不是快捷鍵.
註冊 init-hook: 初始化 shortcut-key 支持.
向 Minder 類擴展方法: {
_initShortcutKey(), _bindShortcutKey(): 綁定 'keydown' 事件, 事件發生時查找綁定於該鍵的處理函數,
並調用它. 實際看了一下, 大約有 backspace, del, enter, tab 等20個鍵盤快捷鍵.
addShortcut(keys, fn): 添加對 keys(可空格分隔多個) 快捷鍵的回調函數 fn. 用 '::' 分隔表示某種東西暫略.
get/addCommandShortcutKeys(cmd, keys): 多是快捷鍵 keys 和命令 cmd 綁定起來.
查看了一下, 若有 bold='ctrl+b', appendchildnode='normal::Insert|Tab' etc.
supportClipboardEvent(): 判斷是否支持原生 clipboard.
== core/status.js 狀態切換控制 ==
向 Minder 類擴展: {
_initStatus(): 此爲 init-hook, 初始化兩個成員變量值.
get/setStatus(): 獲取/設置狀態. 狀態的變化引起 'statuschange' 事件.
rollbackStatus(): 設置狀態爲 _rollbackStatus, 略.
}
彷佛意味着狀態(status)能切換到其它值, 並支持 rollback 狀態. 但只能 rollback 一次, 是什麼意圖呢?
== paper.js: 初始化渲染容器 ==
向 Minder 類擴展方法: {
_initPaper(): 此爲 init-hook 方法. 建立 this._paper = new kity.Paper() 並設置一些東西,
建立根節點, 建立 render-container 等.
get/_addRenderContainer(): 建立 kity.Group() 應該是 <g> 元素 做爲 render-container.
通過查看, 在 svg 元素下面有 g#kity_g_8 元素下面有 g#minder1 元素, 估計是此處建立的 rc.
renderTo(): 估計是將 minder 渲染(放置)到指定 div 元素(容器), 產生事件 paperrender.
getPaper(), getRenderTarget(): 略.
}
這裏把 minder 和 paper 關聯起來.
== select.js 選區管理 ==
向 Minder 類擴展: {
_initSelection(): 此爲 init-hook 方法.
renderChangedSelection(): 若是選擇的元素集合發生了變化則產生事件 'selectionchange'.
並對每一個改變了的元素(節點)調用 render() 方法.
getSelectedNodes(): 獲得當前被選中的節點(數組引用).
getSelectedNode(): 單數的, 獲得第一個被選中的節點, 沒有則爲 null.
removeAllSelectedNodes(): 清空被選中, 產生事件 'selectionclear'.
removeSelectedNodes(): 清除部分被選中..
select(): 選中指定節點s. selectById() 類似.
toggleSelect(): 略. (有註解)
getSelectedAncestors(): 彷佛是找被選中節點的祖先節點?
}
向 MinderNode 擴展方法 isSelected(): 判斷是否被選中.
我是設置一個標誌到 node 中的...
== core/focus.js ==
註冊 init-hook: 綁定事件 'beforemousedown', 'paperrender'.
擴展 Minder 類: {
focus(): 設置焦點給此 minder, 產生 'focus' 事件.
blur(): 取消焦點, 產生 'blur' 事件.
isFocused(): 斷定. 方法是將 'focus' css 類名添加/刪除自 renderTarget(g 元素)
}
(更多待學習...)