| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 | 
							- var _event = require("../core/event");
 
- var addEventListener = _event.addEventListener;
 
- var removeEventListener = _event.removeEventListener;
 
- var normalizeEvent = _event.normalizeEvent;
 
- var getNativeEvent = _event.getNativeEvent;
 
- var zrUtil = require("../core/util");
 
- var Eventful = require("../mixin/Eventful");
 
- var env = require("../core/env");
 
- /* global document */
 
- var TOUCH_CLICK_DELAY = 300;
 
- var globalEventSupported = env.domSupported;
 
- var localNativeListenerNames = function () {
 
-   var mouseHandlerNames = ['click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu'];
 
-   var touchHandlerNames = ['touchstart', 'touchend', 'touchmove'];
 
-   var pointerEventNameMap = {
 
-     pointerdown: 1,
 
-     pointerup: 1,
 
-     pointermove: 1,
 
-     pointerout: 1
 
-   };
 
-   var pointerHandlerNames = zrUtil.map(mouseHandlerNames, function (name) {
 
-     var nm = name.replace('mouse', 'pointer');
 
-     return pointerEventNameMap.hasOwnProperty(nm) ? nm : name;
 
-   });
 
-   return {
 
-     mouse: mouseHandlerNames,
 
-     touch: touchHandlerNames,
 
-     pointer: pointerHandlerNames
 
-   };
 
- }();
 
- var globalNativeListenerNames = {
 
-   mouse: ['mousemove', 'mouseup'],
 
-   pointer: ['pointermove', 'pointerup']
 
- };
 
- function eventNameFix(name) {
 
-   return name === 'mousewheel' && env.browser.firefox ? 'DOMMouseScroll' : name;
 
- }
 
- function isPointerFromTouch(event) {
 
-   var pointerType = event.pointerType;
 
-   return pointerType === 'pen' || pointerType === 'touch';
 
- } // function useMSGuesture(handlerProxy, event) {
 
- //     return isPointerFromTouch(event) && !!handlerProxy._msGesture;
 
- // }
 
- // function onMSGestureChange(proxy, event) {
 
- //     if (event.translationX || event.translationY) {
 
- //         // mousemove is carried by MSGesture to reduce the sensitivity.
 
- //         proxy.handler.dispatchToElement(event.target, 'mousemove', event);
 
- //     }
 
- //     if (event.scale !== 1) {
 
- //         event.pinchX = event.offsetX;
 
- //         event.pinchY = event.offsetY;
 
- //         event.pinchScale = event.scale;
 
- //         proxy.handler.dispatchToElement(event.target, 'pinch', event);
 
- //     }
 
- // }
 
- /**
 
-  * Prevent mouse event from being dispatched after Touch Events action
 
-  * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>
 
-  * 1. Mobile browsers dispatch mouse events 300ms after touchend.
 
-  * 2. Chrome for Android dispatch mousedown for long-touch about 650ms
 
-  * Result: Blocking Mouse Events for 700ms.
 
-  *
 
-  * @param {DOMHandlerScope} scope
 
-  */
 
- function setTouchTimer(scope) {
 
-   scope.touching = true;
 
-   if (scope.touchTimer != null) {
 
-     clearTimeout(scope.touchTimer);
 
-     scope.touchTimer = null;
 
-   }
 
-   scope.touchTimer = setTimeout(function () {
 
-     scope.touching = false;
 
-     scope.touchTimer = null;
 
-   }, 700);
 
- } // Mark touch, which is useful in distinguish touch and
 
- // mouse event in upper applicatoin.
 
- function markTouch(event) {
 
-   event && (event.zrByTouch = true);
 
- } // function markTriggeredFromLocal(event) {
 
- //     event && (event.__zrIsFromLocal = true);
 
- // }
 
- // function isTriggeredFromLocal(instance, event) {
 
- //     return !!(event && event.__zrIsFromLocal);
 
- // }
 
- function normalizeGlobalEvent(instance, event) {
 
-   // offsetX, offsetY still need to be calculated. They are necessary in the event
 
-   // handlers of the upper applications. Set `true` to force calculate them.
 
-   return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true);
 
