OpenLayers学习13-event2 Posted on 2015-02-10 | In OpenLayers学习 | 事件类好些没看懂… 细节比较复杂 等用到时候再返回头来查吧 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703OpenLayers.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"});