@devexperts/dxcharts-lite 2.1.0 → 2.2.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
@@ -23,7 +23,7 @@
23
23
  <img src="https://img.shields.io/static/v1?label=PRs&message=Welcome&color=blue" alt="PRs: Welcome" />
24
24
  </a>&nbsp;
25
25
  <a href="https://devexperts.com/dxcharts-demo/?lang=en">
26
- <img src="https://img.shields.io/static/v1?label=Latest%20version&message=2.1.0&color=blue" alt="Version" />
26
+ <img src="https://img.shields.io/static/v1?label=Latest%20version&message=2.2.0&color=blue" alt="Version" />
27
27
  </a>
28
28
  </p>
29
29
 
@@ -3,7 +3,8 @@
3
3
  * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
4
  * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
5
  */
6
- import { BehaviorSubject, combineLatest, filter } from 'rxjs';
6
+ import { BehaviorSubject, combineLatest } from 'rxjs';
7
+ import { filter } from 'rxjs/operators';
7
8
  import { ChartBaseElement } from '../model/chart-base-element';
8
9
  export class CrossEventProducerComponent extends ChartBaseElement {
9
10
  constructor(canvasInputListener, canvasBoundsContainer) {
@@ -84,7 +84,7 @@ export class HoverProducerComponent extends ChartBaseElement {
84
84
  // special handling for mobile
85
85
  // on long touch - disable panning and show cross tool
86
86
  const hitTest = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.ALL_PANES);
87
- this.addRxSubscription(this.canvasInputListener.observeLongTouch(hitTest).subscribe(event => {
87
+ this.addRxSubscription(this.canvasInputListener.observeLongTouchStart(hitTest).subscribe(event => {
88
88
  this.paneManager.chartPanComponent.deactivatePanHandlers();
89
89
  this.longTouchActivatedSubject.next(true);
90
90
  const x = event.touches[0].clientX - this.canvasBoundsContainer.canvasOnPageLocation.x;
@@ -47,8 +47,9 @@ export declare class CanvasInputListenerComponent extends ChartBaseElement {
47
47
  private touchMoveSubject;
48
48
  private touchEndSubject;
49
49
  private touchCancelSubject;
50
+ private longTouchStartSubject;
51
+ private longTouchEndSubject;
50
52
  private contextMenuSubject;
51
- private longTouchSubject;
52
53
  private pinchSubject;
53
54
  private scrollGestureSubject;
54
55
  mouseLeavesCanvasSubject: Subject<boolean>;
@@ -300,11 +301,17 @@ export declare class CanvasInputListenerComponent extends ChartBaseElement {
300
301
  */
301
302
  observeContextMenu(hitBoundsTest?: HitBoundsTest): Observable<MouseEvent>;
302
303
  /**
303
- * Returns an Observable that emits a TouchEvent when a long touch is detected on the current element.
304
+ * Returns an Observable that emits a TouchEvent when a long touch start is detected on the current element.
304
305
  * @param {HitBoundsTest} [hitBoundsTest=() => true] - A function that returns a boolean indicating whether the touch event occurred within the bounds of the current element.
305
306
  * @returns {Observable<TouchEvent>} - An Observable that emits a TouchEvent when a long touch is detected on the current element.
306
307
  */
307
- observeLongTouch(hitBoundsTest?: HitBoundsTest): Observable<TouchEvent>;
308
+ observeLongTouchStart(hitBoundsTest?: HitBoundsTest): Observable<TouchEvent>;
309
+ /**
310
+ * Returns an Observable that emits a TouchEvent when a long touch end is detected on the current element.
311
+ * @param {HitBoundsTest} [hitBoundsTest=() => true] - A function that returns a boolean indicating whether the touch event occurred within the bounds of the current element.
312
+ * @returns {Observable<TouchEvent>} - An Observable that emits a TouchEvent when a long touch is detected on the current element.
313
+ */
314
+ observeLongTouchEnd(hitBoundsTest?: HitBoundsTest): Observable<TouchEvent>;
308
315
  /**
309
316
  * Returns the current point of the object.
310
317
  * @returns {Point} The current point of the object.
@@ -8,8 +8,8 @@ import { merge, Subject } from 'rxjs';
8
8
  import { ChartBaseElement } from '../model/chart-base-element';
9
9
  import { distinctUntilChanged, filter, map, tap } from 'rxjs/operators';
10
10
  import { EVENT_RESIZED } from '../events/events';
11
- import { deviceDetector } from '../utils/device/device-detector.utils';
12
11
  import { touchpadDetector } from '../utils/device/touchpad.utils';
12
+ import { deviceDetector } from '../utils/device/device-detector.utils';
13
13
  /**
14
14
  * Gathers user input on canvas element:
15
15
  * Chart update order should be following:
@@ -49,8 +49,9 @@ class CanvasInputListenerComponent extends ChartBaseElement {
49
49
  this.touchMoveSubject = new Subject();
50
50
  this.touchEndSubject = new Subject();
51
51
  this.touchCancelSubject = new Subject();
52
+ this.longTouchStartSubject = new Subject();
53
+ this.longTouchEndSubject = new Subject();
52
54
  this.contextMenuSubject = new Subject();
53
- this.longTouchSubject = new Subject();
54
55
  this.pinchSubject = new Subject();
55
56
  this.scrollGestureSubject = new Subject();
56
57
  this.mouseLeavesCanvasSubject = new Subject();
@@ -184,50 +185,58 @@ class CanvasInputListenerComponent extends ChartBaseElement {
184
185
  const device = deviceDetector();
185
186
  if (device === 'apple' || device === 'mobile') {
186
187
  // workaround to handle double taps for iOS
187
- const doubleTapListenerProducer = () => {
188
- let timeoutId = null;
189
- return () => {
190
- if (timeoutId) {
191
- this.dbTapSubject.next(this.currentPoint);
192
- clearTimeout(timeoutId);
193
- timeoutId = null;
188
+ let dbTapTimeout = null;
189
+ const doubleTapListenerProducer = (e) => {
190
+ e.preventDefault();
191
+ if (dbTapTimeout) {
192
+ this.dbTapSubject.next(this.currentPoint);
193
+ clearTimeout(dbTapTimeout);
194
+ dbTapTimeout = null;
195
+ }
196
+ else {
197
+ dbTapTimeout = window.setTimeout(() => {
198
+ dbTapTimeout = null;
199
+ }, 250);
200
+ }
201
+ };
202
+ this.addSubscription(subscribeListener(this.element, doubleTapListenerProducer, 'touchend'));
203
+ // workaround to handle long touch start/end for iOS
204
+ const longTouchListeners = (e, delay = 700, pixelsForMoveReset = 3) => {
205
+ e.preventDefault();
206
+ const initialCoords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
207
+ let coords = { x: 0, y: 0 };
208
+ let longTouchStart = false;
209
+ let timerLongTouchStart = null;
210
+ // start timeout for long touch
211
+ timerLongTouchStart = setTimeout(() => {
212
+ longTouchStart = true;
213
+ this.longTouchStartSubject.next(e);
214
+ }, delay);
215
+ const touchMoveHandler = (e) => {
216
+ e.preventDefault();
217
+ coords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
218
+ // clear long touch timeout if move area is bigger than pixelsForMove
219
+ if (Math.sqrt(Math.pow(coords.x - initialCoords.x, 2) + Math.pow(coords.y - initialCoords.y, 2)) >
220
+ pixelsForMoveReset ||
221
+ e.touches.length > 1) {
222
+ timerLongTouchStart && clearTimeout(timerLongTouchStart);
194
223
  }
195
- else {
196
- timeoutId = window.setTimeout(() => {
197
- timeoutId = null;
198
- }, 250);
224
+ };
225
+ const touchEndHandler = (e) => {
226
+ e.preventDefault();
227
+ timerLongTouchStart && clearTimeout(timerLongTouchStart);
228
+ if (longTouchStart) {
229
+ longTouchStart = false;
230
+ this.longTouchEndSubject.next(e);
199
231
  }
232
+ this.element.removeEventListener('touchend', touchEndHandler);
233
+ this.element.removeEventListener('touchmove', touchMoveHandler);
200
234
  };
235
+ this.element.addEventListener('touchmove', touchMoveHandler);
236
+ this.element.addEventListener('touchend', touchEndHandler);
201
237
  };
202
- const doubleTapListener = doubleTapListenerProducer();
203
- this.addSubscription(subscribeListener(this.element, doubleTapListener, 'touchend'));
238
+ this.addSubscription(subscribeListener(this.element, (e) => longTouchListeners(e), 'touchstart'));
204
239
  }
205
- const longTouchListener = (e, delay = 500, pixelsForMoveReset = 2) => {
206
- e.preventDefault();
207
- let timer = null;
208
- const initialCoords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
209
- let coords = { x: 0, y: 0 };
210
- const touchMoveHandler = (e) => {
211
- coords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
212
- if (Math.sqrt(Math.pow(coords.x - initialCoords.x, 2) + Math.pow(coords.y - initialCoords.y, 2)) >
213
- pixelsForMoveReset ||
214
- e.touches.length > 1) {
215
- touchEnd();
216
- }
217
- };
218
- const touchEnd = () => {
219
- if (timer) {
220
- clearTimeout(timer);
221
- timer = null;
222
- }
223
- this.element.removeEventListener('touchend', touchEnd);
224
- this.element.removeEventListener('touchmove', touchMoveHandler);
225
- };
226
- timer = setTimeout(() => this.longTouchSubject.next(e), delay);
227
- this.element.addEventListener('touchmove', touchMoveHandler, { passive: true });
228
- this.element.addEventListener('touchend', touchEnd);
229
- };
230
- this.addSubscription(subscribeListener(this.element, (e) => longTouchListener(e), 'touchstart'));
231
240
  this.addSubscription(subscribeListener(this.element, leftMouseButtonListener(() => this.dbClickSubject.next(this.currentPoint)), 'dblclick'));
232
241
  this.addSubscription(subscribeListener(this.element, (e) => this.touchStartSubject.next(e), 'touchstart'));
233
242
  this.addSubscription(subscribeListener(this.element, (e) => this.touchMoveSubject.next(e), 'touchmove', true));
@@ -615,12 +624,24 @@ class CanvasInputListenerComponent extends ChartBaseElement {
615
624
  return this.contextMenuSubject.asObservable().pipe(filter(() => hitBoundsTest(this.currentPoint.x, this.currentPoint.y)), tap(p => p.preventDefault()));
616
625
  }
617
626
  /**
618
- * Returns an Observable that emits a TouchEvent when a long touch is detected on the current element.
627
+ * Returns an Observable that emits a TouchEvent when a long touch start is detected on the current element.
619
628
  * @param {HitBoundsTest} [hitBoundsTest=() => true] - A function that returns a boolean indicating whether the touch event occurred within the bounds of the current element.
620
629
  * @returns {Observable<TouchEvent>} - An Observable that emits a TouchEvent when a long touch is detected on the current element.
621
630
  */
622
- observeLongTouch(hitBoundsTest = () => true) {
623
- return this.longTouchSubject.asObservable().pipe(filter(() => hitBoundsTest(this.currentPoint.x, this.currentPoint.y)), tap(p => p.preventDefault()));
631
+ observeLongTouchStart(hitBoundsTest = () => true) {
632
+ return this.longTouchStartSubject
633
+ .asObservable()
634
+ .pipe(filter(() => hitBoundsTest(this.currentPoint.x, this.currentPoint.y)));
635
+ }
636
+ /**
637
+ * Returns an Observable that emits a TouchEvent when a long touch end is detected on the current element.
638
+ * @param {HitBoundsTest} [hitBoundsTest=() => true] - A function that returns a boolean indicating whether the touch event occurred within the bounds of the current element.
639
+ * @returns {Observable<TouchEvent>} - An Observable that emits a TouchEvent when a long touch is detected on the current element.
640
+ */
641
+ observeLongTouchEnd(hitBoundsTest = () => true) {
642
+ return this.longTouchEndSubject
643
+ .asObservable()
644
+ .pipe(filter(() => hitBoundsTest(this.currentPoint.x, this.currentPoint.y)));
624
645
  }
625
646
  /**
626
647
  * Returns the current point of the object.