@devexperts/dxcharts-lite 2.4.5 → 2.5.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.
Files changed (59) hide show
  1. package/dist/chart/__tests__/model/date-time.formatter.test.d.ts +6 -0
  2. package/dist/chart/__tests__/model/date-time.formatter.test.js +30 -0
  3. package/dist/chart/bootstrap.js +1 -1
  4. package/dist/chart/canvas/canvas-bounds-container.d.ts +7 -3
  5. package/dist/chart/canvas/canvas-bounds-container.js +149 -105
  6. package/dist/chart/canvas/y-axis-bounds.container.js +4 -0
  7. package/dist/chart/chart.config.d.ts +4 -10
  8. package/dist/chart/chart.config.js +4 -6
  9. package/dist/chart/components/chart/chart-area-pan.handler.d.ts +9 -6
  10. package/dist/chart/components/chart/chart-area-pan.handler.js +41 -38
  11. package/dist/chart/components/chart/chart.model.d.ts +0 -1
  12. package/dist/chart/components/chart/chart.model.js +0 -1
  13. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-x.component.d.ts +0 -6
  14. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-x.component.js +0 -8
  15. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-y.component.d.ts +0 -5
  16. package/dist/chart/components/dran-n-drop_helper/drag-n-drop-y.component.js +0 -7
  17. package/dist/chart/components/dran-n-drop_helper/drag-n-drop.component.d.ts +1 -12
  18. package/dist/chart/components/dran-n-drop_helper/drag-n-drop.component.js +19 -30
  19. package/dist/chart/components/dynamic-objects/dynamic-objects.model.d.ts +6 -3
  20. package/dist/chart/components/dynamic-objects/dynamic-objects.model.js +14 -3
  21. package/dist/chart/components/hit-test/hit-test.component.d.ts +3 -1
  22. package/dist/chart/components/hit-test/hit-test.component.js +6 -1
  23. package/dist/chart/components/pan/chart-pan.component.d.ts +4 -14
  24. package/dist/chart/components/pan/chart-pan.component.js +10 -21
  25. package/dist/chart/components/pane/extent/y-extent-component.d.ts +2 -0
  26. package/dist/chart/components/pane/pane-manager.component.d.ts +29 -0
  27. package/dist/chart/components/pane/pane-manager.component.js +71 -8
  28. package/dist/chart/components/pane/pane.component.d.ts +5 -17
  29. package/dist/chart/components/pane/pane.component.js +13 -29
  30. package/dist/chart/components/resizer/bar-resizer.component.d.ts +1 -1
  31. package/dist/chart/components/resizer/bar-resizer.component.js +8 -5
  32. package/dist/chart/components/x_axis/x-axis-scale.handler.js +1 -1
  33. package/dist/chart/components/y_axis/price_labels/y-axis-labels.model.d.ts +1 -3
  34. package/dist/chart/components/y_axis/price_labels/y-axis-labels.model.js +1 -3
  35. package/dist/chart/components/y_axis/y-axis-scale.handler.js +6 -8
  36. package/dist/chart/components/y_axis/y-axis.component.d.ts +1 -1
  37. package/dist/chart/components/y_axis/y-axis.component.js +7 -4
  38. package/dist/chart/inputhandlers/hover-producer.component.d.ts +1 -1
  39. package/dist/chart/inputhandlers/main-canvas-touch.handler.d.ts +11 -7
  40. package/dist/chart/inputhandlers/main-canvas-touch.handler.js +34 -7
  41. package/dist/chart/inputlisteners/canvas-input-listener.component.d.ts +0 -14
  42. package/dist/chart/inputlisteners/canvas-input-listener.component.js +1 -35
  43. package/dist/chart/model/baseline.model.d.ts +3 -0
  44. package/dist/chart/model/baseline.model.js +5 -0
  45. package/dist/chart/model/candle-series.model.d.ts +10 -1
  46. package/dist/chart/model/candle-series.model.js +20 -2
  47. package/dist/chart/model/chart-base-element.d.ts +2 -0
  48. package/dist/chart/model/chart-base-element.js +2 -0
  49. package/dist/chart/model/data-series.model.js +5 -3
  50. package/dist/chart/model/date-time.formatter.d.ts +20 -3
  51. package/dist/chart/model/date-time.formatter.js +62 -14
  52. package/dist/chart/model/scale.model.d.ts +5 -0
  53. package/dist/chart/model/scale.model.js +9 -1
  54. package/dist/chart/model/scaling/constrait.functions.d.ts +5 -7
  55. package/dist/chart/model/scaling/constrait.functions.js +3 -3
  56. package/dist/chart/model/time-zone.model.js +3 -1
  57. package/dist/chart/utils/timezone.utils.js +3 -3
  58. package/dist/dxchart.min.js +4 -4
  59. package/package.json +1 -1
