@devexperts/dxcharts-lite 2.5.8 → 2.6.1

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.
Files changed (68) hide show
  1. package/dist/chart/__tests__/chart.test.js +5 -5
  2. package/dist/chart/__tests__/env.js +1 -1
  3. package/dist/chart/bootstrap.js +1 -1
  4. package/dist/chart/canvas/canvas-bounds-container.d.ts +1 -0
  5. package/dist/chart/canvas/canvas-bounds-container.js +28 -4
  6. package/dist/chart/chart.config.d.ts +10 -0
  7. package/dist/chart/chart.config.js +4 -2
  8. package/dist/chart/components/chart/candle-transformer.functions.js +1 -1
  9. package/dist/chart/components/chart/candle.functions.d.ts +1 -1
  10. package/dist/chart/components/chart/candle.functions.js +3 -2
  11. package/dist/chart/components/chart/chart.component.d.ts +29 -8
  12. package/dist/chart/components/chart/chart.component.js +33 -4
  13. package/dist/chart/components/chart/chart.model.d.ts +41 -4
  14. package/dist/chart/components/chart/chart.model.js +90 -16
  15. package/dist/chart/components/chart/fake-candles.js +2 -0
  16. package/dist/chart/components/chart/fake-visual-candle.d.ts +4 -4
  17. package/dist/chart/components/chart/fake-visual-candle.js +4 -4
  18. package/dist/chart/components/cross_tool/cross-tool.component.js +2 -2
  19. package/dist/chart/components/cross_tool/cross-tool.drawer.d.ts +3 -1
  20. package/dist/chart/components/cross_tool/cross-tool.drawer.js +4 -3
  21. package/dist/chart/components/cross_tool/cross-tool.model.d.ts +6 -6
  22. package/dist/chart/components/cross_tool/cross-tool.model.js +42 -11
  23. package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +3 -3
  24. package/dist/chart/components/high_low/high-low.drawer.js +1 -1
  25. package/dist/chart/components/pane/pane-manager.component.d.ts +5 -0
  26. package/dist/chart/components/pane/pane-manager.component.js +20 -0
  27. package/dist/chart/components/pane/pane.component.d.ts +9 -1
  28. package/dist/chart/components/pane/pane.component.js +16 -0
  29. package/dist/chart/components/volumes/separate-volumes.component.d.ts +1 -3
  30. package/dist/chart/components/volumes/separate-volumes.component.js +1 -3
  31. package/dist/chart/components/volumes/volumes.component.js +1 -1
  32. package/dist/chart/components/volumes/volumes.drawer.js +3 -3
  33. package/dist/chart/components/watermark/water-mark.component.d.ts +3 -12
  34. package/dist/chart/components/watermark/water-mark.component.js +1 -1
  35. package/dist/chart/components/x_axis/time/parser/time-formats-parser.functions.js +1 -1
  36. package/dist/chart/components/x_axis/x-axis-draw.functions.js +2 -2
  37. package/dist/chart/components/x_axis/x-axis-scale.handler.d.ts +1 -0
  38. package/dist/chart/components/x_axis/x-axis-scale.handler.js +39 -10
  39. package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +2 -2
  40. package/dist/chart/components/x_axis/x-axis.component.js +1 -1
  41. package/dist/chart/components/y_axis/y-axis-scale.handler.js +3 -3
  42. package/dist/chart/drawers/drawing-manager.d.ts +1 -1
  43. package/dist/chart/drawers/drawing-manager.js +0 -1
  44. package/dist/chart/inputhandlers/cross-event-producer.component.d.ts +22 -0
  45. package/dist/chart/inputhandlers/cross-event-producer.component.js +11 -1
  46. package/dist/chart/inputhandlers/hover-producer.component.d.ts +5 -3
  47. package/dist/chart/inputhandlers/hover-producer.component.js +78 -18
  48. package/dist/chart/inputhandlers/main-canvas-touch.handler.d.ts +10 -0
  49. package/dist/chart/inputhandlers/main-canvas-touch.handler.js +18 -0
  50. package/dist/chart/inputlisteners/canvas-input-listener.component.js +2 -7
  51. package/dist/chart/model/candle-series.model.js +1 -1
  52. package/dist/chart/model/candle.model.d.ts +3 -0
  53. package/dist/chart/model/candle.model.js +7 -1
  54. package/dist/chart/model/data-series.model.d.ts +3 -3
  55. package/dist/chart/model/data-series.model.js +1 -1
  56. package/dist/chart/model/scale.model.js +1 -1
  57. package/dist/chart/model/scaling/viewport.model.d.ts +2 -1
  58. package/dist/chart/model/scaling/viewport.model.js +6 -1
  59. package/dist/chart/model/time-zone.model.js +1 -3
  60. package/dist/chart/utils/candles-generator-ts.utils.d.ts +1 -0
  61. package/dist/chart/utils/candles-generator.utils.d.ts +1 -0
  62. package/dist/chart/utils/candles-generator.utils.js +2 -0
  63. package/dist/chart/utils/string.utils.d.ts +6 -0
  64. package/dist/chart/utils/string.utils.js +19 -0
  65. package/dist/chart/utils/types.utils.d.ts +9 -0
  66. package/dist/chart/utils/types.utils.js +6 -0
  67. package/dist/dxchart.min.js +4 -4
  68. package/package.json +1 -1
