分享

DrawingManager.js

 求知881 2015-09-07
   1 /**
  2  * @fileoverview 百度地图的鼠标绘制工具,对外开放。
  3  * 允许用户在地图上点击完成鼠标绘制的功能。
  4  * 使用者可以自定义所绘制结果的相关样式,例如线宽、颜色、测线段距离、面积等等。
  5  * 主入口类是<a href="symbols/BMapLib.DrawingManager.html">DrawingManager</a>,
  6  * 基于Baidu Map API 1.4。
  7  *
  8  * @author Baidu Map Api Group
  9  * @version 1.4
 10  */
 11
 12 /**
 13  * @namespace BMap的所有library类均放在BMapLib命名空间下
 14  */
 15 var BMapLib = window.BMapLib = BMapLib || {};
 16
 17 /**
 18  * 定义常量, 绘制的模式
 19  * @final {Number} DrawingType
 20  */
 21 var BMAP_DRAWING_MARKER    = "marker",     // 鼠标画点模式
 22     BMAP_DRAWING_POLYLINE  = "polyline",   // 鼠标画线模式
 23     BMAP_DRAWING_CIRCLE    = "circle",     // 鼠标画圆模式
 24     BMAP_DRAWING_RECTANGLE = "rectangle"// 鼠标画矩形模式
 25     BMAP_DRAWING_POLYGON   = "polygon";    // 鼠标画多边形模式
 26
 27 (function() {
 28
 29     /**
 30      * 声明baidu包
 31      */
 32     var baidu = baidu || {guid : "$BAIDU$"};
 33     (function() {
 34         // 一些页面级别唯一的属性,需要挂载在window[baidu.guid]上
 35         window[baidu.guid] = {};
 36
 37         /**
 38          * 将源对象的所有属性拷贝到目标对象中
 39          * @name baidu.extend
 40          * @function
 41          * @grammar baidu.extend(target, source)
 42          * @param {Object} target 目标对象
 43          * @param {Object} source 源对象
 44          * @returns {Object} 目标对象
 45          */
 46         baidu.extend = function (target, source) {
 47             for (var p in source) {
 48                 if (source.hasOwnProperty(p)) {
 49                     target[p] = source[p];
 50                 }
 51             }   
 52             return target;
 53         };
 54
 55         /**
 56          * @ignore
 57          * @namespace
 58          * @baidu.lang 对语言层面的封装,包括类型判断、模块扩展、继承基类以及对象自定义事件的支持。
 59          * @property guid 对象的唯一标识
 60          */
 61         baidu.lang = baidu.lang || {};
 62
 63         /**
 64          * 返回一个当前页面的唯一标识字符串。
 65          * @function
 66          * @grammar baidu.lang.guid()
 67          * @returns {String} 当前页面的唯一标识字符串
 68          */
 69         baidu.lang.guid = function() {
 70             return "TANGRAM__" + (window[baidu.guid]._counter ++).toString(36);
 71         };
 72
 73         window[baidu.guid]._counter = window[baidu.guid]._counter || 1;
 74
 75         /**
 76          * 所有类的实例的容器
 77          * key为每个实例的guid
 78          */
 79         window[baidu.guid]._instances = window[baidu.guid]._instances || {};
 80
 81         /**
 82          * Tangram继承机制提供的一个基类,用户可以通过继承baidu.lang.Class来获取它的属性及方法。
 83          * @function
 84          * @name baidu.lang.Class
 85          * @grammar baidu.lang.Class(guid)
 86          * @param {string} guid 对象的唯一标识
 87          * @meta standard
 88          * @remark baidu.lang.Class和它的子类的实例均包含一个全局唯一的标识guid。
 89          * guid是在构造函数中生成的,因此,继承自baidu.lang.Class的类应该直接或者间接调用它的构造函数。<br>
 90          * baidu.lang.Class的构造函数中产生guid的方式可以保证guid的唯一性,及每个实例都有一个全局唯一的guid。
 91          */
 92         baidu.lang.Class = function(guid) {
 93             this.guid = guid || baidu.lang.guid();
 94             window[baidu.guid]._instances[this.guid] = this;
 95         };
 96
 97         window[baidu.guid]._instances = window[baidu.guid]._instances || {};
 98
 99         /**
100          * 判断目标参数是否string类型或String对象
101          * @name baidu.lang.isString
102          * @function
103          * @grammar baidu.lang.isString(source)
104          * @param {Any} source 目标参数
105          * @shortcut isString
106          * @meta standard
107          *            
108          * @returns {boolean} 类型判断结果
109          */
110         baidu.lang.isString = function (source) {
111             return '[object String]' == Object.prototype.toString.call(source);
112         };
113
114         /**
115          * 判断目标参数是否为function或Function实例
116          * @name baidu.lang.isFunction
117          * @function
118          * @grammar baidu.lang.isFunction(source)
119          * @param {Any} source 目标参数
120          * @returns {boolean} 类型判断结果
121          */
122         baidu.lang.isFunction = function (source) {
123             return '[object Function]' == Object.prototype.toString.call(source);
124         };
125
126         /**
127          * 重载了默认的toString方法,使得返回信息更加准确一些。
128          * @return {string} 对象的String表示形式
129          */
130         baidu.lang.Class.prototype.toString = function(){
131             return "[object " + (this._className || "Object" ) + "]";
132         };
133
134         /**
135          * 释放对象所持有的资源,主要是自定义事件。
136          * @name dispose
137          * @grammar obj.dispose()
138          */
139         baidu.lang.Class.prototype.dispose = function(){
140             delete window[baidu.guid]._instances[this.guid];
141             for(var property in this){
142                 if (!baidu.lang.isFunction(this[property])) {
143                     delete this[property];
144                 }
145             }
146             this.disposed = true;
147         };
148
149         /**
150          * 自定义的事件对象。
151          * @function
152          * @name baidu.lang.Event
153          * @grammar baidu.lang.Event(type[, target])
154          * @param {string} type  事件类型名称。为了方便区分事件和一个普通的方法,事件类型名称必须以"on"(小写)开头。
155          * @param {Object} [target]触发事件的对象
156          * @meta standard
157          * @remark 引入该模块,会自动为Class引入3个事件扩展方法:addEventListener、removeEventListener和dispatchEvent。
158          * @see baidu.lang.Class
159          */
160         baidu.lang.Event = function (type, target) {
161             this.type = type;
162             this.returnValue = true;
163             this.target = target || null;
164             this.currentTarget = null;
165         };
166
167         /**
168          * 注册对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
169          * @grammar obj.addEventListener(type, handler[, key])
170          * @param   {string}   type         自定义事件的名称
171          * @param   {Function} handler      自定义事件被触发时应该调用的回调函数
172          * @param   {string}   [key]        为事件监听函数指定的名称,可在移除时使用。如果不提供,方法会默认为它生成一个全局唯一的key。
173          * @remark  事件类型区分大小写。如果自定义事件名称不是以小写"on"开头,该方法会给它加上"on"再进行判断,即"click"和"onclick"会被认为是同一种事件。
174          */
175         baidu.lang.Class.prototype.addEventListener = function (type, handler, key) {
176             if (!baidu.lang.isFunction(handler)) {
177                 return;
178             }
179             !this.__listeners && (this.__listeners = {});
180             var t = this.__listeners, id;
181             if (typeof key == "string" && key) {
182                 if (/[^\w\-]/.test(key)) {
183                     throw("nonstandard key:" + key);
184                 } else {
185                     handler.hashCode = key;
186                     id = key;
187                 }
188             }
189             type.indexOf("on") != 0 && (type = "on" + type);
190             typeof t[type] != "object" && (t[type] = {});
191             id = id || baidu.lang.guid();
192             handler.hashCode = id;
193             t[type][id] = handler;
194         };
195         
196         /**
197          * 移除对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
198          * @grammar obj.removeEventListener(type, handler)
199          * @param {string}   type     事件类型
200          * @param {Function|string} handler  要移除的事件监听函数或者监听函数的key
201          * @remark  如果第二个参数handler没有被绑定到对应的自定义事件中,什么也不做。
202          */
203         baidu.lang.Class.prototype.removeEventListener = function (type, handler) {
204             if (baidu.lang.isFunction(handler)) {
205                 handler = handler.hashCode;
206             } else if (!baidu.lang.isString(handler)) {
207                 return;
208             }
209             !this.__listeners && (this.__listeners = {});
210             type.indexOf("on") != 0 && (type = "on" + type);
211             var t = this.__listeners;
212             if (!t[type]) {
213                 return;
214             }
215             t[type][handler] && delete t[type][handler];
216         };
217
218         /**
219          * 派发自定义事件,使得绑定到自定义事件上面的函数都会被执行。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
220          * @grammar obj.dispatchEvent(event, options)
221          * @param {baidu.lang.Event|String} event   Event对象,或事件名称(1.1.1起支持)
222          * @param {Object} options 扩展参数,所含属性键值会扩展到Event对象上(1.2起支持)
223          * @remark 处理会调用通过addEventListenr绑定的自定义事件回调函数之外,还会调用直接绑定到对象上面的自定义事件。
224          * 例如:<br>
225          * myobj.onMyEvent = function(){}<br>
226          * myobj.addEventListener("onMyEvent", function(){});
227          */
228         baidu.lang.Class.prototype.dispatchEvent = function (event, options) {
229             if (baidu.lang.isString(event)) {
230                 event = new baidu.lang.Event(event);
231             }
232             !this.__listeners && (this.__listeners = {});
233             options = options || {};
234             for (var i in options) {
235                 event[i] = options[i];
236             }
237             var i, t = this.__listeners, p = event.type;
238             event.target = event.target || this;
239             event.currentTarget = this;
240             p.indexOf("on") != 0 && (p = "on" + p);
241             baidu.lang.isFunction(this[p]) && this[p].apply(this, arguments);
242             if (typeof t[p] == "object") {
243                 for (i in t[p]) {
244                     t[p][i].apply(this, arguments);
245                 }
246             }
247             return event.returnValue;
248         };
249
250         /**
251          * 为类型构造器建立继承关系
252          * @name baidu.lang.inherits
253          * @function
254          * @grammar baidu.lang.inherits(subClass, superClass[, className])
255          * @param {Function} subClass 子类构造器
256          * @param {Function} superClass 父类构造器
257          * @param {string} className 类名标识
258          * @remark 使subClass继承superClass的prototype,
259          * 因此subClass的实例能够使用superClass的prototype中定义的所有属性和方法。<br>
260          * 这个函数实际上是建立了subClass和superClass的原型链集成,并对subClass进行了constructor修正。<br>
261          * <strong>注意:如果要继承构造函数,需要在subClass里面call一下,具体见下面的demo例子</strong>
262          * @shortcut inherits
263          * @meta standard
264          * @see baidu.lang.Class
265          */
266         baidu.lang.inherits = function (subClass, superClass, className) {
267             var key, proto,
268                 selfProps = subClass.prototype,
269                 clazz = new Function();       
270             clazz.prototype = superClass.prototype;
271             proto = subClass.prototype = new clazz();
272             for (key in selfProps) {
273                 proto[key] = selfProps[key];
274             }
275             subClass.prototype.constructor = subClass;
276             subClass.superClass = superClass.prototype;
277
278             if ("string" == typeof className) {
279                 proto._className = className;
280             }
281         };
282
283         /**
284          * @ignore
285          * @namespace baidu.dom 操作dom的方法。
286          */
287         baidu.dom = baidu.dom || {};
288
289         /**
290          * 从文档中获取指定的DOM元素
291          *
292          * @param {string|HTMLElement} id 元素的id或DOM元素
293          * @meta standard
294          * @return {HTMLElement} DOM元素,如果不存在,返回null,如果参数不合法,直接返回参数
295          */
296         baidu._g = baidu.dom._g = function (id) {
297             if (baidu.lang.isString(id)) {
298                 return document.getElementById(id);
299             }
300             return id;
301         };
302
303         /**
304          * 从文档中获取指定的DOM元素
305          * @name baidu.dom.g
306          * @function
307          * @grammar baidu.dom.g(id)
308          * @param {string|HTMLElement} id 元素的id或DOM元素
309          * @meta standard
310          *            
311          * @returns {HTMLElement|null} 获取的元素,查找不到时返回null,如果参数不合法,直接返回参数
312          */
313         baidu.g = baidu.dom.g = function (id) {
314             if ('string' == typeof id || id instanceof String) {
315                 return document.getElementById(id);
316             } else if (id && id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
317                 return id;
318             }
319             return null;
320         };
321
322         /**
323          * 在目标元素的指定位置插入HTML代码
324          * @name baidu.dom.insertHTML
325          * @function
326          * @grammar baidu.dom.insertHTML(element, position, html)
327          * @param {HTMLElement|string} element 目标元素或目标元素的id
328          * @param {string} position 插入html的位置信息,取值为beforeBegin,afterBegin,beforeEnd,afterEnd
329          * @param {string} html 要插入的html
330          * @remark
331          *
332          * 对于position参数,大小写不敏感<br>
333          * 参数的意思:beforeBegin<span>afterBegin   this is span! beforeEnd</span> afterEnd <br />
334          * 此外,如果使用本函数插入带有script标签的HTML字符串,script标签对应的脚本将不会被执行。
335          *
336          * @shortcut insertHTML
337          * @meta standard
338          *            
339          * @returns {HTMLElement} 目标元素
340          */
341         baidu.insertHTML = baidu.dom.insertHTML = function (element, position, html) {
342             element = baidu.dom.g(element);
343             var range,begin;
344
345             if (element.insertAdjacentHTML) {
346                 element.insertAdjacentHTML(position, html);
347             } else {
348                 // 这里不做"undefined" != typeof(HTMLElement) && !window.opera判断,其它浏览器将出错?!
349                 // 但是其实做了判断,其它浏览器下等于这个函数就不能执行了
350                 range = element.ownerDocument.createRange();
351                 // FF下range的位置设置错误可能导致创建出来的fragment在插入dom树之后html结构乱掉
352                 // 改用range.insertNode来插入html, by wenyuxiang @ 2010-12-14.
353                 position = position.toUpperCase();
354                 if (position == 'AFTERBEGIN' || position == 'BEFOREEND') {
355                     range.selectNodeContents(element);
356                     range.collapse(position == 'AFTERBEGIN');
357                 } else {
358                     begin = position == 'BEFOREBEGIN';
359                     range[begin ? 'setStartBefore' : 'setEndAfter'](element);
360                     range.collapse(begin);
361                 }
362                 range.insertNode(range.createContextualFragment(html));
363             }
364             return element;
365         };
366
367         /**
368          * 为目标元素添加className
369          * @name baidu.dom.addClass
370          * @function
371          * @grammar baidu.dom.addClass(element, className)
372          * @param {HTMLElement|string} element 目标元素或目标元素的id
373          * @param {string} className 要添加的className,允许同时添加多个class,中间使用空白符分隔
374          * @remark
375          * 使用者应保证提供的className合法性,不应包含不合法字符,className合法字符参考:http://www./TR/CSS2/syndata.html
376          * @shortcut addClass
377          * @meta standard
378          *             
379          * @returns {HTMLElement} 目标元素
380          */
381         baidu.ac = baidu.dom.addClass = function (element, className) {
382             element = baidu.dom.g(element);
383             var classArray = className.split(/\s+/),
384                 result = element.className,
385                 classMatch = " " + result + " ",
386                 i = 0,
387                 l = classArray.length;
388
389             for (; i < l; i++){
390                  if ( classMatch.indexOf( " " + classArray[i] + " " ) < 0 ) {
391                      result += (result ? ' ' : '') + classArray[i];
392                  }
393             }
394
395             element.className = result;
396             return element;
397         };
398
399         /**
400          * @ignore
401          * @namespace baidu.event 屏蔽浏览器差异性的事件封装。
402          * @property target     事件的触发元素
403          * @property pageX      鼠标事件的鼠标x坐标
404          * @property pageY      鼠标事件的鼠标y坐标
405          * @property keyCode    键盘事件的键值
406          */
407         baidu.event = baidu.event || {};
408
409         /**
410          * 事件监听器的存储表
411          * @private
412          * @meta standard
413          */
414         baidu.event._listeners = baidu.event._listeners || [];
415
416         /**
417          * 为目标元素添加事件监听器
418          * @name baidu.event.on
419          * @function
420          * @grammar baidu.event.on(element, type, listener)
421          * @param {HTMLElement|string|window} element 目标元素或目标元素id
422          * @param {string} type 事件类型
423          * @param {Function} listener 需要添加的监听器
424          * @remark
425          *  1. 不支持跨浏览器的鼠标滚轮事件监听器添加<br>
426          *  2. 改方法不为监听器灌入事件对象,以防止跨iframe事件挂载的事件对象获取失败           
427          * @shortcut on
428          * @meta standard
429          * @see baidu.event.un
430          *            
431          * @returns {HTMLElement|window} 目标元素
432          */
433         baidu.on = baidu.event.on = function (element, type, listener) {
434             type = type.replace(/^on/i, '');
435             element = baidu._g(element);
436             var realListener = function (ev) {
437                 // 1. 这里不支持EventArgument,  原因是跨frame的事件挂载
438                 // 2. element是为了修正this
439                 listener.call(element, ev);
440             },
441             lis = baidu.event._listeners,
442             filter = baidu.event._eventFilter,
443             afterFilter,
444             realType = type;
445             type = type.toLowerCase();
446             // filter过滤
447             if(filter && filter[type]){
448                 afterFilter = filter[type](element, type, realListener);
449                 realType = afterFilter.type;
450                 realListener = afterFilter.listener;
451             }
452             // 事件监听器挂载
453             if (element.addEventListener) {
454                 element.addEventListener(realType, realListener, false);
455             } else if (element.attachEvent) {
456                 element.attachEvent('on' + realType, realListener);
457             }
458          
459             // 将监听器存储到数组中
460             lis[lis.length] = [element, type, listener, realListener, realType];
461             return element;
462         };
463
464         /**
465          * 为目标元素移除事件监听器
466          * @name baidu.event.un
467          * @function
468          * @grammar baidu.event.un(element, type, listener)
469          * @param {HTMLElement|string|window} element 目标元素或目标元素id
470          * @param {string} type 事件类型
471          * @param {Function} listener 需要移除的监听器
472          * @shortcut un
473          * @meta standard
474          *            
475          * @returns {HTMLElement|window} 目标元素
476          */
477         baidu.un = baidu.event.un = function (element, type, listener) {
478             element = baidu._g(element);
479             type = type.replace(/^on/i, '').toLowerCase();
480            
481             var lis = baidu.event._listeners,
482                 len = lis.length,
483                 isRemoveAll = !listener,
484                 item,
485                 realType, realListener;
486            
487             //如果将listener的结构改成json
488             //可以节省掉这个循环,优化性能
489             //但是由于un的使用频率并不高,同时在listener不多的时候
490             //遍历数组的性能消耗不会对代码产生影响
491             //暂不考虑此优化
492             while (len--) {
493                 item = lis[len];
494                
495                 // listener存在时,移除element的所有以listener监听的type类型事件
496                 // listener不存在时,移除element的所有type类型事件
497                 if (item[1] === type
498                     && item[0] === element
499                     && (isRemoveAll || item[2] === listener)) {
500                     realType = item[4];
501                     realListener = item[3];
502                     if (element.removeEventListener) {
503                         element.removeEventListener(realType, realListener, false);
504                     } else if (element.detachEvent) {
505                         element.detachEvent('on' + realType, realListener);
506                     }
507                     lis.splice(len, 1);
508                 }
509             }           
510             return element;
511         };
512
513         /**
514          * 获取event事件,解决不同浏览器兼容问题
515          * @param {Event}
516          * @return {Event}
517          */
518         baidu.getEvent = baidu.event.getEvent = function (event) {
519             return window.event || event;
520         }
521
522         /**
523          * 获取event.target,解决不同浏览器兼容问题
524          * @param {Event}
525          * @return {Target}
526          */
527         baidu.getTarget = baidu.event.getTarget = function (event) {
528             var event = baidu.getEvent(event);
529             return event.target || event.srcElement;
530         }
531
532         /**
533          * 阻止事件的默认行为
534          * @name baidu.event.preventDefault
535          * @function
536          * @grammar baidu.event.preventDefault(event)
537          * @param {Event} event 事件对象
538          * @meta standard
539          */
540         baidu.preventDefault = baidu.event.preventDefault = function (event) {
541            var event = baidu.getEvent(event);
542            if (event.preventDefault) {
543                event.preventDefault();
544            } else {
545                event.returnValue = false;
546            }
547         };
548
549         /**
550          * 停止事件冒泡传播
551          * @param {Event}
552          */
553         baidu.stopBubble = baidu.event.stopBubble = function (event) {
554             event = baidu.getEvent(event);
555             event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
556         }
557
558     })();
559
560     /**
561      * @exports DrawingManager as BMapLib.DrawingManager
562      */
563     var DrawingManager =
564         /**
565          * DrawingManager类的构造函数
566          * @class 鼠标绘制管理类,实现鼠标绘制管理的<b>入口</b>。
567          * 实例化该类后,即可调用该类提供的open
568          * 方法开启绘制模式状态。
569          * 也可加入工具栏进行选择操作。
570          *
571          * @constructor
572          * @param {Map} map Baidu map的实例对象
573          * @param {Json Object} opts 可选的输入参数,非必填项。可输入选项包括:<br />
574          * {"<b>isOpen</b>" : {Boolean} 是否开启绘制模式
575          * <br />"<b>enableDrawingTool</b>" : {Boolean} 是否添加绘制工具栏控件,默认不添加
576          * <br />"<b>drawingToolOptions</b>" : {Json Object} 可选的输入参数,非必填项。可输入选项包括
577          * <br />      "<b>anchor</b>" : {ControlAnchor} 停靠位置、默认左上角
578          * <br />      "<b>offset</b>" : {Size} 偏移值。
579          * <br />      "<b>scale</b>" : {Number} 工具栏的缩放比例,默认为1
580          * <br />      "<b>drawingModes</b>" : {DrawingType<Array>} 工具栏上可以选择出现的绘制模式,将需要显示的DrawingType以数组型形式传入,如[BMAP_DRAWING_MARKER, BMAP_DRAWING_CIRCLE] 将只显示画点和画圆的选项
581          * <br />"<b>enableCalculate</b>" : {Boolean} 绘制是否进行测距(画线时候)、测面(画圆、多边形、矩形)
582          * <br />"<b>markerOptions</b>" : {CircleOptions} 所画的点的可选参数,参考api中的<a href="http://developer.baidu.com/map/reference/index.php?title=Class:%E6%80%BB%E7%B1%BB/%E8%A6%86%E7%9B%96%E7%89%A9%E7%B1%BB">对应类</a>
583          * <br />"<b>circleOptions</b>" : {CircleOptions} 所画的圆的可选参数,参考api中的<a href="http://developer.baidu.com/map/reference/index.php?title=Class:%E6%80%BB%E7%B1%BB/%E8%A6%86%E7%9B%96%E7%89%A9%E7%B1%BB">对应类</a>
584          * <br />"<b>polylineOptions</b>" : {CircleOptions} 所画的线的可选参数,参考api中的<a href="http://developer.baidu.com/map/reference/index.php?title=Class:%E6%80%BB%E7%B1%BB/%E8%A6%86%E7%9B%96%E7%89%A9%E7%B1%BB">对应类</a>
585          * <br />"<b>polygonOptions</b>" : {PolygonOptions} 所画的多边形的可选参数,参考api中的<a href="http://developer.baidu.com/map/reference/index.php?title=Class:%E6%80%BB%E7%B1%BB/%E8%A6%86%E7%9B%96%E7%89%A9%E7%B1%BB">对应类</a>
586          * <br />"<b>rectangleOptions</b>" : {PolygonOptions} 所画的矩形的可选参数,参考api中的<a href="http://developer.baidu.com/map/reference/index.php?title=Class:%E6%80%BB%E7%B1%BB/%E8%A6%86%E7%9B%96%E7%89%A9%E7%B1%BB">对应类</a>
587          *
588          * @example <b>参考示例:</b><br />
589          * var map = new BMap.Map("container");<br />map.centerAndZoom(new BMap.Point(116.404, 39.915), 15);<br />
590          * var myDrawingManagerObject = new BMapLib.DrawingManager(map, {isOpen: true,
591          *     drawingType: BMAP_DRAWING_MARKER, enableDrawingTool: true,
592          *     enableCalculate: false,
593          *     drawingToolOptions: {
594          *         anchor: BMAP_ANCHOR_TOP_LEFT,
595          *         offset: new BMap.Size(5, 5),
596          *         drawingTypes : [
597          *             BMAP_DRAWING_MARKER,
598          *             BMAP_DRAWING_CIRCLE,
599          *             BMAP_DRAWING_POLYLINE,
600          *             BMAP_DRAWING_POLYGON,
601          *             BMAP_DRAWING_RECTANGLE
602          *          ]
603          *     },
604          *     polylineOptions: {
605          *         strokeColor: "#333"
606          *     });
607          */
608         BMapLib.DrawingManager = function(map, opts){
609             if (!map) {
610                 return;
611             }
612             instances.push(this);
613            
614             opts = opts || {};
615
616             this._initialize(map, opts);
617         }
618
619     // 通过baidu.lang下的inherits方法,让DrawingManager继承baidu.lang.Class
620     baidu.lang.inherits(DrawingManager, baidu.lang.Class, "DrawingManager");
621
622     /**
623      * 开启地图的绘制模式
624      *
625      * @example <b>参考示例:</b><br />
626      * myDrawingManagerObject.open();
627      */
628     DrawingManager.prototype.open = function() {
629         // 判断绘制状态是否已经开启
630         if (this._isOpen == true){
631             return true;
632         }
633         closeInstanceExcept(this);
634
635         this._open();
636     }
637
638     /**
639      * 关闭地图的绘制状态
640      *
641      * @example <b>参考示例:</b><br />
642      * myDrawingManagerObject.close();
643      */
644     DrawingManager.prototype.close = function() {
645
646         // 判断绘制状态是否已经开启
647         if (this._isOpen == false){
648             return true;
649         }
650
651         this._close();
652     }
653
654     /**
655      * 设置当前的绘制模式,参数DrawingType,为5个可选常量:
656      * <br/>BMAP_DRAWING_MARKER    画点
657      * <br/>BMAP_DRAWING_CIRCLE    画圆
658      * <br/>BMAP_DRAWING_POLYLINE  画线
659      * <br/>BMAP_DRAWING_POLYGON   画多边形
660      * <br/>BMAP_DRAWING_RECTANGLE 画矩形
661      * @param {DrawingType} DrawingType
662      * @return {Boolean}
663      *
664      * @example <b>参考示例:</b><br />
665      * myDrawingManagerObject.setDrawingMode(BMAP_DRAWING_POLYLINE);
666      */
667     DrawingManager.prototype.setDrawingMode = function(drawingType) {
668         //与当前模式不一样时候才进行重新绑定事件
669         if (this._drawingType != drawingType) {
670             closeInstanceExcept(this);
671             this._setDrawingMode(drawingType);
672         }
673     }
674
675     /**
676      * 获取当前的绘制模式
677      * @return {DrawingType} 绘制的模式
678      *
679      * @example <b>参考示例:</b><br />
680      * alert(myDrawingManagerObject.getDrawingMode());
681      */
682     DrawingManager.prototype.getDrawingMode = function() {
683         return this._drawingType;
684     }
685
686     /**
687      * 打开距离或面积计算
688      *
689      * @example <b>参考示例:</b><br />
690      * myDrawingManagerObject.enableCalculate();
691      */
692     DrawingManager.prototype.enableCalculate = function() {
693         this._enableCalculate = true;
694         this._addGeoUtilsLibrary();
695     }
696
697     /**
698      * 关闭距离或面积计算
699      *
700      * @example <b>参考示例:</b><br />
701      * myDrawingManagerObject.disableCalculate();
702      */
703     DrawingManager.prototype.disableCalculate = function() {
704         this._enableCalculate = false;
705     }
706
707     /**
708      * 鼠标绘制完成后,派发总事件的接口
709      * @name DrawingManager#overlaycomplete
710      * @event
711      * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
712      * <br />{"<b>drawingMode</b> : {DrawingType} 当前的绘制模式
713      * <br />"<b>overlay</b>:{Marker||Polyline||Polygon||Circle} 对应的绘制模式返回对应的覆盖物
714      * <br />"<b>calculate</b>:{Number} 需要开启计算模式才会返回这个值,当绘制线的时候返回距离、绘制多边形、圆、矩形时候返回面积,单位为米,
715      * <br />"<b>label</b>:{Label} 计算面积时候出现在Map上的Label对象
716      *
717      * @example <b>参考示例:</b>
718      * myDrawingManagerObject.addEventListener("overlaycomplete", function(e) {
719      *     alert(e.drawingMode);
720      *     alert(e.overlay);
721      *     alert(e.calculate);
722      *     alert(e.label);
723      * });
724      */
725
726     /**
727      * 绘制点完成后,派发的事件接口
728      * @name DrawingManager#markercomplete
729      * @event
730      * @param {Marker} overlay 回调函数会返回相应的覆盖物,
731      * <br />{"<b>overlay</b> : {Marker}
732      *
733      * @example <b>参考示例:</b>
734      * myDrawingManagerObject.addEventListener("circlecomplete", function(e, overlay) {
735      *     alert(overlay);
736      * });
737      */
738
739     /**
740      * 绘制圆完成后,派发的事件接口
741      * @name DrawingManager#circlecomplete
742      * @event
743      * @param {Circle} overlay 回调函数会返回相应的覆盖物,
744      * <br />{"<b>overlay</b> : {Circle}
745      */
746
747     /**
748      * 绘制线完成后,派发的事件接口
749      * @name DrawingManager#polylinecomplete
750      * @event
751      * @param {Polyline} overlay 回调函数会返回相应的覆盖物,
752      * <br />{"<b>overlay</b> : {Polyline}
753      */
754
755     /**
756      * 绘制多边形完成后,派发的事件接口
757      * @name DrawingManager#polygoncomplete
758      * @event
759      * @param {Polygon} overlay 回调函数会返回相应的覆盖物,
760      * <br />{"<b>overlay</b> : {Polygon}
761      */
762
763     /**
764      * 绘制矩形完成后,派发的事件接口
765      * @name DrawingManager#rectanglecomplete
766      * @event
767      * @param {Polygon} overlay 回调函数会返回相应的覆盖物,
768      * <br />{"<b>overlay</b> : {Polygon}
769      */
770
771     /**
772      * 初始化状态
773      * @param {Map} 地图实例
774      * @param {Object} 参数
775      */
776     DrawingManager.prototype._initialize = function(map, opts) {
777
778         /**
779          * map对象
780          * @private
781          * @type {Map}
782          */
783         this._map = map;
784
785         /**
786          * 配置对象
787          * @private
788          * @type {Object}
789          */
790         this._opts = opts;
791
792         /**
793          * 当前的绘制模式, 默认是绘制点
794          * @private
795          * @type {DrawingType}
796          */
797         this._drawingType = opts.drawingMode || BMAP_DRAWING_MARKER;
798
799         /**
800          * 是否添加添加鼠标绘制工具栏面板
801          */
802         if (opts.enableDrawingTool) {
803             var drawingTool  = new DrawingTool(this, opts.drawingToolOptions);
804             this._drawingTool = drawingTool;
805             map.addControl(drawingTool);
806         }
807
808         //是否计算绘制出的面积
809         if (opts.enableCalculate === true) {
810             this.enableCalculate();
811         } else {
812             this.disableCalculate();
813         }
814
815         /**
816          * 是否已经开启了绘制状态
817          * @private
818          * @type {Boolean}
819          */
820         this._isOpen = !!(opts.isOpen === true);
821         if (this._isOpen) {
822             this._open();
823         }
824
825         this.markerOptions    = opts.markerOptions    || {};
826         this.circleOptions    = opts.circleOptions    || {};
827         this.polylineOptions  = opts.polylineOptions  || {};
828         this.polygonOptions   = opts.polygonOptions   || {};
829         this.rectangleOptions = opts.rectangleOptions || {};
830
831     },
832
833     /**
834      * 开启地图的绘制状态
835      * @return {Boolean},开启绘制状态成功,返回true;否则返回false。
836      */
837     DrawingManager.prototype._open = function() {
838
839         this._isOpen = true;
840
841         //添加遮罩,所有鼠标操作都在这个遮罩上完成
842         if (!this._mask) {
843             this._mask = new Mask();
844         }
845         this._map.addOverlay(this._mask);
846         this._setDrawingMode(this._drawingType);
847
848     }
849
850     /**
851      * 设置当前的绘制模式
852      * @param {DrawingType}
853      */
854     DrawingManager.prototype._setDrawingMode = function(drawingType) {
855
856         this._drawingType = drawingType;
857
858         /**
859          * 开启编辑状态时候才重新进行事件绑定
860          */
861         if (this._isOpen) {
862             //清空之前的自定义事件
863             this._mask.__listeners = {};
864
865             switch (drawingType) {
866                 case BMAP_DRAWING_MARKER:
867                     this._bindMarker();
868                     break;
869                 case BMAP_DRAWING_CIRCLE:
870                     this._bindCircle();
871                     break;
872                 case BMAP_DRAWING_POLYLINE:
873                 case BMAP_DRAWING_POLYGON:
874                     this._bindPolylineOrPolygon();
875                     break;
876                 case BMAP_DRAWING_RECTANGLE:
877                     this._bindRectangle();
878                     break;
879             }
880         }
881
882         /**
883          * 如果添加了工具栏,则也需要改变工具栏的样式
884          */
885         if (this._drawingTool && this._isOpen) {
886             this._drawingTool.setStyleByDrawingMode(drawingType);
887         }
888     }
889
890     /**
891      * 关闭地图的绘制状态
892      * @return {Boolean},关闭绘制状态成功,返回true;否则返回false。
893      */
894     DrawingManager.prototype._close = function() {
895
896         this._isOpen = false;
897
898         if (this._mask) {
899             this._map.removeOverlay(this._mask);
900         }
901
902         /**
903          * 如果添加了工具栏,则关闭时候将工具栏样式设置为拖拽地图
904          */
905         if (this._drawingTool) {
906             this._drawingTool.setStyleByDrawingMode("hander");
907         }
908     }
909
910     /**
911      * 绑定鼠标画点的事件
912      */
913     DrawingManager.prototype._bindMarker = function() {
914
915         var me   = this,
916             map  = this._map,
917             mask = this._mask;
918
919         /**
920          * 鼠标点击的事件
921          */
922         var clickAction = function (e) {
923             // 往地图上添加marker
924             var marker = new BMap.Marker(e.point, me.markerOptions);
925             map.addOverlay(marker);
926             me._dispatchOverlayComplete(marker);
927         }
928
929         mask.addEventListener('click', clickAction);
930     }
931
932     /**
933      * 绑定鼠标画圆的事件
934      */
935     DrawingManager.prototype._bindCircle = function() {
936
937         var me           = this,
938             map          = this._map,
939             mask         = this._mask,
940             circle       = null,
941             centerPoint  = null; //圆的中心点
942
943         /**
944          * 开始绘制圆形
945          */
946         var startAction = function (e) {
947             centerPoint = e.point;
948             circle = new BMap.Circle(centerPoint, 0, me.circleOptions);
949             map.addOverlay(circle);
950             mask.enableEdgeMove();
951             mask.addEventListener('mousemove', moveAction);
952             baidu.on(document, 'mouseup', endAction);
953         }
954
955         /**
956          * 绘制圆形过程中,鼠标移动过程的事件
957          */
958         var moveAction = function(e) {
959             circle.setRadius(me._map.getDistance(centerPoint, e.point));
960         }
961
962         /**
963          * 绘制圆形结束
964          */
965         var endAction = function (e) {
966             var calculate = me._calculate(circle, e.point);
967             me._dispatchOverlayComplete(circle, calculate);
968             centerPoint = null;
969             mask.disableEdgeMove();
970             mask.removeEventListener('mousemove', moveAction);
971             baidu.un(document, 'mouseup', endAction);
972         }
973
974         /**
975          * 鼠标点击起始点
976          */
977         var mousedownAction = function (e) {
978             baidu.preventDefault(e);
979             baidu.stopBubble(e);
980             if (centerPoint == null) {
981                 startAction(e);
982             }
983         }
984
985         mask.addEventListener('mousedown', mousedownAction);
986     }
987
988     /**
989      * 画线和画多边形相似性比较大,公用一个方法
990      */
991     DrawingManager.prototype._bindPolylineOrPolygon = function() {
992
993         var me           = this,
994             map          = this._map,
995             mask         = this._mask,
996             points       = [],   //用户绘制的点
997             drawPoint    = null; //实际需要画在地图上的点
998             overlay      = null,
999             isBinded     = false;
1000
1001         /**
1002          * 鼠标点击的事件
1003          */
1004         var startAction = function (e) {
1005             points.push(e.point);
1006             drawPoint = points.concat(points[points.length - 1]);
1007             if (points.length == 1) {
1008                 if (me._drawingType == BMAP_DRAWING_POLYLINE) {
1009                     overlay = new BMap.Polyline(drawPoint, me.polylineOptions);
1010                 } else if (me._drawingType == BMAP_DRAWING_POLYGON) {
1011                     overlay = new BMap.Polygon(drawPoint, me.polygonOptions);
1012                 }
1013                 map.addOverlay(overlay);
1014             } else {
1015                 overlay.setPath(drawPoint);
1016             }
1017             if (!isBinded) {
1018                 isBinded = true;
1019                 mask.enableEdgeMove();
1020                 mask.addEventListener('mousemove', mousemoveAction);
1021                 mask.addEventListener('dblclick', dblclickAction);
1022             }
1023         }
1024
1025         /**
1026          * 鼠标移动过程的事件
1027          */
1028         var mousemoveAction = function(e) {
1029             overlay.setPositionAt(drawPoint.length - 1, e.point);
1030         }
1031
1032         /**
1033          * 鼠标双击的事件
1034          */
1035         var dblclickAction = function (e) {
1036             baidu.stopBubble(e);
1037             isBinded = false;
1038             mask.disableEdgeMove();
1039             mask.removeEventListener('mousemove', mousemoveAction);
1040             mask.removeEventListener('dblclick', dblclickAction);
1041             overlay.setPath(points);
1042             var calculate = me._calculate(overlay, points.pop());
1043             me._dispatchOverlayComplete(overlay, calculate);
1044             points.length = 0;
1045             drawPoint.length = 0;
1046         }
1047
1048         mask.addEventListener('click', startAction);
1049
1050         //双击时候不放大地图级别
1051         mask.addEventListener('dblclick', function(e){
1052             baidu.stopBubble(e);
1053         });
1054     }
1055
1056     /**
1057      * 绑定鼠标画矩形的事件
1058      */
1059     DrawingManager.prototype._bindRectangle = function() {
1060
1061         var me           = this,
1062             map          = this._map,
1063             mask         = this._mask,
1064             polygon      = null,
1065             startPoint   = null;
1066
1067         /**
1068          * 开始绘制矩形
1069          */
1070         var startAction = function (e) {
1071             baidu.stopBubble(e);
1072             baidu.preventDefault(e);
1073             startPoint = e.point;
1074             var endPoint = startPoint;
1075             polygon = new BMap.Polygon(me._getRectanglePoint(startPoint, endPoint), me.rectangleOptions);
1076             map.addOverlay(polygon);
1077             mask.enableEdgeMove();
1078             mask.addEventListener('mousemove', moveAction);
1079             baidu.on(document, 'mouseup', endAction);
1080         }
1081
1082         /**
1083          * 绘制矩形过程中,鼠标移动过程的事件
1084          */
1085         var moveAction = function(e) {
1086             polygon.setPath(me._getRectanglePoint(startPoint, e.point));
1087         }
1088
1089         /**
1090          * 绘制矩形结束
1091          */
1092         var endAction = function (e) {
1093             var calculate = me._calculate(polygon, polygon.getPath()[2]);
1094             me._dispatchOverlayComplete(polygon, calculate);
1095             startPoint = null;
1096             mask.disableEdgeMove();
1097             mask.removeEventListener('mousemove', moveAction);
1098             baidu.un(document, 'mouseup', endAction);
1099         }
1100
1101         mask.addEventListener('mousedown', startAction);
1102     }
1103
1104     /**
1105      * 添加显示所绘制图形的面积或者长度
1106      * @param {overlay} 覆盖物
1107      * @param {point} 显示的位置
1108      */
1109     DrawingManager.prototype._calculate = function (overlay, point) {
1110         var result = {
1111             data  : 0,    //计算出来的长度或面积
1112             label : null  //显示长度或面积的label对象
1113         };
1114         if (this._enableCalculate && BMapLib.GeoUtils) {
1115             var type = overlay.toString();
1116             //不同覆盖物调用不同的计算方法
1117             switch (type) {
1118                 case "[object Polyline]":
1119                     result.data = BMapLib.GeoUtils.getPolylineDistance(overlay);
1120                     break;
1121                 case "[object Polygon]":
1122                     result.data = BMapLib.GeoUtils.getPolygonArea(overlay);
1123                     break;
1124                 case "[object Circle]":
1125                     var radius = overlay.getRadius();
1126                     result.data = Math.PI * radius * radius;
1127                     break;
1128             }
1129             //一场情况处理
1130             if (!result.data || result.data < 0) {
1131                 result.data = 0;
1132             } else {
1133                 //保留2位小数位
1134                 result.data = result.data.toFixed(2);
1135             }
1136             result.label = this._addLabel(point, result.data);
1137         }
1138         return result;
1139     }
1140
1141     /**
1142      * 开启测距和测面功能需要依赖于GeoUtils库
1143      * 所以这里判断用户是否已经加载,若未加载则用js动态加载
1144      */
1145     DrawingManager.prototype._addGeoUtilsLibrary = function () {
1146         if (!BMapLib.GeoUtils) {
1147             var script = document.createElement('script');
1148             script.setAttribute("type", "text/javascript");
1149             script.setAttribute("src", 'http://api.map.baidu.com/library/GeoUtils/1.2/src/GeoUtils_min.js');
1150             document.body.appendChild(script);
1151         }
1152     }
1153
1154     /**
1155      * 向地图中添加文本标注
1156      * @param {Point}
1157      * @param {String} 所以显示的内容
1158      */
1159     DrawingManager.prototype._addLabel = function (point, content) {
1160         var label = new BMap.Label(content, {
1161             position: point
1162         });
1163         this._map.addOverlay(label);
1164         return label;
1165     }
1166
1167     /**
1168      * 根据起终点获取矩形的四个顶点
1169      * @param {Point} 起点
1170      * @param {Point} 终点
1171      */
1172     DrawingManager.prototype._getRectanglePoint = function (startPoint, endPoint) {
1173         return [
1174             new BMap.Point(startPoint.lng,startPoint.lat),
1175             new BMap.Point(endPoint.lng,startPoint.lat),
1176             new BMap.Point(endPoint.lng,endPoint.lat),
1177             new BMap.Point(startPoint.lng,endPoint.lat)
1178         ];
1179     }
1180
1181     /**
1182      * 派发事件
1183      */
1184     DrawingManager.prototype._dispatchOverlayComplete = function (overlay, calculate) {
1185         var options = {
1186             'overlay'     : overlay,
1187             'drawingMode' : this._drawingType,
1188             'calculate'   : calculate.data  || null,
1189             'label'       : calculate.label || null
1190         };
1191         this.dispatchEvent(this._drawingType + 'complete', overlay);
1192         this.dispatchEvent('overlaycomplete', options);
1193     }
1194
1195     /**
1196      * 创建遮罩对象
1197      */
1198     function Mask(){
1199         /**
1200          * 鼠标到地图边缘的时候是否自动平移地图
1201          */
1202         this._enableEdgeMove = false;
1203     }
1204
1205     Mask.prototype = new BMap.Overlay();
1206
1207     /**
1208      * 这里不使用api中的自定义事件,是为了更灵活使用
1209      */
1210     Mask.prototype.dispatchEvent = baidu.lang.Class.prototype.dispatchEvent;
1211     Mask.prototype.addEventListener = baidu.lang.Class.prototype.addEventListener;
1212     Mask.prototype.removeEventListener = baidu.lang.Class.prototype.removeEventListener;
1213
1214     Mask.prototype.initialize = function(map){
1215         var me = this;
1216         this._map = map;
1217         var div = this.container = document.createElement("div");
1218         var size = this._map.getSize();
1219         div.style.cssText = "position:absolute;background:url(about:blank);cursor:crosshair;width:" + size.width + "px;height:" + size.height + "px";
1220         this._map.addEventListener('resize', function(e) {
1221             me._adjustSize(e.size);
1222         });
1223         this._map.getPanes().floatPane.appendChild(div);
1224         this._bind();
1225         return div;
1226     };
1227
1228     Mask.prototype.draw = function() {
1229         var map   = this._map,
1230             point = map.pixelToPoint(new BMap.Pixel(0, 0)),
1231             pixel = map.pointToOverlayPixel(point);
1232         this.container.style.left = pixel.x + "px";
1233         this.container.style.top  = pixel.y + "px";
1234     };
1235
1236     /**
1237      * 开启鼠标到地图边缘,自动平移地图
1238      */
1239     Mask.prototype.enableEdgeMove = function() {
1240         this._enableEdgeMove = true;
1241     }
1242
1243     /**
1244      * 关闭鼠标到地图边缘,自动平移地图
1245      */
1246     Mask.prototype.disableEdgeMove = function() {
1247         clearInterval(this._edgeMoveTimer);
1248         this._enableEdgeMove = false;
1249     }
1250
1251     /**
1252      * 绑定事件,派发自定义事件
1253      */
1254     Mask.prototype._bind = function() {
1255
1256         var me = this,
1257             map = this._map,
1258             container = this.container,
1259             lastMousedownXY = null,
1260             lastClickXY = null;
1261
1262         /**
1263          * 根据event对象获取鼠标的xy坐标对象
1264          * @param {Event}
1265          * @return {Object} {x:e.x, y:e.y}
1266          */
1267         var getXYbyEvent = function(e){
1268             return {
1269                 x : e.clientX,
1270                 y : e.clientY
1271             }
1272         };
1273
1274         var domEvent = function(e) {
1275             var type = e.type;
1276                 e = baidu.getEvent(e);
1277                 point = me.getDrawPoint(e); //当前鼠标所在点的地理坐标
1278
1279             var dispatchEvent = function(type) {
1280                 e.point = point;
1281                 me.dispatchEvent(e);
1282             }
1283
1284             if (type == "mousedown") {
1285                 lastMousedownXY = getXYbyEvent(e);
1286             }
1287
1288             var nowXY = getXYbyEvent(e);
1289             //click经过一些特殊处理派发,其他同事件按正常的dom事件派发
1290             if (type == "click") {
1291                 //鼠标点击过程不进行移动才派发click和dblclick
1292                 if (Math.abs(nowXY.x - lastMousedownXY.x) < 5 && Math.abs(nowXY.y - lastMousedownXY.y) < 5 ) {
1293                     if (!lastClickXY || !(Math.abs(nowXY.x - lastClickXY.x) < 5 && Math.abs(nowXY.y - lastClickXY.y) < 5)) {
1294                         dispatchEvent('click');
1295                         lastClickXY = getXYbyEvent(e);
1296                     } else {
1297                         lastClickXY = null;
1298                     }
1299                 }
1300             } else {
1301                 dispatchEvent(type);
1302             }
1303         }
1304
1305         /**
1306          * 将事件都遮罩层的事件都绑定到domEvent来处理
1307          */
1308         var events = ['click', 'mousedown', 'mousemove', 'mouseup', 'dblclick'],
1309             index = events.length;
1310         while (index--) {
1311             baidu.on(container, events[index], domEvent);
1312         }
1313
1314         //鼠标移动过程中,到地图边缘后自动平移地图
1315         baidu.on(container, 'mousemove', function(e) {
1316             if (me._enableEdgeMove) {
1317                 me.mousemoveAction(e);
1318             }
1319         });
1320     };
1321
1322     //鼠标移动过程中,到地图边缘后自动平移地图
1323     Mask.prototype.mousemoveAction = function(e) {
1324         function getClientPosition(e) {
1325             var clientX = e.clientX,
1326                 clientY = e.clientY;
1327             if (e.changedTouches) {
1328                 clientX = e.changedTouches[0].clientX;
1329                 clientY = e.changedTouches[0].clientY;
1330             }
1331             return new BMap.Pixel(clientX, clientY);
1332         }
1333
1334         var map       = this._map,
1335             me        = this,
1336             pixel     = map.pointToPixel(this.getDrawPoint(e)),
1337             clientPos = getClientPosition(e),
1338             offsetX   = clientPos.x - pixel.x,
1339             offsetY   = clientPos.y - pixel.y;
1340         pixel = new BMap.Pixel((clientPos.x - offsetX), (clientPos.y - offsetY));
1341         this._draggingMovePixel = pixel;
1342         var point = map.pixelToPoint(pixel),
1343             eventObj = {
1344                 pixel: pixel,
1345                 point: point
1346             };
1347         // 拖拽到地图边缘移动地图
1348         this._panByX = this._panByY = 0;
1349         if (pixel.x <= 20 || pixel.x >= map.width - 20
1350             || pixel.y <= 50 || pixel.y >= map.height - 10) {
1351             if (pixel.x <= 20) {
1352                 this._panByX = 8;
1353             } else if (pixel.x >= map.width - 20) {
1354                 this._panByX = -8;
1355             }
1356             if (pixel.y <= 50) {
1357                 this._panByY = 8;
1358             } else if (pixel.y >= map.height - 10) {
1359                 this._panByY = -8;
1360             }
1361             if (!this._edgeMoveTimer) {
1362                 this._edgeMoveTimer = setInterval(function(){
1363                     map.panBy(me._panByX, me._panByY, {"noAnimation": true});
1364                 }, 30);
1365             }
1366         } else {
1367             if (this._edgeMoveTimer) {
1368                 clearInterval(this._edgeMoveTimer);
1369                 this._edgeMoveTimer = null;
1370             }
1371         }
1372     }
1373
1374     /*
1375      * 调整大小
1376      * @param {Size}
1377      */
1378     Mask.prototype._adjustSize = function(size) {
1379         this.container.style.width  = size.width + 'px';
1380         this.container.style.height = size.height + 'px';
1381     };
1382
1383     /**
1384      * 获取当前绘制点的地理坐标
1385      *
1386      * @param {Event} e e对象
1387      * @return Point对象的位置信息
1388      */
1389     Mask.prototype.getDrawPoint = function(e) {
1390        
1391         var map = this._map,
1392         trigger = baidu.getTarget(e),
1393         x = e.offsetX || e.layerX || 0,
1394         y = e.offsetY || e.layerY || 0;
1395         if (trigger.nodeType != 1) trigger = trigger.parentNode;
1396         while (trigger && trigger != map.getContainer()) {
1397             if (!(trigger.clientWidth == 0 &&
1398                 trigger.clientHeight == 0 &&
1399                 trigger.offsetParent && trigger.offsetParent.nodeName == 'TD')) {
1400                 x += trigger.offsetLeft || 0;
1401                 y += trigger.offsetTop || 0;
1402             }
1403             trigger = trigger.offsetParent;
1404         }
1405         var pixel = new BMap.Pixel(x, y);
1406         var point = map.pixelToPoint(pixel);
1407         return point;
1408
1409     }
1410
1411     /**
1412      * 绘制工具面板,自定义控件
1413      */
1414     function DrawingTool(drawingManager, drawingToolOptions) {
1415         this.drawingManager = drawingManager;
1416
1417         drawingToolOptions = this.drawingToolOptions = drawingToolOptions || {};
1418         // 默认停靠位置和偏移量
1419         this.defaultAnchor = BMAP_ANCHOR_TOP_LEFT;
1420         this.defaultOffset = new BMap.Size(10, 10);
1421
1422         //默认所有工具栏都显示
1423         this.defaultDrawingModes = [
1424             BMAP_DRAWING_MARKER,
1425             BMAP_DRAWING_CIRCLE,
1426             BMAP_DRAWING_POLYLINE,
1427             BMAP_DRAWING_POLYGON,
1428             BMAP_DRAWING_RECTANGLE
1429         ];
1430         //工具栏可显示的绘制模式
1431         if (drawingToolOptions.drawingModes) {
1432             this.drawingModes = drawingToolOptions.drawingModes;
1433         } else {
1434             this.drawingModes = this.defaultDrawingModes
1435         }
1436
1437         //用户设置停靠位置和偏移量
1438         if (drawingToolOptions.anchor) {
1439             this.setAnchor(drawingToolOptions.anchor);
1440         }
1441         if (drawingToolOptions.offset) {
1442             this.setOffset(drawingToolOptions.offset);
1443         }
1444     }
1445
1446     // 通过JavaScript的prototype属性继承于BMap.Control
1447     DrawingTool.prototype = new BMap.Control();
1448
1449     // 自定义控件必须实现自己的initialize方法,并且将控件的DOM元素返回
1450     // 在本方法中创建个div元素作为控件的容器,并将其添加到地图容器中
1451     DrawingTool.prototype.initialize = function(map){
1452         // 创建一个DOM元素
1453         var container = this.container = document.createElement("div");
1454         container.className = "BMapLib_Drawing";
1455         //用来设置外层边框阴影
1456         var panel = this.panel = document.createElement("div");
1457         panel.className = "BMapLib_Drawing_panel";
1458         if (this.drawingToolOptions && this.drawingToolOptions.scale) {
1459             this._setScale(this.drawingToolOptions.scale);
1460         }
1461         container.appendChild(panel);
1462         // 添加内容
1463         panel.innerHTML = this._generalHtml();
1464         //绑定事件
1465         this._bind(panel);
1466         // 添加DOM元素到地图中
1467         map.getContainer().appendChild(container);
1468         // 将DOM元素返回
1469         return container;
1470     }
1471
1472     //生成工具栏的html元素
1473     DrawingTool.prototype._generalHtml = function(map){
1474
1475         //鼠标经过工具栏上的提示信息
1476         var tips = {};
1477         tips["hander"]               = "拖动地图";
1478         tips[BMAP_DRAWING_MARKER]    = "画点";
1479         tips[BMAP_DRAWING_CIRCLE]    = "画圆";
1480         tips[BMAP_DRAWING_POLYLINE]  = "画折线";
1481         tips[BMAP_DRAWING_POLYGON]   = "画多边形";
1482         tips[BMAP_DRAWING_RECTANGLE] = "画矩形";
1483
1484         var getItem = function(className, drawingType) {
1485             return '<a class="' + className + '" drawingType="' + drawingType + '" href="javascript:void(0)" title="' + tips[drawingType] + "" onfocus="this.blur()"></a>';
1486         }
1487
1488         var html = [];
1489         html.push(getItem("BMapLib_box BMapLib_hander", "hander"));
1490         for (var i = 0, len = this.drawingModes.length; i < len; i++) {
1491             var classStr = 'BMapLib_box BMapLib_' + this.drawingModes[i];
1492             if (i == len-1) {
1493                 classStr += ' BMapLib_last';
1494             }
1495             html.push(getItem(classStr, this.drawingModes[i]));
1496         }
1497         return html.join('');
1498     }
1499
1500     /**
1501      * 设置工具栏的缩放比例
1502      */
1503     DrawingTool.prototype._setScale = function(scale){
1504         var width  = 390,
1505             height = 50,
1506             ml = -parseInt((width - width * scale) / 2, 10),
1507             mt = -parseInt((height - height * scale) / 2, 10);
1508         this.container.style.cssText = [
1509             "-moz-transform: scale(" + scale + ");",
1510             "-o-transform: scale(" + scale + ");",
1511             "-webkit-transform: scale(" + scale + ");",
1512             "transform: scale(" + scale + ");",
1513             "margin-left:" + ml + "px;",
1514             "margin-top:" + mt + "px;",
1515             "*margin-left:0px;", //ie6、7
1516             "*margin-top:0px;",  //ie6、7
1517             "margin-left:0px\\0;", //ie8
1518             "margin-top:0px\\0;",  //ie8
1519             //ie下使用滤镜
1520             "filter: progid:DXImageTransform.Microsoft.Matrix(",
1521             "M11=" + scale + ",",
1522             "M12=0,",
1523             "M21=0,",
1524             "M22=" + scale + ",",
1525             "SizingMethod='auto expand');"
1526         ].join('');
1527     }
1528
1529     //绑定工具栏的事件
1530     DrawingTool.prototype._bind = function(panel){
1531         var me = this;
1532         baidu.on(this.panel, 'click', function (e) {
1533             var target = baidu.getTarget(e);
1534             var drawingType = target.getAttribute('drawingType');
1535             me.setStyleByDrawingMode(drawingType);
1536             me._bindEventByDraingMode(drawingType);
1537         });
1538     }
1539
1540     //设置工具栏当前选中的项样式
1541     DrawingTool.prototype.setStyleByDrawingMode = function(drawingType){
1542         if (!drawingType) {
1543             return;
1544         }
1545         var boxs = this.panel.getElementsByTagName("a");
1546         for (var i = 0, len = boxs.length; i < len; i++) {
1547             var box = boxs[i];
1548             if (box.getAttribute('drawingType') == drawingType) {
1549                 var classStr = "BMapLib_box BMapLib_" + drawingType + "_hover";
1550                 if (i == len - 1) {
1551                     classStr += " BMapLib_last";
1552                 }
1553                 box.className = classStr;
1554             } else {
1555                 box.className = box.className.replace(/_hover/, "");
1556             }
1557         }
1558     }
1559
1560     //设置工具栏当前选中的项样式
1561     DrawingTool.prototype._bindEventByDraingMode = function(drawingType){
1562         var drawingManager = this.drawingManager;
1563         //点在拖拽地图的按钮上
1564         if (drawingType == "hander") {
1565             drawingManager.close();
1566         } else {
1567             drawingManager.setDrawingMode(drawingType);
1568             drawingManager.open();
1569         }
1570     }
1571
1572     //用来存储用户实例化出来的drawingmanager对象
1573     var instances = [];
1574
1575     /*
1576      * 关闭其他实例的绘制模式
1577      * @param {DrawingManager} 当前的实例
1578      */
1579     function closeInstanceExcept(instance) {
1580         var index = instances.length;
1581         while (index--) {
1582             if (instances[index] != instance) {
1583                 instances[index].close();
1584             }
1585         }
1586     }
1587
1588 })();
1589

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多