prosthetic-hand 1.4.0 → 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,48 +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.
41
-
42
- ## Similar projects
43
-
44
- * https://github.com/francejs/effroi (three years old)
45
- * The simulator from http://hammerjs.github.io/ (too basic)
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.
46
41
 
47
42
  ## Legalese
48
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,108 +450,48 @@ 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;
479
- if (capabilities.pointerEventConstructor) {
480
- ev = new PointerEvent('pointer' + evType, {
481
- bubbles: true,
482
- button: 0, // Moz doesn't use -1 when no buttons are pressed, WTF?
483
- // buttons: this._state.down ? 1 : 0,
484
- // detail: (evType === 'down' || evType === 'up') ? 1 : 0, // TODO: count consecutive clicks
485
- clientX: this._state.x,
486
- clientY: this._state.y,
487
- screenX: this._state.x, /// TODO: Handle page scrolling
488
- screenY: this._state.y,
489
- pageX: this._state.x,
490
- pageY: this._state.y,
491
- pointerType: 'pen',
492
- pointerId: this._id,
493
- isPrimary: this._id === 1,
494
- width: this._state.width,
495
- height: this._state.height,
496
- tiltX: this._state.tiltX,
497
- tiltY: this._state.tiltY,
498
- pressure: this._state.pressure
499
- // target: document.elementFromPoint(this._state.x, this._state.y), // works with viewport coords
500
- });
501
- } else {
502
- ev = document.createEvent('MSPointerEvent');
503
- // https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/jj192039(v=vs.85)
504
- ev.initPointerEvent(
505
- 'pointer' + evType, // Type
506
- true, // canBubble
507
- true, // cancelable
508
- window, // view
509
- 0, // detail
510
- this._state.x, // screenX
511
- this._state.y, // screenY
512
- this._state.x, // clientX
513
- this._state.y, // clientY
514
- false, // ctrlKey
515
- false, // altKey
516
- false, // shiftKey
517
- false, // metaKey
518
- 0, // button
519
- null, // relatedTarget,
520
- 0, // offsetX?
521
- 0, // offsetY?
522
- this._state.width, // width
523
- this._state.height, // height
524
- this._state.pressure, // pressure
525
- 0, // rotation?
526
- this._state.tiltX, // tiltX
527
- this._state.tiltY, // tiltY
528
- this._id, // pointerId
529
- 'pen', // pointerType
530
- 0, // hwTimestamp?
531
- this._id === 1 // isPrimary
532
- );
533
- }
534
- return ev;
456
+ return new PointerEvent('pointer' + evType, {
457
+ bubbles: true,
458
+ button: 0, // Moz doesn't use -1 when no buttons are pressed, WTF?
459
+ // buttons: this._state.down ? 1 : 0,
460
+ // detail: (evType === 'down' || evType === 'up') ? 1 : 0, // TODO: count consecutive clicks
461
+ clientX: this._state.x,
462
+ clientY: this._state.y,
463
+ screenX: this._state.x, /// TODO: Handle page scrolling
464
+ screenY: this._state.y,
465
+ pageX: this._state.x,
466
+ pageY: this._state.y,
467
+ pointerType: this._state.pointerType,
468
+ pointerId: this._id,
469
+ isPrimary: this._id === 1,
470
+ width: this._state.width,
471
+ height: this._state.height,
472
+ tiltX: this._state.tiltX,
473
+ tiltY: this._state.tiltY,
474
+ pressure: this._state.pressure
475
+ // target: document.elementFromPoint(this._state.x, this._state.y), // works with viewport coords
476
+ });
535
477
  }
536
478
 
537
- // 🖑method private_asMouseEvent(evType: String): PointerEvent
479
+ // 🖐️method private_asMouseEvent(evType: String): PointerEvent
538
480
  // Returns an instance of `PointerEvent` representing the current state of the finger
539
481
  _asMouseEvent(evType) {
540
- var ev;
541
- if (capabilities.mouseEventConstructor) {
542
- ev = new MouseEvent('mouse' + evType, {
543
- bubbles: true,
544
- button: 0, // Moz doesn't use -1 when no buttons are pressed, WTF?
545
- buttons: this._state.down ? 1 : 0,
546
- detail: (evType === 'down' || evType === 'up') ? 1 : 0, // TODO: count consecutive clicks
547
- clientX: this._state.x,
548
- clientY: this._state.y,
549
- screenX: this._state.x, /// TODO: Handle page scrolling
550
- screenY: this._state.y,
551
- pageX: this._state.x,
552
- pageY: this._state.y,
553
- // target: document.elementFromPoint(this._state.x, this._state.y), // works with viewport coords
554
- });
555
- } else {
556
- // For legacy browsers and PhantomJS
557
- ev = document.createEvent('MouseEvent');
558
- ev.initMouseEvent(
559
- 'mouse' + evType, // Type
560
- true, // canBubble
561
- true, // cancellable
562
- window, // view
563
- 0, // detail
564
- this._state.x, // screenX
565
- this._state.y, // screenY
566
- this._state.x, // clientX
567
- this._state.y, // clientY
568
- false, // ctrlKey
569
- false, // altKey
570
- false, // shiftKey
571
- false, // metaKey
572
- 0, // button
573
- null // relatedTarget
574
- );
575
- }
576
- 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
+ });
577
495
  }
578
496
 
579
497