@@ -3,7 +3,7 @@
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 { CanvasElement } from '../../canvas/canvas-bounds-container';
6
+ import { CanvasElement, X_AXIS_MOBILE_PADDING } from '../../canvas/canvas-bounds-container';
7
7
  import { calculateTextWidth } from '../../utils/canvas/canvas-font-measure-tool.utils';
8
8
  /**
9
9
  * This Drawer draws regular time labels for X Axis.
@@ -38,7 +38,7 @@ export class XAxisTimeLabelsDrawer {
38
38
  ctx.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
39
39
  const color = this.config.colors.xAxis.labelTextColor;
40
40
  const labels = this.labelsProvider();
41
- this.drawLabels(ctx, labels, bounds, color, fontHeight, fontFamily, offsetTop);
41
+ this.drawLabels(ctx, labels, bounds, color, fontHeight, fontFamily, offsetTop + X_AXIS_MOBILE_PADDING / 2);
42
42
  ctx.restore();
43
43
  }
44
44
  }
@@ -82,7 +82,7 @@ export class XAxisComponent extends ChartBaseElement {
82
82
  this.xAxisLabelsGenerator.recalculateLabels();
83
83
  }));
84
84
  this.addRxSubscription(this.chartComponent.chartModel.candlesUpdatedSubject
85
- .pipe(map(() => lastOf(this.chartComponent.chartModel.mainCandleSeries.visualPoints)), distinctUntilChanged((a, b) => { var _a, _b; return ((_a = a === null || a === void 0 ? void 0 : a.candle) === null || _a === void 0 ? void 0 : _a.timestamp) === ((_b = b === null || b === void 0 ? void 0 : b.candle) === null || _b === void 0 ? void 0 : _b.timestamp); }), filter(notEmpty))
85
+ .pipe(map(() => lastOf(this.chartComponent.chartModel.mainCandleSeries.visualPoints)), distinctUntilChanged((a, b) => { var _a, _b; return ((_a = a === null || a === void 0 ? void 0 : a.candle) === null || _a === void 0 ? void 0 : _a.id) === ((_b = b === null || b === void 0 ? void 0 : b.candle) === null || _b === void 0 ? void 0 : _b.id); }), filter(notEmpty))
86
86
  .subscribe(x => { var _a, _b; return (_b = (_a = this.xAxisLabelsGenerator) === null || _a === void 0 ? void 0 : _a.updateLastLabel) === null || _b === void 0 ? void 0 : _b.call(_a, x); }));
87
87
  }
88
88
  /**
@@ -4,7 +4,7 @@
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
6
  import { Subject } from 'rxjs';
7
- import { CanvasElement, DEFAULT_MIN_PANE_HEIGHT } from '../../canvas/canvas-bounds-container';
7
+ import { CanvasElement, DEFAULT_MIN_PANE_HEIGHT, } from '../../canvas/canvas-bounds-container';
8
8
  import { ChartBaseElement } from '../../model/chart-base-element';
9
9
  import { DragNDropYComponent } from '../dran-n-drop_helper/drag-n-drop-y.component';
10
10
  // if you drag full Y height from top to bottom - you will have x3 zoom, and vice-versa
@@ -73,8 +73,8 @@ export class YAxisScaleHandler extends ChartBaseElement {
73
73
  // Continue redrawing hit test
74
74
  this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(true);
75
75
  };
76
- this.setDblTapCallback = (cb) => this.dblTapCallback = cb;
77
- this.setDblClickCallback = (cb) => this.dblClickCallback = cb;
76
+ this.setDblTapCallback = (cb) => (this.dblTapCallback = cb);
77
+ this.setDblClickCallback = (cb) => (this.dblClickCallback = cb);
78
78
  this.dblClickCallback = () => scale.autoScale(true);
79
79
  this.dblTapCallback = () => scale.autoScale(true);
80
80
  // drag to Y-scale and double click to auto scale
@@ -6,7 +6,7 @@
6
6
  import EventBus from '../events/event-bus';
7
7
  import { ChartResizeHandler } from '../inputhandlers/chart-resize.handler';
8
8
  export declare const HIT_TEST_PREFIX = "HIT_TEST_";
9
- declare const drawerTypes: readonly ["MAIN_BACKGROUND", "MAIN_CLEAR", "HIT_TEST_CLEAR", "YAXIS_CLEAR", "SERIES_CLEAR", "OVER_SERIES_CLEAR", "HIT_TEST_DRAWINGS", "GRID", "UNDERLAY_VOLUMES_AREA", "X_AXIS", "Y_AXIS", "HIGH_LOW", "DYNAMIC_OBJECTS", "N_MAP_CHART", "PL_CHART", "WATERMARK", "EMPTY_CHART", "OFFLINE_CHART", "LABELS", "EVENTS", "HIT_TEST_EVENTS", "ZERO_LINE", "PL_ZERO_LINE_BACKGROUND", "CROSS_TOOL"];
9
+ declare const drawerTypes: readonly ["MAIN_BACKGROUND", "MAIN_CLEAR", "HIT_TEST_CLEAR", "YAXIS_CLEAR", "SERIES_CLEAR", "OVER_SERIES_CLEAR", "HIT_TEST_DRAWINGS", "GRID", "X_AXIS", "Y_AXIS", "HIGH_LOW", "DYNAMIC_OBJECTS", "N_MAP_CHART", "PL_CHART", "WATERMARK", "EMPTY_CHART", "OFFLINE_CHART", "LABELS", "EVENTS", "HIT_TEST_EVENTS", "ZERO_LINE", "PL_ZERO_LINE_BACKGROUND", "CROSS_TOOL"];
10
10
  export type DrawerType = typeof drawerTypes[number];
11
11
  /**
12
12
  * Manages the drawing process.
@@ -18,7 +18,6 @@ const drawerTypes = [
18
18
  'OVER_SERIES_CLEAR',
19
19
  'HIT_TEST_DRAWINGS',
20
20
  'GRID',
21
- 'UNDERLAY_VOLUMES_AREA',
22
21
  'X_AXIS',
23
22
  'Y_AXIS',
24
23
  'HIGH_LOW',
@@ -8,15 +8,36 @@ import { CanvasBoundsContainer, HitBoundsTest, HitBoundsTestOptionsPartial } fro
8
8
  import { CanvasInputListenerComponent } from '../inputlisteners/canvas-input-listener.component';
9
9
  import { ChartBaseElement } from '../model/chart-base-element';
10
10
  import { Unsubscriber } from '../utils/function.utils';
11
+ import { Pixel } from '../model/scaling/viewport.model';
12
+ import { Hover } from './hover-producer.component';
11
13
  /**
12
14
  * [x, y, uuid - Unique identifier for the subscription]
13
15
  */
