DrawingManager.js 58 KB

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