百度地圖測量工具(DistanceTool.js)在多個地圖上使用錯誤問題

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>百度地圖測量工具測試</title>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.2"></script>
    <script type="text/javascript"
            src="http://api.map.baidu.com/getscript?v=1.2&amp;ak=&amp;services=&amp;t=20130716024057"></script>
    <link rel="stylesheet" type="text/css" href="http://api.map.baidu.com/res/12/bmap.css">
    <script type="text/javascript"
            src="http://api.map.baidu.com/library/DistanceTool/1.2/src/DistanceTool_min.js"></script>
</head>
<body>
<div id="container" style="width: 100%; height: 340px; margin-bottom:20px"></div>
<div id="container1" style="width: 100%; height: 340px;"></div>
<script type="text/javascript">

    var map = new BMap.Map("container");
    var map1 = new BMap.Map("container1");
    map.centerAndZoom(new BMap.Point(116.404, 39.915), 15);
    map1.centerAndZoom(new BMap.Point(116.404, 39.915), 15);
    var myDis = new BMapLib.DistanceTool(map);

    //開始測量
    myDis.open();
    //結束測量
    myDis.close();

    //在第二個地圖上使用測量工具
    var myDis1 = new BMapLib.DistanceTool(map1);
    //開始測量
    myDis1.open();

</script>
</body>
</html>

以上代碼是同時在兩個地圖上使用測量工具,運行效果如下圖所示

代碼的本意是在第二個地圖開啓測量工具,但是卻需要在第一個地圖上點擊才能進行測量。

修改DistanceTool.js後的效果

修改代碼的邏輯就不分析了(因爲我也忘了,也懶得去看了,因爲這個用得也不多,該文章只是做個記錄),附上修改後的JS文件

/**
 * @fileoverview 百度地圖的測距工具類,對外開放。
 * 允許用戶在地圖上點擊完成距離的測量。
 * 使用者可以自定義測距線段的相關樣式,例如線寬、顏色、測距結果所用的單位制等等。
 * 主入口類是<a href="symbols/BMapLib.DistanceTool.html">DistanceTool</a>,
 * 基於Baidu Map API 1.2。
 *
 * @author Baidu Map Api Group 
 * @version 1.2
 */

/** 
 * @namespace BMap的所有library類均放在BMapLib命名空間下
 */
var BMapLib = window.BMapLib = BMapLib || {};

