+
+ obj.removeEventListener(this._touchstart, obj[pre + this._touchstart + id], false);
+ (L.Browser.pointer ? document.documentElement : obj).removeEventListener(
+ this._touchend, obj[pre + this._touchend + id], false);
+
+ if (L.Browser.pointer) {
+ document.documentElement.removeEventListener(L.DomEvent.POINTER_CANCEL, obj[pre + this._touchend + id],
+ false);
+ }
+
+ return this;
+ }
+});
+
+
+/*
+ * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
+ */
+
+L.extend(L.DomEvent, {
+
+ //static
+ POINTER_DOWN: L.Browser.msPointer ? 'MSPointerDown' : 'pointerdown',
+ POINTER_MOVE: L.Browser.msPointer ? 'MSPointerMove' : 'pointermove',
+ POINTER_UP: L.Browser.msPointer ? 'MSPointerUp' : 'pointerup',
+ POINTER_CANCEL: L.Browser.msPointer ? 'MSPointerCancel' : 'pointercancel',
+
+ _pointers: [],
+ _pointerDocumentListener: false,
+
+ // Provides a touch events wrapper for (ms)pointer events.
+ // Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019
+ //ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
+
+ addPointerListener: function (obj, type, handler, id) {
+
+ switch (type) {
+ case 'touchstart':
+ return this.addPointerListenerStart(obj, type, handler, id);
+ case 'touchend':
+ return this.addPointerListenerEnd(obj, type, handler, id);
+ case 'touchmove':
+ return this.addPointerListenerMove(obj, type, handler, id);
+ default:
+ throw 'Unknown touch event type';
+ }
+ },
+
+ addPointerListenerStart: function (obj, type, handler, id) {
+ var pre = '_leaflet_',
+ pointers = this._pointers;
+
+ var cb = function (e) {
+
+ L.DomEvent.preventDefault(e);
+
+ var alreadyInArray = false;
+ for (var i = 0; i < pointers.length; i++) {
+ if (pointers[i].pointerId === e.pointerId) {
+ alreadyInArray = true;
+ break;
+ }
+ }
+ if (!alreadyInArray) {
+ pointers.push(e);
+ }
+
+ e.touches = pointers.slice();
+ e.changedTouches = [e];
+
+ handler(e);
+ };
+
+ obj[pre + 'touchstart' + id] = cb;
+ obj.addEventListener(this.POINTER_DOWN, cb, false);
+
+ // need to also listen for end events to keep the _pointers list accurate
+ // this needs to be on the body and never go away
+ if (!this._pointerDocumentListener) {
+ var internalCb = function (e) {
+ for (var i = 0; i < pointers.length; i++) {
+ if (pointers[i].pointerId === e.pointerId) {
+ pointers.splice(i, 1);
+ break;
+ }
+ }
+ };
+ //We listen on the documentElement as any drags that end by moving the touch off the screen get fired there
+ document.documentElement.addEventListener(this.POINTER_UP, internalCb, false);
+ document.documentElement.addEventListener(this.POINTER_CANCEL, internalCb, false);
+
+ this._pointerDocumentListener = true;
+ }
+
+ return this;
+ },
+
+ addPointerListenerMove: function (obj, type, handler, id) {
+ var pre = '_leaflet_',
+ touches = this._pointers;
+
+ function cb(e) {
+
+ // don't fire touch moves when mouse isn't down
+ if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }
+
+ for (var i = 0; i < touches.length; i++) {
+ if (touches[i].pointerId === e.pointerId) {
+ touches[i] = e;
+ break;
+ }
+ }
+
+ e.touches = touches.slice();
+ e.changedTouches = [e];
+
+ handler(e);
+ }
+
+ obj[pre + 'touchmove' + id] = cb;
+ obj.addEventListener(this.POINTER_MOVE, cb, false);
+
+ return this;
+ },
+
+ addPointerListenerEnd: function (obj, type, handler, id) {
+ var pre = '_leaflet_',
+ touches = this._pointers;
+
+ var cb = function (e) {
+ for (var i = 0; i < touches.length; i++) {
+ if (touches[i].pointerId === e.pointerId) {
+ touches.splice(i, 1);
+ break;
+ }
+ }
+
+ e.touches = touches.slice();
+ e.changedTouches = [e];
+
+ handler(e);
+ };
+
+ obj[pre + 'touchend' + id] = cb;
+ obj.addEventListener(this.POINTER_UP, cb, false);
+ obj.addEventListener(this.POINTER_CANCEL, cb, false);
+
+ return this;
+ },
+
+ removePointerListener: function (obj, type, id) {
+ var pre = '_leaflet_',
+ cb = obj[pre + type + id];
+
+ switch (type) {
+ case 'touchstart':
+ obj.removeEventListener(this.POINTER_DOWN, cb, false);
+ break;
+ case 'touchmove':
+ obj.removeEventListener(this.POINTER_MOVE, cb, false);
+ break;
+ case 'touchend':
+ obj.removeEventListener(this.POINTER_UP, cb, false);
+ obj.removeEventListener(this.POINTER_CANCEL, cb, false);
+ break;
+ }
+