-
Notifications
You must be signed in to change notification settings - Fork 48
Expand file tree
/
Copy pathMarkerTool.js
More file actions
516 lines (470 loc) · 21.4 KB
/
Copy pathMarkerTool.js
File metadata and controls
516 lines (470 loc) · 21.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
/**
* @fileoverview 百度地图的添加标注工具类,对外开放。
* 允许用户在地图上点击后添加一个点标注,允许用户设定标注的图标样式。
* 主入口类是<a href="symbols/BMapLib.MarkerTool.html">MarkerTool</a>,
* 基于Baidu Map API 1.2。
*
* @author Baidu Map Api Group
* @version 1.2
*/
/**
* @namespace BMap的所有library类均放在BMapLib命名空间下
*/
var BMapLib = window.BMapLib = BMapLib || {};
if(typeof BMapLib._toolInUse == "undefined"){
BMapLib._toolInUse = false; //该工具是否在使用,避免多个鼠标工具一起使用的情况
//如:用户打开了添加标注工具,就不能再打开测距工具。
}
(function() {
// 自动检测当前脚本所在目录,用于拼接资源路径
var _scriptPath = (function() {
var scripts = document.getElementsByTagName('script');
var src = document.currentScript
? document.currentScript.src
: scripts[scripts.length - 1].src;
return src.substring(0, src.lastIndexOf('/') + 1);
})();
/**
* baidu tangram 代码部分,tangram代码提供了一些基础的操作,如:类的继承、
* 事件的派发、事件的绑定等,而且兼容各种浏览器,在tangram基础上构建MarkerTool
* 比较快捷。
*/
var baidu = baidu || {guid : "$BAIDU$"};
(function() {
// 一些页面级别唯一的属性,需要挂载在window[baidu.guid]上
window[baidu.guid] = {};
/**
* 将源对象的所有属性拷贝到目标对象中
* @name baidu.extend
* @function
* @grammar baidu.extend(target, source)
* @param {Object} target 目标对象
* @param {Object} source 源对象
* @returns {Object} 目标对象
*/
baidu.extend = function (target, source) {
for (var p in source) {
if (source.hasOwnProperty(p)) {
target[p] = source[p];
}
}
return target;
};
/**
* @ignore
* @namespace
* @baidu.lang 对语言层面的封装,包括类型判断、模块扩展、继承基类以及对象自定义事件的支持。
* @property guid 对象的唯一标识
*/
baidu.lang = baidu.lang || {};
/**
* 返回一个当前页面的唯一标识字符串。
* @function
* @grammar baidu.lang.guid()
* @returns {String} 当前页面的唯一标识字符串
*/
baidu.lang.guid = function() {
return "TANGRAM__" + (window[baidu.guid]._counter ++).toString(36);
};
window[baidu.guid]._counter = window[baidu.guid]._counter || 1;
/**
* 所有类的实例的容器
* key为每个实例的guid
*/
window[baidu.guid]._instances = window[baidu.guid]._instances || {};
/**
* Tangram继承机制提供的一个基类,用户可以通过继承baidu.lang.Class来获取它的属性及方法。
* @function
* @name baidu.lang.Class
* @grammar baidu.lang.Class(guid)
* @param {string} guid 对象的唯一标识
* @meta standard
* @remark baidu.lang.Class和它的子类的实例均包含一个全局唯一的标识guid。
* guid是在构造函数中生成的,因此,继承自baidu.lang.Class的类应该直接或者间接调用它的构造函数。<br>
* baidu.lang.Class的构造函数中产生guid的方式可以保证guid的唯一性,及每个实例都有一个全局唯一的guid。
*/
baidu.lang.Class = function(guid) {
this.guid = guid || baidu.lang.guid();
window[baidu.guid]._instances[this.guid] = this;
};
/**
* 判断目标参数是否string类型或String对象
* @name baidu.lang.isString
* @function
* @grammar baidu.lang.isString(source)
* @param {Any} source 目标参数
* @shortcut isString
* @meta standard
*
* @returns {boolean} 类型判断结果
*/
baidu.lang.isString = function (source) {
return '[object String]' == Object.prototype.toString.call(source);
};
/**
* 判断目标参数是否为function或Function实例
* @name baidu.lang.isFunction
* @function
* @grammar baidu.lang.isFunction(source)
* @param {Any} source 目标参数
* @returns {boolean} 类型判断结果
*/
baidu.lang.isFunction = function (source) {
return '[object Function]' == Object.prototype.toString.call(source);
};
/**
* 重载了默认的toString方法,使得返回信息更加准确一些。
* @return {string} 对象的String表示形式
*/
baidu.lang.Class.prototype.toString = function(){
return "[object " + (this._className || "Object" ) + "]";
};
/**
* 释放对象所持有的资源,主要是自定义事件。
* @name dispose
* @grammar obj.dispose()
*/
baidu.lang.Class.prototype.dispose = function(){
delete window[baidu.guid]._instances[this.guid];
for(var property in this){
if (!baidu.lang.isFunction(this[property])) {
delete this[property];
}
}
this.disposed = true;
};
/**
* 自定义的事件对象。
* @function
* @name baidu.lang.Event
* @grammar baidu.lang.Event(type[, target])
* @param {string} type 事件类型名称。为了方便区分事件和一个普通的方法,事件类型名称必须以"on"(小写)开头。
* @param {Object} [target]触发事件的对象
* @meta standard
* @remark 引入该模块,会自动为Class引入3个事件扩展方法:addEventListener、removeEventListener和dispatchEvent。
* @see baidu.lang.Class
*/
baidu.lang.Event = function (type, target) {
this.type = type;
this.returnValue = true;
this.target = target || null;
this.currentTarget = null;
};
/**
* 注册对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
* @grammar obj.addEventListener(type, handler[, key])
* @param {string} type 自定义事件的名称
* @param {Function} handler 自定义事件被触发时应该调用的回调函数
* @param {string} [key] 为事件监听函数指定的名称,可在移除时使用。如果不提供,方法会默认为它生成一个全局唯一的key。
* @remark 事件类型区分大小写。如果自定义事件名称不是以小写"on"开头,该方法会给它加上"on"再进行判断,即"click"和"onclick"会被认为是同一种事件。
*/
baidu.lang.Class.prototype.addEventListener = function (type, handler, key) {
if (!baidu.lang.isFunction(handler)) {
return;
}
!this.__listeners && (this.__listeners = {});
var t = this.__listeners, id;
if (typeof key == "string" && key) {
if (/[^\w\-]/.test(key)) {
throw("nonstandard key:" + key);
} else {
handler.hashCode = key;
id = key;
}
}
type.indexOf("on") != 0 && (type = "on" + type);
typeof t[type] != "object" && (t[type] = {});
id = id || baidu.lang.guid();
handler.hashCode = id;
t[type][id] = handler;
};
/**
* 移除对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
* @grammar obj.removeEventListener(type, handler)
* @param {string} type 事件类型
* @param {Function|string} handler 要移除的事件监听函数或者监听函数的key
* @remark 如果第二个参数handler没有被绑定到对应的自定义事件中,什么也不做。
*/
baidu.lang.Class.prototype.removeEventListener = function (type, handler) {
if (baidu.lang.isFunction(handler)) {
handler = handler.hashCode;
} else if (!baidu.lang.isString(handler)) {
return;
}
!this.__listeners && (this.__listeners = {});
type.indexOf("on") != 0 && (type = "on" + type);
var t = this.__listeners;
if (!t[type]) {
return;
}
t[type][handler] && delete t[type][handler];
};
/**
* 派发自定义事件,使得绑定到自定义事件上面的函数都会被执行。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
* @grammar obj.dispatchEvent(event, options)
* @param {baidu.lang.Event|String} event Event对象,或事件名称(1.1.1起支持)
* @param {Object} options 扩展参数,所含属性键值会扩展到Event对象上(1.2起支持)
* @remark 处理会调用通过addEventListenr绑定的自定义事件回调函数之外,还会调用直接绑定到对象上面的自定义事件。
* 例如:<br>
* myobj.onMyEvent = function(){}<br>
* myobj.addEventListener("onMyEvent", function(){});
*/
baidu.lang.Class.prototype.dispatchEvent = function (event, options) {
if (baidu.lang.isString(event)) {
event = new baidu.lang.Event(event);
}
!this.__listeners && (this.__listeners = {});
options = options || {};
for (var i in options) {
event[i] = options[i];
}
var i, t = this.__listeners, p = event.type;
event.target = event.target || this;
event.currentTarget = this;
p.indexOf("on") != 0 && (p = "on" + p);
baidu.lang.isFunction(this[p]) && this[p].apply(this, arguments);
if (typeof t[p] == "object") {
for (i in t[p]) {
t[p][i].apply(this, arguments);
}
}
return event.returnValue;
};
/**
* 为类型构造器建立继承关系
* @name baidu.lang.inherits
* @function
* @grammar baidu.lang.inherits(subClass, superClass[, className])
* @param {Function} subClass 子类构造器
* @param {Function} superClass 父类构造器
* @param {string} className 类名标识
* @remark 使subClass继承superClass的prototype,
* 因此subClass的实例能够使用superClass的prototype中定义的所有属性和方法。<br>
* 这个函数实际上是建立了subClass和superClass的原型链集成,并对subClass进行了constructor修正。<br>
* <strong>注意:如果要继承构造函数,需要在subClass里面call一下,具体见下面的demo例子</strong>
* @shortcut inherits
* @meta standard
* @see baidu.lang.Class
*/
baidu.lang.inherits = function (subClass, superClass, className) {
var key, proto,
selfProps = subClass.prototype,
clazz = new Function();
clazz.prototype = superClass.prototype;
proto = subClass.prototype = new clazz();
for (key in selfProps) {
proto[key] = selfProps[key];
}
subClass.prototype.constructor = subClass;
subClass.superClass = superClass.prototype;
if ("string" == typeof className) {
proto._className = className;
}
};
})();
/**
* MarkerTool代码部分, 此类继承基类baidu.lang.Class,便于派发自定义事件,如:markend事件派发
* @exports MarkerTool as BMapLib.MarkerTool
*/
var MarkerTool =
/**
* MarkerTool类的构造函数
* @class 地图上添加标注类,实现点击地图添加点标注<b>入口</b>。
* 实例化该类后,即可调用该类提供的<a href="symbols/BMapLib.MarkerTool.html#open">open</a>
* 方法开启添加点标注状态。
*
* @constructor
* @param {Map} map Baidu map的实例对象
* @param {Json Object} opts 可选的输入参数,非必填项。可输入选项包括:
* <br />"<b>icon</b>" : {Icon} 标注使用到的图标,标注时候鼠标跟随样式也通过此属性设置
* <br />"<b>followText</b>" : {String} 跟随鼠标移动的说明文字,默认为空
* <br />"<b>autoClose</b>" : {Boolean} 是否在每次添加完Marker后自动关闭工具
*
* @example <b>参考示例:</b><br />
* var map = new BMap.Map("container");<br />map.centerAndZoom(new BMap.Point(116.404, 39.915), 15);<br />var mkrTool = new BMapLib.MarkerTool(map, {followText: "添加一个点"});
*/
BMapLib.MarkerTool = function(map, opts){
baidu.lang.Class.call(this);//继承基类baidu.lang.Class的构造函数
this._map = map;
this._opts = {
icon: MarkerTool.SYS_ICONS[8], //默认选择红色雨滴样式
followText: "点击地图添加标注", //鼠标跟随文字提示
autoClose: true //是否添加完毕标注就关闭此工具
};
baidu.extend(this._opts, opts);//用户设定参数覆盖默认设定参数
this._isOpen = false; // 表示控件项当前的状态
this._opts.followText = this._checkStr(this._opts.followText); //检查字串合法性
this._followMarker = null; //鼠标跟随Marker
this._followLabel = null; //鼠标跟随文本提示
}
baidu.lang.inherits(MarkerTool, baidu.lang.Class , "MarkerTool");//继承基类baidu.lang.Class所有prototype属性挂接的方法
/**
* 开启工具
* @return {Boolean} true表示开启成功,false表示开启失败
*/
MarkerTool.prototype.open = function(){
if(!this._map){
return false;
}
if (this._isOpen == true){
return true;
}
if (BMapLib._toolInUse){
return false;
}
BMapLib._toolInUse = true; //当前鼠标状态正在使用中,如果存在多个鼠标工具,
//可以使用此变量限制地图上只能存在一种鼠标操作状态
this._isOpen = true;
// 绑定mousemove 和 click 事件
if (!this._binded){
this._bind();
this._binded = true;
}
//初始化跟随Marker
if (!this._followMarker) {
this._followMarker = new BMap.Marker(this._map.getCenter(), {offset: new BMap.Size(-10, -10)}); //偏移-10像素,解决cursor问题
this._map.addOverlay(this._followMarker);
this._followMarker.setZIndex(1000); // 设置跟随Marker的z轴高度
this._followMarker.hide();
}
//初始化跟随Label
if (!this._followLabel){
this._followLabel = new BMap.Label(this._opts.followText, {offset: new BMap.Size(20, 0)});
}
this._preCursor = this._map.getDefaultCursor(); //记录当前的鼠标cursor
this._map.setDefaultCursor("url(" + MarkerTool.CUR_IMG + "), default");//设置鼠标样式
return true;
};
/**
* 关闭工具
* @return 无返回值
*/
MarkerTool.prototype.close = function(){
if (!this._isOpen){
return;
}
//取消绑定事件
this._map.removeEventListener("mousemove", this._mouseMoveHandler);
this._map.removeEventListener("click", this._clickHandler);
this._followMarker.hide();//隐藏跟随marker
this._map.setDefaultCursor(this._preCursor);//设置鼠标样式
BMapLib._toolInUse = false;
this._isOpen = false;
this._binded = false;
};
/**
* 设置标注的图标及鼠标跟随样式
* @param {Icon} icon 标注样式及鼠标跟随样式,为了方便用户设置Icon,系统提供了
* 24种默认的图标,分别是:BMapLib.MarkerTool.SYS_ICON[0] -- BMapLib.MarkerTool.SYS_ICON[23]
*/
MarkerTool.prototype.setIcon = function(icon){
if (!icon || !(icon instanceof BMap.Icon)){
return;
}
this._opts.icon = icon;
};
/**
* 获取标注图标及鼠标跟随样式
* @return {Icon} 当前标注及鼠标跟随样式
*/
MarkerTool.prototype.getIcon = function(){
return this._opts.icon;
};
/**
* 检查字串的合法性,剔除xss漏洞输入字符
* @return {String} 合法字符
*/
MarkerTool.prototype._checkStr = function(str){
if (!str){
return "";
}
return str.replace(/</g, "<").replace(/>/g, ">");
};
/**
* 绑定地图的mousemove 和 click 事件
* @return 无返回值
*/
MarkerTool.prototype._bind = function(){
var me = this;
if (!me._isOpen){//判断工具是否打开
return;
}
//绑定mousemove事件
me._mouseMoveHandler = function(evt){
var pt = evt.point;
me._followMarker.setIcon(me._opts.icon); //每次都检查最新的Icon
me._followMarker.setPosition(pt);
me._followMarker.setLabel(me._followLabel);
me._followMarker.show();
}
me._map.addEventListener("mousemove", me._mouseMoveHandler);
//绑定click事件
me._clickHandler = function(evt){
var evtPix = evt.pixel;
var iconPix = new BMap.Pixel(evtPix.x - 10, evtPix.y - 10); //补偿_followMarker的-10像素问题,解决cursor问题
var pt = me._map.pixelToPoint(iconPix);
var mkr = new BMap.Marker(pt, {icon: me._opts.icon});
me._map.addOverlay(mkr);
/**
* 添加标注过程中,每次点击地图添加完标注时,派发事件的接口
* @name MarkerTool#onmarkend
* @event
* @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
* <br />"<b>type</b> : {String} 事件类型
* <br />"<b>target</b>:{MarkerTool} 当前MarkerTool对象
* <br />"<b>marker</b>:{Marker} 当前添加的Marker标注
*
* @example <b>参考示例:</b><br />
* mkrTool.addEventListener("markend", function(e) { alert(e.type); });
*/
var event = new baidu.lang.Event("onmarkend");
event.marker = mkr;
me.dispatchEvent(event);
if(me._opts.autoClose){ //自动关闭工具
me.close();
}
}
me._map.addEventListener("click", me._clickHandler);
};
MarkerTool.CUR_IMG = "http://api.map.baidu.com/library/MarkerTool/1.2/src/images/transparent.cur"; //鼠标透明样式,发布时候修改为绝对路径
MarkerTool.ICON_IMG = _scriptPath + "us_mk_icon.png"; //图标样式,自动匹配脚本所在路径
// 4.0 WebGL需要imageSize(精灵图完整尺寸)和正数imageOffset来正确计算纹理坐标
var _isV4 = (BMap.apiVersion === '4.0');
var _sysIconImageSize = _isV4 ? new BMap.Size(144, 92) : null;
function _createSysIcon(width, height, anchorX, anchorY, offsetX, offsetY) {
var opts = {
anchor: new BMap.Size(anchorX, anchorY),
imageOffset: _isV4 ? new BMap.Size(-offsetX, -offsetY) : new BMap.Size(offsetX, offsetY)
};
if (_sysIconImageSize) {
opts.imageSize = _sysIconImageSize;
}
return new BMap.Icon(MarkerTool.ICON_IMG, new BMap.Size(width, height), opts);
}
MarkerTool.SYS_ICONS = [//MarkerTool 提供的系统样式,便于用户选择使用
_createSysIcon(21, 21, 6, 21, 0, 0),
_createSysIcon(21, 21, 6, 21, -23, 0),
_createSysIcon(21, 21, 6, 21, -46, 0),
_createSysIcon(21, 21, 6, 21, -69, 0),
_createSysIcon(21, 21, 6, 21, -92, 0),
_createSysIcon(21, 21, 6, 21, -115, 0),
_createSysIcon(23, 25, 9, 25, 0, -21),
_createSysIcon(23, 25, 9, 25, -23, -21),
_createSysIcon(23, 25, 9, 25, -46, -21),
_createSysIcon(23, 25, 9, 25, -69, -21),
_createSysIcon(23, 25, 9, 25, -92, -21),
_createSysIcon(23, 25, 9, 25, -115, -21),
_createSysIcon(21, 21, 1, 21, 0, -46),
_createSysIcon(21, 21, 1, 21, -23, -46),
_createSysIcon(21, 21, 1, 21, -46, -46),
_createSysIcon(21, 21, 1, 21, -69, -46),
_createSysIcon(21, 21, 1, 21, -92, -46),
_createSysIcon(21, 21, 1, 21, -115, -46),
_createSysIcon(25, 25, 12, 25, 0, -67),
_createSysIcon(25, 25, 12, 25, -25, -67),
_createSysIcon(24, 25, 12, 25, -50, -67),
_createSysIcon(25, 25, 12, 25, -75, -67),
_createSysIcon(25, 25, 12, 25, -100, -67),
_createSysIcon(19, 25, 9, 25, -125, -67)
];
})();//闭包结束