mxGraph源码学习:mxClient

Posted remo0x

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mxGraph源码学习:mxClient相关的知识,希望对你有一定的参考价值。

1. mxClient.js文件

mxClient.js是客户端的引导机制,此文件include了运行mxGraph所需的所有源文件,并加载了其依赖的资源文件,以及配置了客户端的语言。

意思就是只要在需要使用mxGraph的地方用<script>标签加载mxClient.js即可使用该库。这是一种非常好的做法,不仅能方便的进行开发,还能提供mxClient的压缩版本以提升加载速度。

mxClient.js的作用如下:

  1. 设置加载相关文件的全局变量
  2. 设置相关路径
  3. 设置客户端语言
  4. 加载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文件中是作为一个类定义的,主要的作用如下:

  1. 说明当前mxGraph的版本号
  2. 标识客户端的浏览器和操作系统
  3. 定义检查浏览器是否支持的函数
  4. 定义加载css文件、js文件和依赖资源的函数
  5. 保存一些配置相关的变量,比如语言、路径等

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) 
	// 待加载的资源

以上是关于mxGraph源码学习:mxClient的主要内容,如果未能解决你的问题,请参考以下文章

mxGraph源码学习:mxGraph库

mxGraph源码学习:mxGraph

mxGraph源码学习:mxGraph

mxGraph源码学习:mxEventSource

mxGraph源码学习:mxCell

mxGraph源码学习:mxCell