OpenLayers学习13-event2

事件类好些没看懂… 细节比较复杂 等用到时候再返回头来查吧

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
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
OpenLayers.Events = OpenLayers.Class({
//定义浏览器事件
BROWSER_EVENTS: [
"mouseover", "mouseout",
"mousedown", "mouseup", "mousemove",
"click", "dblclick", "rightclick", "dblrightclick",
"resize", "focus", "blur",
"touchstart", "touchmove", "touchend",
"keydown"
],
/**
* Property: listeners
* {Object} Hashtable of Array(Function): events listener functions
*/
//事件监听函数的哈希表
listeners: null,
/**
* Property: object
* {Object} the code object issuing application events
*/
//触发事件的对象
object: null,
/**
* Property: element
* {DOMElement} the DOM element receiving browser events
*/
//接收浏览器事件的DOM元素
element: null,
/**
* Property: eventHandler
* {Function} bound event handler attached to elements
*/
// DOM元素上的事件处理函数
eventHandler: null,
/**
* APIProperty: fallThrough
* {Boolean}
*/
//
fallThrough: null,
//是否在鼠标evt中加入.xy属性, 相当于是否默认执行下列代码
//function named(evt) {
// this.xy = this.object.events.getMousePosition(evt)
// } 完后需要手动GCthis.clearMouseCache()
includeXY: false,
//自定义扩展Event, 如 OpenLayers.Events.foostart = OpenLayers.Class({
extensions: null,
/**
* Property: extensionCount
* {Object} Keys are event types (like in <listeners>), values are the
* number of extension listeners for each event type.
*/
//哈希表缓存, key是事件类型, value是每个事件对应多少个listeners
extensionCount: null,
/**
* Method: clearMouseListener
* A version of <clearMouseCache> that is bound to this instance so that
* it can be used with <OpenLayers.Event.observe> and
* <OpenLayers.Event.stopObserving>.
*/
//实现clearMouseCache()的另一种方法,
clearMouseListener: null,
/**
* Constructor: OpenLayers.Events
* Construct an OpenLayers.Events object.
*
* Parameters:
* object - {Object} The js object to which this Events object is being added
* element - {DOMElement} A dom element to respond to browser events
* eventTypes - {Array(String)} Deprecated. Array of custom application
* events. A listener may be registered for any named event, regardless
* of the values provided here.
* fallThrough - {Boolean} Allow events to fall through after these have
* been handled?
* options - {Object} Options for the events object.
*/
//OpenLayers.Events构造,
//object: 添加事件的js对象
//element: 接收浏览器事件的dom元素
//eventTypes: Ol事件的数组, 监听已经命名过的的时间类型
//fallThrough:
//options:
initialize: function (object, element, eventTypes, fallThrough, options) {
OpenLayers.Util.extend(this, options);//合并选项
//初始化this
this.object = object;
this.fallThrough = fallThrough;
this.listeners = {};
this.extensions = {};
this.extensionCount = {};
this._msTouches = [];
//缓存的元素为空的话, 绑定元素
if (element != null) {
this.attachToElement(element);
}
},
//GC
destroy: function () {
//遍历extensions, GC
for (var e in this.extensions) {
if (typeof this.extensions[e] !== "boolean") {
this.extensions[e].destroy();
}
}
this.extensions = null;
//对元素解除观察, 特意对滚动做了一个兼容
if (this.element) {
OpenLayers.Event.stopObservingElement(this.element);
if(this.element.hasScrollEvent) {
OpenLayers.Event.stopObserving(
window, "scroll", this.clearMouseListener
);
}
}
this.element = null;
//缓存全都至空
this.listeners = null;
this.object = null;
this.fallThrough = null;
this.eventHandler = null;
},
/**
* APIMethod: addEventType
* Deprecated. Any event can be triggered without adding it first.
*
* Parameters:
* eventName - {String}
*/
//没看出这个空方法能干吗
addEventType: function(eventName) {
},
//绑定缓存元素
attachToElement: function (element) {
if (this.element) {
//如果已有的, 先解除观察
OpenLayers.Event.stopObservingElement(this.element);
} else {
// 更换this指针指向
this.eventHandler = OpenLayers.Function.bindAsEventListener(
this.handleBrowserEvent, this
);
this.clearMouseListener = OpenLayers.Function.bind(
this.clearMouseCache, this
);
}
this.element = element;
var msTouch = !!window.navigator.msMaxTouchPoints;
var type;
for (var i = 0, len = this.BROWSER_EVENTS.length; i < len; i++) {
//遍历定义的浏览器事件类型
type = this.BROWSER_EVENTS[i];
//利用OpenLayers.Event缓存注册事件
OpenLayers.Event.observe(element, type, this.eventHandler
);
//特殊处理touch事件
if (msTouch && type.indexOf('touch') === 0) {
this.addMsTouchListener(element, type, this.eventHandler);
}
}
// disable dragstart in IE so that mousedown/move/up works normally
//禁止IE里的dragstart, 保证mousedown/move/up能工作
OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
},
/**
* APIMethod: on
* Convenience method for registering listeners with a common scope.
* Internally, this method calls <register> as shown in the examples
* below.
*
* Example use:
* (code)
* // register a single listener for the "loadstart" event
* events.on({"loadstart": loadStartListener});
*
* // this is equivalent to the following
* events.register("loadstart", undefined, loadStartListener);
*
* // register multiple listeners to be called with the same `this` object
* events.on({
* "loadstart": loadStartListener,
* "loadend": loadEndListener,
* scope: object
* });
*
* // this is equivalent to the following
* events.register("loadstart", object, loadStartListener);
* events.register("loadend", object, loadEndListener);
* (end)
*
* Parameters:
* object - {Object}
*/
//用 this.register注册事件, scope是指作用域, 十个关键字
//events.on({
// "loadstart": loadStartListener,
// "loadend": loadEndListener,
// scope: object
// });
on: function(object) {
for(var type in object) {
if(type != "scope" && object.hasOwnProperty(type)) {
this.register(type, object.scope, object[type]);
}
}
},
/**
* APIMethod: register
* Register an event on the events object.
*
* When the event is triggered, the 'func' function will be called, in the
* context of 'obj'. Imagine we were to register an event, specifying an
* OpenLayers.Bounds Object as 'obj'. When the event is triggered, the
* context in the callback function will be our Bounds object. This means
* that within our callback function, we can access the properties and
* methods of the Bounds object through the "this" variable. So our
* callback could execute something like:
* : leftStr = "Left: " + this.left;
*
* or
*
* : centerStr = "Center: " + this.getCenterLonLat();
*
* Parameters:
* type - {String} Name of the event to register
* obj - {Object} The object to bind the context to for the callback#.
* If no object is specified, default is the Events's 'object' property.
* func - {Function} The callback function. If no callback is
* specified, this function does nothing.
* priority - {Boolean|Object} If true, adds the new listener to the
* *front* of the events queue instead of to the end.
*
* Valid options for priority:
* extension - {Boolean} If true, then the event will be registered as
* extension event. Extension events are handled before all other
* events.
*/
//注册的事件触发后, func会被执行, 上下文this是obj.
//priority为true的话, 会把事件加在这个事件队列最前边
register: function (type, obj, func, priority) {
if (type in OpenLayers.Events && !this.extensions[type]) {
//type缓存在extensions里
this.extensions[type] = new OpenLayers.Events[type](this);
}
if (func != null) {
if (obj == null) {
obj = this.object;//缓存obj
}
var listeners = this.listeners[type];
if (!listeners) {
//此type还没有的话, 就创建个新的[]缓存
listeners = [];
this.listeners[type] = listeners;
this.extensionCount[type] = 0;
}
var listener = {obj: obj, func: func};
if (priority) {
//有priority的话, 放在数组最前边
listeners.splice(this.extensionCount[type], 0, listener);
if (typeof priority === "object" && priority.extension) {
this.extensionCount[type]++;
}
} else {
listeners.push(listener);
}
}
},
/**
* APIMethod: registerPriority
* Same as register() but adds the new listener to the *front* of the
* events queue instead of to the end.
*
* TODO: get rid of this in 3.0 - Decide whether listeners should be
* called in the order they were registered or in reverse order.
*
*
* Parameters:
* type - {String} Name of the event to register
* obj - {Object} The object to bind the context to for the callback#.
* If no object is specified, default is the Events's
* 'object' property.
* func - {Function} The callback function. If no callback is
* specified, this function does nothing.
*/
//最后一个参数固定为true的register
registerPriority: function (type, obj, func) {
this.register(type, obj, func, true);
},
/**
* APIMethod: un
* Convenience method for unregistering listeners with a common scope.
* Internally, this method calls <unregister> as shown in the examples
* below.
*
* Example use:
* (code)
* // unregister a single listener for the "loadstart" event
* events.un({"loadstart": loadStartListener});
*
* // this is equivalent to the following
* events.unregister("loadstart", undefined, loadStartListener);
*
* // unregister multiple listeners with the same `this` object
* events.un({
* "loadstart": loadStartListener,
* "loadend": loadEndListener,
* scope: object
* });
*
* // this is equivalent to the following
* events.unregister("loadstart", object, loadStartListener);
* events.unregister("loadend", object, loadEndListener);
* (end)
*/
// on的逆操作
un: function(object) {
for(var type in object) {
if(type != "scope" && object.hasOwnProperty(type)) {
this.unregister(type, object.scope, object[type]);
}
}
},
/**
* APIMethod: unregister
*
* Parameters:
* type - {String}
* obj - {Object} If none specified, defaults to this.object
* func - {Function}
*/
//register的逆操作
unregister: function (type, obj, func) {
if (obj == null) {
obj = this.object;
}
var listeners = this.listeners[type];
if (listeners != null) {
for (var i=0, len=listeners.length; i<len; i++) {
if (listeners[i].obj == obj && listeners[i].func == func) {
listeners.splice(i, 1);
break;
}
}
}
},
/**
* Method: remove
* Remove all listeners for a given event type. If type is not registered,
* does nothing.
*
* Parameters:
* type - {String}
*/
//删除type类型下的所有 listeners
remove: function(type) {
if (this.listeners[type] != null) {
this.listeners[type] = [];
}
},
/**
* APIMethod: triggerEvent
* Trigger a specified registered event.
*
* Parameters:
* type - {String}
* evt - {Event || Object} will be passed to the listeners.
*
* Returns:
* {Boolean} The last listener return. If a listener returns false, the
* chain of listeners will stop getting called.
*/
//触发事件
triggerEvent: function (type, evt) {
var listeners = this.listeners[type];
//没监听就直接返回
if(!listeners || listeners.length == 0) {
return undefined;
}
//组装evt对象
if (evt == null) {
evt = {};
}
evt.object = this.object;
evt.element = this.element;
if(!evt.type) {
evt.type = type;
}
//拷贝listeners
listeners = listeners.slice();
var continueChain;
for (var i=0, len=listeners.length; i<len; i++) {
var callback = listeners[i];
// bind the context to callback.obj
continueChain = callback.func.apply(callback.obj, [evt]);
if ((continueChain != undefined) && (continueChain == false)) {
// if callback returns false, execute no more callbacks.
break;
}
}
//fallThrough为false的, 执行完直接stop
if (!this.fallThrough) {
OpenLayers.Event.stop(evt, true);
}
return continueChain;
},
// 在triggerEvent()之前添加事件的xy属性
handleBrowserEvent: function (evt) {
var type = evt.type, listeners = this.listeners[type];
if(!listeners || listeners.length == 0) {
return;
}
//触摸事件都有xy
var touches = evt.touches;
if (touches && touches[0]) {
var x = 0;
var y = 0;
var num = touches.length;
var touch;
for (var i=0; i<num; ++i) {
touch = this.getTouchClientXY(touches[i]);
x += touch.clientX;
y += touch.clientY;
}
evt.clientX = x / num;
evt.clientY = y / num;
}
//需要includeXY的话给鼠标事件增加xy
if (this.includeXY) {
evt.xy = this.getMousePosition(evt);
}
this.triggerEvent(type, evt);
},
/**
* Method: getTouchClientXY
* WebKit has a few bugs for clientX/clientY. This method detects them
* and calculate the correct values.
*
* Parameters:
* evt - {Touch} a Touch object from a TouchEvent
*
* Returns:
* {Object} An object with only clientX and clientY properties with the
* calculated values.
*/
//获取touch事件的xy
getTouchClientXY: function (evt) {
// olMochWin is to override window, used for testing
var win = window.olMockWin || window,
winPageX = win.pageXOffset,
winPageY = win.pageYOffset,
x = evt.clientX,
y = evt.clientY;
if (evt.pageY === 0 && Math.floor(y) > Math.floor(evt.pageY) ||
evt.pageX === 0 && Math.floor(x) > Math.floor(evt.pageX)) {
// iOS4 include scroll offset in clientX/Y
x = x - winPageX;
y = y - winPageY;
} else if (y < (evt.pageY - winPageY) || x < (evt.pageX - winPageX) ) {
// Some Android browsers have totally bogus values for clientX/Y
// when scrolling/zooming a page
x = evt.pageX - winPageX;
y = evt.pageY - winPageY;
}
evt.olClientX = x;
evt.olClientY = y;
return {
clientX: x,
clientY: y
};
},
/**
* APIMethod: clearMouseCache
* Clear cached data about the mouse position. This should be called any
* time the element that events are registered on changes position
* within the page.
*/
// 清除鼠标缓存
clearMouseCache: function() {
this.element.scrolls = null;
this.element.lefttop = null;
this.element.offsets = null;
},
/**
* Method: getMousePosition
*
* Parameters:
* evt - {Event}
*
* Returns:
* {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
* for offsets
*/
//获得鼠标位置, 包括处理滚动和偏移
getMousePosition: function (evt) {
if (!this.includeXY) {
this.clearMouseCache();
} else if (!this.element.hasScrollEvent) {
OpenLayers.Event.observe(window, "scroll", this.clearMouseListener);
this.element.hasScrollEvent = true;
}
if (!this.element.scrolls) {
var viewportElement = OpenLayers.Util.getViewportElement();
this.element.scrolls = [
window.pageXOffset || viewportElement.scrollLeft,
window.pageYOffset || viewportElement.scrollTop
];
}
if (!this.element.lefttop) {
this.element.lefttop = [
(document.documentElement.clientLeft || 0),
(document.documentElement.clientTop || 0)
];
}
if (!this.element.offsets) {
this.element.offsets = OpenLayers.Util.pagePosition(this.element);
}
return new OpenLayers.Pixel(
(evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
- this.element.lefttop[0],
(evt.clientY + this.element.scrolls[1]) - this.element.offsets[1]
- this.element.lefttop[1]
);
},
//绑定触摸事件
//element: 绑定的元素
//type: 触摸事件类型
//handler: 包装过的处理函数
addMsTouchListener: function (element, type, handler) {
var eventHandler = this.eventHandler;
var touches = this._msTouches;
//包装处理函数, 对于多点触摸事件, 每个touch都要stop
function msHandler(evt) {
handler(OpenLayers.Util.applyDefaults({
stopPropagation: function() {
for (var i=touches.length-1; i>=0; --i) {
touches[i].stopPropagation();
}
},
preventDefault: function() {
for (var i=touches.length-1; i>=0; --i) {
touches[i].preventDefault();
}
},
type: type
}, evt));
}
//按类型分配
switch (type) {
case 'touchstart':
return this.addMsTouchListenerStart(element, type, msHandler);
case 'touchend':
return this.addMsTouchListenerEnd(element, type, msHandler);
case 'touchmove':
return this.addMsTouchListenerMove(element, type, msHandler);
default:
throw 'Unknown touch event type';
}
},
// 多点touch start
addMsTouchListenerStart: function(element, type, handler) {
var touches = this._msTouches;
var cb = function(e) {
var alreadyInArray = false;
for (var i=0, ii=touches.length; i<ii; ++i) {
if (touches[i].pointerId == e.pointerId) {
alreadyInArray = true;//查找到的对应的
break;
}
}
if (!alreadyInArray) {
touches.push(e);//没有对应的就继续push
}
e.touches = touches.slice();
handler(e);//执行副本
};
OpenLayers.Event.observe(element, 'MSPointerDown', cb);//监听类似mousedown
// Need to also listen for end events to keep the _msTouches list
// accurate
//遍历删除touches数组
var internalCb = function(e) {
for (var i=0, ii=touches.length; i<ii; ++i) {
if (touches[i].pointerId == e.pointerId) {
touches.splice(i, 1);
break;
}
}
};
OpenLayers.Event.observe(element, 'MSPointerUp', internalCb);
},
/**
* Method: addMsTouchListenerMove
*
* Parameters:
* element - {DOMElement} The DOM element to register the listener on
* type - {String} The event type
* handler - {Function} the handler
*/
addMsTouchListenerMove: function (element, type, handler) {
var touches = this._msTouches;
var cb = function(e) {
//Don't fire touch moves when mouse isn't down
if (e.pointerType == e.MSPOINTER_TYPE_MOUSE && e.buttons == 0) {
return;
}
if (touches.length == 1 && touches[0].pageX == e.pageX &&
touches[0].pageY == e.pageY) {
// don't trigger event when pointer has not moved
return;
}
for (var i=0, ii=touches.length; i<ii; ++i) {
if (touches[i].pointerId == e.pointerId) {
touches[i] = e;
break;
}
}
e.touches = touches.slice();
handler(e);
};
OpenLayers.Event.observe(element, 'MSPointerMove', cb);//move事件
},
/**
* Method: addMsTouchListenerEnd
*
* Parameters:
* element - {DOMElement} The DOM element to register the listener on
* type - {String} The event type
* handler - {Function} the handler
*/
addMsTouchListenerEnd: function (element, type, handler) {
var touches = this._msTouches;
var cb = function(e) {
for (var i=0, ii=touches.length; i<ii; ++i) {
if (touches[i].pointerId == e.pointerId) {
touches.splice(i, 1);
break;
}
}
e.touches = touches.slice();
handler(e);
};
OpenLayers.Event.observe(element, 'MSPointerUp', cb);//类似mouseUp
},
CLASS_NAME: "OpenLayers.Events"
});