【mxGraph】原始碼學習:(2)mxClient
阿新 • • 發佈:2019-02-05
1. mxClient.js檔案
mxClient.js
是客戶端的引導機制,此檔案include了執行mxGraph所需的所有原始檔,並載入了其依賴的資原始檔,以及配置了客戶端的語言。
意思就是隻要在需要使用mxGraph的地方用<script>
標籤載入mxClient.js
即可使用該庫。這是一種非常好的做法,不僅能方便的進行開發,還能提供mxClient的壓縮版本以提升載入速度。
mxClient.js
的作用如下:
- 設定載入相關檔案的全域性變數
- 設定相關路徑
- 設定客戶端語言
- 載入css檔案和js檔案
1.1 控制載入相關檔案
mxClient.js
定義了一些用於控制載入相關檔案的全域性變數:
// 用於切換<mxGraph>和<mxEditor>中兩個資原始檔的載入
// 這兩個資原始檔在resource資料夾中,如果應用已經提供則置false,參照GraphEditor
if (typeof(mxLoadResources) == 'undefined') {
mxLoadResources = true;
}
// 用於指定資原始檔的字尾。預設為.txt
if (typeof(mxResourceExtension) == 'undefined') {
mxResourceExtension = '.txt';
}
// 用於強制在開發模式下載入JavaScript檔案。預設為undefined
if (typeof(mxForceIncludes) == 'undefined') {
mxForceIncludes = false;
}
// 用於在初始化庫時切換載入CSS檔案
if (typeof(mxLoadStylesheets) == 'undefined') {
mxLoadStylesheets = true;
}
1.2 相關路徑
還需要設定一些路徑,如果沒有指定則使用預設值:
// 所有檔案的基本路徑,不帶斜槓。預設為'.'
// 在載入mxClient庫之前覆蓋此設定,比如mxBasePath='/path/to/core/directory'
if (typeof (mxBasePath) != 'undefined' && mxBasePath.length > 0) {
// 去掉斜槓
if (mxBasePath.substring(mxBasePath.length - 1) === '/') {
mxBasePath = mxBasePath.substring(0, mxBasePath.length - 1);
}
mxClient.basePath = mxBasePath;
} else {
mxClient.basePath = '.';
}
// 所有圖片的基本路徑,不帶斜槓。預設為<mxClient.basePath> + '/images'
// 在載入mxClient庫之前覆蓋此設定,比如mxImageBasePath='/path/to/image/directory'
if (typeof(mxImageBasePath) != 'undefined' && mxImageBasePath.length > 0) {
// 去掉斜槓
if (mxImageBasePath.substring(mxImageBasePath.length - 1) === '/') {
mxImageBasePath = mxImageBasePath.substring(0, mxImageBasePath.length - 1);
}
mxClient.imageBasePath = mxImageBasePath;
} else {
mxClient.imageBasePath = mxClient.basePath + '/images';
}
1.3 配置語言
還支援主動設定客戶端的語言,或者檢測瀏覽器的語言以配置其語言:
// 設定客戶端的語言,比如en表示英語,de表示德語。預設是en
// 資原始檔的格式是使用下劃線表示語言,比如graph_zh.txt
// 在載入mxClient庫之前覆蓋此設定,比如mxLanguage='en'
if (typeof(mxLanguage) != 'undefined' && mxLanguage != null) {
mxClient.language = mxLanguage;
} else {
// 在GraphEditor中必須設定mxLanguage,介面的語言才更改
mxLanguage = (mxClient.IS_IE) ? navigator.userLanguage : navigator.language;
// 中文分簡體和繁體,這裡只設置簡體
mxLanguage = (mxLanguage === 'zh-CN') ? 'zh' : mxLanguage;
mxClient.language = mxLanguage;
}
// 設定預設語言載入不帶下劃線的資原始檔。預設為en
// 在載入mxClient庫之前覆蓋此設定,比如mxDefaultLanguage='zh'
if (typeof(mxDefaultLanguage) != 'undefined' && mxDefaultLanguage != null) {
mxClient.defaultLanguage = mxDefaultLanguage;
} else {
mxClient.defaultLanguage = 'en';
}
// 設定支援的所有語言。預設語言不用新增到列表中
// 在載入mxClient庫之前覆蓋此設定,比如mxLanguages=['de','it','fr']
if (typeof(mxLanguages) != 'undefined' && mxLanguages != null) {
mxClient.languages = mxLanguages;
}
1.4 載入cs和js檔案
開發環境中,將所有程式碼分成了不同的包便於開發,還需要將它們集中在同一個檔案即mxClient.js
中,這樣可以在HTML通過匯入一個檔案而匯入整個庫:
// 匯入所有樣式和名稱空間
if (mxLoadStylesheets) {
mxClient.link('stylesheet', mxClient.basePath + '/css/common.css');
}
// 為舊的IE瀏覽器新增所需的名稱空間,樣式表和記憶體處理
if (mxClient.IS_VML) {
// 如果支援SVG則使用SVG
if (mxClient.IS_SVG) {
mxClient.IS_VML = false;
} else {
// 允許支援IE8的standards模式,這需要所有VML屬性可以直接賦值,比如node.attr=value
// 不能使用setAttribute
if (document.documentMode == 8) {
document.namespaces.add(mxClient.VML_PREFIX, 'urn:schemas-microsoft-com:vml', '#default#VML');
document.namespaces.add(mxClient.OFFICE_PREFIX, 'urn:schemas-microsoft-com:office:office', '#default#VML');
} else {
document.namespaces.add(mxClient.VML_PREFIX, 'urn:schemas-microsoft-com:vml');
document.namespaces.add(mxClient.OFFICE_PREFIX, 'urn:schemas-microsoft-com:office:office');
}
// IE中有限數量樣式表的解決方法(在標準模式下不起作用)
if (mxClient.IS_QUIRKS && document.styleSheets.length >= 30) {
(function () {
var node = document.createElement('style');
node.type = 'text/css';
node.styleSheet.cssText = mxClient.VML_PREFIX + '\\:*{behavior:url(#default#VML)}' +
mxClient.OFFICE_PREFIX + '\\:*{behavior:url(#default#VML)}';
document.getElementsByTagName('head')[0].appendChild(node);
})();
} else {
document.createStyleSheet().cssText = mxClient.VML_PREFIX + '\\:*{behavior:url(#default#VML)}' +
mxClient.OFFICE_PREFIX + '\\:*{behavior:url(#default#VML)}';
}
if (mxLoadStylesheets) {
mxClient.link('stylesheet', mxClient.basePath + '/css/explorer.css');
}
}
}
// 如果通過CommonJS載入指令碼,不要將<script>標記寫入頁面以獲取依賴項。這些已經包含在編譯版本中
if (mxForceIncludes || !(typeof module === 'object' && module.exports != null)) {
// PREPROCESSOR-REMOVE-END
mxClient.include(mxClient.basePath + '/js/util/mxLog.js');
mxClient.include(mxClient.basePath + '/js/util/mxObjectIdentity.js');
mxClient.include(mxClient.basePath + '/js/util/mxDictionary.js');
mxClient.include(mxClient.basePath + '/js/util/mxResources.js');
...
mxClient.include(mxClient.basePath + '/js/io/mxDefaultKeyHandlerCodec.js');
mxClient.include(mxClient.basePath + '/js/io/mxDefaultToolbarCodec.js');
mxClient.include(mxClient.basePath + '/js/io/mxDefaultPopupMenuCodec.js');
mxClient.include(mxClient.basePath + '/js/io/mxEditorCodec.js');
// PREPROCESSOR-REMOVE-START
}
2. mxClient類
mxClient在mxClient.js
檔案中是作為一個類定義的,主要的作用如下:
- 說明當前mxGraph的版本號
- 標識客戶端的瀏覽器和作業系統
- 定義檢查瀏覽器是否支援的函式
- 定義載入css檔案、js檔案和依賴資源的函式
- 儲存一些配置相關的變數,比如語言、路徑等
2.1 版本號
版本號說明了mxGraph庫的當前版本,格式是主版本.次版本.編譯號
,如下所示:
VERSION: '3.9.9'
2.2 標識瀏覽器
標識瀏覽器的變數如下表所示:
// IE瀏覽器
IS_IE: navigator.userAgent.indexOf('MSIE') >= 0,
IS_IE6: navigator.userAgent.indexOf('MSIE 6') >= 0,
IS_IE11: !!navigator.userAgent.match(/Trident\/7\./),
// 如果是IE瀏覽器,標識是否是Quirks模式
IS_QUIRKS: navigator.userAgent.indexOf('MSIE') >= 0 &&
(document.documentMode == null || document.documentMode == 5),
// IE11的enterprise模式(IE8的standards模式)
IS_EM: 'spellcheck' in document.createElement('textarea') &&
document.documentMode == 8,
// Edge瀏覽器
IS_EDGE: !!navigator.userAgent.match(/Edge\//),
// VML名稱空間中結點的字首,預設為v
VML_PREFIX: 'v',
// VML office命令空間中結點的字首,預設為o
OFFICE_PREFIX: 'o',
// Netscape瀏覽器(包括Firefox瀏覽器)
IS_NS: navigator.userAgent.indexOf('Mozilla/') >= 0 &&
navigator.userAgent.indexOf('MSIE') < 0 &&
navigator.userAgent.indexOf('Edge/') < 0,
// Opera瀏覽器
IS_OP: navigator.userAgent.indexOf('Opera/') >= 0 ||
navigator.userAgent.indexOf('OPR/') >= 0,
// 如果-o-transform可用作CSS樣式,則為True,即基於具有2.5或更高版本的Presto引擎的Opera瀏覽器。
IS_OT: navigator.userAgent.indexOf('Presto/') >= 0 &&
navigator.userAgent.indexOf('Presto/2.4.') < 0 &&
navigator.userAgent.indexOf('Presto/2.3.') < 0 &&
navigator.userAgent.indexOf('Presto/2.2.') < 0 &&
navigator.userAgent.indexOf('Presto/2.1.') < 0 &&
navigator.userAgent.indexOf('Presto/2.0.') < 0 &&
navigator.userAgent.indexOf('Presto/1.') < 0,
// Safari瀏覽器
IS_SF: navigator.userAgent.indexOf('AppleWebKit/') >= 0 &&
navigator.userAgent.indexOf('Chrome/') < 0 &&
navigator.userAgent.indexOf('Edge/') < 0,
// Google Chrome瀏覽器
IS_GC: navigator.userAgent.indexOf('Chrome/') >= 0 &&
navigator.userAgent.indexOf('Edge/') < 0,
// Chrome App
IS_CHROMEAPP: window.chrome != null &&
chrome.app != null &&
chrome.app.runtime != null,
// Firefox瀏覽器
IS_FF: navigator.userAgent.indexOf('Firefox/') >= 0,
// 如果-moz-transform可用作CSS樣式,則為True。
// 所有基於Firefox的瀏覽器都是3或者等於3的情況,例如Camino,Iceweasel,Seamonkey和Iceape。
IS_MT: (navigator.userAgent.indexOf('Firefox/') >= 0 &&
navigator.userAgent.indexOf('Firefox/1.') < 0 &&
navigator.userAgent.indexOf('Firefox/2.') < 0) ||
(navigator.userAgent.indexOf('Iceweasel/') >= 0 &&
navigator.userAgent.indexOf('Iceweasel/1.') < 0 &&
navigator.userAgent.indexOf('Iceweasel/2.') < 0) ||
(navigator.userAgent.indexOf('SeaMonkey/') >= 0 &&
navigator.userAgent.indexOf('SeaMonkey/1.') < 0) ||
(navigator.userAgent.indexOf('Iceape/') >= 0 &&
navigator.userAgent.indexOf('Iceape/1.') < 0),
// 瀏覽器是否支援SVG
IS_SVG: navigator.userAgent.indexOf('Firefox/') >= 0 || // FF and Camino
navigator.userAgent.indexOf('Iceweasel/') >= 0 || // Firefox on Debian
navigator.userAgent.indexOf('Seamonkey/') >= 0 || // Firefox-based
navigator.userAgent.indexOf('Iceape/') >= 0 || // Seamonkey on Debian
navigator.userAgent.indexOf('Galeon/') >= 0 || // Gnome Browser (old)
navigator.userAgent.indexOf('Epiphany/') >= 0 || // Gnome Browser (new)
navigator.userAgent.indexOf('AppleWebKit/') >= 0 || // Safari/Google Chrome
navigator.userAgent.indexOf('Gecko/') >= 0 || // Netscape/Gecko
navigator.userAgent.indexOf('Opera/') >= 0 || // Opera
(document.documentMode != null && document.documentMode >= 9), // IE9+
// 如果foreignObject支援不可用,則為True。 這是Opera,較舊的基於SVG的瀏覽器和所有版本的IE的情況。
NO_FO: !document.createElementNS ||
document.createElementNS('http://www.w3.org/2000/svg','foreignObject') !=
'[object SVGForeignObjectElement]' ||
navigator.userAgent.indexOf('Opera/') >= 0,
// 瀏覽器是否支援VML
IS_VML: navigator.appName.toUpperCase() == 'MICROSOFT INTERNET EXPLORER',
2.3 標識系統
標識系統的變數如下所示:
// iPad、iPhone和iPod平臺
IS_IOS: (navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false),
// Windows系統
IS_WIN: navigator.appVersion.indexOf('Win') > 0,
// Mac系統
IS_MAC: navigator.appVersion.indexOf('Mac') > 0,
// 如果此裝置支援touchstart/-move/-end事件,
// 啟用觸控的裝置上的Apple iOS,Android,Chromebook和Chrome瀏覽器,則為True。
IS_TOUCH: 'ontouchstart' in document.documentElement,
// 如果此裝置支援Microsoft指標事件,則為True(在Mac上始終為false)。
IS_POINTER: window.PointerEvent != null && !(navigator.appVersion.indexOf('Mac') > 0),
// 是否是本地執行(如果文件位置不以http://或https://開頭,則為True)。
IS_LOCAL: document.location.href.indexOf('http://') < 0 &&
document.location.href.indexOf('https://') < 0,
2.4 瀏覽器支援
檢查瀏覽器是否支援VML或者SVG,因為mxGraph的cell可以用VML或者SVG在畫出來,所以必須要瀏覽器支援其中一種語言:
isBrowserSupported: function () {
return mxClient.IS_VML || mxClient.IS_SVG;
},
2.5 載入檔案
mxClient類中定義了三個函式用於載入css檔案、js檔案和資原始檔。
載入css檔案到HTML的head中,link標籤的charset固定為UTF-8
,type固定為text/css
:
/**
* rel:link標籤的rel屬性
* href:link標籤的href屬性,相對路徑
* doc:可選的link標籤所屬的document
*/
link: function (rel, href, doc) {
// 使用指定的document。如果未指定,則使用當前頁面的document
doc = doc || document;
// 如果是IE6則直接在head中新增link標籤
if (mxClient.IS_IE6) {
doc.write('<link rel="' + rel + '" href="' + href + '" charset="UTF-8" type="text/css"/>');
} else {
var link = doc.createElement('link');
link.setAttribute('rel', rel);
link.setAttribute('href', href);
link.setAttribute('charset', 'UTF-8');
link.setAttribute('type', 'text/css');
var head = doc.getElementsByTagName('head')[0];
head.appendChild(link);
}
}
載入js檔案到HTML的head中,這個函式只在開發環境中使用,因為在生成環境中使用的是mxClient.min.js
,如下所示:
/**
* src:script標籤的src屬性,相對路徑
*/
include: function (src) {
document.write('<script src="' + src + '"></script>');
}
如果mxLoadResources
全域性變數為false,則使用該函式載入mxClient的依賴資源:
/**
* fn:在所有資原始檔載入之後呼叫的函式
* lan:可選的傳遞給<mxResources.add>的引數
*/
loadResources: function (fn, lan) {
// 待載入的資原始檔數
var pending = mxClient.defaultBundles.length;
// 如果沒有需要載入的資原始檔,則直接呼叫fn
function callback() {
if (--pending === 0) {
fn();
}
}
// 使用<mxResources.add>載入資原始檔
for (var i = 0; i < mxClient.defaultBundles.length; i++) {
mxResources.add(mxClient.defaultBundles[i], lan, callback);
}
}