學習 kityminder 筆記(五)

接着學習 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 元素)
}

 

(更多待學習...)

相關文章
相關標籤/搜索