|
var Eventful = require("../mixin/Eventful");
exports.Dispatcher = Eventful;
var env = require("./env");
/**
* 事件辅助类
* @module zrender/core/event
* @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
*/
var isDomLevel2 = typeof window !== 'undefined' && !!window.addEventListener;
var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;
function getBoundingClientRect(el) {
// BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect
return el.getBoundingClientRect ? el.getBoundingClientRect() : {
left: 0,
top: 0
};
} // `calculate` is optional, default false
function clientToLocal(el, e, out, calculate) {
out = out || {}; // According to the W3C Working Draft, offsetX and offsetY should be relative
// to the padding edge of the target element. The only browser using this convention
// is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does
// not support the properties.
// (see http://www.jacklmoore.com/notes/mouse-position/)
// In zr painter.dom, padding edge equals to border edge.
// FIXME
// When mousemove event triggered on ec tooltip, target is not zr painter.dom, and
// offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y
// is too complex. So css-transfrom dont support in this case temporarily.
if (calculate || !env.canvasSupported) {
defaultGetZrXY(el, e, out);
} // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned
// ancestor element, so we should make sure el is positioned (e.g., not position:static).
// BTW1, Webkit don't return the same results as FF in non-simple cases (like add
// zoom-factor, overflow / opacity layers, transforms ...)
// BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.
// <https://bugs.jquery.com/ticket/8523#comment:14>
// BTW3, In ff, offsetX/offsetY is always 0.
else if (env.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {
out.zrX = e.layerX;
out.zrY = e.layerY;
} // For IE6+, chrome, safari, opera. (When will ff support offsetX?)
else if (e.offsetX != null) {
out.zrX = e.offsetX;
out.zrY = e.offsetY;
} // For some other device, e.g., IOS safari.
else {
defaultGetZrXY(el, e, out);
}
return out;
}
function defaultGetZrXY(el, e, out) {
// This well-known method below does not support css transform.
var box = getBoundingClientRect(el);
out.zrX = e.clientX - box.left;
out.zrY = e.clientY - box.top;
}
/**
* 如果存在第三方嵌入的一些dom触发的事件,或touch事件,需要转换一下事件坐标.
* `calculate` is optional, default false.
*/
function normalizeEvent(el, e, calculate) {
e = e || window.event;
if (e.zrX != null) {
return e;
}
var eventType = e.type;
var isTouch = eventType && eventType.indexOf('touch') >= 0;
if (!isTouch) {
clientToLocal(el, e, e, calculate);
e.zrDelta = e.wheelDelta ? e.wheelDelta / 120 : -(e.detail || 0) / 3;
} else {
var touch = eventType != 'touchend' ? e.targetTouches[0] : e.changedTouches[0];
touch && clientToLocal(el, touch, e, calculate);
} // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;
// See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js
// If e.which has been defined, if may be readonly,
// see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which
var button = e.button;
if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {
e.which = button & 1 ? 1 : button & 2 ? 3 : button & 4 ? 2 : 0;
}
return e;
}
/**
* @param {HTMLElement} el
* @param {string} name
* @param {Function} handler
*/
function addEventListener(el, name, handler) {
if (isDomLevel2) {
// Reproduct the console warning:
// [Violation] Added non-passive event listener to a scroll-blocking <some> event.
// Consider marking event handler as 'passive' to make the page more responsive.
// Just set console log level: verbose in chrome dev tool.
// then the warning log will be printed when addEventListener called.
// See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
// We have not yet found a neat way to using passive. Because in zrender the dom event
// listener delegate all of the upper events of element. Some of those events need
// to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.
// Before passive can be adopted, these issues should be considered:
// (1) Whether and how a zrender user specifies an event listener passive. And by default,
// passive or not.
// (2) How to tread that some zrender event listener is passive, and some is not. If
// we use other way but not preventDefault of mousewheel and touchmove, browser
// compatibility should be handled.
// var opts = (env.passiveSupported && name === 'mousewheel')
// ? {passive: true}
// // By default, the third param of el.addEventListener is `capture: false`.
// : void 0;
// el.addEventListener(name, handler /* , opts */);
el.addEventListener(name, handler);
} else {
el.attachEvent('on' + name, handler);
}
}
function removeEventListener(el, name, handler) {
if (isDomLevel2) {
el.removeEventListener(name, handler);
} else {
el.detachEvent('on' + name, handler);
}
}
/**
* preventDefault and stopPropagation.
* Notice: do not do that in zrender. Upper application
* do that if necessary.
*
* @memberOf module:zrender/core/event
* @method
* @param {Event} e : event对象
*/
var stop = isDomLevel2 ? function (e) {
e.preventDefault();
e.stopPropagation();
e.cancelBubble = true;
} : function (e) {
e.returnValue = false;
e.cancelBubble = true;
};
function notLeftMouse(e) {
// If e.which is undefined, considered as left mouse event.
return e.which > 1;
} // 做向上兼容
exports.clientToLocal = clientToLocal;
exports.normalizeEvent = normalizeEvent;
exports.addEventListener = addEventListener;
exports.removeEventListener = removeEventListener;
exports.stop = stop;
exports.notLeftMouse = notLeftMouse;
|