- }
 
- /**
 
-  * Detect whether the given el is in `painterRoot`.
 
-  */
 
- function isLocalEl(instance, el) {
 
-   var elTmp = el;
 
-   var isLocal = false;
 
-   while (elTmp && elTmp.nodeType !== 9 && !(isLocal = elTmp.domBelongToZr || elTmp !== el && elTmp === instance.painterRoot)) {
 
-     elTmp = elTmp.parentNode;
 
-   }
 
-   return isLocal;
 
- }
 
- /**
 
-  * Make a fake event but not change the original event,
 
-  * becuase the global event probably be used by other
 
-  * listeners not belonging to zrender.
 
-  * @class
 
-  */
 
- function FakeGlobalEvent(instance, event) {
 
-   this.type = event.type;
 
-   this.target = this.currentTarget = instance.dom;
 
-   this.pointerType = event.pointerType; // Necessray for the force calculation of zrX, zrY
 
-   this.clientX = event.clientX;
 
-   this.clientY = event.clientY; // Because we do not mount global listeners to touch events,
 
-   // we do not copy `targetTouches` and `changedTouches` here.
 
- }
 
- var fakeGlobalEventProto = FakeGlobalEvent.prototype; // we make the default methods on the event do nothing,
 
- // otherwise it is dangerous. See more details in
 
- // [Drag outside] in `Handler.js`.
 
- fakeGlobalEventProto.stopPropagation = fakeGlobalEventProto.stopImmediatePropagation = fakeGlobalEventProto.preventDefault = zrUtil.noop;
 
- /**
 
-  * Local DOM Handlers
 
-  * @this {HandlerProxy}
 
-  */
 
- var localDOMHandlers = {
 
-   mousedown: function (event) {
 
-     event = normalizeEvent(this.dom, event);
 
-     this._mayPointerCapture = [event.zrX, event.zrY];
 
-     this.trigger('mousedown', event);
 
-   },
 
-   mousemove: function (event) {
 
-     event = normalizeEvent(this.dom, event);
 
-     var downPoint = this._mayPointerCapture;
 
-     if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) {
 
-       togglePointerCapture(this, true);
 
-     }
 
-     this.trigger('mousemove', event);
 
-   },
 
-   mouseup: function (event) {
 
-     event = normalizeEvent(this.dom, event);
 
-     togglePointerCapture(this, false);
 
-     this.trigger('mouseup', event);
 
-   },
 
-   mouseout: function (event) {
 
-     event = normalizeEvent(this.dom, event); // Similarly to the browser did on `document` and touch event,
 
-     // `globalout` will be delayed to final pointer cature release.
 
-     if (this._pointerCapturing) {
 
-       event.zrEventControl = 'no_globalout';
 
-     } // There might be some doms created by upper layer application
 
-     // at the same level of painter.getViewportRoot() (e.g., tooltip
 
-     // dom created by echarts), where 'globalout' event should not
 
-     // be triggered when mouse enters these doms. (But 'mouseout'
 
-     // should be triggered at the original hovered element as usual).
 
-     var element = event.toElement || event.relatedTarget;
 
-     event.zrIsToLocalDOM = isLocalEl(this, element);
 
-     this.trigger('mouseout', event);
 
-   },
 
-   touchstart: function (event) {
 
-     // Default mouse behaviour should not be disabled here.
 
-     // For example, page may needs to be slided.
 
-     event = normalizeEvent(this.dom, event);
 
-     markTouch(event);
 
-     this._lastTouchMoment = new Date();
 
-     this.handler.processGesture(event, 'start'); // For consistent event listener for both touch device and mouse device,
 
-     // we simulate "mouseover-->mousedown" in touch device. So we trigger
 
-     // `mousemove` here (to trigger `mouseover` inside), and then trigger
 
-     // `mousedown`.
 
-     localDOMHandlers.mousemove.call(this, event);
 
-     localDOMHandlers.mousedown.call(this, event);
 
-   },
 
