[fix] consistency of nativeEvent.location{X,Y} between touch and mouse

Calculate `location{X,Y}` in the same way for both touch and mouse
events. Also defer the call to `getBoundingClientRect` to avoid
unnecessary DOM queries when the data is not used.
This commit is contained in:
Nicolas Gallagher
2018-03-07 19:55:16 -08:00
parent a67bf0f490
commit 2050730b77
2 changed files with 42 additions and 21 deletions
@@ -51,8 +51,8 @@ Object {
"clientY": 100, "clientY": 100,
"force": false, "force": false,
"identifier": 0, "identifier": 0,
"locationX": 100, "locationX": undefined,
"locationY": 100, "locationY": undefined,
"pageX": 300, "pageX": 300,
"pageY": 300, "pageY": 300,
"screenX": 400, "screenX": 400,
@@ -63,8 +63,8 @@ Object {
], ],
"defaultPrevented": undefined, "defaultPrevented": undefined,
"identifier": 0, "identifier": 0,
"locationX": 200, "locationX": undefined,
"locationY": 200, "locationY": undefined,
"pageX": 300, "pageX": 300,
"pageY": 300, "pageY": 300,
"preventDefault": [Function], "preventDefault": [Function],
@@ -10,6 +10,15 @@
const emptyArray = []; const emptyArray = [];
const emptyFunction = () => {}; const emptyFunction = () => {};
const getRect = node => {
if (node) {
const isElement = node.nodeType === 1 /* Node.ELEMENT_NODE */;
if (isElement && typeof node.getBoundingClientRect === 'function') {
return node.getBoundingClientRect();
}
}
};
// Mobile Safari re-uses touch objects, so we copy the properties we want and normalize the identifier // Mobile Safari re-uses touch objects, so we copy the properties we want and normalize the identifier
const normalizeTouches = touches => { const normalizeTouches = touches => {
if (!touches) { if (!touches) {
@@ -18,25 +27,25 @@ const normalizeTouches = touches => {
return Array.prototype.slice.call(touches).map(touch => { return Array.prototype.slice.call(touches).map(touch => {
const identifier = touch.identifier > 20 ? touch.identifier % 20 : touch.identifier; const identifier = touch.identifier > 20 ? touch.identifier % 20 : touch.identifier;
let locationX, locationY; let rect;
const node = touch.target;
if (node) {
const isElement = node.nodeType === 1 /* Node.ELEMENT_NODE */;
if (isElement && typeof node.getBoundingClientRect === 'function') {
const rect = node.getBoundingClientRect();
locationX = touch.pageX - rect.left;
locationY = touch.pageY - rect.top;
}
}
return { return {
_normalized: true, _normalized: true,
clientX: touch.clientX, clientX: touch.clientX,
clientY: touch.clientY, clientY: touch.clientY,
force: touch.force, force: touch.force,
locationX: locationX, get locationX() {
locationY: locationY, rect = rect || getRect(touch.target);
if (rect) {
return touch.pageX - rect.left;
}
},
get locationY() {
rect = rect || getRect(touch.target);
if (rect) {
return touch.pageY - rect.top;
}
},
identifier: identifier, identifier: identifier,
pageX: touch.pageX, pageX: touch.pageX,
pageY: touch.pageY, pageY: touch.pageY,
@@ -105,15 +114,27 @@ function normalizeTouchEvent(nativeEvent) {
} }
function normalizeMouseEvent(nativeEvent) { function normalizeMouseEvent(nativeEvent) {
let rect;
const touches = [ const touches = [
{ {
_normalized: true, _normalized: true,
clientX: nativeEvent.clientX, clientX: nativeEvent.clientX,
clientY: nativeEvent.clientY, clientY: nativeEvent.clientY,
force: nativeEvent.force, force: nativeEvent.force,
locationX: nativeEvent.clientX,
locationY: nativeEvent.clientY,
identifier: 0, identifier: 0,
get locationX() {
rect = rect || getRect(nativeEvent.target);
if (rect) {
return nativeEvent.pageX - rect.left;
}
},
get locationY() {
rect = rect || getRect(nativeEvent.target);
if (rect) {
return nativeEvent.pageY - rect.top;
}
},
pageX: nativeEvent.pageX, pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY, pageY: nativeEvent.pageY,
screenX: nativeEvent.screenX, screenX: nativeEvent.screenX,
@@ -143,8 +164,8 @@ function normalizeMouseEvent(nativeEvent) {
changedTouches: touches, changedTouches: touches,
defaultPrevented: nativeEvent.defaultPrevented, defaultPrevented: nativeEvent.defaultPrevented,
identifier: touches[0].identifier, identifier: touches[0].identifier,
locationX: nativeEvent.offsetX, locationX: touches[0].locationX,
locationY: nativeEvent.offsetY, locationY: touches[0].locationY,
pageX: nativeEvent.pageX, pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY, pageY: nativeEvent.pageY,
preventDefault, preventDefault,