prosthetic-hand 1.3.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,43 +1,43 @@
1
1
 
2
- # 🖑 prosthetic-hand 🖑
2
+ # 🖐️ prosthetic-hand 🖐️
3
3
 
4
- A javascript library to emulate mouse/touch/pointer events, designed to help
5
- unit-test touch gestures.
4
+ A JavaScript library to emulate mouse/touch/pointer events, designed to help unit-test touch gestures.
6
5
 
6
+ ## Installation
7
7
 
8
- ## Demos
8
+ ```bash
9
+ npm install prosthetic-hand
10
+ ```
9
11
 
10
- http://leaflet.github.io/prosthetic-hand/demos/
12
+ ## Usage
11
13
 
12
- ## API documentation
14
+ ```js
15
+ import Hand from 'prosthetic-hand';
13
16
 
14
- http://leaflet.github.io/prosthetic-hand/api-docs.html
17
+ const hand = new Hand();
18
+ const finger = h.growFinger('pointer', { pointerType: 'touch', pressure: 0.9 });
15
19
 
20
+ finger
21
+ .wait(500)
22
+ .moveTo(200, 250, 0)
23
+ .down()
24
+ .moveBy(100, 150, 2000)
25
+ .up();
26
+ ```
16
27
 
28
+ For more information see the [API documentation](http://leaflet.github.io/prosthetic-hand/api-docs.html) and [demos](http://leaflet.github.io/prosthetic-hand/demos/).
17
29
 
18
- ## Install
30
+ ## Testing
19
31
 
20
- Run `npm install prosthetic-hand`.
32
+ Run `npm install` and `npm start`, then open the URL printed in the console in your preferred browser.
21
33
 
22
- Files will be in `node_modules/prosthetic-hand/dist/`
34
+ ## Building the documentation
23
35
 
24
- ## Build & test
25
-
26
- Run `npm install`, then `npm start`, then point your favourite web browser at
27
- `http://localhost:4567/demos/`
28
-
29
- ## Compatibility note
30
-
31
- Please note that in order to emulate `TouchEvent`s or `PointerEvent`s, your
32
- web browser must support (or polyfill) these events. Short version: use
33
- Chrome when running code that emulates `TouchEvents`, and IE11 or Edge when
34
- emulating `PointerEvent`s.
36
+ Run `npm run build-docs` and open the `api-docs.html` file generated by it.
35
37
 
36
38
  ## Contributing code
37
39
 
38
- Read the Leaflet guidelines at https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md
39
-
40
- Whenever making a bugfix or a new feature, notify [IvanSanchez](https://github.com/IvanSanchez) so that a new version can be published to NPM.
40
+ Read the [Leaflet guidelines](https://github.com/Leaflet/Leaflet/blob/main/CONTRIBUTING.md). Whenever making a bugfix or a new feature, notify [IvanSanchez](https://github.com/IvanSanchez) so that a new version can be published to NPM.
41
41
 
42
42
  ## Legalese
43
43
 
@@ -0,0 +1,33 @@
1
+
2
+ // Detects some browser capabilities. Only for internal use, not exposed to the
3
+ // API user.
4
+
5
+ // touchConstructor, for Touch
6
+ export var touchConstructor = true;
7
+
8
+ try {
9
+ var foo = new Touch({ identifier: 0, target: document });
10
+ } catch(e) {
11
+ touchConstructor = false;
12
+ }
13
+
14
+
15
+ // touchEventConstructor, for TouchEvent
16
+ // Weirdly, Safari on iOS has Touch constructor but no TouchEvent constructor.
17
+ export var touchEventConstructor = true;
18
+
19
+ try {
20
+ var foo = new TouchEvent('touchdown')
21
+ } catch(e) {
22
+ touchEventConstructor = false;
23
+ }
24
+
25
+ // touch: `true` if the browser implements `TouchEvent`
26
+ export var touch = !!('TouchEvent' in window);
27
+
28
+ // Some bits borrowed from Leaflet's L.Browser
29
+ const ua = navigator.userAgent.toLowerCase();
30
+ const webkit = ua.includes('webkit');
31
+ const chrome = ua.includes('chrome');
32
+ export const gecko = ua.includes('gecko') && !webkit;
33
+ export const safari = !chrome && ua.includes('safari');
@@ -8,12 +8,12 @@ import * as capabilities from './Capabilities.js';
8
8
  // ID whenever they go down.
9
9
  var fingerIdSequence = 1;
10
10
 
11
- // 🖑class Finger
11
+ // 🖐️class Finger
12
12
  // Represents a finger, capable of performing single touch/pointer/mouse synthetic
13
13
  // events.
14
14
 
15
15
  /*
16
- 🖑example
16
+ 🖐️example
17
17
 
18
18
  ```js
19
19
  var h = new Hand();
@@ -26,7 +26,7 @@ fatFinger.wait(500).moveTo(200, 250, 0).down().moveBy(100, 150, 2000).up();
26
26
  */
27
27
  export default class Finger {
28
28
 
29
- // 🖑factory Finger(eventMode: String, options?: Finger state): Finger
29
+ // 🖐️factory Finger(eventMode: String, options?: Finger state): Finger
30
30
  // Instantiates a new `Finger`. `eventMode` must be `mouse`, `touch` or `pointer`
31
31
  // for `MouseEvent`s, `TouchEvent`s or `PointerEvent`s, respectively.
32
32
  constructor(eventMode, options) {
@@ -40,36 +40,36 @@ export default class Finger {
40
40
  /// TODO: parkinsonFactor or shakesFactor or jitteryness or something
41
41
 
42
42
 
43
- // 🖑section Finger state
43
+ // 🖐️section Finger state
44
44
  // The internal state of a `Finger` has options which will be reflected as
45
45
  // properties of the events fired afterwards. Some of these state options
46
46
  // apply only to a specific event mode.
47
47
  this._state = Object.assign({}, {
48
- // 🖑option x: Number; The number of pixels from the left boundary the finger is at.
48
+ // 🖐️option x: Number; The number of pixels from the left boundary the finger is at.
49
49
  x: 0,
50
50
 
51
- // 🖑option y: Number; The number of pixels from the top boundary the finger is at.
51
+ // 🖐️option y: Number; The number of pixels from the top boundary the finger is at.
52
52
  y: 0,
53
53
 
54
- // 🖑option down: Boolean; Whether the finger is down (clicking/touching/pressing) or not. This is referred to as "active" in some of the events specifications.
54
+ // 🖐️option down: Boolean; Whether the finger is down (clicking/touching/pressing) or not. This is referred to as "active" in some of the events specifications.
55
55
  down: false,
56
56
 
57
- // 🖑option pressure: Number = 0.5; The value for [`Touch.force`](`https://developer.mozilla.org/docs/Web/API/Touch/force`) or [`PointerEvent.pressure`](https://developer.mozilla.org/docs/Web/API/PointerEvent/pressure), between `0.0` and `1.0`
57
+ // 🖐️option pressure: Number = 0.5; The value for [`Touch.force`](`https://developer.mozilla.org/docs/Web/API/Touch/force`) or [`PointerEvent.pressure`](https://developer.mozilla.org/docs/Web/API/PointerEvent/pressure), between `0.0` and `1.0`
58
58
  pressure: 0.5,
59
59
 
60
- // 🖑option tiltX: Number = 0; The value for [`PointerEvent.tiltX`](https://developer.mozilla.org/docs/Web/API/PointerEvent/tiltX)
60
+ // 🖐️option tiltX: Number = 0; The value for [`PointerEvent.tiltX`](https://developer.mozilla.org/docs/Web/API/PointerEvent/tiltX)
61
61
  tiltX: 0,
62
62
 
63
- // 🖑option tiltY: Number = 0; The value for [`PointerEvent.tiltX`](https://developer.mozilla.org/docs/Web/API/PointerEvent/tiltY)
63
+ // 🖐️option tiltY: Number = 0; The value for [`PointerEvent.tiltX`](https://developer.mozilla.org/docs/Web/API/PointerEvent/tiltY)
64
64
  tiltY: 0,
65
65
 
66
- // 🖑option width: Number = 25; The value for [`Touch.radiusX`](`https://developer.mozilla.org/docs/Web/API/Touch/radiusX`) or [`PointerEvent.width`](https://developer.mozilla.org/docs/Web/API/PointerEvent/width)
66
+ // 🖐️option width: Number = 25; The value for [`Touch.radiusX`](`https://developer.mozilla.org/docs/Web/API/Touch/radiusX`) or [`PointerEvent.width`](https://developer.mozilla.org/docs/Web/API/PointerEvent/width)
67
67
  width: 25,
68
68
 
69
- // 🖑option radiusY: Number = 25; The value for [`Touch.radiusY`](`https://developer.mozilla.org/docs/Web/API/Touch/radiusY`) or [`PointerEvent.height`](https://developer.mozilla.org/docs/Web/API/PointerEvent/height)
69
+ // 🖐️option radiusY: Number = 25; The value for [`Touch.radiusY`](`https://developer.mozilla.org/docs/Web/API/Touch/radiusY`) or [`PointerEvent.height`](https://developer.mozilla.org/docs/Web/API/PointerEvent/height)
70
70
  height: 25,
71
71
 
72
- // 🖑option pointerType: String = 'pen'; The value for [`PointerEvent.pointerType`](https://developer.mozilla.org/docs/Web/API/PointerEvent/pointerType)
72
+ // 🖐️option pointerType: String = 'pen'; The value for [`PointerEvent.pointerType`](https://developer.mozilla.org/docs/Web/API/PointerEvent/pointerType)
73
73
  pointerType: 'pen'
74
74
  }, options);
75
75
 
@@ -111,15 +111,9 @@ export default class Finger {
111
111
  } else {
112
112
  this._initGraphicCircle();
113
113
  }
114
- if (!capabilities.pointer) {
115
- console.warn('This browser cannot emulate pointer events.');
116
- }
117
114
  } else {
118
115
  this._mode = 'mouse';
119
116
  this._initGraphicCircle();
120
- if (!capabilities.mouse) {
121
- console.warn('This browser cannot emulate mouse events.');
122
- }
123
117
  }
124
118
 
125
119
 
@@ -135,28 +129,28 @@ export default class Finger {
135
129
  }
136
130
 
137
131
 
138
- // 🖑method isIdle(): Boolean
132
+ // 🖐️method isIdle(): Boolean
139
133
  // Returns true when the finger has no more pending movements/waits/wiggles/etc.
140
134
  isIdle() {
141
135
  return !(this._movements.length);
142
136
  }
143
137
 
144
138
 
145
- // 🖑method down(delay?: Number): this
139
+ // 🖐️method down(delay?: Number): this
146
140
  // Puts the finger down, optionally after a delay.
147
141
  down(delay) {
148
142
  return this.update({ down: true, getState: this._falseFn, duration: delay || 0 });
149
143
  }
150
144
 
151
145
 
152
- // 🖑method up(options?: {}): this
146
+ // 🖐️method up(options?: {}): this
153
147
  // Lifts the finger up, after an optional delay.
154
148
  up(delay) {
155
149
  return this.update({ down: false, getState: this._falseFn, duration: delay || 0 });
156
150
  }
157
151
 
158
152
 
159
- // 🖑method wait(delay): this
153
+ // 🖐️method wait(delay): this
160
154
  // Don't move this finger for `delay` milliseconds.
161
155
  wait(delay) {
162
156
  this._queueMove({finalState: this._finalState, getState: this._falseFn, duration: delay});
@@ -164,7 +158,7 @@ export default class Finger {
164
158
  }
165
159
 
166
160
 
167
- // 🖑method waitUntil(timestamp): this
161
+ // 🖐️method waitUntil(timestamp): this
168
162
  // Don't move this finger until the given timestamp is reached.
169
163
  waitUntil(timestamp) {
170
164
  if (this._movements.length) {
@@ -185,7 +179,7 @@ export default class Finger {
185
179
  }
186
180
 
187
181
 
188
- // 🖑method update(options?: {}): this
182
+ // 🖐️method update(options?: {}): this
189
183
  // Updates some of the finger options, like pressure or touch angle,
190
184
  // without disturbing its movement, after an optional delay.
191
185
  update(options, delay) {
@@ -194,7 +188,7 @@ export default class Finger {
194
188
  }
195
189
 
196
190
 
197
- // 🖑method reset(options?: {}): this
191
+ // 🖐️method reset(options?: {}): this
198
192
  // Clears all the queued movements for this finger and immediately lifts it up
199
193
  reset(options) {
200
194
  return this;
@@ -202,7 +196,7 @@ export default class Finger {
202
196
 
203
197
 
204
198
 
205
- // 🖑method moveTo(x: Number, y: Number, delay: Number, options?: {}): this
199
+ // 🖐️method moveTo(x: Number, y: Number, delay: Number, options?: {}): this
206
200
  // Queues moving this finger to an absolute position at `(x, y)`; the
207
201
  // movement will last for `delay` milliseconds.
208
202
  moveTo(x, y, delay) {
@@ -210,7 +204,7 @@ export default class Finger {
210
204
  }
211
205
 
212
206
 
213
- // 🖑method moveBy(x: Number, y: Number, delay: Number, options?: {}): this
207
+ // 🖐️method moveBy(x: Number, y: Number, delay: Number, options?: {}): this
214
208
  // Queues a move of this finger to an position relative to its last position
215
209
  // plus`(x, y)`; the movement will last for `delay` milliseconds.
216
210
  moveBy(x, y, delay) {
@@ -270,7 +264,7 @@ export default class Finger {
270
264
 
271
265
 
272
266
  // Returns the timestamp when the next movement will be finished
273
- // 🖑method getNextMoveEndTime(): Number|undefined
267
+ // 🖐️method getNextMoveEndTime(): Number|undefined
274
268
  getNextMoveEndTime() {
275
269
  if (!this._movements.length) {
276
270
  return undefined;
@@ -280,7 +274,7 @@ export default class Finger {
280
274
 
281
275
 
282
276
  /*
283
- * 🖑method getEvents(timestamp?: Number, justOne: Boolean): []
277
+ * 🖐️method getEvents(timestamp?: Number, justOne: Boolean): []
284
278
  * Updates the private properties of the finger (x, y, timestamp) by
285
279
  * running the next movement(s) as far as indicated by the timestamp (or
286
280
  * as fas as to `performance.now()`), then checks if the state has changed
@@ -403,7 +397,7 @@ export default class Finger {
403
397
 
404
398
 
405
399
 
406
- // 🖑method private_asTouch(): Touch
400
+ // 🖐️method private_asTouch(): Touch
407
401
  // Returns an instance of `Touch` representing the current state of the finger
408
402
  // Note this is not an event - a `TouchEvent` must be created later, with several
409
403
  // `Touch`es.
@@ -426,23 +420,7 @@ export default class Finger {
426
420
  });
427
421
  } else {
428
422
 
429
- if (capabilities.chrome) {
430
- touch = document.createTouch(
431
- window, // view
432
- this._touchTargetWhenDowned, // target
433
- this._id, // identifier
434
- this._state.x, // clientX
435
- this._state.y, // clientY
436
- this._state.x, // screenX
437
- this._state.y, // screenY
438
-
439
- // Inconsistency: These break anything other than chrome:
440
- 25, // radiusX
441
- 25, // radiusY
442
- 0, // rotationAngle
443
- this._state.pressure // force
444
- );
445
- } else if (capabilities.gecko) {
423
+ if (capabilities.gecko) {
446
424
  touch = document.createTouch(
447
425
  window, // view
448
426
  this._touchTargetWhenDowned, // target
@@ -472,21 +450,21 @@ export default class Finger {
472
450
  return touch;
473
451
  }
474
452
 
475
- // 🖑method private_asPointerEvent(): PointerEvent
453
+ // 🖐️method private_asPointerEvent(): PointerEvent
476
454
  // Returns an instance of `PointerEvent` representing the current state of the finger
477
455
  _asPointerEvent(evType) {
478
- var ev = new PointerEvent('pointer' + evType, {
456
+ return new PointerEvent('pointer' + evType, {
479
457
  bubbles: true,
480
458
  button: 0, // Moz doesn't use -1 when no buttons are pressed, WTF?
481
459
  // buttons: this._state.down ? 1 : 0,
482
- // detail: (evType === 'down' || evType === 'up') ? 1 : 0, // TODO: count consecutive clicks
460
+ // detail: (evType === 'down' || evType === 'up') ? 1 : 0, // TODO: count consecutive clicks
483
461
  clientX: this._state.x,
484
462
  clientY: this._state.y,
485
463
  screenX: this._state.x, /// TODO: Handle page scrolling
486
464
  screenY: this._state.y,
487
465
  pageX: this._state.x,
488
466
  pageY: this._state.y,
489
- pointerType: 'pen',
467
+ pointerType: this._state.pointerType,
490
468
  pointerId: this._id,
491
469
  isPrimary: this._id === 1,
492
470
  width: this._state.width,
@@ -496,49 +474,24 @@ export default class Finger {
496
474
  pressure: this._state.pressure
497
475
  // target: document.elementFromPoint(this._state.x, this._state.y), // works with viewport coords
498
476
  });
499
- return ev;
500
477
  }
501
478
 
502
- // 🖑method private_asMouseEvent(evType: String): PointerEvent
479
+ // 🖐️method private_asMouseEvent(evType: String): PointerEvent
503
480
  // Returns an instance of `PointerEvent` representing the current state of the finger
504
481
  _asMouseEvent(evType) {
505
- var ev;
506
- if (capabilities.mouseEventConstructor) {
507
- ev = new MouseEvent('mouse' + evType, {
508
- bubbles: true,
509
- button: 0, // Moz doesn't use -1 when no buttons are pressed, WTF?
510
- buttons: this._state.down ? 1 : 0,
511
- detail: (evType === 'down' || evType === 'up') ? 1 : 0, // TODO: count consecutive clicks
512
- clientX: this._state.x,
513
- clientY: this._state.y,
514
- screenX: this._state.x, /// TODO: Handle page scrolling
515
- screenY: this._state.y,
516
- pageX: this._state.x,
517
- pageY: this._state.y,
518
- // target: document.elementFromPoint(this._state.x, this._state.y), // works with viewport coords
519
- });
520
- } else {
521
- // For legacy browsers and PhantomJS
522
- ev = document.createEvent('MouseEvent');
523
- ev.initMouseEvent(
524
- 'mouse' + evType, // Type
525
- true, // canBubble
526
- true, // cancellable
527
- window, // view
528
- 0, // detail
529
- this._state.x, // screenX
530
- this._state.y, // screenY
531
- this._state.x, // clientX
532
- this._state.y, // clientY
533
- false, // ctrlKey
534
- false, // altKey
535
- false, // shiftKey
536
- false, // metaKey
537
- 0, // button
538
- null // relatedTarget
539
- );
540
- }
541
- return ev;
482
+ return new MouseEvent('mouse' + evType, {
483
+ bubbles: true,
484
+ button: 0, // Moz doesn't use -1 when no buttons are pressed, WTF?
485
+ buttons: this._state.down ? 1 : 0,
486
+ detail: (evType === 'down' || evType === 'up') ? 1 : 0, // TODO: count consecutive clicks
487
+ clientX: this._state.x,
488
+ clientY: this._state.y,
489
+ screenX: this._state.x, /// TODO: Handle page scrolling
490
+ screenY: this._state.y,
491
+ pageX: this._state.x,
492
+ pageY: this._state.y,
493
+ // target: document.elementFromPoint(this._state.x, this._state.y), // works with viewport coords
494
+ });
542
495
  }
543
496
 
544
497
 
@@ -1,14 +1,20 @@
1
1
 
2
2
  import Finger from './Finger.js';
3
- import * as enums from './Enums.js';
4
3
  import * as capabilities from './Capabilities.js';
5
- import {} from './CustomEventPolyfill.js';
6
4
 
7
- // 🖑class Hand
5
+ const TimingMode = {
6
+ Interval: 'INTERVAL',
7
+ Minimal: 'MINIMAL',
8
+ Instant: 'INSTANT',
9
+ Frame: 'FRAME',
10
+ FastFrame: 'FAST_FRAME'
11
+ };
12
+
13
+ // 🖐️class Hand
8
14
  // Represents a set of `Finger`s, capable of performing synthetic touch gestures
9
15
 
10
16
  /*
11
- 🖑example
17
+ 🖐️example
12
18
 
13
19
  ```js
14
20
  var h = new Hand({ timing: '20ms' });
@@ -17,7 +23,7 @@ var h = new Hand({ timing: '20ms' });
17
23
  */
18
24
  export default class Hand {
19
25
 
20
- // 🖑factory Hand(options?: Hand options): Hand
26
+ // 🖐️factory Hand(options?: Hand options): Hand
21
27
  // Instantiates a new `Hand` with the given options.
22
28
  constructor(options) {
23
29
 
@@ -32,71 +38,71 @@ export default class Hand {
32
38
 
33
39
  /// TODO: Timing modes: minimal, interval, frames
34
40
 
35
- // 🖑option timing: Timing= '20ms'
41
+ // 🖐️option timing: Timing= '20ms'
36
42
  // Defines how often new events will be fired, in one of the possible
37
43
  // timing modes
38
44
 
39
- // 🖑miniclass Timing (Hand)
45
+ // 🖐️miniclass Timing (Hand)
40
46
  this._timeInterval = 20;
41
- this._timingMode = enums.INTERVAL;
47
+ this._timingMode = TimingMode.Interval;
42
48
  this._framesPending = 0;
43
49
  if (options.timing) {
44
50
  var timing = options.timing.toString();
45
51
 
46
- // 🖑option ms
52
+ // 🖐️option ms
47
53
  // Preceded by a number (e.g. `'20ms'`), this mode triggers an event
48
54
  // dispatch every that many milliseconds.
49
55
  if (timing.match(/^\d+ms$/)) {
50
- this._timingMode = enums.INTERVAL;
56
+ this._timingMode = TimingMode.Interval;;
51
57
  this._timeInterval = parseInt(timing);
52
58
  }
53
59
 
54
- // 🖑option frame
60
+ // 🖐️option frame
55
61
  // This mode dispatches an event every [animation frame](https://developer.mozilla.org/docs/Web/API/Window/requestAnimationFrame).
56
62
  if (timing === 'frame') {
57
- this._timingMode = enums.FRAME;
63
+ this._timingMode = TimingMode.Frame;
58
64
  this._timeInterval = parseInt(timing);
59
65
  }
60
66
 
61
- // 🖑option minimal
67
+ // 🖐️option minimal
62
68
  // This mode triggers an event dispatch per finger change, and ensures
63
69
  // that every move can trigger its own event (no two movements will be
64
70
  // rolled into one event if they are very close).
65
71
  if (timing === 'minimal') {
66
- this._timingMode = enums.MINIMAL;
72
+ this._timingMode = TimingMode.Minimal;
67
73
  this._timeInterval = false;
68
74
  }
69
75
 
70
- // 🖑option instant
76
+ // 🖐️option instant
71
77
  // Like the `minimal` mode, but ignores timings completely and dispatches
72
78
  // all events instantaneously. This might cause misbehaviour in graphical
73
79
  // browsers, and the `onStart` and `onStop` callbacks will be called at.
74
80
  // every step of the movement (as the movement ends before the next step
75
81
  // is chained in)
76
82
  if (timing === 'instant') {
77
- this._timingMode = enums.INSTANT;
83
+ this._timingMode = TimingMode.Instant;
78
84
  this._timeInterval = false;
79
85
  }
80
86
 
81
- // 🖑option fastframe
87
+ // 🖐️option fastframe
82
88
  // This mode ignores timings completely like the `instant` mode, and
83
89
  // dispatches a new event every so many frames.
84
90
  if (timing === 'fastframe') {
85
- this._timingMode = enums.FASTFRAME;
91
+ this._timingMode = TimingMode.FastFrame;
86
92
  this._timeInterval = parseInt(timing);
87
93
  }
88
94
  }
89
95
 
90
- // 🖑class Hand
96
+ // 🖐️class Hand
91
97
 
92
- // 🖑option onStart: Function
98
+ // 🖐️option onStart: Function
93
99
  // If set to a callback function, it will be called (with the `Hand`
94
100
  // as its only argument) whenever the movements start.
95
101
  if (options.onStart) {
96
102
  this._onStart = options.onStart;
97
103
  }
98
104
 
99
- // 🖑option onStop: Function
105
+ // 🖐️option onStop: Function
100
106
  // If set to a callback function, it will be called (with the `Hand`
101
107
  // as its only argument) whenever the movements are completed.
102
108
  if (options.onStop) {
@@ -111,7 +117,7 @@ export default class Hand {
111
117
  }
112
118
 
113
119
 
114
- // 🖑method growFinger(eventMode, options): Finger
120
+ // 🖐️method growFinger(eventMode, options): Finger
115
121
  // Creates a new `Finger` with the same parameters as the [`Finger` constructor](#finger-finger),
116
122
  // and adds it to the hand.
117
123
  growFinger(fingerMode, options) {
@@ -130,7 +136,7 @@ export default class Hand {
130
136
 
131
137
 
132
138
 
133
- // 🖑method fingerIsBusy(): this
139
+ // 🖐️method fingerIsBusy(): this
134
140
  // Used by this hand's fingers to signal that there are movements to be
135
141
  // performed by at least one finger.
136
142
  fingerIsBusy() {
@@ -138,10 +144,10 @@ export default class Hand {
138
144
  /// TODO: Start up the event loop
139
145
 
140
146
  if (this._fingersAreIdle) {
141
- // 🖑section
147
+ // 🖐️section
142
148
  // Use `document.addEventListener('prostheticHandStop', fn)` to
143
149
  // do stuff with it.
144
- // 🖑event prostheticHandStart: CustomEvent
150
+ // 🖐️event prostheticHandStart: CustomEvent
145
151
  // Fired when all movements are complete.
146
152
  document.dispatchEvent(new CustomEvent('prostheticHandStart', {target: this}));
147
153
 
@@ -156,32 +162,18 @@ export default class Hand {
156
162
  return this;
157
163
  }
158
164
 
159
- // 🖑method fingerIsIdle(): this
165
+ // 🖐️method fingerIsIdle(): this
160
166
  // Used by this hand's fingers to signal that one finger has finished doing
161
167
  // all the queued movements.
162
168
  fingerIsIdle() {
163
169
 
164
170
  if (this._fingers.every( f => f.isIdle())) {
165
-
166
- if (!this._fingersAreIdle) {
167
- // 🖑event prostheticHandStop: CustomEvent
168
- // Fired when all movements are complete.
169
-
170
- document.dispatchEvent(new CustomEvent('prostheticHandStop', {target: this}));
171
-
172
-
173
- if (this._onStop && this._onStop instanceof Function) {
174
- this._onStop(this);
175
- }
176
-
177
- }
178
-
179
171
  this._fingersAreIdle = true;
180
172
  }
181
173
  }
182
174
 
183
175
 
184
- // 🖑method sync(delay): this
176
+ // 🖐️method sync(delay): this
185
177
  // Synchronizes the finger movements by adding a delay of **at least** `delay`
186
178
  // milliseconds to each finger. After a sync, the movements of the fingers
187
179
  // will happen at exactly the same time.
@@ -207,13 +199,13 @@ export default class Hand {
207
199
 
208
200
 
209
201
 
210
- // 🖑method private_dispatchEvents(): this
202
+ // 🖐️method private_dispatchEvents(): this
211
203
  // Updates all the fingers, fetching their events/touchpoints, and dispatches
212
204
  // all `Event`s triggered by the update.
213
205
  // This is meant to be called on an internal timer.
214
206
  _dispatchEvents(timestamp) {
215
207
 
216
- // 🖑event prostheticHandTick: CustomEvent
208
+ // 🖐️event prostheticHandTick: CustomEvent
217
209
  // Fired a movement is about to start, just before the mouse/touch/pointer
218
210
  // events are fired.
219
211
  document.dispatchEvent(new CustomEvent('prostheticHandStart', {target: this}));
@@ -229,9 +221,9 @@ export default class Hand {
229
221
  var hasTouchEnd = false;
230
222
  var touchEndTarget = undefined;
231
223
 
232
- var fast = this._timingMode === enums.MINIMAL ||
233
- this._timingMode === enums.INSTANT ||
234
- this._timingMode === enums.FASTFRAME;
224
+ var fast = this._timingMode === TimingMode.Minimal ||
225
+ this._timingMode === TimingMode.Instant ||
226
+ this._timingMode === TimingMode.FastFrame;
235
227
 
236
228
  this._fingers.forEach(f=> {
237
229
 
@@ -453,7 +445,18 @@ export default class Hand {
453
445
 
454
446
 
455
447
  _scheduleNextDispatch(){
456
- if (!this._fingersAreIdle) {
448
+ if (this._fingersAreIdle) {
449
+ // 🖐️event prostheticHandStop: CustomEvent
450
+ // Fired when all movements are complete.
451
+
452
+ document.dispatchEvent(new CustomEvent('prostheticHandStop', {target: this}));
453
+
454
+
455
+ if (this._onStop && this._onStop instanceof Function) {
456
+ this._onStop(this);
457
+ }
458
+
459
+ } else {
457
460
 
458
461
  // Calculate time for next movement end. Could be refactored out for
459
462
  // some timing modes.
@@ -469,19 +472,19 @@ export default class Hand {
469
472
  });
470
473
 
471
474
 
472
- if (this._timingMode === enums.INTERVAL) {
475
+ if (this._timingMode === TimingMode.Interval) {
473
476
  this._nextDispatch = setTimeout(this._dispatchEvents.bind(this), this._timeInterval);
474
477
 
475
- } else if (this._timingMode === enums.MINIMAL) {
478
+ } else if (this._timingMode === TimingMode.Minimal) {
476
479
  this._nextDispatch = setTimeout(this._dispatchEvents.bind(this), min - performance.now());
477
480
 
478
- } else if (this._timingMode === enums.INSTANT) {
481
+ } else if (this._timingMode === TimingMode.Instant) {
479
482
  return this._dispatchEvents(min);
480
483
 
481
- } else if (this._timingMode === enums.FRAME) {
484
+ } else if (this._timingMode === TimingMode.Frame) {
482
485
  this._nextDispatch = requestAnimationFrame( this._dispatchEvents.bind(this) );
483
486
 
484
- } else if (this._timingMode === enums.FASTFRAME) {
487
+ } else if (this._timingMode === TimingMode.FastFrame) {
485
488
  this._nextDispatch = requestAnimationFrame( function() {
486
489
  this._dispatchEvents(min);
487
490
  }.bind(this));