-   touchmove: function (event) {
 
-     event = normalizeEvent(this.dom, event);
 
-     markTouch(event);
 
-     this.handler.processGesture(event, 'change'); // Mouse move should always be triggered no matter whether
 
-     // there is gestrue event, because mouse move and pinch may
 
-     // be used at the same time.
 
-     localDOMHandlers.mousemove.call(this, event);
 
-   },
 
-   touchend: function (event) {
 
-     event = normalizeEvent(this.dom, event);
 
-     markTouch(event);
 
-     this.handler.processGesture(event, 'end');
 
-     localDOMHandlers.mouseup.call(this, event); // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is
 
-     // triggered in `touchstart`. This seems to be illogical, but by this mechanism,
 
-     // we can conveniently implement "hover style" in both PC and touch device just
 
-     // by listening to `mouseover` to add "hover style" and listening to `mouseout`
 
-     // to remove "hover style" on an element, without any additional code for
 
-     // compatibility. (`mouseout` will not be triggered in `touchend`, so "hover
 
-     // style" will remain for user view)
 
-     // click event should always be triggered no matter whether
 
-     // there is gestrue event. System click can not be prevented.
 
-     if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {
 
-       localDOMHandlers.click.call(this, event);
 
-     }
 
-   },
 
-   pointerdown: function (event) {
 
-     localDOMHandlers.mousedown.call(this, event); // if (useMSGuesture(this, event)) {
 
-     //     this._msGesture.addPointer(event.pointerId);
 
-     // }
 
-   },
 
-   pointermove: function (event) {
 
-     // FIXME
 
-     // pointermove is so sensitive that it always triggered when
 
-     // tap(click) on touch screen, which affect some judgement in
 
-     // upper application. So, we dont support mousemove on MS touch
 
-     // device yet.
 
-     if (!isPointerFromTouch(event)) {
 
-       localDOMHandlers.mousemove.call(this, event);
 
-     }
 
-   },
 
-   pointerup: function (event) {
 
-     localDOMHandlers.mouseup.call(this, event);
 
-   },
 
-   pointerout: function (event) {
 
-     // pointerout will be triggered when tap on touch screen
 
-     // (IE11+/Edge on MS Surface) after click event triggered,
 
-     // which is inconsistent with the mousout behavior we defined
 
-     // in touchend. So we unify them.
 
-     // (check localDOMHandlers.touchend for detailed explanation)
 
-     if (!isPointerFromTouch(event)) {
 
-       localDOMHandlers.mouseout.call(this, event);
 
-     }
 
-   }
 
- };
 
- /**
 
-  * Othere DOM UI Event handlers for zr dom.
 
-  * @this {HandlerProxy}
 
-  */
 
- zrUtil.each(['click', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
 
-   localDOMHandlers[name] = function (event) {
 
-     event = normalizeEvent(this.dom, event);
 
-     this.trigger(name, event);
 
-   };
 
- });
 
- /**
 
-  * DOM UI Event handlers for global page.
 
-  *
 
-  * [Caution]:
 
-  * those handlers should both support in capture phase and bubble phase!
 
-  *
 
-  * @this {HandlerProxy}
 
-  */
 
- var globalDOMHandlers = {
 
-   pointermove: function (event) {
 
-     // FIXME
 
-     // pointermove is so sensitive that it always triggered when
 
-     // tap(click) on touch screen, which affect some judgement in
 
-     // upper application. So, we dont support mousemove on MS touch
 
-     // device yet.
 
-     if (!isPointerFromTouch(event)) {
 
-       globalDOMHandlers.mousemove.call(this, event);
 
-     }
 
-   },
 
-   pointerup: function (event) {
 
-     globalDOMHandlers.mouseup.call(this, event);
 
-   },
 
-   mousemove: function (event) {
 
-     this.trigger('mousemove', event);
 
-   },
 
-   mouseup: function (event) {
 
-     var pointerCaptureReleasing = this._pointerCapturing;
 
-     togglePointerCapture(this, false);
 
-     this.trigger('mouseup', event);
 
-     if (pointerCaptureReleasing) {
 
-       event.zrEventControl = 'only_globalout';
 
-       this.trigger('mouseout', event);
 
-     }
 
-   }
 
- };
 