@@ -0,0 +1,6 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2024 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ import '../env';
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2024 Devexperts Solutions IE Limited
3
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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
+ */
6
+ import '../env';
7
+ import { formatDate, getShortDays, getShortMonths } from '../../model/date-time.formatter';
8
+ import { getDefaultConfig } from '../../chart.config';
9
+ import { getTimezoneOffset } from '../../utils/timezone.utils';
10
+ describe('Date time formatter', () => {
11
+ const config = getDefaultConfig();
12
+ const days = getShortDays(config);
13
+ const months = getShortMonths(config);
14
+ const timestamp = 1710501810500;
15
+ const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
16
+ const utcTimestamp = timestamp - getTimezoneOffset(tz, timestamp);
17
+ const utcDate = new Date(utcTimestamp); // 03/15/2024 @ 11:23am UTC
18
+ describe('Timezones', () => {
19
+ it('should always be UTC', () => {
20
+ expect(getTimezoneOffset('UTC', utcTimestamp)).toBe(0);
21
+ });
22
+ });
23
+ describe('Formatter', () => {
24
+ it('should return formatted value according to given pattern', () => {
25
+ expect(formatDate(utcDate, 'YYYY', days, months)).toEqual('2024');
26
+ expect(formatDate(utcDate, 'HH:mm:ss', days, months)).toEqual('11:23:30');
27
+ expect(formatDate(utcDate, 'dd.MM.YYYY', days, months)).toEqual('15.03.2024');
28
+ });
29
+ });
30
+ });
@@ -127,7 +127,7 @@ export default class ChartBootstrap {
127
127
  this.chartPanComponent = chartPanComponent;
128
128
  this.chartComponents.push(chartPanComponent);
129
129
  this.userInputListenerComponents.push(chartPanComponent.chartAreaPanHandler);
130
- const hitTestComponent = new HitTestComponent(hitTestCanvasModel, canvasAnimation);
130
+ const hitTestComponent = new HitTestComponent(hitTestCanvasModel, canvasAnimation, eventBus);
131
131
  this.hitTestComponent = hitTestComponent;
132
132
  this.chartComponents.push(hitTestComponent);
133
133
  const paneManager = new PaneManager(chartBaseModel, this.dynamicObjectsCanvasModel, this.userInputListenerComponents, eventBus, scaleModel, canvasBoundsContainer, config, canvasAnimation, canvasInputListener, drawingManager, this.cursorHandler, this.crossEventProducer, chartPanComponent, mainCanvasModel, yAxisLabelsCanvasModel, this.hitTestCanvasModel);
@@ -44,6 +44,7 @@ export declare class CanvasElement {
44
44
  static Y_AXIS: string;
45
45
  }
46
46
  export declare const DEFAULT_BOUNDS: Bounds;
47
+ export declare const DEFAULT_MIN_PANE_HEIGHT = 20;
47
48
  /**
48
49
  * This component listens EVENT_DRAW and recalculates bounds of canvas chart elements.
49
50
  * {@link getBounds} method will always give actual placement of element you want.
@@ -61,6 +62,7 @@ export declare class CanvasBoundsContainer {
61
62
  canvasOnPageLocation: Bounds;
62
63
  panesOrder: Array<string>;
63
64
  panesOrderChangedSubject: Subject<string[]>;
65
+ paneVisibilityChangedSubject: Subject<void>;
64
66
  xAxisHeight: number | undefined;
65
67
  yAxisWidths: YAxisWidths;
66
68
  leftRatio: number;
@@ -85,8 +87,7 @@ export declare class CanvasBoundsContainer {
85
87
  * @param {Record<string, number>} heightRatios - An object containing the height ratios to be set.
86
88
  * @returns {void}
87
89
  * @throws {Error} If the sum of the height ratios is not equal to 1.
88
-
89
- */
90
+ */
90
91
  overrideChartHeightRatios(heightRatios: Record<string, number>): void;
91
92
  /**
92
93
  * Moves a pane up in the panesOrder array.
@@ -109,12 +110,14 @@ export declare class CanvasBoundsContainer {
109
110
  * result: ['3', '2', '1']
110
111
  */
111
112
  reorderPanes(newPanesOrder: string[]): void;
113
+ hidePaneBounds(uuid: string): void;
114
+ showPaneBounds(uuid: string): void;
112
115
  /**
113
116
  * Removes the bounds of a pane with the given uuid from the canvas element.
114
117
  * @param {string} uuid - The uuid of the pane to remove.
115
118
  * @returns {void}
116
119
  */
117
- removedPaneBounds(uuid: string): void;
120
+ removePaneBounds(uuid: string): void;
118
121
  /**
119
122
  * Recalculates the bounds of the chart elements based on the current configuration and canvas size.
120
123
  * The function updates the bounds of the canvas, the main chart, the panes, the y-axis, and the chart with y-axis.
@@ -326,6 +329,7 @@ export declare class CanvasBoundsContainer {
326
329
  */
327
330
  setMainCandleSeries(candleSeries: CandleSeriesModel): void;
328
331
  }
332
+ export declare const getHeightRatios: (pecLength: number) => [number, number];
329
333
  export declare const isInBounds: (point: Point, bounds: Bounds) => boolean;
330
334
  export declare const isInVerticalBounds: (y: number, bounds: Bounds) => boolean;
331
335
  export declare const limitYToBounds: (y: Pixel, bounds: Bounds) => number;
@@ -40,7 +40,7 @@ CanvasElement.CHART = CanvasElement.PANE_UUID(CHART_UUID);
40
40
  CanvasElement.Y_AXIS = CanvasElement.PANE_UUID_Y_AXIS(CHART_UUID);