14
16
  export type CrossEvent = [number, number, string];
17
+ interface CrossToolTouchInfo {
18
+ fixed: {
19
+ x: Pixel;
20
+ y: Pixel;
21
+ };
22
+ temp: {
23
+ x: Pixel;
24
+ y: Pixel;
25
+ };
26
+ isSet: boolean;
27
+ /**
28
+ * additional flag to determine ordinary and long taps
29
+ * crosstool shouldn't be hidden after longtouch event even if coordinates are the same
30
+ * becomes true after touchStart and false after longTouchStart
31
+ */
32
+ isCommonTap: boolean;
33
+ }
15
34
  export declare class CrossEventProducerComponent extends ChartBaseElement {
16
35
  private canvasInputListener;
17
36
  private canvasBoundsContainer;
18
37
  panesSubscriptions: Partial<Record<string, Subscription>>;
19
38
  crossSubject: BehaviorSubject<CrossEvent | null>;
39
+ crossToolHover: Hover | null;
40
+ crossToolTouchInfo: CrossToolTouchInfo;
20
41
  constructor(canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer);
21
42
  protected doActivate(): void;
22
43
  /**
@@ -45,3 +66,4 @@ export declare class CrossEventProducerComponent extends ChartBaseElement {
45
66
  */
46
67
  subscribeMouseOverHT(uuid: string, hitTest: HitBoundsTest): Unsubscriber;
47
68
  }
69
+ export {};
@@ -6,6 +6,7 @@
6
6
  import { BehaviorSubject, combineLatest } from 'rxjs';
7
7
  import { filter } from 'rxjs/operators';
8
8
  import { ChartBaseElement } from '../model/chart-base-element';
