@devexperts/dxcharts-lite 2.2.0 → 2.4.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 (72) hide show
  1. package/dist/chart/bootstrap.js +4 -3
  2. package/dist/chart/canvas/canvas-bounds-container.d.ts +2 -2
  3. package/dist/chart/canvas/canvas-bounds-container.js +7 -5
  4. package/dist/chart/canvas/cursor.handler.js +2 -2
  5. package/dist/chart/chart.config.d.ts +17 -4
  6. package/dist/chart/chart.config.js +6 -2
  7. package/dist/chart/components/chart/chart-area-pan.handler.js +13 -8
  8. package/dist/chart/components/chart/chart.component.d.ts +6 -3
  9. package/dist/chart/components/chart/chart.component.js +18 -7
  10. package/dist/chart/components/chart/chart.model.d.ts +1 -2
  11. package/dist/chart/components/chart/chart.model.js +2 -3
  12. package/dist/chart/components/cross_tool/cross-tool.model.js +1 -1
  13. package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +4 -2
  14. package/dist/chart/components/high_low/high-low.drawer.js +9 -2
  15. package/dist/chart/components/highlights/highlights.drawer.js +1 -1
  16. package/dist/chart/components/pane/pane.component.js +6 -3
  17. package/dist/chart/components/snapshot/snapshot.component.js +1 -0
  18. package/dist/chart/components/volumes/separate-volumes.component.js +2 -1
  19. package/dist/chart/components/volumes/volumes.drawer.js +1 -1
  20. package/dist/chart/components/volumes/volumes.formatter.d.ts +1 -1
  21. package/dist/chart/components/volumes/volumes.formatter.js +28 -25
  22. package/dist/chart/components/x_axis/time/parser/time-formats-matchers.functions.js +1 -1
  23. package/dist/chart/components/x_axis/time/parser/time-formats.model.d.ts +1 -1
  24. package/dist/chart/components/x_axis/time/x-axis-weights.functions.js +2 -2
  25. package/dist/chart/components/x_axis/time/x-axis-weights.generator.js +6 -7
  26. package/dist/chart/components/x_axis/x-axis-labels.generator.d.ts +11 -3
  27. package/dist/chart/components/x_axis/x-axis-labels.generator.js +47 -19
  28. package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +0 -4
  29. package/dist/chart/components/x_axis/x-axis.component.js +7 -11
  30. package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.js +5 -5
  31. package/dist/chart/components/y_axis/price_labels/price-label.drawer.js +21 -22
  32. package/dist/chart/components/y_axis/y-axis-labels.drawer.d.ts +18 -6
  33. package/dist/chart/components/y_axis/y-axis-labels.drawer.js +23 -12
  34. package/dist/chart/components/y_axis/y-axis-scale.handler.d.ts +9 -4
  35. package/dist/chart/components/y_axis/y-axis-scale.handler.js +22 -15
  36. package/dist/chart/components/y_axis/y-axis.component.js +1 -0
  37. package/dist/chart/components/y_axis/y-axis.drawer.js +1 -1
  38. package/dist/chart/drawers/chart-background.drawer.d.ts +2 -3
  39. package/dist/chart/drawers/chart-background.drawer.js +16 -22
  40. package/dist/chart/drawers/data-series-drawers/candle-series-wrapper.js +1 -1
  41. package/dist/chart/drawers/data-series.drawer.d.ts +0 -2
  42. package/dist/chart/drawers/data-series.drawer.js +2 -7
  43. package/dist/chart/drawers/ht-data-series.drawer.js +1 -1
  44. package/dist/chart/inputhandlers/hover-producer.component.d.ts +1 -1
  45. package/dist/chart/inputlisteners/canvas-input-listener.component.d.ts +9 -0
  46. package/dist/chart/inputlisteners/canvas-input-listener.component.js +38 -1
  47. package/dist/chart/model/compare-series-hover.d.ts +1 -1
  48. package/dist/chart/model/compare-series-hover.js +5 -0
  49. package/dist/chart/model/data-series.model.js +1 -1
  50. package/dist/chart/model/hit-test-canvas.model.js +2 -2
  51. package/dist/chart/model/scale.model.d.ts +6 -3
  52. package/dist/chart/model/scale.model.js +46 -9
  53. package/dist/chart/model/scaling/constrait.functions.d.ts +1 -1
  54. package/dist/chart/model/scaling/constrait.functions.js +1 -2
  55. package/dist/chart/model/scaling/lock-ratio.model.d.ts +8 -2
  56. package/dist/chart/model/scaling/lock-ratio.model.js +18 -3
  57. package/dist/chart/model/scaling/viewport.model.d.ts +2 -0
  58. package/dist/chart/model/scaling/viewport.model.js +13 -4
  59. package/dist/chart/model/time-zone.model.d.ts +0 -14
  60. package/dist/chart/model/time-zone.model.js +13 -33
  61. package/dist/chart/utils/canvas/canvas-drawing-functions.utils.d.ts +12 -1
  62. package/dist/chart/utils/canvas/canvas-drawing-functions.utils.js +16 -1
  63. package/dist/chart/utils/canvas/canvas-text-functions.utils.d.ts +3 -2
  64. package/dist/chart/utils/canvas/canvas-text-functions.utils.js +8 -3
  65. package/dist/chart/utils/device/touchpad.utils.d.ts +3 -3
  66. package/dist/chart/utils/device/touchpad.utils.js +3 -5
  67. package/dist/chart/utils/math.utils.d.ts +1 -1
  68. package/dist/chart/utils/math.utils.js +4 -1
  69. package/dist/chart/utils/timezone.utils.d.ts +13 -0
  70. package/dist/chart/utils/timezone.utils.js +48 -0
  71. package/dist/dxchart.min.js +6 -6
  72. package/package.json +1 -2