41
41
  export { CanvasElement };
42
42
  export const DEFAULT_BOUNDS = { x: 0, y: 0, pageX: 0, pageY: 0, width: 0, height: 0 };
43
- const DEFAULT_MIN_PANE_HEIGHT = 20;
43
+ export const DEFAULT_MIN_PANE_HEIGHT = 20;
44
44
  const N_MAP_H = 35;
45
45
  const N_MAP_BUTTON_W = 15;
46
46
  const KNOTS_W_MOBILE_MULTIPLIER = 1.5;
@@ -72,6 +72,7 @@ export class CanvasBoundsContainer {
72
72
  // holds ordered "top to bottom" array of panes UUID's (studies in past)
73
73
  this.panesOrder = [];
74
74
  this.panesOrderChangedSubject = new Subject();
75
+ this.paneVisibilityChangedSubject = new Subject();
75
76
  // both will be calculated based on font/content size
76
77
  this.xAxisHeight = undefined;
77
78
  this.yAxisWidths = {
@@ -120,8 +121,7 @@ export class CanvasBoundsContainer {
120
121
  * @param {Record<string, number>} heightRatios - An object containing the height ratios to be set.
121
122
  * @returns {void}
122
123
  * @throws {Error} If the sum of the height ratios is not equal to 1.
123
-
124
- */
124
+ */
125
125
  overrideChartHeightRatios(heightRatios) {
126
126
  const resultRatio = Object.assign(Object.assign({}, this.graphsHeightRatio), heightRatios);
127
127
  const ratioSum = Object.values(resultRatio).reduce((sum, ratio) => sum + ratio, 0);
@@ -174,12 +174,33 @@ export class CanvasBoundsContainer {
174
174
  this.recalculateBounds();
175
175
  this.panesOrderChangedSubject.next(this.panesOrder);
176
176
  }
177
+ hidePaneBounds(uuid) {
178
+ this.graphsHeightRatio[uuid] = 0;
179
+ this.recalculatePanesHeightRatios();
180
+ this.paneVisibilityChangedSubject.next();
181
+ }
182
+ showPaneBounds(uuid) {
183
+ if (uuid === CHART_UUID) {
184
+ const [defaultChartHeightRatio] = getHeightRatios(this.panesOrder.length - 1);
185
+ this.graphsHeightRatio[uuid] = defaultChartHeightRatio;
186
+ }
187
+ else {
188
+ // when pane is hidden it has ratio of 0
189
+ // when we want pane to be visible again we want `recalculatePanesHeightRatios` function
190
+ // to treat it as a new pane
191
+ // to do so we need to delete its ratio (which is 0 because it is hidden) from graphsHeightRatio
192
+ // NOTE: CHART_UUID pane is exception, it is treated differently and should always have some ratio
193
+ delete this.graphsHeightRatio[uuid];
194
+ }
195
+ this.recalculatePanesHeightRatios();
196
+ this.paneVisibilityChangedSubject.next();
197
+ }
177
198
  /**
178
199
  * Removes the bounds of a pane with the given uuid from the canvas element.
179
200
  * @param {string} uuid - The uuid of the pane to remove.
180
201
  * @returns {void}
181
202
  */
182
- removedPaneBounds(uuid) {
203
+ removePaneBounds(uuid) {
183
204
  arrayRemove2(this.panesOrder, uuid);
184
205
  delete this.graphsHeightRatio[uuid];
185
206
  delete this.bounds[CanvasElement.PANE_UUID(uuid)];
@@ -223,13 +244,14 @@ export class CanvasBoundsContainer {
223
244
  const chartWidth = canvas.width - totalYAxisWidthLeft - totalYAxisWidthRight;
224
245
  let nextY = initialY;
225
246
  // panes
247
+ const firstVisiblePaneIdx = this.panesOrder.findIndex(uuid => this.graphsHeightRatio[uuid] > 0);
226
248
  this.panesOrder.forEach((uuid, index) => {
227
249
  var _a;
228
250
  const paneHeightRatio = this.graphsHeightRatio[this.panesOrder[index]];
229
- // hide resizer for first pane with index === 0
230
- const resizerVisible = this.config.components.paneResizer.visible && index !== 0;
251
+ // hide resizer for the first visible pane
231
252
  const resizerUUID = CanvasElement.PANE_UUID_RESIZER(uuid);
232
253
  const paneUUID = CanvasElement.PANE_UUID(uuid);
254
+ const resizerVisible = this.config.components.paneResizer.visible && index > firstVisiblePaneIdx && paneHeightRatio > 0;
233
255
  if (resizerVisible) {
234
256
  upsertBounds(this.bounds, resizerUUID, 0, nextY, canvas.width, paneResizerHeight, this.canvasOnPageLocation);
235
257
  }
@@ -237,7 +259,7 @@ export class CanvasBoundsContainer {
237
259
  upsertBounds(this.bounds, resizerUUID, 0, 0, 0, 0, this.canvasOnPageLocation);
238
260
  }
239
261
  const paneYStart = nextY + (resizerVisible ? paneResizerHeight : 0);
240
- const paneBounds = upsertBounds(this.bounds, paneUUID, paneXStart, paneYStart, chartWidth, chartHeight * paneHeightRatio - (resizerVisible ? this.config.components.paneResizer.height : 0), this.canvasOnPageLocation);
262
+ const paneBounds = upsertBounds(this.bounds, paneUUID, paneXStart, paneYStart, chartWidth, chartHeight * paneHeightRatio - (resizerVisible ? paneResizerHeight : 0), this.canvasOnPageLocation);
241
263
  // y axis
242
264
  if (this.config.components.yAxis.visible) {
243
265
  const extents = this.yAxisBoundsContainer.extentsOrder.get(uuid);
@@ -425,34 +447,46 @@ export class CanvasBoundsContainer {
425
447
  // NOTE: pec stands for panesExceptMainChart
426
448
  const pec = [];
427
449
  pec.push(...this.panesOrder.filter(p => p !== CHART_UUID));
428
- this.panesOrder.forEach(pane => {
429
- if (this.graphsHeightRatio[pane] === 0) {
430
- delete this.graphsHeightRatio[pane];
431
- }
432
- });
433
- const pecRatios = pec.map(graph => this.graphsHeightRatio[graph] === undefined ? undefined : this.graphsHeightRatio[graph]);
434
- const oldPecNumber = pecRatios.filter(ratio => ratio !== undefined).length;
450
+ const pecRatios = pec.map(uuid => this.graphsHeightRatio[uuid] === undefined ? undefined : this.graphsHeightRatio[uuid]);
451
+ // we should count only visible panes, to escape wheight distribution for hidden panes
452
+ const visiblePecRatios = pecRatios.filter(ratio => ratio !== 0);
453
+ const visiblePecNumber = visiblePecRatios.length;
454
+ // we don't count as an old PEC panes that are not visible, because they don't whey in the final result
455
+ const oldPecNumber = visiblePecRatios.filter(ratio => ratio !== undefined).length;
456
+ // if ratio in undefined for a given pane it means that it's a new pane
435
457
  const newPecNumber = pecRatios.filter(ratio => ratio === undefined).length;
436
458
  let freeRatioForPec = 0;
437
459
  let freeRatio = 0;
438
460
  let ratioForOldPec = 1;
439
461
  let ratioForNewPec = 0;
440
462
  if (newPecNumber > 0) {
441
- [ratioForOldPec, ratioForNewPec] = getHeightRatios(pec.length);
463
+ [ratioForOldPec, ratioForNewPec] = getHeightRatios(visiblePecNumber);
442
464
  chartRatio *= ratioForOldPec;
443
465
  }
466
+ // this means we should keep in mind only new panes
444
467
  if (oldPecNumber === 0) {
445
468
  chartRatio = 1 - ratioForNewPec * newPecNumber;
446
469
  }
447
470
  freeRatio = 1 - chartRatio - ratioForNewPec * newPecNumber;
448
- pecRatios.forEach(ratio => {
471
+ visiblePecRatios.forEach(ratio => {
449
472
  if (ratio) {
450
473
  freeRatio -= ratio * ratioForOldPec;
451
474
  }
452
475
  });
453
- freeRatioForPec = freeRatio / (pec.length + 1);
454
- const proportions = pecRatios.map(ratio => ratio ? ratio * ratioForOldPec + freeRatioForPec : ratioForNewPec + freeRatioForPec);
455
- chartRatio += freeRatioForPec;
476
+ // || 1 to escape division by zero
477
+ // because there's might be no visible panes except CHART
478
+ freeRatioForPec = freeRatio / (visiblePecNumber || 1);
479
+ // distribute left free ratio between new and old panes
480
+ const proportions = pecRatios.map(ratio => {
481
+ // if ratio === 0 it means, that it's hidden
482
+ if (ratio === 0) {
483
+ return ratio;
484
+ }
485
+ if (!ratio) {
486
+ return ratioForNewPec + freeRatioForPec;
487
+ }
488
+ return ratio * ratioForOldPec + freeRatioForPec;
489
+ });
456
490
  this._graphsHeightRatio = {};
457
491
  this.graphsHeightRatio[CHART_UUID] = chartRatio;
458
492
  proportions.forEach((ratio, index) => {
@@ -478,88 +512,89 @@ export class CanvasBoundsContainer {
478
512
  */
479
513
  recalculateNavigationMapElementBounds() {
480
514
  var _a, _b, _c, _d;
481
- if (this.config.components.navigationMap.visible) {
482
- const nMap = this.getBounds(CanvasElement.N_MAP);
483
- const { height, width } = this.config.components.navigationMap.knots;
484
- const knotHeightFromConfig = height !== null && height !== void 0 ? height : 0;
485
- const knotWidthFromConfig = isMobile() ? width * KNOTS_W_MOBILE_MULTIPLIER : width !== null && width !== void 0 ? width : 0;
486
- const knotY = !knotHeightFromConfig ? nMap.y : nMap.y + (nMap.height - knotHeightFromConfig) / 2;
487
- // time labels
488
- const timeLabelsVisible = (_b = (_a = this.config.components.navigationMap) === null || _a === void 0 ? void 0 : _a.timeLabels) === null || _b === void 0 ? void 0 : _b.visible;
489
- const calcLabelBounds = (timestamp) => {
490
- return calcTimeLabelBounds(this.canvasModel.ctx, timestamp, this.formatterFactory, this.config)[0];
491
- };
492
- const candleSource = flat((_d = (_c = this.mainCandleSeries) === null || _c === void 0 ? void 0 : _c.getSeriesInViewport()) !== null && _d !== void 0 ? _d : []);
493
- const leftTimeLabelWidth = timeLabelsVisible && candleSource.length ? calcLabelBounds(candleSource[0].candle.timestamp) : 0;
494
- const rightTimeLabelWidth = timeLabelsVisible && candleSource.length
495
- ? calcLabelBounds(candleSource[candleSource.length - 1].candle.timestamp)
496
- : 0;
497
- const timeLabelWidth = Math.max(leftTimeLabelWidth, rightTimeLabelWidth);
498
- if (timeLabelsVisible) {
499
- const nMapLabelL = this.getBounds(CanvasElement.N_MAP_LABEL_L);
500
- nMapLabelL.x = nMap.x;
501
- nMapLabelL.y = nMap.y;
502
- nMapLabelL.width = timeLabelWidth;
503
- nMapLabelL.height = nMap.height;
504
- const nMapLabelR = this.getBounds(CanvasElement.N_MAP_LABEL_R);
505
- nMapLabelR.x = nMap.x + nMap.width - timeLabelWidth;
506
- nMapLabelR.y = nMap.y;
507
- nMapLabelR.width = timeLabelWidth;
508
- nMapLabelR.height = nMap.height;
509
- }
510
- // buttons left and right
511
- const nMapBtnL = this.getBounds(CanvasElement.N_MAP_BTN_L);
512
- nMapBtnL.x = nMap.x + timeLabelWidth;
513
- nMapBtnL.y = nMap.y;
514
- nMapBtnL.width = N_MAP_BUTTON_W;
515
- nMapBtnL.height = nMap.height;
516
- const nMapBtnR = this.getBounds(CanvasElement.N_MAP_BTN_R);
517
- nMapBtnR.x = nMap.x + nMap.width - N_MAP_BUTTON_W - timeLabelWidth;
518
- nMapBtnR.y = nMap.y;
519
- nMapBtnR.width = N_MAP_BUTTON_W;
520
- nMapBtnR.height = nMap.height;
521
- // knots
522
- const navMapChartStart = nMapBtnL.x + nMapBtnL.width;
523
- const navMapChartWidth = nMapBtnR.x - navMapChartStart;
524
- const navMapChartEnd = navMapChartStart + navMapChartWidth;
525
- const minSliderW = this.config.components.navigationMap.minSliderWindowWidth;
526
- const knotW = knotWidthFromConfig !== null && knotWidthFromConfig !== void 0 ? knotWidthFromConfig : N_MAP_KNOT_W;
527
- const knotH = knotHeightFromConfig !== null && knotHeightFromConfig !== void 0 ? knotHeightFromConfig : nMap.height;
528
- const minDistanceBetweenKnotsX = knotW + minSliderW;
529
- // Left drag button
530
- const knotL = this.getBounds(CanvasElement.N_MAP_KNOT_L);
531
- knotL.x = navMapChartStart + navMapChartWidth * this.leftRatio;
532
- // limit left knot to min distance from right border
533
- knotL.x = Math.min(knotL.x, navMapChartEnd - minDistanceBetweenKnotsX);
534
- knotL.y = knotY;
535
- knotL.width = knotW;
536
- knotL.height = knotH;
537
- // Right drag button
538
- const knotR = this.getBounds(CanvasElement.N_MAP_KNOT_R);
539
- knotR.x = navMapChartStart + navMapChartWidth * this.rightRatio - N_MAP_KNOT_W;
540
- // limit right knot to min distance from left border
541
- knotR.x = Math.max(knotR.x, navMapChartStart + minDistanceBetweenKnotsX);
542
- knotR.y = knotY;
543
- knotR.width = knotW;
544
- knotR.height = knotH;
545
- const distanceDiff = minDistanceBetweenKnotsX - (knotR.x - knotL.x);
546
- // if distance between knots is less than min distance - move left knot start
547
- if (distanceDiff > 0) {
548
- knotL.x -= distanceDiff;
549
- }
550
- // slider
551
- const slider = this.getBounds(CanvasElement.N_MAP_SLIDER_WINDOW);
552
- slider.x = knotL.x + knotL.width;
553
- slider.y = nMap.y;
554
- slider.width = knotR.x - slider.x;
555
- slider.height = nMap.height;
556
- // chart
557
- const nMapChart = this.getBounds(CanvasElement.N_MAP_CHART);
558
- nMapChart.x = navMapChartStart;
559
- nMapChart.y = nMap.y;
560
- nMapChart.width = navMapChartWidth;
561
- nMapChart.height = nMap.height;
515
+ if (!this.config.components.navigationMap.visible) {
516
+ return;
517
+ }
518
+ const nMap = this.getBounds(CanvasElement.N_MAP);
519
+ const { height, width } = this.config.components.navigationMap.knots;
520
+ const knotHeightFromConfig = height !== null && height !== void 0 ? height : 0;
521
+ const knotWidthFromConfig = isMobile() ? width * KNOTS_W_MOBILE_MULTIPLIER : width !== null && width !== void 0 ? width : 0;
522
+ const knotY = !knotHeightFromConfig ? nMap.y : nMap.y + (nMap.height - knotHeightFromConfig) / 2;
523
+ // time labels
524
+ const timeLabelsVisible = (_b = (_a = this.config.components.navigationMap) === null || _a === void 0 ? void 0 : _a.timeLabels) === null || _b === void 0 ? void 0 : _b.visible;
525
+ const calcLabelBounds = (timestamp) => {
526
+ return calcTimeLabelBounds(this.canvasModel.ctx, timestamp, this.formatterFactory, this.config)[0];
527
+ };
528
+ const candleSource = flat((_d = (_c = this.mainCandleSeries) === null || _c === void 0 ? void 0 : _c.getSeriesInViewport()) !== null && _d !== void 0 ? _d : []);
529
+ const leftTimeLabelWidth = timeLabelsVisible && candleSource.length ? calcLabelBounds(candleSource[0].candle.timestamp) : 0;
530
+ const rightTimeLabelWidth = timeLabelsVisible && candleSource.length
531
+ ? calcLabelBounds(candleSource[candleSource.length - 1].candle.timestamp)
532
+ : 0;
533
+ const timeLabelWidth = Math.max(leftTimeLabelWidth, rightTimeLabelWidth);
534
+ if (timeLabelsVisible) {
535
+ const nMapLabelL = this.getBounds(CanvasElement.N_MAP_LABEL_L);
536
+ nMapLabelL.x = nMap.x;
537
+ nMapLabelL.y = nMap.y;
538
+ nMapLabelL.width = timeLabelWidth;
539
+ nMapLabelL.height = nMap.height;
540
+ const nMapLabelR = this.getBounds(CanvasElement.N_MAP_LABEL_R);
541
+ nMapLabelR.x = nMap.x + nMap.width - timeLabelWidth;
542
+ nMapLabelR.y = nMap.y;
543
+ nMapLabelR.width = timeLabelWidth;
544
+ nMapLabelR.height = nMap.height;
545
+ }
546
+ // buttons left and right
547
+ const nMapBtnL = this.getBounds(CanvasElement.N_MAP_BTN_L);
548
+ nMapBtnL.x = nMap.x + timeLabelWidth;
549
+ nMapBtnL.y = nMap.y;
550
+ nMapBtnL.width = N_MAP_BUTTON_W;
551
+ nMapBtnL.height = nMap.height;
552
+ const nMapBtnR = this.getBounds(CanvasElement.N_MAP_BTN_R);
553
+ nMapBtnR.x = nMap.x + nMap.width - N_MAP_BUTTON_W - timeLabelWidth;
554
+ nMapBtnR.y = nMap.y;
555
+ nMapBtnR.width = N_MAP_BUTTON_W;
556
+ nMapBtnR.height = nMap.height;
557
+ // knots
558
+ const navMapChartStart = nMapBtnL.x + nMapBtnL.width;
559
+ const navMapChartWidth = nMapBtnR.x - navMapChartStart;
560
+ const navMapChartEnd = navMapChartStart + navMapChartWidth;
561
+ const minSliderW = this.config.components.navigationMap.minSliderWindowWidth;
562
+ const knotW = knotWidthFromConfig !== null && knotWidthFromConfig !== void 0 ? knotWidthFromConfig : N_MAP_KNOT_W;
563
+ const knotH = knotHeightFromConfig !== null && knotHeightFromConfig !== void 0 ? knotHeightFromConfig : nMap.height;
564
+ const minDistanceBetweenKnotsX = knotW + minSliderW;
565
+ // Left drag button
566
+ const knotL = this.getBounds(CanvasElement.N_MAP_KNOT_L);
567
+ knotL.x = navMapChartStart + navMapChartWidth * this.leftRatio;
568
+ // limit left knot to min distance from right border
569
+ knotL.x = Math.min(knotL.x, navMapChartEnd - minDistanceBetweenKnotsX);
570
+ knotL.y = knotY;
571
+ knotL.width = knotW;
572
+ knotL.height = knotH;
573
+ // Right drag button
574
+ const knotR = this.getBounds(CanvasElement.N_MAP_KNOT_R);
575
+ knotR.x = navMapChartStart + navMapChartWidth * this.rightRatio - N_MAP_KNOT_W;
576
+ // limit right knot to min distance from left border
577
+ knotR.x = Math.max(knotR.x, navMapChartStart + minDistanceBetweenKnotsX);
578
+ knotR.y = knotY;
579
+ knotR.width = knotW;
580
+ knotR.height = knotH;
581
+ const distanceDiff = minDistanceBetweenKnotsX - (knotR.x - knotL.x);
582
+ // if distance between knots is less than min distance - move left knot start
583
+ if (distanceDiff > 0) {
584
+ knotL.x -= distanceDiff;
562
585
  }
586
+ // slider
587
+ const slider = this.getBounds(CanvasElement.N_MAP_SLIDER_WINDOW);
588
+ slider.x = knotL.x + knotL.width;
589
+ slider.y = nMap.y;
590
+ slider.width = knotR.x - slider.x;
591
+ slider.height = nMap.height;
592
+ // chart
593
+ const nMapChart = this.getBounds(CanvasElement.N_MAP_CHART);
594
+ nMapChart.x = navMapChartStart;
595
+ nMapChart.y = nMap.y;
596
+ nMapChart.width = navMapChartWidth;
597
+ nMapChart.height = nMap.height;
563
598
  }
564
599
  /**
565
600
  * Checks if the volumes are set to be visible and if they should be shown in a separate pane
@@ -683,11 +718,20 @@ export class CanvasBoundsContainer {
683
718
  * @returns {void}
684
719
  */
685
720
  doResizePaneVertically(idx, yDeltaPixels) {
686
- const prevPaneIdx = idx - 1;
721
+ // get prev visible pane index
722
+ let prevVisiblePaneIdx = idx - 1;
723
+ const prevPaneUUID = this.panesOrder[prevVisiblePaneIdx];
724
+ if (this._graphsHeightRatio[prevPaneUUID] <= 0) {
725
+ for (let i = 0; i < idx; i++) {
726
+ if (this._graphsHeightRatio[this.panesOrder[i]] > 0) {
727
+ prevVisiblePaneIdx = i;
728
+ }
729
+ }
730
+ }
687
731
  const allPanesHeight = this.getBounds(CanvasElement.ALL_PANES).height;
688
- const minAllowedPaneHeight = this.config.components.paneResizer.height + DEFAULT_MIN_PANE_HEIGHT;
732
+ const minAllowedPaneHeight = DEFAULT_MIN_PANE_HEIGHT;
689
733
  const resultPaneHeight = allPanesHeight * this.graphsHeightRatio[this.panesOrder[idx]];
690
- const dependResultPaneHeight = allPanesHeight * this.graphsHeightRatio[this.panesOrder[prevPaneIdx]];
734
+ const dependResultPaneHeight = allPanesHeight * this.graphsHeightRatio[this.panesOrder[prevVisiblePaneIdx]];
691
735
  // check if changes fit allowed minimal pane height
692
736
  const fitPane = resultPaneHeight + yDeltaPixels > minAllowedPaneHeight;
693
737
  const fitDependPane = dependResultPaneHeight - yDeltaPixels > minAllowedPaneHeight;
@@ -695,7 +739,7 @@ export class CanvasBoundsContainer {
695
739
  // convert pixels to percent
696
740
  const yDeltaPercent = yDeltaPixels / allPanesHeight;
697
741
  this.graphsHeightRatio[this.panesOrder[idx]] += yDeltaPercent;
698
- this.graphsHeightRatio[this.panesOrder[prevPaneIdx]] -= yDeltaPercent;
742
+ this.graphsHeightRatio[this.panesOrder[prevVisiblePaneIdx]] -= yDeltaPercent;
699
743
  this.recalculateBounds();
700
744
  }
701
745
  }
@@ -791,7 +835,7 @@ const DEFAULT_RATIOS = {
791
835
  5: 0.2,
792
836
  };
793
837
  // NOTE: pec stands for panes except main chart
794
- const getHeightRatios = (pecLength) => {
838
+ export const getHeightRatios = (pecLength) => {
795
839
  var _a;
796
840
  const chartHeightRatio = (_a = DEFAULT_RATIOS[pecLength]) !== null && _a !== void 0 ? _a : 0.4;
797
841
  const singlePecHeightRatio = (1 - chartHeightRatio) / pecLength;
@@ -50,6 +50,10 @@ export class YAxisBoundsContainer {
50
50
  this.yAxisWidthContributors.forEach(c => {
51
51
  var _a, _b, _c;
52
52
  const state = c.getYAxisState();
53
+ // if YAxis is not visible, do not add it to contributors width
54
+ if (!state.visible) {
55
+ return;
56
+ }
53
57
  const margin = state.labelBoxMargin.start + state.labelBoxMargin.end;
54
58
  const width = this.getTextWidth(c.getLargestLabel()) + margin;
55
59
  const idx = c.getYAxisIndex();
@@ -237,18 +237,12 @@ export interface ChartScale {
237
237
  /**
238
238
  * Value is related to zoom event (zooming chart via mouse wheel)
239
239
  * 0..1 ratio of full viewport; 0.5 = middle, 0.75 = 3/4 of viewport
240
+ * This value is also related to touchpad.
241
+ * Touchpad sensitivity is dynamic, and based on delta distance event:
242
+ * - if distance is small, zoom sencitivity is minimal, which allows you to zoom in/out on the chart and view each candle in details
243
+ * - if distance is big, zoom sencitivity is becomes close to the config value below, which allows you to zoom in/out on the chart and quickly change zoom with big sensitivity
240
244
  */
241
245
  wheel: number;
242
- /**
243
- * Value is related to pinch touchpad event (zooming chart via touchpad)
244
- * 0..1 ratio of full viewport; 0.5 = middle, 0.75 = 3/4 of viewport
245
- */
246
- pinch: number;
247
- /**
248
- * Value is related to glide touchpad event (scrolling chart via touchpad)
249
- * 0..1 ratio of full viewport; 0.5 = middle, 0.75 = 3/4 of viewport
250
- */
251
- glide: number;
252
246
  };
253
247
  /**
254
248
  * Defines how much items (candles) will be in viewport when chart applies basic scale
@@ -43,8 +43,6 @@ export const getDefaultConfig = () => ({
43
43
  inverse: false,
44
44
  zoomSensitivity: {
45
45
  wheel: 0.25,
46
- pinch: 0.05,
47
- glide: 0.05,
48
46
  },
49
47
  defaultViewportItems: 100,
50
48
  disableAnimations: false,
@@ -211,20 +209,20 @@ export const getDefaultConfig = () => ({
211
209
  {
212
210
  format: 'dd.MM.YYYY',
213
211
  showWhen: {
214
- periodMoreThen: 84600000,
212
+ periodMoreThen: 24 * 60 * 60 * 1000,
215
213
  },
216
214
  },
217
215
  {
218
216
  format: 'dd.MM.YYYY HH:mm',
219
217
  showWhen: {
220
- periodLessThen: 84600000,
221
- periodMoreThen: 6000,
218
+ periodLessThen: 24 * 60 * 60 * 1000,
219
+ periodMoreThen: 6 * 1000,
222
220
  },
223
221
  },
224
222
  {
225
223
  format: 'dd.MM.YYYY HH:mm:ss',
226
224
  showWhen: {
227
- periodLessThen: 6000,
225
+ periodLessThen: 6 * 1000,
228
226
  },
229
227
  },
230
228
  ],
@@ -17,10 +17,13 @@ export interface ChartWheelEvent {
17
17
  readonly originalEvent: WheelEvent;
18
18
  readonly candleIdx: number;
19
19
  }
20
+ interface ChartPanningOptions {
21
+ horizontal: boolean;
22
+ vertical: boolean;
23
+ }
20
24
  /**
21
25
  * ChartAreaPanHandler is a class that handles the panning and zooming of the chart area.
22
26
  * It extends the ChartBaseElement class and has the following properties:
23
- * @property {MainCanvasTouchHandler} touchHandler - An instance of the MainCanvasTouchHandler class.
24
27
  * @property {Point} currentPoint - An object that represents the current point of the chart area.
25
28
  * @property {number} xDraggedCandlesDelta - A number that represents the number of candles delta changed during X dragging.
26
29
  * @property {number} lastXStart - A number that represents the last X start position.
@@ -30,7 +33,6 @@ export interface ChartWheelEvent {
30
33
  * @param {EventBus} bus - An instance of the EventBus class.
31
34
  * @param {FullChartConfig} config - An instance of the FullChartConfig class.
32
35
  * @param {ScaleModel} scaleModel - An instance of the ScaleModel class.
33
- * @param {Element} mainCanvasParent - The parent element of the main canvas.
34
36
  * @param {CanvasInputListenerComponent} canvasInputListener - An instance of the CanvasInputListenerComponent class.
35
37
  * @param {CanvasBoundsContainer} canvasBoundsContainer - An instance of the CanvasBoundsContainer class.
36
38
  * @param {CanvasAnimation} canvasAnimation - An instance of the CanvasAnimation class.
@@ -41,18 +43,17 @@ export declare class ChartAreaPanHandler extends ChartBaseElement {
41
43
  private bus;
42
44
  private config;
43
45
  private scale;
44
- private mainCanvasParent;
45
46
  private canvasInputListener;
46
47
  private canvasBoundsContainer;
47
48
  private canvasAnimation;
48
49
  private chartPanComponent;
49
50
  private hitTestCanvasModel;
50
- private readonly touchHandler;
51
51
  private currentPoint;
52
52
  xDraggedCandlesDelta: number;
53
53
  lastXStart: number;
54
- wheelTrottleTime: number;
55
- constructor(bus: EventBus, config: FullChartConfig, scale: ScaleModel, mainCanvasParent: Element, canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer, canvasAnimation: CanvasAnimation, chartPanComponent: ChartPanComponent, hitTestCanvasModel: HitTestCanvasModel);
54
+ wheelThrottleTime: number;
55
+ chartPanningOptions: ChartPanningOptions;
56
+ constructor(bus: EventBus, config: FullChartConfig, scale: ScaleModel, canvasInputListener: CanvasInputListenerComponent, canvasBoundsContainer: CanvasBoundsContainer, canvasAnimation: CanvasAnimation, chartPanComponent: ChartPanComponent, hitTestCanvasModel: HitTestCanvasModel);
56
57
  /**
57
58
  * It observes the wheel event on all panes of the canvas and throttles it to the specified time.
58
59
  * It then calculates the zoom sensitivity based on whether the event was triggered by a touchpad or not.
@@ -70,6 +71,7 @@ export declare class ChartAreaPanHandler extends ChartBaseElement {
70
71
  * @returns {void}
71
72
  */
72
73
  protected doActivate(): void;
74
+ private calculateDynamicSesitivity;
73
75
  /**
74
76
  * Registers a handler for panning the chart along the Y-axis.
75
77
  * @param {ScaleModel} scaleModel - The scale model of the extent.
@@ -89,3 +91,4 @@ export declare class ChartAreaPanHandler extends ChartBaseElement {
89
91
  * @doc-tags chart-core,auto-scale,y-axis
90
92
  */
91
93
  export declare const shouldDisableAutoScale: (point: Point, config: Required<AutoScaleDisableOnDrag>) => boolean;
94
+ export {};