9
+ import { isMobile } from '../utils/device/browser.utils';
9
10
  export class CrossEventProducerComponent extends ChartBaseElement {
10
11
  constructor(canvasInputListener, canvasBoundsContainer) {
11
12
  super();
@@ -13,6 +14,14 @@ export class CrossEventProducerComponent extends ChartBaseElement {
13
14
  this.canvasBoundsContainer = canvasBoundsContainer;
14
15
  this.panesSubscriptions = {};
15
16
  this.crossSubject = new BehaviorSubject(null);
17
+ // mobile specific crosstool hover and touch info
18
+ this.crossToolHover = null;
19
+ this.crossToolTouchInfo = {
20
+ fixed: { x: 0, y: 0 },
21
+ temp: { x: 0, y: 0 },
22
+ isSet: false,
23
+ isCommonTap: false,
24
+ };
16
25
  }
17
26
  doActivate() {
18
27
  super.doActivate();
@@ -62,7 +71,8 @@ export class CrossEventProducerComponent extends ChartBaseElement {
62
71
  this.crossSubject.next(cross);
63
72
  closeHoverFired = false;
64
73
  }
65
- else {
74
+ // crosstool should be hidden if hovering nonpane only on desktop
75
+ if (!enter && !isMobile()) {
66
76
  this.crossSubject.next(null);
67
77
  closeHoverFired = true;
68
78
  }
@@ -17,6 +17,7 @@ import { ScaleModel } from '../model/scale.model';
17
17
  import VisualCandle from '../model/visual-candle';
18
18
  import { CrossEvent, CrossEventProducerComponent } from './cross-event-producer.component';
19
19
  import { TimeZoneModel } from '../model/time-zone.model';
20
+ import { MainCanvasTouchHandler } from './main-canvas-touch.handler';
20
21
  export interface BaseHover {
21
22
  readonly x: number;
22
23
  readonly y: number;
@@ -52,13 +53,14 @@ export declare class HoverProducerComponent extends ChartBaseElement {
52
53
  private canvasBoundsContainer;
53
54
  private paneManager;
54
55
  private timeZoneModel;
56
+ private mainCanvasTouchHandler;
55
57
  private formatterFactory;
56
58
  hoverSubject: BehaviorSubject<Hover | null>;
57
59
  get hover(): Hover | null;
58
- private longTouchActivatedSubject;
60
+ longTouchActivatedSubject: BehaviorSubject<boolean>;
59
61
  private hoverProducerParts;
60
62
  xFormatter: DateTimeFormatter;
61
- constructor(crossEventProducer: CrossEventProducerComponent, scale: ScaleModel, config: FullChartConfig, chartModel: ChartModel, canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer, paneManager: PaneManager, timeZoneModel: TimeZoneModel, formatterFactory: (format: string) => (timestamp: number) => string);
63
+ constructor(crossEventProducer: CrossEventProducerComponent, scale: ScaleModel, config: FullChartConfig, chartModel: ChartModel, canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer, paneManager: PaneManager, timeZoneModel: TimeZoneModel, mainCanvasTouchHandler: MainCanvasTouchHandler, formatterFactory: (format: string) => (timestamp: number) => string);
62
64
  /**
63
65
  * This method is responsible for activating the chart hover functionality. It subscribes to several observables to
64
66
  * update the hover when the chart is updated or when the user interacts with it. It also handles special behavior
@@ -89,7 +91,7 @@ export declare class HoverProducerComponent extends ChartBaseElement {
89
91
  * @returns {Hover | undefined} - The hover object or undefined if there are no candles in the chart model.
90
92
  * @todo Check if uuid is still useful here.
91
93
  */
92
- private createHover;
94
+ createHover(x: number, y: number, uuid: string): Hover | undefined;
93
95
  /**
94
96
  * Creates a hover from a VisualCandle object and fires it.
95
97
  * @param {VisualCandle} candle - The VisualCandle object to create the hover from.
@@ -4,12 +4,14 @@
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
6
  import { BehaviorSubject, merge } from 'rxjs';
7
+ import { filter, switchMap } from 'rxjs/operators';
7
8
  import { CHART_UUID, CanvasElement } from '../canvas/canvas-bounds-container';
8
9
  import { CandleHoverProducerPart } from '../model/candle-hover';
9
10
  import { ChartBaseElement } from '../model/chart-base-element';
10
11
  import { CompareSeriesHoverProducerPart } from '../model/compare-series-hover';
11
12
  import { recalculateXFormatter } from '../model/date-time.formatter';
12
13
  import { isMobile } from '../utils/device/browser.utils';
14
+ import { checkChartIsMoving } from './main-canvas-touch.handler';
13
15
  /**
14
16
  * Produces the Hover event.
15
17
  * Hover is used for displaying values in legend and NOT related to displaying cross tool.
@@ -18,7 +20,7 @@ export class HoverProducerComponent extends ChartBaseElement {
18
20
  get hover() {
19
21
  return this.hoverSubject.getValue();
20
22
  }
21
- constructor(crossEventProducer, scale, config, chartModel, canvasInputListener, canvasBoundsContainer, paneManager, timeZoneModel, formatterFactory) {
23
+ constructor(crossEventProducer, scale, config, chartModel, canvasInputListener, canvasBoundsContainer, paneManager, timeZoneModel, mainCanvasTouchHandler, formatterFactory) {
22
24
  super();
23
25
  this.crossEventProducer = crossEventProducer;
24
26
  this.scale = scale;
@@ -28,6 +30,7 @@ export class HoverProducerComponent extends ChartBaseElement {
28
30
  this.canvasBoundsContainer = canvasBoundsContainer;
29
31
  this.paneManager = paneManager;
30
32
  this.timeZoneModel = timeZoneModel;
33
+ this.mainCanvasTouchHandler = mainCanvasTouchHandler;
31
34
  this.formatterFactory = formatterFactory;
32
35
  this.hoverSubject = new BehaviorSubject(null);
33
36
  this.longTouchActivatedSubject = new BehaviorSubject(false);
@@ -50,8 +53,13 @@ export class HoverProducerComponent extends ChartBaseElement {
50
53
  */
51
54
  doActivate() {
52
55
  super.doActivate();
53
- this.addRxSubscription(this.chartModel.candlesSetSubject.subscribe(() => {
54
- // required for initial legend initialization, do not show cross tool
56
+ this.addRxSubscription(
57
+ // required for initial legend initialization, do not show cross tool
58
+ this.chartModel.candlesSetSubject
59
+ .pipe(
60
+ // check the scale is valid before doing candle-based hover event
61
+ switchMap(() => this.scale.initialViewportValidSubject.pipe(filter(Boolean))))
62
+ .subscribe(() => {
55
63
  const lastCandle = this.chartModel.getLastVisualCandle();
56
64
  lastCandle && this.createAndFireHoverFromCandle(lastCandle);
57
65
  }));
@@ -73,37 +81,86 @@ export class HoverProducerComponent extends ChartBaseElement {
73
81
  }
74
82
  }));
75
83
  this.addRxSubscription(this.scale.xChanged.subscribe(() => this.fireLastCross()));
84
+ this.addRxSubscription(merge(this.chartModel.candlesSetSubject, this.timeZoneModel.observeTimeZoneChanged()).subscribe(() => this.recalculateCrossToolXFormatter()));
85
+ //#region crosstool touch events, special handling for mobile
76
86
  this.addRxSubscription(this.canvasInputListener.observeTouchStart().subscribe(event => {
77
87
  var _a;
78
- const x = event.touches[0].clientX - this.canvasBoundsContainer.canvasOnPageLocation.x;
79
- const y = event.touches[0].clientY - this.canvasBoundsContainer.canvasOnPageLocation.y;
80
- const candle = this.chartModel.candleFromX(x, true);
81
- const paneId = ((_a = this.paneManager.getPaneIfHit({ x, y })) === null || _a === void 0 ? void 0 : _a.uuid) || '';
82
- if (candle) {
83
- this.createAndFireHover([x, y, paneId]);
88
+ this.crossEventProducer.crossToolTouchInfo.isCommonTap = true;
89
+ const { clientX, clientY } = event.touches[0];
90
+ // if common tap - fire hover
91
+ if (!this.longTouchActivatedSubject.getValue()) {
92
+ const paneId = ((_a = this.paneManager.getPaneIfHit({ x: clientX, y: clientY })) === null || _a === void 0 ? void 0 : _a.uuid) || '';
93
+ this.createAndFireHover([clientX, clientY, paneId]);
94
+ }
95
+ else {
96
+ // update crosstool placement coordinates
97
+ this.crossEventProducer.crossToolTouchInfo.temp = {
98
+ x: clientX - this.canvasBoundsContainer.canvasOnPageLocation.x,
99
+ y: clientY - this.canvasBoundsContainer.canvasOnPageLocation.y,
100
+ };
84
101
  }
85
102
  }));
86
- // special handling for mobile
87
103
  // on long touch - disable panning and show cross tool
88
104
  const hitTest = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.ALL_PANES);
89
105
  this.addRxSubscription(this.canvasInputListener.observeLongTouchStart(hitTest).subscribe(event => {
90
106
  var _a;
91
- this.paneManager.chartPanComponent.deactivatePanHandlers();
107
+ this.crossEventProducer.crossToolHover = null;
108
+ this.crossEventProducer.crossToolTouchInfo.isCommonTap = false;
109
+ // don't lock chart and show crosshair if chart is being moved, crosstool is not enabled or we do pinch event
110
+ const longTouchCrosshairPredicate = this.mainCanvasTouchHandler.canvasTouchInfo.isMoving ||
111
+ this.chartModel.config.components.crossTool.type === 'none' ||
112
+ event.touches.length > 1;
113
+ if (longTouchCrosshairPredicate) {
114
+ return;
115
+ }
92
116
  this.longTouchActivatedSubject.next(true);
117
+ this.crossEventProducer.crossToolTouchInfo.isSet = false;
93
118
  const x = event.touches[0].clientX - this.canvasBoundsContainer.canvasOnPageLocation.x;
94
119
  const y = event.touches[0].clientY - this.canvasBoundsContainer.canvasOnPageLocation.y;
120
+ this.crossEventProducer.crossToolTouchInfo.fixed = {
121
+ x,
122
+ y,
123
+ };
95
124
  const paneId = ((_a = this.paneManager.getPaneIfHit({ x, y })) === null || _a === void 0 ? void 0 : _a.uuid) || '';
96
125
  this.createAndFireHover([x, y, paneId]);
97
126
  this.crossEventProducer.crossSubject.next([x, y, paneId]);
127
+ this.paneManager.chartPanComponent.setChartPanningOptions(false, false);
98
128
  }));
99
- this.addRxSubscription(this.canvasInputListener.observeTouchEndDocument().subscribe(() => {
100
- this.paneManager.chartPanComponent.activateChartPanHandlers();
101
- if (this.longTouchActivatedSubject.getValue()) {
129
+ this.addRxSubscription(this.canvasInputListener.observeTouchEndDocument().subscribe(event => {
130
+ var _a, _b;
131
+ const { clientX, clientY } = event.changedTouches[0];
132
+ const { fixed, temp } = this.crossEventProducer.crossToolTouchInfo;
133
+ const x = clientX - this.canvasBoundsContainer.canvasOnPageLocation.x;
134
+ const y = clientY - this.canvasBoundsContainer.canvasOnPageLocation.y;
135
+ // common tap without moving, hide crosstool
136
+ if (this.crossEventProducer.crossToolTouchInfo.isCommonTap &&
137
+ !checkChartIsMoving(x, temp.x, y, temp.y)) {
138
+ this.paneManager.chartPanComponent.setChartPanningOptions(true, true);
102
139
  this.longTouchActivatedSubject.next(false);
103
140
  this.crossEventProducer.fireCrossClose();
141
+ this.crossEventProducer.crossToolHover = null;
142
+ }
143
+ if (!this.crossEventProducer.crossToolTouchInfo.isSet) {
144
+ this.crossEventProducer.crossToolTouchInfo.isSet = true;
145
+ this.crossEventProducer.crossToolTouchInfo.fixed = {
146
+ x,
147
+ y,
148
+ };
149
+ this.crossEventProducer.crossToolTouchInfo.isSet = true;
150
+ }
151
+ else {
152
+ const pane = (_b = (_a = this.crossEventProducer.crossToolHover) === null || _a === void 0 ? void 0 : _a.paneId) !== null && _b !== void 0 ? _b : 'CHART';
153
+ const paneBounds = this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID(pane));
154
+ const paneYStart = paneBounds.y + 5;
155
+ const paneYEnd = paneBounds.y + paneBounds.height - 5;
156
+ const xDiff = x - temp.x;
157
+ const yDiff = y - temp.y;
158
+ const newX = fixed.x < 0 ? 0 : fixed.x > paneBounds.width ? paneBounds.width : (fixed.x += xDiff);
159
+ const newY = fixed.y < paneYStart ? paneYStart : fixed.y > paneYEnd ? paneYEnd : (fixed.y += yDiff);
160
+ this.crossEventProducer.crossToolTouchInfo.fixed = { x: newX, y: newY };
104
161
  }
105
162
  }));
106
- this.addRxSubscription(merge(this.chartModel.candlesSetSubject, this.timeZoneModel.observeTimeZoneChanged()).subscribe(() => this.recalculateCrossToolXFormatter()));
163
+ //#endregion
107
164
  }
108
165
  /**
109
166
  * Recalculates the cross tool X formatter.
@@ -192,12 +249,15 @@ export class HoverProducerComponent extends ChartBaseElement {
192
249
  * @returns {void}
193
250
  */
194
251
  fireHover(hover) {
195
- var _a;
252
+ var _a, _b;
196
253
  if (hover) {
197
254
  // special handling for mobile
198
- // set active candle + show cross tool only when long tap
255
+ // set active candle + show cross tool only when crosstool is active
199
256
  if (isMobile() && this.config.components.crossTool.type !== 'none') {
200
- const candle = (_a = hover.candleHover) === null || _a === void 0 ? void 0 : _a.visualCandle.candle;
257
+ const crossToolHover = this.crossEventProducer.crossToolHover;
258
+ const candle = crossToolHover
259
+ ? (_a = crossToolHover.candleHover) === null || _a === void 0 ? void 0 : _a.visualCandle.candle
260
+ : (_b = hover.candleHover) === null || _b === void 0 ? void 0 : _b.visualCandle.candle;
201
261
  candle && this.chartModel.mainCandleSeries.setActiveCandle(candle);
202
262
  }
203
263
  this.hoverSubject.next(hover);
@@ -8,6 +8,8 @@ import { CanvasInputListenerComponent } from '../inputlisteners/canvas-input-lis
8
8
  import { ScaleModel } from '../model/scale.model';
9
9
  import { ChartAreaPanHandler } from '../components/chart/chart-area-pan.handler';
10
10
  import { HitBoundsTest } from '../canvas/canvas-bounds-container';
11
+ import { Pixel } from '../model/scaling/viewport.model';
12
+ export declare const PIXELS_FOR_MOVE = 2;
11
13
  /**
12
14
  * Handles chart touch events.
13
15
  */
@@ -18,6 +20,13 @@ export declare class MainCanvasTouchHandler extends ChartBaseElement {
18
20
  private mainCanvasParent;
19
21
  private hitTest;
20
22
  private touchedCandleIndexes;
23
+ canvasTouchInfo: {
24
+ touchStart: {
25
+ x: Pixel;
26
+ y: Pixel;
27
+ };
28
+ isMoving?: boolean;
29
+ };
21
30
  constructor(chartAreaPanHandler: ChartAreaPanHandler, scale: ScaleModel, canvasInputListeners: CanvasInputListenerComponent, mainCanvasParent: Element, hitTest: HitBoundsTest);
22
31
  /**
23
32
  * Activates canvas input listeners for touch start and touch move events.
@@ -56,3 +65,4 @@ export declare class MainCanvasTouchHandler extends ChartBaseElement {
56
65
  */
57
66
  pinchHandler(candleIndexes: Array<number>, touchPositions: number[]): void;
58
67
  }
68
+ export declare const checkChartIsMoving: (x1: Pixel, x2: Pixel, y1: Pixel, y2: Pixel, pixelsToMove?: Pixel) => boolean;
@@ -4,6 +4,7 @@
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
6
  import { ChartBaseElement } from '../model/chart-base-element';
7
+ export const PIXELS_FOR_MOVE = 2;
7
8
  /**
8
9
  * Handles chart touch events.
9
10
  */
@@ -17,6 +18,12 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
17
18
  this.hitTest = hitTest;
18
19
  // 2 candles indexes touched by 2 fingers when pinching
19
20
  this.touchedCandleIndexes = [0, 0];
21
+ // stores the information about touch events
22
+ this.canvasTouchInfo = {
23
+ touchStart: { x: 0, y: 0 },
24
+ // uses touch start to determine if chart is being moved
25
+ isMoving: false,
26
+ };
20
27
  }
21
28
  /**
22
29
  * Activates canvas input listeners for touch start and touch move events.
@@ -34,6 +41,10 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
34
41
  * @returns {void}
35
42
  */
36
43
  handleTouchStartEvent(e) {
44
+ const { clientX, clientY } = e.touches[0];
45
+ if (e.touches.length === 1) {
46
+ this.canvasTouchInfo.touchStart = { x: clientX, y: clientY };
47
+ }
37
48
  if (e.touches.length === 2) {
38
49
  this.chartAreaPanHandler.deactivate();
39
50
  // @ts-ignore
@@ -47,6 +58,11 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
47
58
  * @returns {void}
48
59
  */
49
60
  handleTouchMoveEvent(e) {
61
+ const { clientX, clientY } = e.touches[0];
62
+ const { touchStart } = this.canvasTouchInfo;
63
+ if (e.touches.length === 1) {
64
+ this.canvasTouchInfo.isMoving = checkChartIsMoving(clientX, touchStart.x, clientY, touchStart.y);
65
+ }
50
66
  if (e.touches.length === 2) {
51
67
  this.pinchHandler(this.touchedCandleIndexes, this.getXPositions(e));
52
68
  }
@@ -56,6 +72,7 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
56
72
  * @returns {void}
57
73
  */
58
74
  handleTouchEndEvent(e) {
75
+ this.canvasTouchInfo.isMoving = false;
59
76
  // zero touches means the user stopped resizing completely (both fingers are up)
60
77
  if (e.touches.length === 0) {
61
78
  this.chartAreaPanHandler.activate();
@@ -95,3 +112,4 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
95
112
  this.scale.setXScale(first, last);
96
113
  }
97
114
  }
115
+ export const checkChartIsMoving = (x1, x2, y1, y2, pixelsToMove = PIXELS_FOR_MOVE) => Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) > pixelsToMove;
@@ -200,10 +200,8 @@ class CanvasInputListenerComponent extends ChartBaseElement {
200
200
  };
201
201
  this.addSubscription(subscribeListener(this.element, doubleTapListenerProducer, 'touchend'));
202
202
  // workaround to handle long touch start/end for iOS
203
- const longTouchListeners = (e, delay = 700, pixelsForMoveReset = 3) => {
203
+ const longTouchListeners = (e, delay = 200) => {
204
204
  e.preventDefault();
205
- const initialCoords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
206
- let coords = { x: 0, y: 0 };
207
205
  let longTouchStart = false;
208
206
  let timerLongTouchStart = null;
209
207
  // start timeout for long touch
@@ -213,11 +211,8 @@ class CanvasInputListenerComponent extends ChartBaseElement {
213
211
  }, delay);
214
212
  const touchMoveHandler = (e) => {
215
213
  e.preventDefault();
216
- coords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
217
214
  // clear long touch timeout if move area is bigger than pixelsForMove
218
- if (Math.sqrt(Math.pow(coords.x - initialCoords.x, 2) + Math.pow(coords.y - initialCoords.y, 2)) >
219
- pixelsForMoveReset ||
220
- e.touches.length > 1) {
215
+ if (e.touches.length > 1) {
221
216
  timerLongTouchStart && clearTimeout(timerLongTouchStart);
222
217
  }
223
218
  };
@@ -123,7 +123,7 @@ export class CandleSeriesModel extends DataSeriesModel {
123
123
  * @returns {HighLowWithIndex} - An object containing the high-low values along with their corresponding indexes.
124
124
  */
125
125
  recalculateZippedHighLow() {
126
- return (this.zippedHighLow = calculateCandlesHighLow(this.visualPoints.slice(this.dataIdxStart, this.dataIdxEnd)));
126
+ return (this.zippedHighLow = calculateCandlesHighLow(this.visualPoints.slice(this.dataIdxStart, this.dataIdxEnd + 1)));
127
127
  }
128
128
  /**
129
129
  * Updates the current price and the last price movement.
@@ -11,6 +11,7 @@ export declare const BASIC_CANDLE_WIDTH: Unit;
11
11
  * @doc-tags-name Candle
12
12
  */
13
13
  export interface Candle {
14
+ readonly id: string;
14
15
  readonly hi: number;
15
16
  readonly lo: number;
16
17
  readonly open: number;
@@ -22,6 +23,8 @@ export interface Candle {
22
23
  readonly impVolatility?: number;
23
24
  readonly vwap?: number;
24
25
  }
26
+ export declare const defaultSortCandles: (candles: Candle[]) => Candle[];
27
+ export declare const generateCandleId: (timestamp: number, hashValue: number | string) => string;
25
28
  /**
26
29
  * Provides the name of candle difference
27
30
  * @param {Number} open
@@ -3,9 +3,14 @@
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 { hashCode } from '../utils/string.utils';
6
7
  // Has no specific rule, just any number to use in units calculation.
7
8
  // 1 - because why not? Easy to debug.
8
9
  export const BASIC_CANDLE_WIDTH = 1;
10
+ export const defaultSortCandles = (candles) => candles.slice().sort((a, b) => (a.timestamp === b.timestamp ? 0 : a.timestamp > b.timestamp ? 1 : -1));
11
+ export const generateCandleId = (timestamp, hashValue) => {
12
+ return `${timestamp}_${hashCode(hashValue.toString())}`;
13
+ };
9
14
  /**
10
15
  * Provides the name of candle difference
11
16
  * @param {Number} open
@@ -45,7 +50,7 @@ export function hollowDirection(open, close) {
45
50
  * @returns {Candle} A new Candle object with the same properties as the base object, with the option to modify the prices.
46
51
  */
47
52
  export function copyCandle(base, idx, pricesAsClose = false) {
48
- const { expansion, impVolatility, vwap, volume, timestamp } = base;
53
+ const { id, expansion, impVolatility, vwap, volume, timestamp } = base;
49
54
  let hi = base.hi;
50
55
  let lo = base.lo;
51
56
  let open = base.open;
@@ -60,6 +65,7 @@ export function copyCandle(base, idx, pricesAsClose = false) {
60
65
  _idx = idx;
61
66
  }
62
67
  return {
68
+ id,
63
69
  hi,
64
70
  lo,
65
71
  open,
@@ -11,7 +11,7 @@ import { DataSeriesView } from './data-series-view';
11
11
  import { DataSeriesConfig, DataSeriesPaintConfig, DataSeriesType } from './data-series.config';
12
12
  import { HighLowWithIndex, ScaleModel } from './scale.model';
13
13
  import { HighLowProvider } from './scaling/auto-scale.model';
14
- import { Index, Unit, Viewable } from './scaling/viewport.model';
14
+ import { Index, Pixel, Unit, Viewable } from './scaling/viewport.model';
15
15
  /**
16
16
  * Properties are named in order to match VisualCandle interface
17
17
  */
@@ -22,11 +22,11 @@ export declare class VisualSeriesPoint {
22
22
  /**
23
23
  * returns y coordinate in pixels
24
24
  */
25
- y(viewable: Viewable): Unit;
25
+ y(viewable: Viewable): Pixel;
26
26
  /**
27
27
  * returns x coordinate in pixels
28
28
  */
29
- x(viewable: Viewable): Unit;
29
+ x(viewable: Viewable): Pixel;
30
30
  clone(): VisualSeriesPoint;
31
31
  }
32
32
  export interface DataSeriesPoint {
@@ -30,7 +30,7 @@ export class VisualSeriesPoint {
30
30
  * returns x coordinate in pixels
31
31
  */
32
32
  x(viewable) {
33
- return floorToDPR(viewable.toX(this.centerUnit));
33
+ return viewable.toX(this.centerUnit);
34
34
  }
35
35
  clone() {
36
36
  return new VisualSeriesPoint(this.centerUnit, this.close);
@@ -125,7 +125,7 @@ export class ScaleModel extends ViewportModel {
125
125
  }
126
126
  }
127
127
  zoomXTo(state, zoomIn, forceNoAnimation) {
128
- const initialStateCopy = Object.assign({}, state);
128
+ const initialStateCopy = this.export();
129
129
  const constrainedState = this.scalePostProcessor(initialStateCopy, state);
130
130
  this.zoomReached = this.calculateZoomReached(constrainedState.zoomX, zoomIn);
131
131
  if (this.zoomReached.zoomIn || this.zoomReached.zoomOut) {
@@ -3,7 +3,7 @@
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 { Subject } from 'rxjs';
6
+ import { BehaviorSubject, Subject } from 'rxjs';
7
7
  import { ChartBaseElement } from '../chart-base-element';
8
8
  import { ViewportMovementAnimation } from '../../animation/types/viewport-movement-animation';
9
9
  import { Bounds } from '../bounds.model';
@@ -92,6 +92,7 @@ export declare abstract class ViewportModel extends ChartBaseElement implements
92
92
  start: number;
93
93
  end: number;
94
94
  }>;
95
+ initialViewportValidSubject: BehaviorSubject<boolean>;
95
96
  protected doActivate(): void;
96
97
  protected doDeactivate(): void;
97
98
  /**
@@ -3,7 +3,7 @@
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 { Subject } from 'rxjs';
6
+ import { BehaviorSubject, Subject } from 'rxjs';
7
7
  import { distinctUntilChanged, map, share } from 'rxjs/operators';
8
8
  import { ChartBaseElement } from '../chart-base-element';
9
9
  import { keys } from '../../utils/object.utils';
@@ -50,10 +50,15 @@ export class ViewportModel extends ChartBaseElement {
50
50
  start: this.yStart,
51
51
  end: this.yEnd,
52
52
  })), distinctUntilChanged((p, c) => p.start === c.start && p.end === c.end), share());
53
+ this.initialViewportValidSubject = new BehaviorSubject(false);
53
54
  }
54
55
  //endregion
55
56
  doActivate() {
56
57
  super.doActivate();
58
+ this.addRxSubscription(this.changed.subscribe(() => {
59
+ !this.initialViewportValidSubject.getValue() &&
60
+ this.initialViewportValidSubject.next(this.isViewportValid());
61
+ }));
57
62
  }
58
63
  doDeactivate() {
59
64
  super.doDeactivate();
@@ -87,9 +87,7 @@ export class TimeZoneModel {
87
87
  // In JS Date object is created with local tz offset,
88
88
  // so we have to subtract localOffset from current time
89
89
  return time => {
90
- return new Date(time +
91
- getTimezoneOffset(timezone, time) +
92
- new Date(time).getTimezoneOffset() * timeMultiplier);
90
+ return new Date(time + getTimezoneOffset(timezone, time) + new Date(time).getTimezoneOffset() * timeMultiplier);
93
91
  };
94
92
  }
95
93
  }
@@ -32,6 +32,7 @@ export interface GenerateCandlesDataConfig {
32
32
  * @doc-tags tricky
33
33
  */
34
34
  export declare function generateCandlesDataTS(config?: GenerateCandlesDataConfig): {
35
+ id: string;
35
36
  hi: number;
36
37
  lo: number;
37
38
  open: any;
@@ -4,6 +4,7 @@
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
6
  export default function generateCandlesData(config: any): {
7
+ id: string;
7
8
  hi: number;
8
9
  lo: number;
9
10
  open: any;