@@ -9,10 +9,9 @@ import { FullChartConfig } from '../chart.config';
9
9
  export declare class BackgroundDrawer implements Drawer {
10
10
  private canvasModel;
11
11
  private config;
12
- constructor(canvasModel: CanvasModel, config: FullChartConfig);
12
+ private backgroundDrawPredicate;
13
+ constructor(canvasModel: CanvasModel, config: FullChartConfig, backgroundDrawPredicate?: () => boolean);
13
14
  private prevState;
14
- private prevWidth;
15
- private prevHeight;
16
15
  draw(): void;
17
16
  getCanvasIds(): Array<string>;
18
17
  }
@@ -4,39 +4,33 @@
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 { getDPR } from '../utils/device/device-pixel-ratio.utils';
7
- import { deepEqual } from '../utils/object.utils';
8
7
  import { floor } from '../utils/math.utils';
8
+ import { deepEqual } from '../utils/object.utils';
9
9
  export class BackgroundDrawer {
10
- constructor(canvasModel, config) {
10
+ constructor(canvasModel, config, backgroundDrawPredicate = () => true) {
11
11
  this.canvasModel = canvasModel;
12
12
  this.config = config;
13
+ this.backgroundDrawPredicate = backgroundDrawPredicate;
13
14
  // we need to save previous state to avoid unnecessary redraws
14
15
  this.prevState = {};
15
- this.prevWidth = 0;
16
- this.prevHeight = 0;
17
16
  }
18
17
  draw() {
19
- if (deepEqual(this.config.colors.chartAreaTheme, this.prevState) &&
20
- this.prevHeight === this.canvasModel.height &&
21
- this.prevWidth === this.canvasModel.width) {
22
- return;
23
- }
24
- this.canvasModel.clear();
25
- const ctx = this.canvasModel.ctx;
26
- if (this.config.colors.chartAreaTheme.backgroundMode === 'gradient') {
27
- const grd = ctx.createLinearGradient(0, 0, this.canvasModel.width, this.canvasModel.height);
28
- grd.addColorStop(0, this.config.colors.chartAreaTheme.backgroundGradientTopColor);
29
- grd.addColorStop(1, this.config.colors.chartAreaTheme.backgroundGradientBottomColor);
30
- ctx.fillStyle = grd;
31
- }
32
- else {
33
- ctx.fillStyle = this.config.colors.chartAreaTheme.backgroundColor;
18
+ if (this.backgroundDrawPredicate() || !deepEqual(this.config.colors.chartAreaTheme, this.prevState)) {
19
+ this.canvasModel.clear();
20
+ const ctx = this.canvasModel.ctx;
21
+ if (this.config.colors.chartAreaTheme.backgroundMode === 'gradient') {
22
+ const grd = ctx.createLinearGradient(0, 0, this.canvasModel.width, this.canvasModel.height);
23
+ grd.addColorStop(0, this.config.colors.chartAreaTheme.backgroundGradientTopColor);
24
+ grd.addColorStop(1, this.config.colors.chartAreaTheme.backgroundGradientBottomColor);
25
+ ctx.fillStyle = grd;
26
+ }
27
+ else {
28
+ ctx.fillStyle = this.config.colors.chartAreaTheme.backgroundColor;
29
+ }
30
+ ctx.fillRect(0, 0, this.canvasModel.width, this.canvasModel.height);
34
31
  }
35
- ctx.fillRect(0, 0, this.canvasModel.width, this.canvasModel.height);
36
32
  // save prev state
37
33
  this.prevState = Object.assign({}, this.config.colors.chartAreaTheme);
38
- this.prevWidth = this.canvasModel.width;
39
- this.prevHeight = this.canvasModel.height;
40
34
  }
41
35
  getCanvasIds() {
42
36
  return [this.canvasModel.canvasId];
@@ -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 { clipToBounds } from '../data-series.drawer';
6
+ import { clipToBounds } from '../../utils/canvas/canvas-drawing-functions.utils';
7
7
  export const candleTypesList = [
8
8
  'candle',
9
9
  'bar',
@@ -5,7 +5,6 @@
5
5
  */
6
6
  import { DynamicModelDrawer } from '../components/dynamic-objects/dynamic-objects.drawer';
7
7
  import { PaneManager } from '../components/pane/pane-manager.component';
8
- import { Bounds } from '../model/bounds.model';
9
8
  import { CanvasModel } from '../model/canvas.model';
10
9
  import { DataSeriesModel, VisualSeriesPoint } from '../model/data-series.model';
11
10
  export interface ChartDrawerConfig {
@@ -33,5 +32,4 @@ export declare class DataSeriesDrawer implements DynamicModelDrawer<DataSeriesMo
33
32
  draw(canvasModel: CanvasModel, model: DataSeriesModel, paneUUID?: string): void;
34
33
  drawSeries(ctx: CanvasRenderingContext2D, series: DataSeriesModel): void;
35
34
  }
36
- export declare const clipToBounds: (ctx: CanvasRenderingContext2D, bounds: Bounds) => void;
37
35
  export declare const setLineWidth: (ctx: CanvasRenderingContext2D, lineWidth: number, dataSeries: DataSeriesModel, drawerConfig: ChartDrawerConfig, seriesSelectedWidth?: number) => void;
@@ -3,6 +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 { clipToBounds } from '../utils/canvas/canvas-drawing-functions.utils';
6
7
  export const transformToTwoDimension = (points) => (Array.isArray(points[0]) ? points : [points]);
7
8
  /**
8
9
  * Basic data series drawer.
@@ -42,18 +43,12 @@ export class DataSeriesDrawer {
42
43
  }
43
44
  }
44
45
  }
45
- export const clipToBounds = (ctx, bounds) => {
46
- ctx.beginPath();
47
- ctx.rect(bounds.x, bounds.y, bounds.width, bounds.height);
48
- ctx.clip();
49
- ctx.closePath();
50
- };
51
46
  export const setLineWidth = (ctx, lineWidth, dataSeries, drawerConfig, seriesSelectedWidth = lineWidth) => {
52
47
  if (drawerConfig.forceBold) {
53
48
  ctx.lineWidth = drawerConfig.forceBold;
54
49
  }
55
50
  else if (dataSeries.hovered) {
56
- ctx.lineWidth = seriesSelectedWidth;
51
+ ctx.lineWidth = lineWidth !== seriesSelectedWidth ? lineWidth + 1 : seriesSelectedWidth;
57
52
  }
58
53
  else {
59
54
  ctx.lineWidth = lineWidth;
@@ -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 { clipToBounds } from './data-series.drawer';
6
+ import { clipToBounds } from '../utils/canvas/canvas-drawing-functions.utils';
7
7
  /***
8
8
  * HitTest Chart drawer. It's used to draw hit test for chart types on the hit-test canvas.
9
9
  */
@@ -32,7 +32,7 @@ export interface HoverParts {
32
32
  export interface Hover extends BaseHover, HoverParts {
33
33
  }
34
34
  export interface HoverProducerPart<T = unknown> {
35
- getData(hover: BaseHover): T;
35
+ getData(hover: BaseHover): T | undefined;
36
36
  }
37
37
  export interface HoverProducerParts {
38
38
  candleHover: CandleHoverProducerPart;
@@ -44,6 +44,7 @@ export declare class CanvasInputListenerComponent extends ChartBaseElement {
44
44
  private mouseUpDocumentSubject;
45
45
  private wheelSubject;
46
46
  private touchStartSubject;
47
+ private touchStartTimestamp;
47
48
  private touchMoveSubject;
48
49
  private touchEndSubject;
49
50
  private touchCancelSubject;
@@ -52,6 +53,7 @@ export declare class CanvasInputListenerComponent extends ChartBaseElement {
52
53
  private contextMenuSubject;
53
54
  private pinchSubject;
54
55
  private scrollGestureSubject;
56
+ private fastTouchScroll;
55
57
  mouseLeavesCanvasSubject: Subject<boolean>;
56
58
  dragStartPoint: Point;
57
59
  prevDragPoint: Point;
@@ -312,6 +314,13 @@ export declare class CanvasInputListenerComponent extends ChartBaseElement {
312
314
  * @returns {Observable<TouchEvent>} - An Observable that emits a TouchEvent when a long touch is detected on the current element.
313
315
  */
314
316
  observeLongTouchEnd(hitBoundsTest?: HitBoundsTest): Observable<TouchEvent>;
317
+ /**
318
+ * Returns an Observable that emits a Touch whenever a fast scroll is detected.
319
+ * Fast scroll happens whenever chart or any other pane were moved faster than usual
320
+ * The Observable is created from a Subject that is subscribed to by the component's template.
321
+ * @returns {Observable<TouchEvent>} An Observable that emits a TouchEvent whenever a fast scroll is detected.
322
+ */
323
+ observeFastTouchScroll(hitBoundsTest?: HitBoundsTest): Observable<TouchEvent>;
315
324
  /**
316
325
  * Returns the current point of the object.
317
326
  * @returns {Point} The current point of the object.
@@ -46,6 +46,7 @@ class CanvasInputListenerComponent extends ChartBaseElement {
46
46
  this.mouseUpDocumentSubject = new Subject();
47
47
  this.wheelSubject = new Subject();
48
48
  this.touchStartSubject = new Subject();
49
+ this.touchStartTimestamp = 0;
49
50
  this.touchMoveSubject = new Subject();
50
51
  this.touchEndSubject = new Subject();
51
52
  this.touchCancelSubject = new Subject();
@@ -54,6 +55,7 @@ class CanvasInputListenerComponent extends ChartBaseElement {
54
55
  this.contextMenuSubject = new Subject();
55
56
  this.pinchSubject = new Subject();
56
57
  this.scrollGestureSubject = new Subject();
58
+ this.fastTouchScroll = new Subject();
57
59
  this.mouseLeavesCanvasSubject = new Subject();
58
60
  // point at which start dragging
59
61
  this.dragStartPoint = { x: 0, y: 0 };
@@ -236,9 +238,33 @@ class CanvasInputListenerComponent extends ChartBaseElement {
236
238
  this.element.addEventListener('touchend', touchEndHandler);
237
239
  };
238
240
  this.addSubscription(subscribeListener(this.element, (e) => longTouchListeners(e), 'touchstart'));
241
+ const fastScrollListenerProducer = (e) => {
242
+ e.preventDefault();
243
+ // should work only if dragged to the left
244
+ if (this.prevDragPoint.x > this.dragStartPoint.x) {
245
+ // in percent, perhaps should be changed to just pixels,
246
+ // because landscape and portait orientations would give different % results
247
+ const minDistance = 35;
248
+ // in ms, should be lower to detect as "fast"
249
+ const maxTime = 250;
250
+ const touchStartTs = this.touchStartTimestamp;
251
+ const touchEndTs = Date.now();
252
+ const time = touchEndTs - touchStartTs;
253
+ const distance = ((this.prevDragPoint.x - this.dragStartPoint.x) / this.canvasBounds.width) * 100;
254
+ const isRightDistance = distance > minDistance;
255
+ const isRightTime = time <= maxTime;
256
+ if (isRightDistance && isRightTime) {
257
+ this.fastTouchScroll.next(e);
258
+ }
259
+ }
260
+ };
261
+ this.addSubscription(subscribeListener(this.element, fastScrollListenerProducer, 'touchend'));
239
262
  }
240
263
  this.addSubscription(subscribeListener(this.element, leftMouseButtonListener(() => this.dbClickSubject.next(this.currentPoint)), 'dblclick'));
241
- this.addSubscription(subscribeListener(this.element, (e) => this.touchStartSubject.next(e), 'touchstart'));
264
+ this.addSubscription(subscribeListener(this.element, (e) => {
265
+ this.touchStartSubject.next(e);
266
+ this.touchStartTimestamp = Date.now();
267
+ }, 'touchstart'));
242
268
  this.addSubscription(subscribeListener(this.element, (e) => this.touchMoveSubject.next(e), 'touchmove', true));
243
269
  this.addSubscription(subscribeListener(this.element, (e) => this.touchEndSubject.next(e), 'touchend'));
244
270
  this.addSubscription(subscribeListener(this.element, (e) => this.touchCancelSubject.next(e), 'touchcancel'));
@@ -643,6 +669,17 @@ class CanvasInputListenerComponent extends ChartBaseElement {
643
669
  .asObservable()
644
670
  .pipe(filter(() => hitBoundsTest(this.currentPoint.x, this.currentPoint.y)));
645
671
  }
672
+ /**
673
+ * Returns an Observable that emits a Touch whenever a fast scroll is detected.
674
+ * Fast scroll happens whenever chart or any other pane were moved faster than usual
675
+ * The Observable is created from a Subject that is subscribed to by the component's template.
676
+ * @returns {Observable<TouchEvent>} An Observable that emits a TouchEvent whenever a fast scroll is detected.
677
+ */
678
+ observeFastTouchScroll(hitBoundsTest = () => true) {
679
+ return this.fastTouchScroll
680
+ .asObservable()
681
+ .pipe(filter(() => hitBoundsTest(this.currentPoint.x, this.currentPoint.y)));
682
+ }
646
683
  /**
647
684
  * Returns the current point of the object.
648
685
  * @returns {Point} The current point of the object.
@@ -19,5 +19,5 @@ export declare class CompareSeriesHoverProducerPart implements HoverProducerPart
19
19
  * @param {BaseHover} hover - The hover object containing the x-coordinate.
20
20
  * @returns {CompareSeriesHover[]} An array of objects containing the instrument symbol, price and id of each series of candles.
21
21
  */
22
- getData(hover: BaseHover): CompareSeriesHover[];
22
+ getData(hover: BaseHover): CompareSeriesHover[] | undefined;
23
23
  }
@@ -3,6 +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 { MainCandleSeriesModel } from './main-candle-series.model';
6
7
  export class CompareSeriesHoverProducerPart {
7
8
  constructor(chartModel) {
8
9
  this.chartModel = chartModel;
@@ -13,6 +14,10 @@ export class CompareSeriesHoverProducerPart {
13
14
  * @returns {CompareSeriesHover[]} An array of objects containing the instrument symbol, price and id of each series of candles.
14
15
  */
15
16
  getData(hover) {
17
+ if (this.chartModel.candleSeries.length === 1 &&
18
+ this.chartModel.candleSeries[0] instanceof MainCandleSeriesModel) {
19
+ return;
20
+ }
16
21
  const { x } = hover;
17
22
  const candle = this.chartModel.candleFromX(x);
18
23
  const idx = candle.idx || 0;
@@ -138,7 +138,7 @@ export class DataSeriesModel extends ChartBaseElement {
138
138
  }
139
139
  doActivate() {
140
140
  this.addRxSubscription(this.scale.xChanged.subscribe(() => this.recalculateDataViewportIndexes()));
141
- this.addRxSubscription(this.scale.scaleInversedSubject.subscribe(() => this.recalculateVisualPoints()));
141
+ this.addRxSubscription(this.scale.scaleInversedSubject.subscribe(() => { this.recalculateVisualPoints(); }));
142
142
  }
143
143
  /**
144
144
  * Sets the data points and recalculates internal state
@@ -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 { merge, Subject } from 'rxjs';
6
+ import { merge, Subject, animationFrameScheduler } from 'rxjs';
7
7
  import { map, throttleTime } from 'rxjs/operators';
8
8
  import { CanvasElement } from '../canvas/canvas-bounds-container';
9
9
  import { CanvasModel, initCanvasWithConfig } from './canvas.model';
@@ -50,7 +50,7 @@ export class HitTestCanvasModel extends CanvasModel {
50
50
  const bounds = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.ALL_PANES);
51
51
  const hoverSub = this.canvasInputListener
52
52
  .observeMouseMove()
53
- .pipe(throttleTime(100, undefined, { trailing: true }))
53
+ .pipe(throttleTime(100, animationFrameScheduler, { trailing: true }))
54
54
  .subscribe(point => this.eventHandler(point, 'hover'));
55
55
  const touchStartSub = this.canvasInputListener
56
56
  .observeTouchStart()
@@ -48,6 +48,8 @@ export declare class ScaleModel extends ViewportModel {
48
48
  xConstraints: Constraints[];
49
49
  readonly state: ChartScale;
50
50
  constructor(config: FullChartConfig, getBounds: BoundsProvider, canvasAnimation: CanvasAnimation);
51
+ protected doActivate(): void;
52
+ protected doDeactivate(): void;
51
53
  /**
52
54
  * The method adds a new "constraint" to the existing list of x-axis constraints for charting.
53
55
  * The "constraint" is expected to be an object containing information about the constraints, such as the minimum and maximum values for the x-axis.
@@ -71,13 +73,13 @@ export declare class ScaleModel extends ViewportModel {
71
73
  * @param forceNoAnimation Whether to skip animation.
72
74
  * @param zoomSensitivity The sensitivity of the zoom.
73
75
  */
74
- zoomXToPercent(viewportPercent: ViewportPercent, zoomIn: boolean, forceNoAnimation?: boolean, zoomSensitivity?: number): void;
76
+ zoomXToPercent(viewportPercent: ViewportPercent, zoomIn: boolean, forceNoAnimation: boolean | undefined, zoomSensitivity: number): void;
75
77
  /**
76
78
  * Zooms the X axis of the chart relativly to the end of the data range.
77
79
  * @param zoomIn - If true, the chart will be zoomed in. If false, the chart will be zoomed out.
78
80
  * @param zoomSensitivity - The sensitivity of the zoom. Default value is taken from the configuration object.
79
81
  */
80
- zoomXToEnd(zoomIn: boolean, zoomSensitivity?: number): void;
82
+ zoomXToEnd(zoomIn: boolean, zoomSensitivity: number): void;
81
83
  haltAnimation(): void;
82
84
  private zoomXTo;
83
85
  /**
@@ -88,7 +90,8 @@ export declare class ScaleModel extends ViewportModel {
88
90
  * @param fireChanged
89
91
  * @param forceNoAutoScale - force NOT apply auto-scaling (for lazy loading)
90
92
  */
91
- setXScale(xStart: Unit, xEnd: Unit): void;
93
+ setXScale(xStart: Unit, xEnd: Unit, forceNoAnimation?: boolean): void;
94
+ setYScale(yStart: Unit, yEnd: Unit, fire?: boolean): void;
92
95
  /**
93
96
  * Moves both xStart and xEnd without changing the viewport width (zoom).
94
97
  * Works without animation.
@@ -8,7 +8,7 @@ import { startViewportModelAnimation } from '../animation/viewport-model-animati
8
8
  import { cloneUnsafe } from '../utils/object.utils';
9
9
  import { AutoScaleViewportSubModel } from './scaling/auto-scale.model';
10
10
  import { zoomConstraint } from './scaling/constrait.functions';
11
- import { lockedYEndViewportCalculator, ratioFromZoomXY } from './scaling/lock-ratio.model';
11
+ import { changeXToKeepRatio, changeYToKeepRatio, ratioFromZoomXY } from './scaling/lock-ratio.model';
12
12
  import { moveXStart, moveYStart } from './scaling/move-chart.functions';
13
13
  import { ViewportModel, compareStates } from './scaling/viewport.model';
14
14
  import { zoomXToEndViewportCalculator, zoomXToPercentViewportCalculator } from './scaling/x-zooming.functions';
@@ -51,6 +51,19 @@ export class ScaleModel extends ViewportModel {
51
51
  this.offsets = this.config.components.offsets;
52
52
  this.addXConstraint((initialState, state) => zoomConstraint(initialState, state, this.config.components.chart, this.getBounds));
53
53
  }
54
+ doActivate() {
55
+ super.doActivate();
56
+ this.scaleInversedSubject = new Subject();
57
+ this.beforeStartAnimationSubject = new Subject();
58
+ this.addRxSubscription(this.scaleInversedSubject.subscribe(() => {
59
+ this.fireChanged();
60
+ }));
61
+ }
62
+ doDeactivate() {
63
+ super.doDeactivate();
64
+ this.scaleInversedSubject.complete();
65
+ this.beforeStartAnimationSubject.complete();
66
+ }
54
67
  /**
55
68
  * The method adds a new "constraint" to the existing list of x-axis constraints for charting.
56
69
  * The "constraint" is expected to be an object containing information about the constraints, such as the minimum and maximum values for the x-axis.
@@ -81,7 +94,7 @@ export class ScaleModel extends ViewportModel {
81
94
  * @param forceNoAnimation Whether to skip animation.
82
95
  * @param zoomSensitivity The sensitivity of the zoom.
83
96
  */
84
- zoomXToPercent(viewportPercent, zoomIn, forceNoAnimation = false, zoomSensitivity = this.config.scale.zoomSensitivity) {
97
+ zoomXToPercent(viewportPercent, zoomIn, forceNoAnimation = false, zoomSensitivity) {
85
98
  const disabledAnimations = this.config.scale.disableAnimations || forceNoAnimation;
86
99
  if (disabledAnimations) {
87
100
  this.haltAnimation();
@@ -96,7 +109,7 @@ export class ScaleModel extends ViewportModel {
96
109
  * @param zoomIn - If true, the chart will be zoomed in. If false, the chart will be zoomed out.
97
110
  * @param zoomSensitivity - The sensitivity of the zoom. Default value is taken from the configuration object.
98
111
  */
99
- zoomXToEnd(zoomIn, zoomSensitivity = this.config.scale.zoomSensitivity) {
112
+ zoomXToEnd(zoomIn, zoomSensitivity) {
100
113
  if (this.config.scale.disableAnimations) {
101
114
  this.haltAnimation();
102
115
  }
@@ -116,7 +129,7 @@ export class ScaleModel extends ViewportModel {
116
129
  const initialStateCopy = Object.assign({}, state);
117
130
  const constrainedState = this.scalePostProcessor(initialStateCopy, state);
118
131
  if (this.state.lockPriceToBarRatio) {
119
- lockedYEndViewportCalculator(constrainedState, this.zoomXYRatio);
132
+ changeYToKeepRatio(constrainedState, this.zoomXYRatio);
120
133
  }
121
134
  if (this.state.auto) {
122
135
  this.autoScaleModel.doAutoYScale(constrainedState);
@@ -136,18 +149,42 @@ export class ScaleModel extends ViewportModel {
136
149
  * @param fireChanged
137
150
  * @param forceNoAutoScale - force NOT apply auto-scaling (for lazy loading)
138
151
  */
139
- setXScale(xStart, xEnd) {
152
+ setXScale(xStart, xEnd, forceNoAnimation = true) {
140
153
  const initialState = this.export();
141
- super.setXScale(xStart, xEnd, false);
142
- const state = this.export();
154
+ const zoomX = this.calculateZoomX(xStart, xEnd);
155
+ const state = Object.assign(Object.assign({}, initialState), { zoomX, xStart, xEnd });
143
156
  const constrainedState = this.scalePostProcessor(initialState, state);
144
157
  if (this.state.lockPriceToBarRatio) {
145
- lockedYEndViewportCalculator(constrainedState, this.zoomXYRatio);
158
+ changeYToKeepRatio(constrainedState, this.zoomXYRatio);
146
159
  }
147
160
  if (this.state.auto) {
148
161
  this.autoScaleModel.doAutoYScale(constrainedState);
149
162
  }
150
- this.apply(constrainedState);
163
+ if (forceNoAnimation || this.config.scale.disableAnimations) {
164
+ this.haltAnimation();
165
+ this.apply(constrainedState);
166
+ }
167
+ else {
168
+ startViewportModelAnimation(this.canvasAnimation, this, constrainedState);
169
+ }
170
+ }
171
+ setYScale(yStart, yEnd, fire = false) {
172
+ const initialState = this.export();
173
+ super.setYScale(yStart, yEnd, fire);
174
+ const state = this.export();
175
+ const constrainedState = this.scalePostProcessor(initialState, state);
176
+ if (this.state.lockPriceToBarRatio) {
177
+ changeXToKeepRatio(constrainedState, this.zoomXYRatio);
178
+ this.setXScale(constrainedState.xStart, constrainedState.xEnd);
179
+ // TODO: rewrite logic for applying constraints to consider both axes, now constraints on Y may not work correctly
180
+ return;
181
+ }
182
+ else {
183
+ if (this.state.auto) {
184
+ this.autoScaleModel.doAutoYScale(constrainedState);
185
+ }
186
+ this.apply(constrainedState);
187
+ }
151
188
  }
152
189
  /**
153
190
  * Moves both xStart and xEnd without changing the viewport width (zoom).
@@ -32,7 +32,7 @@ export declare const candleEdgesConstrait: (state: ViewportModelState, visualCan
32
32
  * @returns
33
33
  * @doc-tags viewport,zoom,scaling
34
34
  */
35
- export declare const zoomConstraint: (initialState: ViewportModelState, state: ViewportModelState, chartConfig: ChartConfigComponentsChart, boundsProvider: BoundsProvider) => {
35
+ export declare const zoomConstraint: (_: ViewportModelState, state: ViewportModelState, chartConfig: ChartConfigComponentsChart, boundsProvider: BoundsProvider) => {
36
36
  xStart: number;
37
37
  xEnd: number;
38
38
  yStart: number;
@@ -40,7 +40,7 @@ export const candleEdgesConstrait = (state, visualCandlesCoordinates, candleLimi
40
40
  * @returns
41
41
  * @doc-tags viewport,zoom,scaling
42
42
  */
43
- export const zoomConstraint = (initialState, state, chartConfig, boundsProvider) => {
43
+ export const zoomConstraint = (_, state, chartConfig, boundsProvider) => {
44
44
  const newState = Object.assign({}, state);
45
45
  const bounds = boundsProvider();
46
46
  // 1 - is an average candle width: newXEnd - newXStart = avg candles amount in the viewport
@@ -56,7 +56,6 @@ export const zoomConstraint = (initialState, state, chartConfig, boundsProvider)
56
56
  return newState;
57
57
  }
58
58
  if (minViewportReached) {
59
- newState.xEnd = initialState.xEnd;
60
59
  newState.xStart = newState.xEnd - chartConfig.minCandles;
61
60
  newState.zoomX = calculateZoom(newState.xEnd - newState.xStart, bounds.width);
62
61
  return newState;
@@ -9,8 +9,14 @@ export declare const ratioFromZoomXY: (zoomX: Zoom, zoomY: Zoom) => ZoomXToZoomY
9
9
  export declare const zoomXToZoomY: (zoomX: Zoom, ratio: ZoomXToZoomYRatio) => Zoom;
10
10
  export declare const zoomYToZoomX: (zoomY: Zoom, ratio: ZoomXToZoomYRatio) => Zoom;
11
11
  /**
12
- * Locks the zoomY with zoomX and moves yEnd according to ratio changes.
12
+ * Locks the zoomY with zoomX and zooms y-scale depending on x-scale.
13
13
  * @param state
14
14
  * @param zoomXYRatio
15
15
  */
16
- export declare const lockedYEndViewportCalculator: (state: ViewportModelState, zoomXYRatio: ZoomXToZoomYRatio) => void;
16
+ export declare const changeYToKeepRatio: (state: ViewportModelState, zoomXYRatio: ZoomXToZoomYRatio) => void;
17
+ /**
18
+ * Locks the zoomY with zoomX and zooms x-scale depending on y-scale.
19
+ * @param state
20
+ * @param zoomXYRatio
21
+ */
22
+ export declare const changeXToKeepRatio: (state: ViewportModelState, zoomXYRatio: ZoomXToZoomYRatio) => void;
@@ -7,16 +7,31 @@ export const ratioFromZoomXY = (zoomX, zoomY) => zoomX / zoomY;
7
7
  export const zoomXToZoomY = (zoomX, ratio) => zoomX / ratio;
8
8
  export const zoomYToZoomX = (zoomY, ratio) => zoomY * ratio;
9
9
  /**
10
- * Locks the zoomY with zoomX and moves yEnd according to ratio changes.
10
+ * Locks the zoomY with zoomX and zooms y-scale depending on x-scale.
11
11
  * @param state
12
12
  * @param zoomXYRatio
13
13
  */
14
- export const lockedYEndViewportCalculator = (state, zoomXYRatio) => {
14
+ export const changeYToKeepRatio = (state, zoomXYRatio) => {
15
15
  const prevZoomY = state.zoomY;
16
16
  state.zoomY = zoomXToZoomY(state.zoomX, zoomXYRatio);
17
17
  const zoomYMult = state.zoomY / prevZoomY;
18
18
  const lastYHeight = state.yEnd - state.yStart;
19
19
  const newYHeight = lastYHeight * zoomYMult;
20
20
  const delta = newYHeight - lastYHeight;
21
- state.yEnd = state.yEnd + delta;
21
+ state.yEnd = state.yEnd + delta / 2;
22
+ state.yStart = state.yStart - delta / 2;
23
+ };
24
+ /**
25
+ * Locks the zoomY with zoomX and zooms x-scale depending on y-scale.
26
+ * @param state
27
+ * @param zoomXYRatio
28
+ */
29
+ export const changeXToKeepRatio = (state, zoomXYRatio) => {
30
+ const prevZoomX = state.zoomX;
31
+ state.zoomX = zoomYToZoomX(state.zoomY, zoomXYRatio);
32
+ const zoomXMult = state.zoomX / prevZoomX;
33
+ const lastXWidth = state.xEnd - state.xStart;
34
+ const newXWidth = lastXWidth * zoomXMult;
35
+ const delta = newXWidth - lastXWidth;
36
+ state.xStart = state.xStart - delta;
22
37
  };
@@ -92,6 +92,8 @@ export declare abstract class ViewportModel extends ChartBaseElement implements
92
92
  start: number;
93
93
  end: number;
94
94
  }>;
95
+ protected doActivate(): void;
96
+ protected doDeactivate(): void;
95
97
  /**
96
98
  * Converts a unit value to pixels based on the current zoom level and xStart value.
97
99
  * @param {Unit} unit - The unit value to be converted to pixels.
@@ -52,6 +52,13 @@ export class ViewportModel extends ChartBaseElement {
52
52
  })), distinctUntilChanged((p, c) => p.start === c.start && p.end === c.end), share());
53
53
  }
54
54
  //endregion
55
+ doActivate() {
56
+ super.doActivate();
57
+ }
58
+ doDeactivate() {
59
+ super.doDeactivate();
60
+ this.changed.complete();
61
+ }
55
62
  //region conversion methods
56
63
  /**
57
64
  * Converts a unit value to pixels based on the current zoom level and xStart value.
@@ -75,12 +82,13 @@ export class ViewportModel extends ChartBaseElement {
75
82
  * @returns {Pixel} - The pixel value of the given unit value in the Y-axis.
76
83
  */
77
84
  toY(unit) {
85
+ const bounds = this.getBounds();
78
86
  if (this.inverseY) {
79
- return this.getBounds().y + unitToPixels(unit - this.yStart, this.zoomY);
87
+ return bounds.y + unitToPixels(unit - this.yStart, this.zoomY);
80
88
  }
81
89
  else {
82
90
  // inverse by default because canvas calculation [0,0] point starts from top-left corner
83
- return this.getBounds().y + this.getBounds().height - unitToPixels(unit - this.yStart, this.zoomY);
91
+ return bounds.y + bounds.height - unitToPixels(unit - this.yStart, this.zoomY);
84
92
  }
85
93
  }
86
94
  /**
@@ -106,13 +114,14 @@ export class ViewportModel extends ChartBaseElement {
106
114
  * @returns {void}
107
115
  */
108
116
  fromY(px) {
109
- const normalizedPx = px - this.getBounds().y;
117
+ const bounds = this.getBounds();
118
+ const normalizedPx = px - bounds.y;
110
119
  if (this.inverseY) {
111
120
  return pixelsToUnits(normalizedPx + unitToPixels(this.yStart, this.zoomY), this.zoomY);
112
121
  }
113
122
  else {
114
123
  // inverse by default because canvas calculation [0,0] point starts from top-left corner
115
- return pixelsToUnits(this.getBounds().height - normalizedPx + unitToPixels(this.yStart, this.zoomY), this.zoomY);
124
+ return pixelsToUnits(bounds.height - normalizedPx + unitToPixels(this.yStart, this.zoomY), this.zoomY);
116
125
  }
117
126
  }
118
127
  //endregion
@@ -3,7 +3,6 @@
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 { getTimezoneOffset as getTimezoneOffsetDateFnsTz } from 'date-fns-tz';
7
6
  import { Observable } from 'rxjs';
8
7
  import { DateFormatter, FullChartConfig } from '../chart.config';
9
8
  import { DateTimeFormatter, DateTimeFormatterFactory } from './date-time.formatter';
@@ -13,8 +12,6 @@ export interface TimeZone {
13
12
  readonly name: string;
14
13
  readonly utcOffset: string;
15
14
  }
16
- export declare const memoizedTZOffset: typeof getTimezoneOffsetDateFnsTz;
17
- export declare const getTimezoneOffset: (timezone: string, time: Timestamp) => number;
18
15
  export declare class TimeZoneModel {
19
16
  private config;
20
17
  private timeZoneChangedSubject;
@@ -50,16 +47,5 @@ export declare class TimeZoneModel {
50
47
  getFormatterFactory(): DateTimeFormatterFactory;
51
48
  private formatterCache;
52
49
  getDateTimeFormatter(format: string): DateTimeFormatter;
53
- /**
54
- * Calculates the offset of a given timezone from the local timezone.
55
- * @private
56
- * @param {string} timezone - The timezone to calculate the offset for.
57
- */
58
- private getOffset;
59
- /**
60
- * Gets the timezone offset value in milliseconds
61
- * @param {string} timezone name
62
- * @returns {function(time:Number):Date}
63
- */
64
50
  tzOffset(timezone: string): (time: number) => Date;
65
51
  }