- /**
 
-  * @param {HandlerProxy} instance
 
-  * @param {DOMHandlerScope} scope
 
-  */
 
- function mountLocalDOMEventListeners(instance, scope) {
 
-   var domHandlers = scope.domHandlers;
 
-   if (env.pointerEventsSupported) {
 
-     // Only IE11+/Edge
 
-     // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),
 
-     // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event
 
-     // at the same time.
 
-     // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on
 
-     // screen, which do not occurs in pointer event.
 
-     // So we use pointer event to both detect touch gesture and mouse behavior.
 
-     zrUtil.each(localNativeListenerNames.pointer, function (nativeEventName) {
 
-       mountSingleDOMEventListener(scope, nativeEventName, function (event) {
 
-         // markTriggeredFromLocal(event);
 
-         domHandlers[nativeEventName].call(instance, event);
 
-       });
 
-     }); // FIXME
 
-     // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,
 
-     // which does not prevent defuault behavior occasionally (which may cause view port
 
-     // zoomed in but use can not zoom it back). And event.preventDefault() does not work.
 
-     // So we have to not to use MSGesture and not to support touchmove and pinch on MS
 
-     // touch screen. And we only support click behavior on MS touch screen now.
 
-     // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.
 
-     // We dont support touch on IE on win7.
 
-     // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>
 
-     // if (typeof MSGesture === 'function') {
 
-     //     (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line
 
-     //     dom.addEventListener('MSGestureChange', onMSGestureChange);
 
-     // }
 
-   } else {
 
-     if (env.touchEventsSupported) {
 
-       zrUtil.each(localNativeListenerNames.touch, function (nativeEventName) {
 
-         mountSingleDOMEventListener(scope, nativeEventName, function (event) {
 
-           // markTriggeredFromLocal(event);
 
-           domHandlers[nativeEventName].call(instance, event);
 
-           setTouchTimer(scope);
 
-         });
 
-       }); // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.
 
-       // addEventListener(root, 'mouseout', this._mouseoutHandler);
 
-     } // 1. Considering some devices that both enable touch and mouse event (like on MS Surface
 
-     // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise
 
-     // mouse event can not be handle in those devices.
 
-     // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent
 
-     // mouseevent after touch event triggered, see `setTouchTimer`.
 
-     zrUtil.each(localNativeListenerNames.mouse, function (nativeEventName) {
 
-       mountSingleDOMEventListener(scope, nativeEventName, function (event) {
 
-         event = getNativeEvent(event);
 
-         if (!scope.touching) {
 
-           // markTriggeredFromLocal(event);
 
-           domHandlers[nativeEventName].call(instance, event);
 
-         }
 
-       });
 
-     });
 
-   }
 
- }
 
- /**
 
-  * @param {HandlerProxy} instance
 
-  * @param {DOMHandlerScope} scope
 
-  */
 
- function mountGlobalDOMEventListeners(instance, scope) {
 
-   // Only IE11+/Edge. See the comment in `mountLocalDOMEventListeners`.
 
-   if (env.pointerEventsSupported) {
 
-     zrUtil.each(globalNativeListenerNames.pointer, mount);
 
-   } // Touch event has implemented "drag outside" so we do not mount global listener for touch event.
 
-   // (see https://www.w3.org/TR/touch-events/#the-touchmove-event)
 
-   // We do not consider "both-support-touch-and-mouse device" for this feature (see the comment of
 
-   // `mountLocalDOMEventListeners`) to avoid bugs util some requirements come.
 
-   else if (!env.touchEventsSupported) {
 
-       zrUtil.each(globalNativeListenerNames.mouse, mount);
 
-     }
 
-   function mount(nativeEventName) {
 
-     function nativeEventListener(event) {
 
-       event = getNativeEvent(event); // See the reason in [Drag outside] in `Handler.js`
 
-       // This checking supports both `useCapture` or not.
 
-       // PENDING: if there is performance issue in some devices,
 
-       // we probably can not use `useCapture` and change a easier
 
-       // to judes whether local (mark).
 
-       if (!isLocalEl(instance, event.target)) {
 
-         event = normalizeGlobalEvent(instance, event);
 
-         scope.domHandlers[nativeEventName].call(instance, event);
 
-       }
 
-     }
 
-     mountSingleDOMEventListener(scope, nativeEventName, nativeEventListener, {
 
-       capture: true
 
-     } // See [Drag Outside] in `Handler.js`
 
-     );
 
-   }
 
- }
 