(function() {
    /**
     * 聲明baidu包
     */
    var baidu = baidu || {guid : "$BAIDU$"};
    (function() {
        // 一些頁面級別唯一的屬性,需要掛載在window[baidu.guid]上
        window[baidu.guid] = {};

        /**
         * 將源對象的所有屬性拷貝到目標對象中
         * @name baidu.extend
         * @function
         * @grammar baidu.extend(target, source)
         * @param {Object} target 目標對象
         * @param {Object} source 源對象
         * @returns {Object} 目標對象
         */
        baidu.extend = function (target, source) {
            for (var p in source) {
                if (source.hasOwnProperty(p)) {
                    target[p] = source[p];
                }
            }    
            return target;
        };

        /**
         * @ignore
         * @namespace
         * @baidu.lang 對語言層面的封裝,包括類型判斷、模塊擴展、繼承基類以及對象自定義事件的支持。
         * @property guid 對象的唯一標識
        */
        baidu.lang = baidu.lang || {};

        /**
         * 返回一個當前頁面的唯一標識字符串。
         * @function
         * @grammar baidu.lang.guid()
         * @returns {String} 當前頁面的唯一標識字符串
         */
        baidu.lang.guid = function() {
            return "TANGRAM__" + (window[baidu.guid]._counter ++).toString(36);
        };

        window[baidu.guid]._counter = window[baidu.guid]._counter || 1;

        /**
         * 所有類的實例的容器
         * key爲每個實例的guid
         */
        window[baidu.guid]._instances = window[baidu.guid]._instances || {};

        /**
         * Tangram繼承機制提供的一個基類,用戶可以通過繼承baidu.lang.Class來獲取它的屬性及方法。
         * @function
         * @name baidu.lang.Class
         * @grammar baidu.lang.Class(guid)
         * @param {string} guid	對象的唯一標識
         * @meta standard
         * @remark baidu.lang.Class和它的子類的實例均包含一個全局唯一的標識guid。
         * guid是在構造函數中生成的,因此,繼承自baidu.lang.Class的類應該直接或者間接調用它的構造函數。<br>
         * baidu.lang.Class的構造函數中產生guid的方式可以保證guid的唯一性,及每個實例都有一個全局唯一的guid。
         */
        baidu.lang.Class = function(guid) {
            this.guid = guid || baidu.lang.guid();
            window[baidu.guid]._instances[this.guid] = this;
        };

        window[baidu.guid]._instances = window[baidu.guid]._instances || {};

        /**
         * 判斷目標參數是否string類型或String對象
         * @name baidu.lang.isString
         * @function
         * @grammar baidu.lang.isString(source)
         * @param {Any} source 目標參數
         * @shortcut isString
         * @meta standard
         *             
         * @returns {boolean} 類型判斷結果
         */
        baidu.lang.isString = function (source) {
            return '[object String]' == Object.prototype.toString.call(source);
        };

        /**
         * 判斷目標參數是否爲function或Function實例
         * @name baidu.lang.isFunction
         * @function
         * @grammar baidu.lang.isFunction(source)
         * @param {Any} source 目標參數
         * @returns {boolean} 類型判斷結果
         */
        baidu.lang.isFunction = function (source) {
            return '[object Function]' == Object.prototype.toString.call(source);
        };

        /**
         * 重載了默認的toString方法,使得返回信息更加準確一些。
         * @return {string} 對象的String表示形式
         */
        baidu.lang.Class.prototype.toString = function(){
            return "[object " + (this._className || "Object" ) + "]";
        };

        /**
         * 釋放對象所持有的資源,主要是自定義事件。
         * @name dispose
         * @grammar obj.dispose()
         */
        baidu.lang.Class.prototype.dispose = function(){
            delete window[baidu.guid]._instances[this.guid];
            for(var property in this){
                if (!baidu.lang.isFunction(this[property])) {
                    delete this[property];
                }
            }
            this.disposed = true;
        };

        /**
         * 自定義的事件對象。
         * @function
         * @name baidu.lang.Event
         * @grammar baidu.lang.Event(type[, target])
         * @param {string} type	 事件類型名稱。爲了方便區分事件和一個普通的方法,事件類型名稱必須以"on"(小寫)開頭。
         * @param {Object} [target]觸發事件的對象
         * @meta standard
         * @remark 引入該模塊,會自動爲Class引入3個事件擴展方法:addEventListener、removeEventListener和dispatchEvent。
         * @see baidu.lang.Class
         */
        baidu.lang.Event = function (type, target) {
            this.type = type;
            this.returnValue = true;
            this.target = target || null;
            this.currentTarget = null;
        };

        /**
         * 註冊對象的事件監聽器。引入baidu.lang.Event後,Class的子類實例纔會獲得該方法。
         * @grammar obj.addEventListener(type, handler[, key])
         * @param 	{string}   type         自定義事件的名稱
         * @param 	{Function} handler      自定義事件被觸發時應該調用的回調函數
         * @param 	{string}   [key]		爲事件監聽函數指定的名稱,可在移除時使用。如果不提供,方法會默認爲它生成一個全局唯一的key。
         * @remark 	事件類型區分大小寫。如果自定義事件名稱不是以小寫"on"開頭,該方法會給它加上"on"再進行判斷,即"click"和"onclick"會被認爲是同一種事件。 
         */
        baidu.lang.Class.prototype.addEventListener = function (type, handler, key) {
            if (!baidu.lang.isFunction(handler)) {
                return;
            }
            !this.__listeners && (this.__listeners = {});
            var t = this.__listeners, id;
            if (typeof key == "string" && key) {
                if (/[^\w\-]/.test(key)) {
                    throw("nonstandard key:" + key);
                } else {
                    handler.hashCode = key; 
                    id = key;
                }
            }
            type.indexOf("on") != 0 && (type = "on" + type);
            typeof t[type] != "object" && (t[type] = {});
            id = id || baidu.lang.guid();
            handler.hashCode = id;
            t[type][id] = handler;
        };
         
        /**
         * 移除對象的事件監聽器。引入baidu.lang.Event後,Class的子類實例纔會獲得該方法。
         * @grammar obj.removeEventListener(type, handler)
         * @param {string}   type     事件類型
         * @param {Function|string} handler  要移除的事件監聽函數或者監聽函數的key
         * @remark 	如果第二個參數handler沒有被綁定到對應的自定義事件中,什麼也不做。
         */
        baidu.lang.Class.prototype.removeEventListener = function (type, handler) {
            if (baidu.lang.isFunction(handler)) {
                handler = handler.hashCode;
            } else if (!baidu.lang.isString(handler)) {
                return;
            }
            !this.__listeners && (this.__listeners = {});
            type.indexOf("on") != 0 && (type = "on" + type);
            var t = this.__listeners;
            if (!t[type]) {
                return;
            }
            t[type][handler] && delete t[type][handler];
        };

        /**
         * 派發自定義事件,使得綁定到自定義事件上面的函數都會被執行。引入baidu.lang.Event後,Class的子類實例纔會獲得該方法。
         * @grammar obj.dispatchEvent(event, options)
         * @param {baidu.lang.Event|String} event 	Event對象,或事件名稱(1.1.1起支持)
         * @param {Object} options 擴展參數,所含屬性鍵值會擴展到Event對象上(1.2起支持)
         * @remark 處理會調用通過addEventListenr綁定的自定義事件回調函數之外,還會調用直接綁定到對象上面的自定義事件。
         * 例如:<br>
         * myobj.onMyEvent = function(){}<br>
         * myobj.addEventListener("onMyEvent", function(){});
         */
        baidu.lang.Class.prototype.dispatchEvent = function (event, options) {
            if (baidu.lang.isString(event)) {
                event = new baidu.lang.Event(event);
            }
            !this.__listeners && (this.__listeners = {});
            options = options || {};
            for (var i in options) {
                event[i] = options[i];
            }
            var i, t = this.__listeners, p = event.type;
            event.target = event.target || this;
            event.currentTarget = this;
            p.indexOf("on") != 0 && (p = "on" + p);
            baidu.lang.isFunction(this[p]) && this[p].apply(this, arguments);
            if (typeof t[p] == "object") {
                for (i in t[p]) {
                    t[p][i].apply(this, arguments);
                }
            }
            return event.returnValue;
        };

        /**
         * 爲類型構造器建立繼承關係
         * @name baidu.lang.inherits
         * @function
         * @grammar baidu.lang.inherits(subClass, superClass[, className])
         * @param {Function} subClass 子類構造器
         * @param {Function} superClass 父類構造器
         * @param {string} className 類名標識
         * @remark 使subClass繼承superClass的prototype,
         * 因此subClass的實例能夠使用superClass的prototype中定義的所有屬性和方法。<br>
         * 這個函數實際上是建立了subClass和superClass的原型鏈集成,並對subClass進行了constructor修正。<br>
         * <strong>注意:如果要繼承構造函數,需要在subClass裏面call一下,具體見下面的demo例子</strong>
         * @shortcut inherits
         * @meta standard
         * @see baidu.lang.Class
         */
        baidu.lang.inherits = function (subClass, superClass, className) {
            var key, proto, 
                selfProps = subClass.prototype, 
                clazz = new Function();        
            clazz.prototype = superClass.prototype;
            proto = subClass.prototype = new clazz();
            for (key in selfProps) {
                proto[key] = selfProps[key];
            }
            subClass.prototype.constructor = subClass;
            subClass.superClass = superClass.prototype;

            if ("string" == typeof className) {
                proto._className = className;
            }
        };

        /**
         * @ignore
         * @namespace baidu.dom 操作dom的方法。
         */
        baidu.dom = baidu.dom || {};

        /**
         * 從文檔中獲取指定的DOM元素
         * 
         * @param {string|HTMLElement} id 元素的id或DOM元素
         * @meta standard
         * @return {HTMLElement} DOM元素,如果不存在,返回null,如果參數不合法,直接返回參數
         */
        baidu._g = baidu.dom._g = function (id) {
            if (baidu.lang.isString(id)) {
                return document.getElementById(id);
            }
            return id;
        };

        /**
         * 從文檔中獲取指定的DOM元素
         * @name baidu.dom.g
         * @function
         * @grammar baidu.dom.g(id)
         * @param {string|HTMLElement} id 元素的id或DOM元素
         * @meta standard
         *             
         * @returns {HTMLElement|null} 獲取的元素,查找不到時返回null,如果參數不合法,直接返回參數
         */
        baidu.g = baidu.dom.g = function (id) {
            if ('string' == typeof id || id instanceof String) {
                return document.getElementById(id);
            } else if (id && id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
                return id;
            }
            return null;
        };

        /**
         * 在目標元素的指定位置插入HTML代碼
         * @name baidu.dom.insertHTML
         * @function
         * @grammar baidu.dom.insertHTML(element, position, html)
         * @param {HTMLElement|string} element 目標元素或目標元素的id
         * @param {string} position 插入html的位置信息,取值爲beforeBegin,afterBegin,beforeEnd,afterEnd
         * @param {string} html 要插入的html
         * @remark
         * 
         * 對於position參數,大小寫不敏感<br>
         * 參數的意思:beforeBegin&lt;span&gt;afterBegin   this is span! beforeEnd&lt;/span&gt; afterEnd <br />
         * 此外,如果使用本函數插入帶有script標籤的HTML字符串,script標籤對應的腳本將不會被執行。
         * 
         * @shortcut insertHTML
         * @meta standard
         *             
         * @returns {HTMLElement} 目標元素
         */
        baidu.insertHTML = baidu.dom.insertHTML = function (element, position, html) {
            element = baidu.dom.g(element);
            var range,begin;

            if (element.insertAdjacentHTML) {
                element.insertAdjacentHTML(position, html);
            } else {
                // 這裏不做"undefined" != typeof(HTMLElement) && !window.opera判斷,其它瀏覽器將出錯?!
                // 但是其實做了判斷,其它瀏覽器下等於這個函數就不能執行了
                range = element.ownerDocument.createRange();
                // FF下range的位置設置錯誤可能導致創建出來的fragment在插入dom樹之後html結構亂掉
                // 改用range.insertNode來插入html, by wenyuxiang @ 2010-12-14.
                position = position.toUpperCase();
                if (position == 'AFTERBEGIN' || position == 'BEFOREEND') {
                    range.selectNodeContents(element);
                    range.collapse(position == 'AFTERBEGIN');
                } else {
                    begin = position == 'BEFOREBEGIN';
                    range[begin ? 'setStartBefore' : 'setEndAfter'](element);
                    range.collapse(begin);
                }
                range.insertNode(range.createContextualFragment(html));
            }
            return element;
        };

        /**
         * 爲目標元素添加className
         * @name baidu.dom.addClass
         * @function
         * @grammar baidu.dom.addClass(element, className)
         * @param {HTMLElement|string} element 目標元素或目標元素的id
         * @param {string} className 要添加的className,允許同時添加多個class,中間使用空白符分隔
         * @remark
         * 使用者應保證提供的className合法性,不應包含不合法字符,className合法字符參考:http://www.w3.org/TR/CSS2/syndata.html。
         * @shortcut addClass
         * @meta standard
         * 	            
         * @returns {HTMLElement} 目標元素
         */
        baidu.ac = baidu.dom.addClass = function (element, className) {
            element = baidu.dom.g(element);
            var classArray = className.split(/\s+/),
                result = element.className,
                classMatch = " " + result + " ",
                i = 0,
                l = classArray.length;

            for (; i < l; i++){
                 if ( classMatch.indexOf( " " + classArray[i] + " " ) < 0 ) {
                     result += (result ? ' ' : '') + classArray[i];
                 }
            }

            element.className = result;
            return element;
        };

        /**
         * @ignore
         * @namespace baidu.event 屏蔽瀏覽器差異性的事件封裝。
         * @property target 	事件的觸發元素
         * @property pageX 		鼠標事件的鼠標x座標
         * @property pageY 		鼠標事件的鼠標y座標
         * @property keyCode 	鍵盤事件的鍵值
         */
        baidu.event = baidu.event || {};

        /**
         * 事件監聽器的存儲表
         * @private
         * @meta standard
         */
        baidu.event._listeners = baidu.event._listeners || [];

        /**
         * 爲目標元素添加事件監聽器
         * @name baidu.event.on
         * @function
         * @grammar baidu.event.on(element, type, listener)
         * @param {HTMLElement|string|window} element 目標元素或目標元素id
         * @param {string} type 事件類型
         * @param {Function} listener 需要添加的監聽器
         * @remark
         *  1. 不支持跨瀏覽器的鼠標滾輪事件監聽器添加<br>
         *  2. 改方法不爲監聽器灌入事件對象,以防止跨iframe事件掛載的事件對象獲取失敗            
         * @shortcut on
         * @meta standard
         * @see baidu.event.un
         *             
         * @returns {HTMLElement|window} 目標元素
         */
        baidu.on = baidu.event.on = function (element, type, listener) {
            type = type.replace(/^on/i, '');
            element = baidu._g(element);
            var realListener = function (ev) {
                // 1. 這裏不支持EventArgument,  原因是跨frame的事件掛載
                // 2. element是爲了修正this
                listener.call(element, ev);
            },
            lis = baidu.event._listeners,
            filter = baidu.event._eventFilter,
            afterFilter,
            realType = type;
            type = type.toLowerCase();
            // filter過濾
            if(filter && filter[type]){
                afterFilter = filter[type](element, type, realListener);
                realType = afterFilter.type;
                realListener = afterFilter.listener;
            }
            // 事件監聽器掛載
            if (element.addEventListener) {
                element.addEventListener(realType, realListener, false);
            } else if (element.attachEvent) {
                element.attachEvent('on' + realType, realListener);
            }
          
            // 將監聽器存儲到數組中
            lis[lis.length] = [element, type, listener, realListener, realType];
            return element;
        };

        /**
         * 爲目標元素移除事件監聽器
         * @name baidu.event.un
         * @function
         * @grammar baidu.event.un(element, type, listener)
         * @param {HTMLElement|string|window} element 目標元素或目標元素id
         * @param {string} type 事件類型
         * @param {Function} listener 需要移除的監聽器
         * @shortcut un
         * @meta standard
         *             
         * @returns {HTMLElement|window} 目標元素
         */
        baidu.un = baidu.event.un = function (element, type, listener) {
            element = baidu._g(element);
            type = type.replace(/^on/i, '').toLowerCase();
            
            var lis = baidu.event._listeners, 
                len = lis.length,
                isRemoveAll = !listener,
                item,
                realType, realListener;
            
            //如果將listener的結構改成json
            //可以節省掉這個循環,優化性能
            //但是由於un的使用頻率並不高,同時在listener不多的時候
            //遍歷數組的性能消耗不會對代碼產生影響
            //暫不考慮此優化
            while (len--) {
                item = lis[len];
                
                // listener存在時,移除element的所有以listener監聽的type類型事件
                // listener不存在時,移除element的所有type類型事件
                if (item[1] === type
                    && item[0] === element
                    && (isRemoveAll || item[2] === listener)) {
                    realType = item[4];
                    realListener = item[3];
                    if (element.removeEventListener) {
                        element.removeEventListener(realType, realListener, false);
                    } else if (element.detachEvent) {
                        element.detachEvent('on' + realType, realListener);
                    }
                    lis.splice(len, 1);
                }
            }            
            return element;
        };

        /**
         * 阻止事件的默認行爲
         * @name baidu.event.preventDefault
         * @function
         * @grammar baidu.event.preventDefault(event)
         * @param {Event} event 事件對象
         * @meta standard
         */
        baidu.preventDefault = baidu.event.preventDefault = function (event) {
           if (event.preventDefault) {
               event.preventDefault();
           } else {
               event.returnValue = false;
           }
        };
    })();

    /** 
     * @exports DistanceTool as BMapLib.DistanceTool 
     */
    var DistanceTool =
        /**
         * DistanceTool類的構造函數
         * @class 距離測算類,實現測距效果的<b>入口</b>。
         * 實例化該類後,即可調用該類提供的open
         * 方法開啓測距狀態。
         * 
         * @constructor
         * @param {Map} map Baidu map的實例對象
         * @param {Json Object} opts 可選的輸入參數,非必填項。可輸入選項包括:<br />
         * {"<b>followText</b>" : {String} 測距過程中,提示框文字,
         * <br />"<b>unit</b>" : {String} 測距結果所用的單位制,可接受的屬性爲"metric"表示米制和"us"表示美國傳統單位,
         * <br />"<b>lineColor</b>" : {String} 折線顏色,
         * <br />"<b>lineStroke</b>" : {Number} 折線寬度,
         * <br />"<b>opacity</b>" : {Number} 透明度,
         * <br />"<b>lineStyle</b>" : {String} 折線的樣式,只可設置solid和dashed,
         * <br />"<b>secIcon</b>" : {BMap.Icon} 轉折點的Icon,
         * <br />"<b>closeIcon</b>" : {BMap.Icon} 關閉按鈕的Icon,
         * <br />"<b>cursor</b>" : {String} 跟隨的鼠標樣式}
         *
         * @example <b>參考示例:</b><br />
         * var map = new BMap.Map("container");<br />map.centerAndZoom(new BMap.Point(116.404, 39.915), 15);<br />var myDistanceToolObject = new BMapLib.DistanceTool(map, {lineStroke : 2});
         */
        BMapLib.DistanceTool = function(map, opts){
            if (!map) {
                return;
            }
			
			//以下部分是添加的代碼
            if( OperationMask._maskElement ){
              OperationMask._maskElement = null;
            }
			//以上部分是添加的代碼
			
            /**
             * map對象
             * @private
             * @type {Map}
             */
            this._map = map;
			
            opts = opts || {};
            /**
             * _opts是默認參數賦值。
             * 下面通過用戶輸入的opts,對默認參數賦值
             * @private
             * @type {Json}
             */
            this._opts = baidu.extend(
                baidu.extend(this._opts || {}, {

                    /**
                     * 測距提示
                     * @private
                     * @type {String}
                     */
                    tips : "測距",

                    /**
                     * 測距過程中,提示框文字
                     * @private
                     * @type {String}
                     */
                    followText : "單擊確定地點,雙擊結束",

                    /**
                     * 測距結果所用的單位制,可接受的屬性爲"metric"表示米制和"us"表示美國傳統單位
                     * @private
                     * @type {String}
                     */
                    unit : "metric",

                    /**
                     * 折線顏色
                     * @private
                     * @type {String}
                     */
                    lineColor : "#ff6319",

                    /**
                     * 折線線寬
                     * @private
                     * @type {Number}
                     */
                    lineStroke : 2,

                    /**
                     * 折線透明度
                     * @private
                     * @type {Number}
                     */
                    opacity : 0.8,

                    /**
                     * 折線樣式
                     * @private
                     * @type {String}
                     */
                    lineStyle     : "solid",

                    /**
                     * 跟隨鼠標樣式
                     * @private
                     * @type {String}
                     */
                    cursor : "http://api.map.baidu.com/images/ruler.cur",

                    /**
                     * 轉折點的ICON樣式
                     * @private
                     * @type {BMap.Icon}
                     */
                     secIcon : null,
                      
                    /**
                     * 轉折點的ICON樣式
                     * @private
                     * @type {BMap.Icon}
                     */
                     closeIcon : null
                })
            , opts);

            /**
             * 跟隨的title覆蓋物
             * @private
             * @type {BMap.Label}
             */
            this._followTitle = null;

            /**
             * 折線包含所有點的數組
             * @private
             * @type {Array}
             */
            this._points = [];

            /**
             * 折線所包含的所有path數組
             * @private
             * @type {Array}
             */
            this._paths = [];

            /**
             * 折線結點圖片數組
             * @private
             * @type {Array}
             */
            this._dots = [];

            /**
             * 折線測距包含所有線段的距離
             * @private
             * @type {Array}
             */
            this._segDistance = [];

            /**
             * 覆蓋物的數組
             * @private
             * @type {Array}
             */
            this._overlays = [];

            /**
             * 是否在調用map.clearOverlays清除畫線需要建立的相關overlay元素
             * @private
             * @type {Boolean}
             */
            this._enableMassClear = true,
           
            /**
             * 單位制,存儲語言包中定義的單位名稱
             * @private
             * @type {Json}
             */
            this._units = {
                // metric 表示米制
                metric : {
                    /**
                     * 米制的名稱
                     * @type {String}
                     */
                    name : "metric",

                    /**
                     * 和米制的換算關係
                     * @type {Number}
                     */
                    conv : 1,

                    /**
                     * 米制單位下兩個單位制之間的換算關係
                     * @type {Number}
                     */
                    incon : 1000,

                    /**
                     * 米制單位下較小單位
                     * @type {String}
                     */
                    u1 : "米",

                    /**
                     * 米制單位下較大單位
                     * @type {String}
                     */
                    u2 : "公里"
                },
                // us 表示美國傳統單位,各參數意義同上metric
                us : {
                    name : "us",
                    conv : 3.2808,
                    incon : 5279.856,
                    u1 : "英尺",
                    u2 : "英里"
                }
            };

            /**
             * 是否已經開啓了測距狀態
             * @private
             * @type {Boolean}
             */
            this._isOpen = false;

            /**
             * 未點擊任何一點時,鼠標移動時的跟隨提示文字
             * @private
             * @type {String}
             */
            this._startFollowText = "單擊確定起點";

            /**
             * 地圖移動的計時器
             * @private
             * @type {Object}
             */
            this._movingTimerId = null;

            /**
             * 測距需要添加的CSS樣式
             * @private
             * @type {Json}
             */
             this._styles = {
                 "BMapLib_diso" : "height:17px;width:5px;position:absolute;background:url(http://api.map.baidu.com/images/dis_box_01.gif) no-repeat left top"
                 ,"BMapLib_disi" : "color:#7a7a7a;position:absolute;left:5px;padding:0 4px 1px 0;line-height:17px;background:url(http://api.map.baidu.com/images/dis_box_01.gif) no-repeat right top" 
                 ,"BMapLib_disBoxDis" : "color:#ff6319;font-weight:bold"
             };

            if (this._opts.lineStroke <= 0) {
                this._opts.lineStroke = 2;
            }
            if (this._opts.opacity > 1) {
                this._opts.opacity = 1;
            } else if (this._opts.opacity < 0) {
                this._opts.opacity = 0;
            }
            if (this._opts.lineStyle != "solid" &&
                this._opts.lineStyle != "dashed") {
                    this._opts.lineStyle = "solid";
            }
            if (!this._units[this._opts.unit]) {
                this._opts.unit = "metric";
            }
            
            this.text = "測距";
        }
    
    // 通過baidu.lang下的inherits方法,讓DistanceTool繼承baidu.lang.Class
    baidu.lang.inherits(DistanceTool, baidu.lang.Class, "DistanceTool");

    /**
     * 地圖區域的移動事件綁定
     * @return 無返回值
     */
    DistanceTool.prototype._bind = function(){
        // 設置鼠標樣式
        this._setCursor(this._opts.cursor);
        var me = this;
        // 在裝載地圖的頁面元素上,綁定鼠標移動事件
        baidu.on(this._map.getContainer(), "mousemove", function(e){
            if (!me._isOpen) {
                return;
            }
            if (!me._followTitle) {
                return;
            }
            e = window.event || e;
            var t = e.target || e.srcElement;
            // 如果觸發該事件的頁面元素不是遮蓋效果層,則返回,無操作
            if (t != OperationMask.getDom(me._map)) {
                me._followTitle.hide();
                return;
            }
            if (!me._mapMoving) {
                me._followTitle.show();
            }
            // 設置鼠標移動過程中,跟隨的文字提示框的位置
            var pt = OperationMask.getDrawPoint(e, true);
            me._followTitle.setPosition(pt);
        });
        // 創建鼠標跟隨的文字提示框
        if (this._startFollowText) {
            var t = this._followTitle = new BMap.Label(this._startFollowText, {offset : new BMap.Size(14, 16)});
            this._followTitle.setStyles({color : "#333", borderColor : "#ff0103"});
        }
    };

    /**
     * 開啓地圖的測距狀態
     * @return {Boolean},開啓測距狀態成功,返回true;否則返回false。
     *
     * @example <b>參考示例:</b><br />
     * myDistanceToolObject.open();
     */
    DistanceTool.prototype.open = function(){
        // 判斷測距狀態是否已經開啓
        if (this._isOpen == true){
            return true;
        }
        // 已有其他地圖上的鼠標操作工具開啓
        if (!!BMapLib._toolInUse) {
            return;
        }
        this._isOpen = true;
        BMapLib._toolInUse = true;

        // 判斷是否是否在移動過程中
        if (this._mapMoving){
            delete this._mapMoving;
        }

        var me = this;
        // 增加鼠標在地圖區域移動的事件
        // 通過binded參數,避免多次綁定
        if (!this._binded) {
            this._binded = true;
            // 綁定控件項事件
            this._bind();
            // 地圖的移動過程中,需要隱藏相關的提示框
            this._map.addEventListener("moving", function(){
                me._hideCurrent();
            });
        }

        // 將文字提示框作爲BMap.Label元素,提交給Map Api進行管理
        if (this._followTitle) {
            this._map.addOverlay(this._followTitle);
            this._followTitle.hide();
        }

        /**
         * 測距過程中,點擊地圖時,觸發的操作
         * @ignore
         * @param {Object} e event對象
         */
        var distClick = function(e) {
            var map = me._map;
            if (!me._isOpen) {
                    return;
            }
            // 通過event對象,計算得出點擊位置的物理座標,poi爲一個BMap.Point對象
            e = window.event || e;
            var poi = OperationMask.getDrawPoint(e, true);
            // 驗證計算得出的該點的位置合理性
            if (!me._isPointValid(poi)) {
                return;
            }
            // 記錄當前點的屏幕位置
            me._bind.initX = e.pageX || e.clientX || 0;
            me._bind.initY = e.pageY || e.clientY || 0;

            // 這個if循環內的計算是,判斷當前這個點,與存儲內的最後一個點的距離,
            // 如果距離過小,比如小於5,可以認爲是用戶的誤點,可以忽略掉
            if (me._points.length > 0){
                var lstPx = map.pointToPixel(me._points[me._points.length - 1]);
                var thisPx = map.pointToPixel(poi);
                var dis = Math.sqrt(Math.pow(lstPx.x - thisPx.x, 2) + Math.pow(lstPx.y - thisPx.y, 2));
                if (dis < 5) {
                    return;
                }
            }

            me._bind.x = e.layerX || e.offsetX || 0;
            me._bind.y = e.layerY || e.offsetY || 0;
            me._points.push(poi);
            // 添加測距結點
            me._addSecPoint(poi);

            // 調整跟蹤鼠標的標籤
            if (me._paths.length == 0) {
                me._formatTitle(1, me._opts.followText, me._getTotalDistance());
            }

            // 修改確定線的顏色
            if (me._paths.length > 0) {
                me._paths[me._paths.length - 1].show();
                me._paths[me._paths.length - 1].setStrokeOpacity(me._opts.opacity);
            }

            var path = new BMap.Polyline([poi, poi], {enableMassClear : me._enableMassClear});
            me._map.addOverlay(path);
            me._paths.push(path);
            me._overlays.push(path);

            // 測距模式下線樣式固定
            path.setStrokeWeight(me._opts.lineStroke);
            path.setStrokeColor(me._opts.lineColor);
            path.setStrokeOpacity(me._opts.opacity / 2);
            path.setStrokeStyle(me._opts.lineStyle);           

            // 如果地圖正在移動則隱藏掉
            if (me._mapMoving){
                path.hide();
            }

            if (me._points.length > 1) {
                var siblingPath = me._paths[me._points.length - 2];
                siblingPath.setPositionAt(1, poi);
            }

            // 生成節點旁邊的距離顯示框
            var disText = "";
            if (me._points.length > 1) {
                // 非起點的節點,顯示當前的距離
                var segDis = me._setSegDistance(me._points[me._points.length - 2], me._points[me._points.length - 1]);
                var meters = me._getTotalDistance();
                disText = me._formatDisStr(meters);
            } else {
                disText = "起點";
            }                
            var disLabel = new BMap.Label(disText, {offset : new BMap.Size(10, -5), enableMassClear : me._enableMassClear});
            disLabel.setStyles({color : "#333", borderColor : "#ff0103"});
            me._map.addOverlay(disLabel);
            me._formatSegLabel(disLabel, disText);
            me._overlays.push(disLabel);
            poi.disLabel = disLabel;
            disLabel.setPosition(poi);

            /**
             * 測距過程中,每次點擊底圖添加節點時,派發事件的接口
             * @name DistanceTool#onaddpoint
             * @event
             * @param {Event Object} e 回調函數會返回event參數,包括以下返回值:
             * <br />{"<b>point</b> : {BMap.Point} 最新添加上的節點BMap.Point對象,
             * <br />"<b>pixel</b>:{BMap.pixel} 最新添加上的節點BMap.Pixel對象,
             * <br />"<b>index</b>:{Number} 最新添加的節點的索引,
             * <br />"<b>distance</b>:{Number} 截止最新添加的節點的總距離}
             *
             * @example <b>參考示例:</b><br />
             * myDistanceToolObject.addEventListener("addpoint", function(e) {  alert(e.distance);  });
             */

            // 生成名爲onaddpoint的baidu.lang.Event對象
            // 並給該event對象添加上point、pixel、index和distance等屬性字段
            // 然後在此刻,將綁定在onaddpoint上事件,全部賦予event參數,然後派發出去
            var event = new baidu.lang.Event("onaddpoint");
            event.point = poi;
            event.pixel = me._map.pointToPixel(poi);
            event.index = me._points.length - 1;
            event.distance = me._getTotalDistance().toFixed(0);
            me.dispatchEvent(event);
        };

        /**
         * 測距過程中,鼠標在地圖上移動時,觸發的操作
         * @ignore
         * @param {Object} e event對象
         */
        var distMove = function(e) {
            if (!me._isOpen){
                return;
            }
            // 通過判斷數組me._paths的長度,判斷當前是否已經有測量節點
            // 也就是,如果沒有節點,則還沒有開始測量
            if (me._paths.length > 0) {
                // 通過event參數,計算當前點的位置
                e = window.event || e;
                var curX = e.pageX || e.clientX || 0;
                var curY = e.pageY || e.clientY || 0;
                if (typeof me._bind.initX == "undefined") {
                    me._bind.x = e.layerX || e.offsetX || 0;
                    me._bind.y = e.layerY || e.offsetY || 0;
                    me._bind.initX = curX;
                    me._bind.initY = curY;
                }
                var x = me._bind.x + curX - me._bind.initX;
                var y = me._bind.y + curY - me._bind.initY;

                // 修改最後一條折線的終點位置,使之隨着鼠標移動畫線
                var path = me._paths[me._paths.length - 1];
                var poi = me._map.pixelToPoint(new BMap.Pixel(x, y));
                path.setPositionAt(1, poi);

                if (!me._mapMoving) {
                    path.show();
                }
                var dx = 0;
                var dy = 0;
                // 計算當前鼠標位置,是否靠近邊界、或者已經出了邊界
                // 如果在邊界位置,則需要向對應的方向移動地圖,來進行測量
                // 每次移動的距離,設定爲8
                if (x < 10) {
                    dx = 8;
                } else if (x > me._map.getSize().width - 10){
                    dx = -8;
                }
                if (y < 10) {
                    dy = 8;
                } else if (y > me._map.getSize().height - 10){
                    dy = -8;
                }
                // 如果dx和dy都等於0,表明不需要移動地圖
                if (dx != 0 || dy != 0){
                    // 此時需要向一個方向,平移地圖
                    if (!distMove._movingTimerId){
                        me._mapMoving = true;
                        me._map.panBy(dx, dy, {noAnimation : true});                        
                        me._movingTimerId = distMove._movingTimerId = setInterval(function(){
                            me._map.panBy(dx, dy, {noAnimation : true});
                        }, 30);
                        // 地圖移動過程中,隱藏線段和標籤
                        path.hide();
                        me._followTitle && me._followTitle.hide();
                    }
                } else {
                    if (distMove._movingTimerId) {
                        // 此時用戶不在需要移動地圖來測量,可以清除計時器
                        clearInterval(distMove._movingTimerId);
                        delete distMove._movingTimerId;
                        delete me._movingTimerId;

                        // 顯示跟隨提示框,並修改線路位置
                        var lstP = me._paths[me._paths.length - 1];
                        var poiN = me._map.pixelToPoint(new BMap.Pixel(x, y));
                        if (!lstP) {
                            return;
                        }
                        lstP.setPositionAt(1, poiN);
                        lstP.show();
                        if (me._followTitle) {
                            me._followTitle.setPosition(poiN);
                            me._followTitle.show();
                        }
                        me._bind.i = 0;
                        me._bind.j = 0;
                        delete me._mapMoving;
                    }
                }
                // 實時更新文字提示框中的距離
                if (me._followTitle) {
                    var td = me._getTotalDistance();
                    var dis = me._map.getDistance(me._points[me._points.length - 1], poi);
                    me._updateInstDis(me._followTitle, td + dis);
                }
            } else {
                // 此時用戶還沒有開始測量,只是鼠標隨便在地圖上移動
                if (me._followTitle) {
                    me._followTitle.show();
                    e = window.event || e;
                    var t = e.target || e.srcElement;
                    if (t != OperationMask.getDom()) {
                        me._followTitle.hide();
                    }
                }        
            }
        };

        /**
         * 測距要結束時,雙擊地圖,觸發的操作
         * @ignore
         * @param {Object} e event對象
         */
        var distDblclick = function(e) {
            if (!me._isOpen) {
                return;
            }
            // 結束時,刪除綁定的事件
            baidu.un(OperationMask.getDom(me._map), "click", distClick);
            baidu.un(document, "mousemove", distMove);
            baidu.un(OperationMask.getDom(me._map), "dblclick", distDblclick);            
            baidu.un(document, "keydown", distKeyDown);
            baidu.un(OperationMask.getDom(me._map), "mouseup", distMouseUp);

            // 調用close()關閉測距狀態
            setTimeout(function(){
                me.close();
            }, 50);
        };
        
        /**
         * 測距時的鍵盤操作
         * @ignore
         * @param {Object} e event對象
         */
        var distKeyDown = function(e){
            e = window.event || e;
            if (e.keyCode == 27){ 
                // [ESC]退出本次測距
                me._clearCurData();
                setTimeout(function(){
                    me.close();
                }, 50);
            }
        };

        /**
         * 測距過程中,鼠標彈起時,觸發的操作
         * @ignore
         * @param {Object} e event對象
         */
        var distMouseUp = function(e) {
            e = window.event || e;
            var ieVersion = 0;
            if (/msie (\d+\.\d)/i.test(navigator.userAgent)) {
               ieVersion = document.documentMode || + RegExp['\x241'];
            }
            if (ieVersion && 
                e.button != 1 || 
                e.button == 2){
                    me.close();
            }
        };

        // 初始化存儲數據
        me._initData();

        // 調整title的內容
        this._formatTitle();

        // 創建透明覆蓋層,並設置鼠標樣式
        OperationMask.show(this._map);
        this._setCursor(this._opts.cursor);

        // 綁定全部事件
        baidu.on(OperationMask.getDom(this._map), "click", distClick);
        baidu.on(document, "mousemove", distMove);
        baidu.on(OperationMask.getDom(this._map), "dblclick", distDblclick);
        baidu.on(document, "keydown", distKeyDown);
        baidu.on(OperationMask.getDom(this._map), "mouseup", distMouseUp);
        
        // 將綁定的事件、和對應的綁定對象,記錄在數組中
        this.bindFunc = [
            {elem : OperationMask.getDom(this._map), type : "click", func : distClick}, 
            {elem : OperationMask.getDom(this._map), type : "dblclick", func : distDblclick},
            {elem : document, type : "mousemove", func : distMove},
            {elem : document, type : "keydown", func : distKeyDown},
            {elem : OperationMask.getDom(this._map), type : "mouseup", func : distMouseUp}];
        return true;
    };

    /**
     * 畫線結束時,派發drawend事件
     * @return 無返回值
     */
    DistanceTool.prototype._dispatchLastEvent = function() {
        /**
         * 測距時,每次雙擊底圖結束當前測距折線時,派發事件的接口
         * @name DistanceTool#ondrawend
         * @event
         * @param {Event Object} e 回調函數會返回event參數,包括以下返回值:
         * <br />{"<b>points</b> : {BMap.Point} 所有測量時,打下的節點BMap.Point對象,
         * <br />"<b>overlays</b>:{Array} 所有測量時,生成的線段BMap.Overlay對象,
         * <br />"<b>distance</b>:{Number} 測量解釋時的最終距離}
         *
         * @example <b>參考示例:</b><br />
         * myDistanceToolObject.addEventListener("drawend", function(e) {  alert(e.distance);  });
         */

        // 生成名爲ondrawend的baidu.lang.Event對象
        // 並給該event對象添加上points、overlays和distance等屬性字段
        // 然後在此刻,將綁定在ondrawend上事件,全部賦予event參數,然後派發出去
        var event = new baidu.lang.Event("ondrawend");
        event.points = 
            this._points ? 
                this._points.slice(0) : 
                [];
        event.overlays = 
            this._paths ? 
                this._paths.slice(0, this._paths.length - 1) : 
                [];
        event.distance = this._getTotalDistance().toFixed(0);
        this.dispatchEvent(event);
    };

    /**
     * 關閉測距狀態
     * @return 無返回值
     *
     * @example <b>參考示例:</b><br />
     * myDistanceToolObject.close();
     */
    DistanceTool.prototype.close = function(){
        if (this._isOpen == false){
            return;
        }
        this._isOpen = false;
        BMapLib._toolInUse = false;

        if (this._mapMoving){
            delete this._mapMoving;
        }
        var me = this;
        me._dispatchLastEvent();
        if (me._points.length < 2){
            // 不是有效繪製,清除所有內容
            me._clearCurData();
        } else {
            me._paths[me._paths.length - 1].remove();
            me._paths[me._paths.length - 1] = null;
            me._paths.length = me._paths.length - 1;
            // 移除最近一次標記
            var pt = me._points[me._points.length - 1];
            if (pt.disLabel){
                pt.disLabel.remove();
            }
            me._processLastOp();
        }
        OperationMask.hide();

        // 刪除綁定的事件
        for (var i = 0, l = this.bindFunc.length; i < l; i ++){
            baidu.un(this.bindFunc[i].elem, this.bindFunc[i].type, this.bindFunc[i].func);
        }

        // 停止地圖移動
        if (me._movingTimerId){
            clearInterval(me._movingTimerId);
            me._movingTimerId = null;
        }

        if (this._followTitle){
            this._followTitle.hide();
        }
    };

    /**
     * 清除本次測距的暫存數據
     * @return 無返回值
     */
    DistanceTool.prototype._clearCurData = function(){
        for (var i = 0, l = this._points.length; i < l; i ++){
            if (this._points[i].disLabel){
                this._points[i].disLabel.remove();
            }
        }
        for (var i = 0, l = this._paths.length; i < l; i ++){
            this._paths[i].remove();
        }
        for (var i = 0, l = this._dots.length; i < l; i ++){
            this._dots[i].remove();
        }
        this._initData();
    };

    /**
     * 初始化存儲數組
     * @return 無返回值
     */
    DistanceTool.prototype._initData = function(){
        // 初始化point數組
        this._points.length = 0;
        // 初始化path數組
        this._paths.length = 0;
        // 初始化分段距離數組
        this._segDistance.length = 0;
        // 初始化結點圖像數組
        this._dots.length = 0;
    };

    /**
     * 計算兩點之間距離並存放在分段距離數組中
     * @param {Point}
     * @param {Point}
     * @return {Number} 兩個地理點之間的距離
     */
    DistanceTool.prototype._setSegDistance = function(pt0, pt1){
        if (!pt0 || !pt1){
            return;
        }
        var dis = this._map.getDistance(pt0, pt1);
        this._segDistance.push(dis);
        return dis;
    };

    /**
     * 獲得總距離
     * @return {Number} 總距離
     */
    DistanceTool.prototype._getTotalDistance = function(){
        var totalDis = 0;
        for (var i = 0, l = this._segDistance.length; i < l; i ++){
            totalDis += this._segDistance[i];
        }
        return totalDis;
    };

    /**
     * 將米制單位的數值換算成爲目標單位下的數值
     * @type {Number} 需要轉換的數值
     * @type {String} 字符串描述的目標單位,
     * "metric" 表示米制單位,
     * "us" 表示美國傳統單位制
     * @return {Number} 轉換後的數值
     */
    DistanceTool.prototype._convertUnit = function(num, unit){
        unit = unit || "metric";
        if (this._units[unit]){
            return num * this._units[unit].conv;
        }
        return num;
    };

    /**
     * 添加測距結點
     * @param {BMap.Point} 節點
     * @return 無返回值
     */
    DistanceTool.prototype._addSecPoint = function(pt){
        var ico = 
            this._opts.secIcon ? 
                this._opts.secIcon :
                new BMap.Icon("http://api.map.baidu.com/images/mapctrls.png", new BMap.Size(11, 11), {imageOffset: new BMap.Size(-26, -313)});
        var secPt = new BMap.Marker(pt, {
            icon : ico, 
            clickable : false, 
            baseZIndex : 3500000, 
            zIndexFixed : true,
            enableMassClear : this._enableMassClear
        });
        this._map.addOverlay(secPt);
        this._dots.push(secPt);
    };

    /**
     * 格式化距離字符串
     * @param {Number} 距離
     * @return {String} 格式化的字符串
     */
    DistanceTool.prototype._formatDisStr = function(distance){
        var u = this._opts.unit;
        var unit = this._units[u].u1;
        var dis = this._convertUnit(distance, u);

        if (dis > this._units[u].incon){
            dis = dis / this._units[u].incon;
            unit = this._units[u].u2;
            dis = dis.toFixed(1);
        } else {
            dis = dis.toFixed(0); 
        }
        return dis + unit;
    };

    /**
     * 設置鼠標樣式
     * @param {String} cursor 鼠標樣式
     * @return 沒有返回值
     */
    DistanceTool.prototype._setCursor = function(cursor){
        // 由於webkit內核瀏覽器下,cursor設置後默認不會居中,所以需要對偏移值進行設置
        var csr = 
            /webkit/.test(navigator.userAgent.toLowerCase()) ?
                "url(" + this._opts.cursor + ") 3 6, crosshair" :
                "url(" + this._opts.cursor + "), crosshair"
        OperationMask._setCursor(csr);
    };

    /**
     * 獲取鼠標樣式
     * @return {String} 跟隨的鼠標樣式
     */
    DistanceTool.prototype._getCursor = function(){
        return this._opts.cursor;
    };

    /**
     * 調整分段距離樣式
     * @param {BMap.Label} label 提示框的Label
     * @param {String} 需要填入的文字
     * @return 沒有返回值
     */
    DistanceTool.prototype._formatSegLabel = function(label, text){
        label.setStyle({"border" : "none", "padding" : "0"});
        label.setContent("<span style='" + this._styles.BMapLib_diso + "'><span style='" + this._styles.BMapLib_disi + "'>" + text + "</span></span>");
    };

    /**
     * 處理最後一次操作,當用戶雙擊或測距被強行退出時調用
     * @return 沒有返回值
     */
    DistanceTool.prototype._processLastOp = function() {
        var me = this;
        // 刪除上次移動臨時數據
        delete me._bind.x;
        delete me._bind.y;
        delete me._bind.initX;
        delete me._bind.initY;
        // 驗證路徑
        if (me._paths.length > me._points.length - 1){
            var l = me._paths.length - 1;
            me._paths[l].remove();
            me._paths[l] = null;
            me._paths.length = l;
        }
        // 保存本次測距對象
        var disObj = {};
        disObj.points = me._points.slice(0);
        disObj.paths  = me._paths.slice(0);
        disObj.dots   = me._dots.slice(0);
        disObj.segDis = me._segDistance.slice(0);
        // 判斷總距離和按鈕位置
        var lstPx = me._map.pointToPixel(disObj.points[disObj.points.length - 1]);
        var prePx = me._map.pointToPixel(disObj.points[disObj.points.length - 2]);
        var btnOffset = [0, 0];
        var disOffset = [0, 0];
        if (lstPx.y - prePx.y >= 0){
            // 距離位於下端
            disOffset = [-5, 11];
        } else {
            // 距離位於上端
            disOffset = [-5, -35];
        }
        if (lstPx.x - prePx.x >= 0){
            // 按鈕位於右側
            btnOffset = [14, 0];
        } else {
            // 按鈕位於左側
            btnOffset = [-14, 0];
        }
        // 顯示總距離
        var pt = disObj.points[disObj.points.length - 1];
        pt.disLabel = new BMap.Label("", {offset: new BMap.Size(-15, -40), enableMassClear: me._enableMassClear});
        pt.disLabel.setStyles({color: "#333", borderColor: "#ff0103"});
        me._map.addOverlay(pt.disLabel);
        pt.disLabel.setOffset(new BMap.Size(disOffset[0], disOffset[1]));
        pt.disLabel.setPosition(pt);
        me._formatTitle(2, "", "", pt.disLabel);
        // 添加關閉按鈕
        var bico = 
            this._opts.closeIcon ? 
                this._opts.closeIcon :
                new BMap.Icon("http://api.map.baidu.com/images/mapctrls.gif", new BMap.Size(12, 12), {imageOffset: new BMap.Size(0, -14)});
        disObj.closeBtn = new BMap.Marker(disObj.points[disObj.points.length - 1], 
            {icon : bico, 
            offset : new BMap.Size(btnOffset[0], btnOffset[1]), 
            baseZIndex : 3600000,
            enableMassClear : me._enableMassClear}
        );
        me._map.addOverlay(disObj.closeBtn);
        disObj.closeBtn.setTitle("清除本次測距");
        // 點擊關閉按鈕,綁定關閉按鈕事件
        disObj.closeBtn.addEventListener("click", function(e){
            // 關閉本次測距,清除相關存儲和變量
            for (var i = 0, l = disObj.points.length; i < l; i ++){
                disObj.points[i].disLabel.remove();
                disObj.points[i].disLabel = null;
            }
            for (var i = 0, l = disObj.paths.length; i < l; i ++){
                disObj.paths[i].remove();
                disObj.paths[i] = null;
            }
            for (var i = 0, l = disObj.dots.length; i < l; i ++){
                disObj.dots[i].remove();
                disObj.dots[i] = null;
            }
            disObj.closeBtn.remove();
            disObj.closeBtn = null;
            stopBubble(e);
            
            /**
             * @ignore
             * 測距結束後,點擊線段上最後一個節點旁的關閉按鈕時,派發事件的接口
             * @name DistanceTool#onremovepolyline
             * @event
             * @param {Event Object} e 回調函數會返回event參數
             *
             * @example <b>參考示例:</b><br />
             * myDistanceToolObject.addEventListener("removepolyline", function(e) {  alert(e.type);  });
             */

            // 生成名爲onremovepolyline的baidu.lang.Event對象
            // 然後在此刻,將綁定在onremovepolyline上事件,全部賦予event參數,然後派發出去
            var event = new baidu.lang.Event("onremovepolyline");
            me.dispatchEvent(event);
        });        
        me._initData();
    };

    /**
     * 生成測距過程中的文字提示框
     * @param {String} type
     * @param {String} text 
     * @param {String} distance
     * @param {Label} label
     * @return 無返回值
     */
    DistanceTool.prototype._formatTitle = function(type, text, distance, label){
        var title = label || this._followTitle;
        if (!title){
            return;
        }
        title.setStyle({"lineHeight" : "16px", "zIndex" : "85", "padding" : "3px 5px"});
        var t = this._startFollowText || "";
        var htmls = [];
        if (type == 1){
            // 測距過程中的提示
            title.setOffset(0, 25);
            var u = this._opts.unit;
            var unit = this._units[u].u1;
            var dis = this._convertUnit(distance, u);
            if (dis > this._units[u].incon){
                dis = dis / this._units[u].incon;
                unit = this._units[u].u2;
                dis = dis.toFixed(1);
            } else {
                dis = dis.toFixed(0);
            }
            htmls.push("<span>總長:<span style='" + this._styles.BMapLib_disBoxDis+"'>" + dis + "</span>" + unit + "</span><br />");
            htmls.push("<span style='color:#7a7a7a'>" + text + "</span>");
        } else if (type == 2) {
            // 結束時的總距離展示
            var u = this._opts.unit;
            var unit = this._units[u].u1;
            var dis = this._convertUnit(this._getTotalDistance(), u);
            if (dis > this._units[u].incon){
                dis = dis / this._units[u].incon;
                unit = this._units[u].u2;
                dis = dis.toFixed(1);
            } else{
                dis = dis.toFixed(0);
            }
            htmls.push("總長:<span style='" + this._styles.BMapLib_disBoxDis + "'>" + dis + "</span>" + unit);
        } else {
            title.setOffset(0, 25);
            htmls.push(t);
        }
        title.setContent(htmls.join(""));
    };

    /**
     * 更新label的距離
     * @param HTMLElement label的DOM元素
     * @param Number 距離
     */
    DistanceTool.prototype._updateInstDis = function(label, dis){
        // 換算距離
        var u = this._opts.unit;
        var unit = this._units[u].u1;
        if (dis > this._units[u].incon){
            dis = dis / this._units[u].incon;
            unit = this._units[u].u2;
            dis = dis.toFixed(1);
        } else {
            dis = dis.toFixed(0);
        }
        // 修改Label的內容
        if (label) {
            var htmls = [];
            htmls.push("<span>總長:<span style='" + this._styles.BMapLib_disBoxDis + "'>" + dis + "</span>" + unit + "</span><br />");
            htmls.push("<span style='color:#7a7a7a'>" + this._opts.followText + "</span>");
            label.setContent(htmls.join(""));
        }
    };

    /**
     * 隱藏相關的線段和提示框文字
     * @return 無返回值
     */
    DistanceTool.prototype._hideCurrent = function(){
        if (!this._isOpen){
            return;
        }
        if (this._paths.length > 0){
            var p = this._paths[this._paths.length - 1];
            p.hide();
        }
        this._followTitle && this._followTitle.hide();
    };

    /**
     * 驗證傳入點的位置合理性
     * @param {BMap.Point} pt 需要被驗證的point點
     * @return 無返回值
     */
    DistanceTool.prototype._isPointValid = function(pt){
        if (!pt){
            return false;
        }
        var mapBounds = this._map.getBounds();
        var sw = mapBounds.getSouthWest(),
              ne = mapBounds.getNorthEast();
        if (pt.lng < sw.lng ||
            pt.lng > ne.lng ||
            pt.lat < sw.lat ||
            pt.lat > ne.lat) {
                return false;
        }
        return true;
    };


    /**
     * OperationMask,透明覆蓋層,在地圖上進行鼠標繪製操作時使用,
     * 閉包,對外不暴露
     */
    var OperationMask = {
        /**
         * map對象
         * @type {Map}
         */
        _map : null,

        /**
         * HTML字符串
         * @type {String}
         */
        _html : "<div style='background:transparent url(http://api.map.baidu.com/images/blank.gif);position:absolute;left:0;top:0;width:100%;height:100%;z-index:1000' unselectable='on'></div>",

        /**
         * html元素
         * @type {HTMLElement}
         */
        _maskElement : null,

        /**
         * 鼠標指針
         * @type {String}
         */
        _cursor: 'default',

        /**
         * 操作層是否在使用中
         * @type {Boolean}
         */
        _inUse: false,

        /**
         * 透明覆蓋層的顯示
         *
         * @param {Map} map map對象
         * @return 無返回值
         */
        show : function(map) {
            if (!this._map) {
                this._map = map;
            }
            this._inUse = true;
            if (!this._maskElement) {
                this._createMask(map);
            }
            this._maskElement.style.display = 'block';
        },

        /**
         * 創建覆蓋層
         *
         * @param {Map} map map對象
         * @return 無返回值
         */
        _createMask : function(map) {
            this._map = map;
            if (!this._map) {
                return;
            }
            baidu.insertHTML(this._map.getContainer(), "beforeEnd", this._html);
            var elem = this._maskElement = this._map.getContainer().lastChild;

            var stopAndPrevent = function(e) {
                stopBubble(e);
                return baidu.preventDefault(e);
            }
            baidu.on(elem, 'mouseup', function(e) {
                if (e.button == 2) {
                    stopAndPrevent(e);
                }
            });
            baidu.on(elem, 'contextmenu', stopAndPrevent);
            elem.style.display = 'none';
        },

        /**
         * 獲取當前繪製點的地理座標
         *
         * @param {Event} e e對象
         * @param {Boolean} n 是否向上查到相對於地圖container元素的座標位置
         * @return Point對象的位置信息
         */
        getDrawPoint : function(e, n) {
            e = window.event || e;
            var x = e.layerX || e.offsetX || 0;
            var y = e.layerY || e.offsetY || 0;
            var t = e.target || e.srcElement;
            if (t != OperationMask.getDom(this._map) && n == true) {
                while (t && t != this._map.getContainer()) {
                    if (!(t.clientWidth == 0 && 
                         t.clientHeight == 0 && 
                         t.offsetParent && 
                         t.offsetParent.nodeName.toLowerCase() == 'td')) {
                            x += t.offsetLeft;
                            y += t.offsetTop;
                    }
                    t = t.offsetParent;
                }
            }

            if (t != OperationMask.getDom(this._map) && 
                t != this._map.getContainer()) {
                    return;
            }
            if (typeof x === 'undefined' || 
                typeof y === 'undefined') {
                    return;
            }
            if (isNaN(x) || isNaN(y)) {
                return;
            }
            return this._map.pixelToPoint(new BMap.Pixel(x, y));
        },

        /**
         * 透明覆蓋層的隱藏
         *
         * @return 無返回值
         */
        hide : function() {
            if (!this._map) {
                return;
            }
            this._inUse = false;
            if (this._maskElement) {
                this._maskElement.style.display = 'none';
            }
        },

        /**
         * 獲取HTML容器
         *
         * @param {Map} map map對象
         * @return HTML容器元素
         */
        getDom : function(map) {
            if (!this._maskElement) {
                this._createMask(map);
            }
            return this._maskElement;
        },

        /**
         * 設置鼠標樣式
         *
         * @type {String} cursor 鼠標樣式
         * @return 無返回值
         */
        _setCursor : function(cursor) {
            this._cursor = cursor || 'default';
            if (this._maskElement) {
                this._maskElement.style.cursor = this._cursor;                
            }
        }
    };

    /**
     * 停止事件冒泡傳播,
     * 閉包,對外不暴露
     *
     * @type {Event} e e對象
     */
    function stopBubble(e){
        var e = window.event || e;
        e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
    };
})();

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章