Skip to content
This repository was archived by the owner on Feb 11, 2021. It is now read-only.

Commit a0d41f5

Browse files
committed
Improve performance
- Use raw Event objects with assignments - Significantly faster than new MouseEvent and defineProperty - Break spec compatibility about "readonly" properties - Remove WeakMap Dependency - Forward pageX/pageY
1 parent 30493f1 commit a0d41f5

9 files changed

+68
-159
lines changed

bower.json

-3
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
"keywords": [
1010
"PointerEvents"
1111
],
12-
"dependencies": {
13-
"WeakMap": "Polymer/WeakMap#master"
14-
},
1512
"license": "BSD",
1613
"private": true,
1714
"ignore": [

build.json

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
[
2-
"../WeakMap/weakmap.js",
32
"src/boot.js",
43
"src/touch-action.js",
54
"src/PointerEvent.js",

pointerevents.js

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
var thisFile = 'pointerevents.js';
88
var scopeName = 'PointerEventsPolyfill';
99
var modules = [
10-
'../WeakMap/weakmap.js',
1110
'src/boot.js',
1211
'src/touch-action.js',
1312
'src/PointerEvent.js',

src/PointerEvent.js

+23-86
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@
1919
* @return {Event} A new PointerEvent of type `inType` and initialized with properties from `inDict`.
2020
*/
2121
(function(scope) {
22-
// test for DOM Level 4 Events
23-
var NEW_MOUSE_EVENT = false;
24-
var HAS_BUTTONS = false;
25-
try {
26-
var ev = new MouseEvent('click', {buttons: 1});
27-
NEW_MOUSE_EVENT = true;
28-
HAS_BUTTONS = ev.buttons === 1;
29-
ev = null;
30-
} catch(e) {
31-
}
3222

3323
var MOUSE_PROPS = [
3424
'bubbles',
@@ -45,6 +35,8 @@
4535
'metaKey',
4636
'button',
4737
'relatedTarget',
38+
'pageX',
39+
'pageY'
4840
];
4941

5042
var MOUSE_DEFAULTS = [
@@ -61,101 +53,46 @@
6153
false,
6254
false,
6355
0,
64-
null
56+
null,
57+
0,
58+
0
6559
];
6660

6761
function PointerEvent(inType, inDict) {
68-
inDict = inDict || {};
69-
// According to the w3c spec,
70-
// http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button
71-
// MouseEvent.button == 0 can mean either no mouse button depressed, or the
72-
// left mouse button depressed.
73-
//
74-
// As of now, the only way to distinguish between the two states of
75-
// MouseEvent.button is by using the deprecated MouseEvent.which property, as
76-
// this maps mouse buttons to positive integers > 0, and uses 0 to mean that
77-
// no mouse button is held.
78-
//
79-
// MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,
80-
// but initMouseEvent does not expose an argument with which to set
81-
// MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set
82-
// MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations
83-
// of app developers.
84-
//
85-
// The only way to propagate the correct state of MouseEvent.which and
86-
// MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0
87-
// is to call initMouseEvent with a buttonArg value of -1.
88-
//
89-
// This is fixed with DOM Level 4's use of buttons
90-
var buttons = inDict.buttons;
91-
// touch has two possible buttons state: 0 and 1, rely on being told the right one
92-
if (!HAS_BUTTONS && !buttons && inType !== 'touch') {
93-
switch (inDict.which) {
94-
case 1: buttons = 1; break;
95-
case 2: buttons = 4; break;
96-
case 3: buttons = 2; break;
97-
default: buttons = 0;
98-
}
99-
}
100-
101-
var e;
102-
if (NEW_MOUSE_EVENT) {
103-
e = new MouseEvent(inType, inDict);
104-
} else {
105-
e = document.createEvent('MouseEvent');
62+
inDict = inDict || Object.create(null);
10663

107-
// import values from the given dictionary
108-
var props = {}, p;
109-
for(var i = 0; i < MOUSE_PROPS.length; i++) {
110-
p = MOUSE_PROPS[i];
111-
props[p] = inDict[p] || MOUSE_DEFAULTS[i];
112-
}
64+
var e = document.createEvent('Event');
65+
e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false);
11366

114-
// define the properties inherited from MouseEvent
115-
e.initMouseEvent(
116-
inType, props.bubbles, props.cancelable, props.view, props.detail,
117-
props.screenX, props.screenY, props.clientX, props.clientY, props.ctrlKey,
118-
props.altKey, props.shiftKey, props.metaKey, props.button, props.relatedTarget
119-
);
120-
}
121-
122-
// make the event pass instanceof checks
123-
e.__proto__ = PointerEvent.prototype;
124-
125-
// define the buttons property according to DOM Level 3 spec
126-
if (!HAS_BUTTONS) {
127-
// IE 10 has buttons on MouseEvent.prototype as a getter w/o any setting
128-
// mechanism
129-
Object.defineProperty(e, 'buttons', {get: function(){ return buttons; }, enumerable: true});
67+
// define inherited MouseEvent properties
68+
for(var i = 0, p; i < MOUSE_PROPS.length; i++) {
69+
p = MOUSE_PROPS[i];
70+
e[p] = inDict[p] || MOUSE_DEFAULTS[i];
13071
}
72+
e.buttons = inDict.buttons || 0;
13173

13274
// Spec requires that pointers without pressure specified use 0.5 for down
13375
// state and 0 for up state.
13476
var pressure = 0;
13577
if (inDict.pressure) {
13678
pressure = inDict.pressure;
13779
} else {
138-
pressure = buttons ? 0.5 : 0;
80+
pressure = e.buttons ? 0.5 : 0;
13981
}
14082

14183
// define the properties of the PointerEvent interface
142-
Object.defineProperties(e, {
143-
pointerId: { value: inDict.pointerId || 0, enumerable: true },
144-
width: { value: inDict.width || 0, enumerable: true },
145-
height: { value: inDict.height || 0, enumerable: true },
146-
pressure: { value: pressure, enumerable: true },
147-
tiltX: { value: inDict.tiltX || 0, enumerable: true },
148-
tiltY: { value: inDict.tiltY || 0, enumerable: true },
149-
pointerType: { value: inDict.pointerType || '', enumerable: true },
150-
hwTimestamp: { value: inDict.hwTimestamp || 0, enumerable: true },
151-
isPrimary: { value: inDict.isPrimary || false, enumerable: true }
152-
});
84+
e.pointerId = inDict.pointerId || 0;
85+
e.width = inDict.width || 0;
86+
e.height = inDict.height || 0;
87+
e.pressure = pressure;
88+
e.tiltX = inDict.tiltX || 0;
89+
e.tiltY = inDict.tiltY || 0;
90+
e.pointerType = inDict.pointerType || '';
91+
e.hwTimestamp = inDict.hwTimestamp || 0;
92+
e.isPrimary = inDict.isPrimary || false;
15393
return e;
15494
}
15595

156-
// PointerEvent extends MouseEvent
157-
PointerEvent.prototype = Object.create(MouseEvent.prototype);
158-
15996
// attach to window
16097
if (!scope.PointerEvent) {
16198
scope.PointerEvent = PointerEvent;

src/dispatcher.js

+13-11
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
'type',
3838
'target',
3939
'currentTarget',
40-
'which'
40+
'which',
41+
'pageX',
42+
'pageY'
4143
];
4244

4345
var CLONE_DEFAULTS = [
@@ -72,6 +74,8 @@
7274
'',
7375
null,
7476
null,
77+
0,
78+
0,
7579
0
7680
];
7781

@@ -90,13 +94,11 @@
9094
* - pointercancel: a pointer will no longer generate events
9195
*/
9296
var dispatcher = {
93-
targets: new WeakMap(),
94-
handledEvents: new WeakMap(),
9597
pointermap: new scope.PointerMap(),
9698
eventMap: {},
9799
// Scope objects for native events.
98100
// This exists for ease of testing.
99-
eventSources: {},
101+
eventSources: Object.create(null),
100102
eventSourceList: [],
101103
/**
102104
* Add a new event source that will generate pointer events.
@@ -186,15 +188,15 @@
186188
// This is used to prevent multiple dispatch of pointerevents from
187189
// platform events. This can happen when two elements in different scopes
188190
// are set up to create pointer events, which is relevant to Shadow DOM.
189-
if (this.handledEvents.get(inEvent)) {
191+
if (inEvent._handledByPE) {
190192
return;
191193
}
192194
var type = inEvent.type;
193195
var fn = this.eventMap && this.eventMap[type];
194196
if (fn) {
195197
fn(inEvent);
196198
}
197-
this.handledEvents.set(inEvent, true);
199+
inEvent._handledByPE = true;
198200
},
199201
// set up event listeners
200202
listen: function(target, events) {
@@ -232,7 +234,7 @@
232234
if (inEvent.preventDefault) {
233235
e.preventDefault = inEvent.preventDefault;
234236
}
235-
this.targets.set(e, this.targets.get(inEvent) || inEvent.target);
237+
e._target = e._target || inEvent.target;
236238
return e;
237239
},
238240
// make and dispatch an event in one call
@@ -248,7 +250,7 @@
248250
* properties.
249251
*/
250252
cloneEvent: function(inEvent) {
251-
var eventCopy = {}, p;
253+
var eventCopy = Object.create(null), p;
252254
for (var i = 0; i < CLONE_PROPS.length; i++) {
253255
p = CLONE_PROPS[i];
254256
eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
@@ -277,7 +279,7 @@
277279
return this.captureInfo.target;
278280
}
279281
}
280-
return this.targets.get(inEvent);
282+
return inEvent._target;
281283
},
282284
setCapture: function(inPointerId, inTarget) {
283285
if (this.captureInfo) {
@@ -288,7 +290,7 @@
288290
this.implicitRelease = this.releaseCapture.bind(this, inPointerId);
289291
document.addEventListener('pointerup', this.implicitRelease);
290292
document.addEventListener('pointercancel', this.implicitRelease);
291-
this.targets.set(e, inTarget);
293+
e._target = inTarget;
292294
this.asyncDispatchEvent(e);
293295
},
294296
releaseCapture: function(inPointerId) {
@@ -298,7 +300,7 @@
298300
this.captureInfo = null;
299301
document.removeEventListener('pointerup', this.implicitRelease);
300302
document.removeEventListener('pointercancel', this.implicitRelease);
301-
this.targets.set(e, t);
303+
e._target = t;
302304
this.asyncDispatchEvent(e);
303305
}
304306
},

src/mouse.js

+10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
// radius around touchend that swallows mouse events
1111
var DEDUP_DIST = 25;
1212

13+
var WHICH_TO_BUTTONS = [0, 1, 4, 2];
14+
15+
var HAS_BUTTONS = false;
16+
try {
17+
HAS_BUTTONS = new MouseEvent('test', {buttons: 1}).buttons === 1;
18+
} catch (e) {}
19+
1320
// handler block for native mouse events
1421
var mouseEvents = {
1522
POINTER_ID: 1,
@@ -51,6 +58,9 @@
5158
e.pointerId = this.POINTER_ID;
5259
e.isPrimary = true;
5360
e.pointerType = this.POINTER_TYPE;
61+
if (!HAS_BUTTONS) {
62+
e.buttons = WHICH_TO_BUTTONS[e.which] || 0;
63+
}
5464
return e;
5565
},
5666
mousedown: function(inEvent) {

0 commit comments

Comments
 (0)