- function mountSingleDOMEventListener(scope, nativeEventName, listener, opt) {
 
-   scope.mounted[nativeEventName] = listener;
 
-   scope.listenerOpts[nativeEventName] = opt;
 
-   addEventListener(scope.domTarget, eventNameFix(nativeEventName), listener, opt);
 
- }
 
- function unmountDOMEventListeners(scope) {
 
-   var mounted = scope.mounted;
 
-   for (var nativeEventName in mounted) {
 
-     if (mounted.hasOwnProperty(nativeEventName)) {
 
-       removeEventListener(scope.domTarget, eventNameFix(nativeEventName), mounted[nativeEventName], scope.listenerOpts[nativeEventName]);
 
-     }
 
-   }
 
-   scope.mounted = {};
 
- }
 
- /**
 
-  * See [Drag Outside] in `Handler.js`.
 
-  * @implement
 
-  * @param {boolean} isPointerCapturing Should never be `null`/`undefined`.
 
-  *        `true`: start to capture pointer if it is not capturing.
 
-  *        `false`: end the capture if it is capturing.
 
-  */
 
- function togglePointerCapture(instance, isPointerCapturing) {
 
-   instance._mayPointerCapture = null;
 
-   if (globalEventSupported && instance._pointerCapturing ^ isPointerCapturing) {
 
-     instance._pointerCapturing = isPointerCapturing;
 
-     var globalHandlerScope = instance._globalHandlerScope;
 
-     isPointerCapturing ? mountGlobalDOMEventListeners(instance, globalHandlerScope) : unmountDOMEventListeners(globalHandlerScope);
 
-   }
 
- }
 
- /**
 
-  * @inner
 
-  * @class
 
-  */
 
- function DOMHandlerScope(domTarget, domHandlers) {
 
-   this.domTarget = domTarget;
 
-   this.domHandlers = domHandlers; // Key: eventName, value: mounted handler funcitons.
 
-   // Used for unmount.
 
-   this.mounted = {};
 
-   this.listenerOpts = {};
 
-   this.touchTimer = null;
 
-   this.touching = false;
 
- }
 
- /**
 
-  * @public
 
-  * @class
 
-  */
 
- function HandlerDomProxy(dom, painterRoot) {
 
-   Eventful.call(this);
 
-   this.dom = dom;
 
-   this.painterRoot = painterRoot;
 
-   this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers);
 
-   if (globalEventSupported) {
 
-     this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers);
 
-   }
 
-   /**
 
-    * @type {boolean}
 
-    */
 
-   this._pointerCapturing = false;
 
-   /**
 
-    * @type {Array.<number>} [x, y] or null.
 
-    */
 
-   this._mayPointerCapture = null;
 
-   mountLocalDOMEventListeners(this, this._localHandlerScope);
 
- }
 
- var handlerDomProxyProto = HandlerDomProxy.prototype;
 
- handlerDomProxyProto.dispose = function () {
 
-   unmountDOMEventListeners(this._localHandlerScope);
 
-   if (globalEventSupported) {
 
-     unmountDOMEventListeners(this._globalHandlerScope);
 
-   }
 
- };
 
- handlerDomProxyProto.setCursor = function (cursorStyle) {
 
-   this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');
 
- };
 
- zrUtil.mixin(HandlerDomProxy, Eventful);
 
- var _default = HandlerDomProxy;
 
- module.exports = _default;
 
 
  |