@devexperts/dxcharts-lite 2.7.10 → 2.7.12

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 (37) hide show
  1. package/dist/chart/__tests__/env.js +2 -2
  2. package/dist/chart/canvas/canvas-bounds-container.js +1 -2
  3. package/dist/chart/canvas/chart-elements.d.ts +1 -1
  4. package/dist/chart/chart.config.js +2 -2
  5. package/dist/chart/chart.js +2 -1
  6. package/dist/chart/components/chart/chart.component.js +2 -0
  7. package/dist/chart/components/chart/chart.model.d.ts +1 -1
  8. package/dist/chart/components/chart/price-formatters/treasury-price.formatter.d.ts +1 -0
  9. package/dist/chart/components/chart/price-formatters/treasury-price.formatter.js +1 -0
  10. package/dist/chart/components/labels_generator/numeric-axis-labels.generator.d.ts +3 -3
  11. package/dist/chart/components/labels_generator/numeric-axis-labels.generator.js +2 -4
  12. package/dist/chart/components/pane/extent/y-extent-component.d.ts +1 -1
  13. package/dist/chart/components/pane/extent/y-extent-component.js +11 -1
  14. package/dist/chart/components/pane/pane.component.d.ts +2 -2
  15. package/dist/chart/components/volumes/separate-volumes.component.js +1 -2
  16. package/dist/chart/components/x_axis/time/parser/time-formats.model.d.ts +3 -3
  17. package/dist/chart/components/x_axis/x-axis-labels.generator.d.ts +8 -13
  18. package/dist/chart/components/x_axis/x-axis-labels.generator.js +87 -23
  19. package/dist/chart/components/x_axis/x-axis.component.js +12 -5
  20. package/dist/chart/components/y_axis/numeric-y-axis-labels.generator.d.ts +2 -1
  21. package/dist/chart/components/y_axis/numeric-y-axis-labels.generator.js +7 -2
  22. package/dist/chart/drawers/data-series-drawers/difference-cloud.drawer.d.ts +1 -1
  23. package/dist/chart/drawers/data-series-drawers/linear-trend.drawer.d.ts +12 -0
  24. package/dist/chart/drawers/data-series-drawers/linear-trend.drawer.js +42 -0
  25. package/dist/chart/inputhandlers/hover-producer.component.d.ts +1 -1
  26. package/dist/chart/inputlisteners/canvas-input-listener.component.js +1 -2
  27. package/dist/chart/model/data-series-view.d.ts +1 -1
  28. package/dist/chart/model/data-series.config.d.ts +1 -1
  29. package/dist/chart/model/data-series.model.d.ts +5 -5
  30. package/dist/chart/model/data-series.model.js +3 -2
  31. package/dist/chart/model/scaling/constrait.functions.d.ts +6 -6
  32. package/dist/chart/utils/array.utils.d.ts +5 -5
  33. package/dist/chart/utils/candles.utils.d.ts +2 -2
  34. package/dist/chart/utils/performance/memoize.utils.d.ts +1 -1
  35. package/dist/chart/utils/price-increments.utils.js +1 -2
  36. package/dist/dxchart.min.js +6 -6
  37. package/package.json +31 -33
@@ -11,8 +11,8 @@ Object.defineProperty(window, 'matchMedia', {
11
11
  matches: false,
12
12
  media: query,
13
13
  onchange: null,
14
- addListener: jest.fn(),
15
- removeListener: jest.fn(),
14
+ addListener: jest.fn(), // deprecated
15
+ removeListener: jest.fn(), // deprecated
16
16
  addEventListener: jest.fn(),
17
17
  removeEventListener: jest.fn(),
18
18
  dispatchEvent: jest.fn(),
@@ -11,7 +11,7 @@ import { calcTimeLabelBounds } from '../components/navigation_map/navigation-map
11
11
  import { calculateSymbolHeight } from '../utils/canvas/canvas-font-measure-tool.utils';
12
12
  import { YAxisBoundsContainer } from './y-axis-bounds.container';
13
13
  export const CHART_UUID = 'CHART';
14
- class CanvasElement {
14
+ export class CanvasElement {
15
15
  }
16
16
  CanvasElement.CANVAS = 'CANVAS';
17
17
  CanvasElement.N_MAP = 'N_MAP';
@@ -38,7 +38,6 @@ CanvasElement.CHART = CanvasElement.PANE_UUID(CHART_UUID);
38
38
  * @returns y-axis bounds for the main chart
39
39
  */
40
40
  CanvasElement.Y_AXIS = CanvasElement.PANE_UUID_Y_AXIS(CHART_UUID);
41
- export { CanvasElement };
42
41
  export const DEFAULT_BOUNDS = { x: 0, y: 0, pageX: 0, pageY: 0, width: 0, height: 0 };
43
42
  export const DEFAULT_MIN_PANE_HEIGHT = 20;
44
43
  const N_MAP_H = 35;
@@ -17,4 +17,4 @@ export interface ChartElements {
17
17
  chartContainer?: HTMLElement;
18
18
  }
19
19
  export type ValidatedChartElements = Required<ChartElements>;
20
- export declare const validateChartElements: (els: ChartElements) => els is Required<ChartElements>;
20
+ export declare const validateChartElements: (els: ChartElements) => els is ValidatedChartElements;
@@ -52,7 +52,7 @@ export const getDefaultConfig = () => ({
52
52
  defaultViewportItems: 100,
53
53
  disableAnimations: false,
54
54
  },
55
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
55
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, // local timezone
56
56
  components: {
57
57
  chart: {
58
58
  type: 'candle',
@@ -63,7 +63,7 @@ export const getDefaultConfig = () => ({
63
63
  lineWidth: 1,
64
64
  areaLineWidth: 1,
65
65
  barLineWidth: 1,
66
- minWidth: 0.5,
66
+ minWidth: 0.5, // minimum candle width in canvas units - not real pixels! for mac with DPR=2 it will be equal 1 pixel
67
67
  minCandles: 10,
68
68
  candlePaddingPercent: 0.25,
69
69
  highlightActiveCandle: true,
@@ -109,7 +109,8 @@ export class Chart extends ChartBootstrap {
109
109
  setTreasuryFormat(treasuryFormat) {
110
110
  this.config.components.yAxis.treasuryFormat = treasuryFormat;
111
111
  this.paneManager.yExtents.forEach(ext => {
112
- ext.yAxis.updateOrderedLabels(true);
112
+ ext.yAxis.model.labelsGenerator.updateTreasuryFormat(treasuryFormat);
113
+ ext.yAxis.model.labelsGenerator.doGenerateLabels();
113
114
  ext.yAxis.model.fancyLabelsModel.updateLabels(true);
114
115
  ext.yAxis.model.baseLabelsModel.updateLabels();
115
116
  });
@@ -33,6 +33,7 @@ import { defaultCandleTransformer, hollowCandleTransformer, lineCandleTransforme
33
33
  import { deleteCandlesIndex } from './candle.functions';
34
34
  import { TrendHistogramDrawer } from '../../drawers/data-series-drawers/trend-histogram.drawer';
35
35
  import { debounce } from '../../utils/performance/debounce.utils';
36
+ import { LinearTrendDrawer } from '../../drawers/data-series-drawers/linear-trend.drawer';
36
37
  /**
37
38
  * Represents a financial instrument to be displayed on a chart
38
39
  * @class
@@ -182,6 +183,7 @@ export class ChartComponent extends ChartBaseElement {
182
183
  const chartPaneId = CanvasElement.PANE_UUID(CHART_UUID);
183
184
  const mainChartBoundsProvider = () => this.canvasBoundsContainer.getBounds(chartPaneId);
184
185
  this.registerDataSeriesTypeDrawer('LINEAR', new LinearDrawer());
186
+ this.registerDataSeriesTypeDrawer('LINEAR_TREND', new LinearTrendDrawer());
185
187
  this.registerDataSeriesTypeDrawer('HISTOGRAM', new HistogramDrawer());
186
188
  this.registerDataSeriesTypeDrawer('TREND_HISTOGRAM', new TrendHistogramDrawer());
187
189
  this.registerDataSeriesTypeDrawer('POINTS', new PointsDrawer());
@@ -55,7 +55,7 @@ export declare class ChartModel extends ChartBaseElement {
55
55
  secondaryChartColors: SecondaryChartColorsPool;
56
56
  lastTimeFrame: TimeFrameRange;
57
57
  basicScaleViewportTransformer: (visualCandleSource: VisualCandle[], scaleOptions?: import("./basic-scale").BasicScaleOptions) => void;
58
- timeFrameViewportTransformer: (timeframe: [number, number], zoomIn?: boolean | null) => void;
58
+ timeFrameViewportTransformer: (timeframe: [Timestamp, Timestamp], zoomIn?: boolean | null) => void;
59
59
  private FAKE_CANDLES_DEFAULT;
60
60
  readonly pane: PaneComponent;
61
61
  constructor(chartBaseModel: ChartBaseModel<'candle'>, paneManager: PaneManager, bus: EventBus, canvasModel: CanvasModel, config: FullChartConfig, scale: ScaleModel, formatterFactory: (format: string) => (timestamp: number) => string, mainCanvasParent: Element, canvasBoundsContainer: CanvasBoundsContainer, chartResizeHandler: ChartResizeHandler);
@@ -14,3 +14,4 @@
14
14
  */
15
15
  export declare const TREASURY_32ND: number;
16
16
  export declare const treasuryPriceFormatter: (value: number) => string;
17
+ export declare const isTreasuryPriceFormat: (value: string) => boolean;
@@ -24,3 +24,4 @@ export const treasuryPriceFormatter = (value) => {
24
24
  const thirtySecondsFormatted = thirtySeconds.toString().padStart(2, '0');
25
25
  return `${integerValue}'${thirtySecondsFormatted}`;
26
26
  };
27
+ export const isTreasuryPriceFormat = (value) => Boolean(value.match(/^\-?0*(\d+)'(\d{2})$/));
@@ -6,7 +6,7 @@
6
6
  import { Observable, Subject } from 'rxjs';
7
7
  import { Unit } from '../../model/scaling/viewport.model';
8
8
  import { AnimationFrameCache } from '../../utils/performance/animation-frame-cache.utils';
9
- import { YAxisConfig } from '../../chart.config';
9
+ import { YAxisConfig, YAxisConfigTreasuryFormat } from '../../chart.config';
10
10
  export type PriceAxisType = 'regular' | 'percent' | 'logarithmic';
11
11
  export interface LabelsGenerator {
12
12
  readonly observeLabelsChanged: () => Observable<NumericAxisLabel[]>;
@@ -36,8 +36,8 @@ export declare class NumericAxisLabelsGenerator implements LabelsGenerator {
36
36
  newGeneratedLabelsSubject: Subject<NumericAxisLabel[]>;
37
37
  private lastStart;
38
38
  private lastEnd;
39
- private treasuryFormat;
40
- constructor(increment: number | null, startEndProvider: () => [Unit, Unit], lengthProvider: () => Unit, valueFormatter: (value: number) => string, withZero: boolean, axisTypeProvider: () => PriceAxisType, baseLineProvider: () => number, labelFilter?: (labels: NumericAxisLabel[]) => NumericAxisLabel[], singleLabelHeightPixels?: number, yAxisConfig?: YAxisConfig | undefined);
39
+ protected treasuryFormat: YAxisConfigTreasuryFormat | undefined;
40
+ constructor(increment: number | null, startEndProvider: () => [Unit, Unit], lengthProvider: () => Unit, valueFormatter: (value: number) => string, withZero: boolean | undefined, axisTypeProvider: () => PriceAxisType, baseLineProvider: () => number, labelFilter?: (labels: NumericAxisLabel[]) => NumericAxisLabel[], singleLabelHeightPixels?: number, yAxisConfig?: YAxisConfig | undefined);
41
41
  private generateRegularLabels;
42
42
  private generatePercentLabels;
43
43
  private generateLogarithmLabels;
@@ -154,19 +154,17 @@ export class NumericAxisLabelsGenerator {
154
154
  return this.adjustIncrementOnAxisType(DEFAULT_REGULAR_INCREMENT);
155
155
  }
156
156
  adjustIncrementOnAxisType(increment) {
157
- var _a;
158
- const calculatedIncrement = ((_a = this.treasuryFormat) === null || _a === void 0 ? void 0 : _a.enabled) ? TREASURY_32ND : increment;
159
157
  switch (this.axisTypeProvider()) {
160
158
  case 'percent':
161
159
  return increment;
162
160
  case 'logarithmic':
163
161
  const [logMin] = this.calculateMinMax();
164
162
  const regularMin = logValueToUnit(logMin);
165
- const regularIncrementedValue = regularMin + calculatedIncrement;
163
+ const regularIncrementedValue = regularMin + increment;
166
164
  const incrementedLogValue = calcLogValue(regularIncrementedValue);
167
165
  return incrementedLogValue - logMin;
168
166
  case 'regular':
169
- return calculatedIncrement;
167
+ return increment;
170
168
  }
171
169
  }
172
170
  // TODO rework, generator should act as model and update itself on scaleChanged
@@ -74,7 +74,7 @@ export declare class YExtentComponent extends ChartBaseElement {
74
74
  */
75
75
  removeDataSeries(series: DataSeriesModel): void;
76
76
  valueFormatter: (value: Unit, dataSeries?: DataSeriesModel) => string;
77
- get regularFormatter(): (value: number, precision?: number | undefined) => string;
77
+ get regularFormatter(): (value: number, precision?: number) => string;
78
78
  /**
79
79
  * Sets the pane value formatters for the current instance.
80
80
  * @param {YExtentFormatters} formatters - The pane value formatters to be set.
@@ -3,7 +3,12 @@
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
+ /*
7
+ * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited
8
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
9
+ * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
10
+ */
11
+ import { CanvasElement, CHART_UUID } from '../../../canvas/canvas-bounds-container';
7
12
  import { ChartBaseElement } from '../../../model/chart-base-element';
8
13
  import { DataSeriesModel, VisualSeriesPoint, defaultValueFormatter, } from '../../../model/data-series.model';
9
14
  import { mergeHighLow } from '../../../model/scaling/auto-scale.model';
@@ -93,6 +98,11 @@ export class YExtentComponent extends ChartBaseElement {
93
98
  if (this.dataSeries.size === 1) {
94
99
  this.mainDataSeries = series;
95
100
  }
101
+ else if (this.paneComponent.yExtentComponents.length > 1 && this.paneUUID !== CHART_UUID) {
102
+ this.mainDataSeries = series;
103
+ const ds = Array.from(this.paneComponent.mainExtent.dataSeries);
104
+ this.paneComponent.mainExtent.mainDataSeries = ds[ds.length - 1];
105
+ }
96
106
  this.paneComponent.updateView();
97
107
  this.paneComponent.seriesAddedSubject.next(series);
98
108
  }
@@ -54,7 +54,7 @@ export declare class PaneComponent extends ChartBaseElement {
54
54
  yExtentComponentsChangedSubject: Subject<void>;
55
55
  get scale(): ScaleModel;
56
56
  get yAxis(): YAxisComponent;
57
- get dataSeries(): DataSeriesModel<import("../../model/data-series.model").DataSeriesPoint, import("../../model/data-series.model").VisualSeriesPoint>[];
57
+ get dataSeries(): DataSeriesModel<import("../../model/data-series.model").DataSeriesPoint, import("../../model/data-series.model").VisualSeriesPoint, import("../../model/data-series.config").DataSeriesConfig>[];
58
58
  get visible(): boolean;
59
59
  mainExtent: YExtentComponent;
60
60
  constructor(chartBaseModel: ChartBaseModel<'candle'>, mainCanvasModel: CanvasModel, yAxisLabelsCanvasModel: CanvasModel, dynamicObjectsCanvasModel: CanvasModel, hitTestController: PaneHitTestController, config: FullChartConfig, mainScale: ScaleModel, drawingManager: DrawingManager, chartPanComponent: ChartPanComponent, canvasInputListener: CanvasInputListenerComponent, canvasAnimation: CanvasAnimation, cursorHandler: CursorHandler, eventBus: EventBus, canvasBoundsContainer: CanvasBoundsContainer, uuid: string, seriesAddedSubject: Subject<DataSeriesModel>, seriesRemovedSubject: Subject<DataSeriesModel>, hitTestCanvasModel: HitTestCanvasModel, chartResizeHandler: ChartResizeHandler, options?: AtLeastOne<YExtentCreationOptions>);
@@ -160,7 +160,7 @@ export declare class PaneComponent extends ChartBaseElement {
160
160
  */
161
161
  canMoveDown(): boolean;
162
162
  valueFormatter: (value: Unit, dataSeries?: DataSeriesModel) => string;
163
- get regularFormatter(): (value: number, precision?: number | undefined) => string;
163
+ get regularFormatter(): (value: number, precision?: number) => string;
164
164
  /**
165
165
  * Sets the pane value formatters for the current instance.
166
166
  * @param {YExtentFormatters} formatters - The pane value formatters to be set.
@@ -6,7 +6,7 @@
6
6
  import { ChartBaseElement } from '../../model/chart-base-element';
7
7
  import { createCandlesOffsetProvider } from '../chart/data-series.high-low-provider';
8
8
  import { volumeFormatter } from './volumes.formatter';
9
- class SeparateVolumesComponent extends ChartBaseElement {
9
+ export class SeparateVolumesComponent extends ChartBaseElement {
10
10
  constructor(chartComponent, config, volumesModel, paneManager) {
11
11
  super();
12
12
  this.chartComponent = chartComponent;
@@ -64,4 +64,3 @@ class SeparateVolumesComponent extends ChartBaseElement {
64
64
  }
65
65
  }
66
66
  SeparateVolumesComponent.UUID = 'volumes';
67
- export { SeparateVolumesComponent };
@@ -27,7 +27,7 @@ export interface ParsedNCTimeFormat {
27
27
  }
28
28
  export type ParsedTimeFormat = ParsedCTimeFormat | ParsedWeekFormat | ParsedNCTimeFormat;
29
29
  export type SpecialSymbol = '!' | '$';
30
- export declare const timeFormatConfirugableGuard: (key: string) => key is "year" | "month" | "day" | "hour" | "minute" | "second";
31
- export declare const weekWeekdayGuard: (key: string) => key is "week-weekday";
32
- export declare const timeFormatNoNConfirugableGuard: (key: string) => key is "lessThanSecond";
30
+ export declare const timeFormatConfirugableGuard: (key: string) => key is TimeFormatConfirugableType;
31
+ export declare const weekWeekdayGuard: (key: string) => key is TimeFormatWeekWeekdayType;
32
+ export declare const timeFormatNoNConfirugableGuard: (key: string) => key is TimeFormatNonConfirugableType;
33
33
  export {};
@@ -18,7 +18,7 @@ export interface XAxisLabelsGenerator {
18
18
  /**
19
19
  * Generates x-axis labels from scratch. Heavy operation.
20
20
  */
21
- generateLabels(prependedCandles?: VisualCandle[]): void;
21
+ generateLabels(prependedCandles?: VisualCandle[], generateFromCache?: boolean): void;
22
22
  /**
23
23
  * Updates current labels state (x-position). Lightweight operation.
24
24
  */
@@ -53,6 +53,7 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
53
53
  private labelsGroupedByWeight;
54
54
  private weightedCache?;
55
55
  private levelsCache;
56
+ private labelCache;
56
57
  get labels(): XAxisLabelWeighted[];
57
58
  private formatsByWeightMap;
58
59
  private weightToTimeFormatMatcherArray;
@@ -61,9 +62,9 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
61
62
  constructor(eventBus: EventBus, config: FullChartConfig, chartModel: ChartModel, scale: ScaleModel, timeZoneModel: TimeZoneModel, canvasModel: CanvasModel, canvasBoundsContainer: CanvasBoundsContainer);
62
63
  private filterLabelsInViewport;
63
64
  private getLabelsFromChartType;
64
- /**
65
- * Make a prediction(750) about how many candles we need to fake to fill all X axis by labels
66
- */
65
+ private getVisualCandleAtIndex;
66
+ private getVisualCandlesWithFake;
67
+ private getViewportCandlesWithFake;
67
68
  private getAllCandlesWithFake;
68
69
  /**
69
70
  * Maps an array of weighted points to an array of XAxisLabelWeighted objects.
@@ -78,13 +79,6 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
78
79
  * @returns {void}
79
80
  */
80
81
  setFormatsForLabelsConfig(newFormatsByWeightMap: Record<TimeFormatWithDuration, string>): void;
81
- /**
82
- * Generates weighted labels based on allCandlesWithFake, weightToTimeFormatMatcherDict and timeZoneModel.
83
- * @private
84
- * @function
85
- * @returns {void}
86
- */
87
- private generateWeightedLabels;
88
82
  /**
89
83
  * Retrieves the labels from the cache for a given coverUpLevel.
90
84
  * @param {number} coverUpLevel - The coverUpLevel to retrieve the labels from the cache.
@@ -104,10 +98,10 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
104
98
  */
105
99
  updateHistoryLabels(candles: VisualCandle[]): void;
106
100
  /**
107
- * Calls the method generateWeightedLabels to generate labels.
101
+ * Generates labels based on allCandlesWithFake, weightToTimeFormatMatcherDict and timeZoneModel.
108
102
  * @returns {void}
109
103
  */
110
- generateLabels(prependedCandles?: VisualCandle[]): void;
104
+ generateLabels(prependedCandles?: VisualCandle[], generateFromCache?: boolean): void;
111
105
  /**
112
106
  * Recalculates the labels by calling the method recalculateCachedLabels.
113
107
  * @returns {void}
@@ -146,4 +140,5 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
146
140
  * @returns {Record<number, XAxisLabelWeighted[]>} - Object containing the filtered labels grouped by weight.
147
141
  */
148
142
  private filterLabelsByExtendedRules;
143
+ private clearLabelCache;
149
144
  }
@@ -24,6 +24,7 @@ export class XAxisTimeLabelsGenerator {
24
24
  this.canvasBoundsContainer = canvasBoundsContainer;
25
25
  this.labelsGroupedByWeight = {};
26
26
  this.levelsCache = {};
27
+ this.labelCache = new Map();
27
28
  this.weightToTimeFormatMatcherArray = [];
28
29
  this.weightToTimeFormatsDict = {};
29
30
  this.extendedLabelsFilterConfig = {
@@ -83,10 +84,14 @@ export class XAxisTimeLabelsGenerator {
83
84
  return labels;
84
85
  }
85
86
  }
86
- /**
87
- * Make a prediction(750) about how many candles we need to fake to fill all X axis by labels
88
- */
89
- getAllCandlesWithFake(prependedCandles = []) {
87
+ getVisualCandleAtIndex(idx, dataPoints, visualPoints, meanCandleWidth, period) {
88
+ if (idx >= 0 && idx < visualPoints.length) {
89
+ return visualPoints[idx];
90
+ }
91
+ // generate fake candle for out-of-range index
92
+ return fakeVisualCandle(dataPoints, visualPoints, meanCandleWidth, idx, period);
93
+ }
94
+ getVisualCandlesWithFake(prependedCandles = []) {
90
95
  const visualCandles = this.chartModel.mainCandleSeries.visualPoints;
91
96
  if (visualCandles.length === 0) {
92
97
  return [];
@@ -95,6 +100,53 @@ export class XAxisTimeLabelsGenerator {
95
100
  const appendFakeCandle = fakeCandlesForSides.map((_, idx) => fakeVisualCandle(this.chartModel.mainCandleSeries.dataPoints, this.chartModel.mainCandleSeries.visualPoints, this.chartModel.mainCandleSeries.meanCandleWidth, visualCandles.length + idx, this.chartModel.getPeriod()));
96
101
  return [...prependedCandles, ...visualCandles, ...appendFakeCandle];
97
102
  }
103
+ getViewportCandlesWithFake() {
104
+ var _a;
105
+ const visualCandles = this.chartModel.mainCandleSeries.visualPoints;
106
+ if (visualCandles.length === 0 || this.scale.xEnd - this.scale.xStart <= 1) {
107
+ return [];
108
+ }
109
+ const meanCandleWidth = this.chartModel.mainCandleSeries.meanCandleWidth;
110
+ const period = this.chartModel.getPeriod();
111
+ const dataPoints = this.chartModel.mainCandleSeries.dataPoints;
112
+ // calculate visible pixel range for the chart area
113
+ const bounds = this.canvasBoundsContainer.getBounds(CanvasElement.CHART);
114
+ const leftPx = 0;
115
+ const rightPx = bounds.width;
116
+ // convert to units
117
+ const leftUnit = this.scale.fromX(leftPx);
118
+ const rightUnit = this.scale.fromX(rightPx);
119
+ // anchor everything to index 0 (absolute index)
120
+ // find the X position of index 0 (anchor)
121
+ let anchorX = 0;
122
+ if (visualCandles.length > 0) {
123
+ // if we have visible candles, use the X of the first visible candle at its idx
124
+ const firstVisible = visualCandles[0];
125
+ anchorX = firstVisible.centerUnit - ((_a = firstVisible.candle.idx) !== null && _a !== void 0 ? _a : 0) * meanCandleWidth;
126
+ }
127
+ // buffer is needed to to avoid empty space when moving viewport
128
+ const buffer = 500;
129
+ // allows to round labels better
130
+ const modulus = 500;
131
+ // use anchorX and meanCandleWidth to map units to indices
132
+ const rawFirstIdx = Math.floor((leftUnit - anchorX) / meanCandleWidth) - buffer;
133
+ const rawLastIdx = Math.ceil((rightUnit - anchorX) / meanCandleWidth) + buffer;
134
+ const firstIdx = Math.floor(rawFirstIdx / modulus) * modulus;
135
+ const lastIdx = Math.ceil(rawLastIdx / modulus) * modulus;
136
+ const allCandles = [];
137
+ for (let idx = firstIdx; idx <= lastIdx; idx++) {
138
+ allCandles.push(this.getVisualCandleAtIndex(idx, dataPoints, visualCandles, meanCandleWidth, period));
139
+ }
140
+ return [...allCandles];
141
+ }
142
+ getAllCandlesWithFake(prependedCandles = []) {
143
+ if (this.config.components.chart.minCandlesOffset) {
144
+ return this.getVisualCandlesWithFake(prependedCandles);
145
+ }
146
+ else {
147
+ return this.getViewportCandlesWithFake();
148
+ }
149
+ }
98
150
  /**
99
151
  * Maps an array of weighted points to an array of XAxisLabelWeighted objects.
100
152
  * @param {WeightedPoint[]} weightedPoints - An array of weighted points to be mapped.
@@ -125,28 +177,14 @@ export class XAxisTimeLabelsGenerator {
125
177
  * @returns {void}
126
178
  */
127
179
  setFormatsForLabelsConfig(newFormatsByWeightMap) {
180
+ this.clearLabelCache();
128
181
  const { weightToTimeFormatsDict, weightToTimeFormatMatcherDict } = generateWeightsMapForConfig(newFormatsByWeightMap);
129
182
  this.formatsByWeightMap = newFormatsByWeightMap;
130
183
  this.weightToTimeFormatMatcherArray = Object.entries(weightToTimeFormatMatcherDict)
131
184
  .map(([k, v]) => [parseInt(k, 10), v])
132
185
  .sort(([a], [b]) => b - a);
133
186
  this.weightToTimeFormatsDict = weightToTimeFormatsDict;
134
- this.generateWeightedLabels();
135
- }
136
- /**
137
- * Generates weighted labels based on allCandlesWithFake, weightToTimeFormatMatcherDict and timeZoneModel.
138
- * @private
139
- * @function
140
- * @returns {void}
141
- */
142
- generateWeightedLabels(prependedCandles = []) {
143
- const allCandlesWithFake = this.getAllCandlesWithFake(prependedCandles);
144
- const weightedPoints = mapCandlesToWeightedPoints(allCandlesWithFake, this.weightToTimeFormatMatcherArray, this.timeZoneModel.tzOffset(this.config.timezone));
145
- const weightedLabels = this.mapWeightedPointsToLabels(weightedPoints, allCandlesWithFake);
146
- this.labelsGroupedByWeight = groupLabelsByWeight(weightedLabels);
147
- this.weightedCache = undefined;
148
- this.levelsCache = {};
149
- this.recalculateCachedLabels();
187
+ this.generateLabels();
150
188
  }
151
189
  /**
152
190
  * Retrieves the labels from the cache for a given coverUpLevel.
@@ -250,11 +288,34 @@ export class XAxisTimeLabelsGenerator {
250
288
  this.recalculateCachedLabels();
251
289
  }
252
290
  /**
253
- * Calls the method generateWeightedLabels to generate labels.
291
+ * Generates labels based on allCandlesWithFake, weightToTimeFormatMatcherDict and timeZoneModel.
254
292
  * @returns {void}
255
293
  */
256
- generateLabels(prependedCandles) {
257
- this.generateWeightedLabels(prependedCandles);
294
+ generateLabels(prependedCandles, generateFromCache = false) {
295
+ var _a;
296
+ const allCandlesWithFake = this.getAllCandlesWithFake(prependedCandles);
297
+ const weightedPoints = mapCandlesToWeightedPoints(allCandlesWithFake, this.weightToTimeFormatMatcherArray, this.timeZoneModel.tzOffset(this.config.timezone));
298
+ let weightedLabels = [];
299
+ if (generateFromCache) {
300
+ for (let i = 0; i < allCandlesWithFake.length; i++) {
301
+ const idx = (_a = allCandlesWithFake[i].candle.idx) !== null && _a !== void 0 ? _a : i;
302
+ const ts = allCandlesWithFake[i].candle.timestamp;
303
+ const cacheKey = `${idx}_${ts}`;
304
+ let label = this.labelCache.get(cacheKey);
305
+ if (!label) {
306
+ label = this.mapWeightedPointsToLabels([weightedPoints[i]], [allCandlesWithFake[i]])[0];
307
+ this.labelCache.set(cacheKey, label);
308
+ }
309
+ weightedLabels.push(label);
310
+ }
311
+ }
312
+ else {
313
+ weightedLabels = this.mapWeightedPointsToLabels(weightedPoints, allCandlesWithFake);
314
+ }
315
+ this.labelsGroupedByWeight = groupLabelsByWeight(weightedLabels);
316
+ this.weightedCache = undefined;
317
+ this.levelsCache = {};
318
+ this.recalculateCachedLabels();
258
319
  }
259
320
  /**
260
321
  * Recalculates the labels by calling the method recalculateCachedLabels.
@@ -362,4 +423,7 @@ export class XAxisTimeLabelsGenerator {
362
423
  return acc;
363
424
  }, {});
364
425
  }
426
+ clearLabelCache() {
427
+ this.labelCache.clear();
428
+ }
365
429
  }
@@ -76,11 +76,18 @@ export class XAxisComponent extends ChartBaseElement {
76
76
  (_b = (_a = this.xAxisLabelsGenerator).updateHistoryLabels) === null || _b === void 0 ? void 0 : _b.call(_a, newCandles);
77
77
  }
78
78
  }));
79
- this.addRxSubscription(merge(this.scale.xChanged, this.chartResizeHandler.canvasResized)
80
- .pipe(throttleTime(50, animationFrameScheduler, { trailing: true, leading: true }))
81
- .subscribe(() => {
82
- this.xAxisLabelsGenerator.recalculateLabels();
83
- }));
79
+ // recalculate existing ones, the number of labels is static
80
+ if (this.config.components.chart.minCandlesOffset) {
81
+ this.addRxSubscription(merge(this.scale.xChanged, this.chartResizeHandler.canvasResized)
82
+ .pipe(throttleTime(50, animationFrameScheduler, { trailing: true, leading: true }))
83
+ .subscribe(() => this.xAxisLabelsGenerator.recalculateLabels()));
84
+ // generate visible viewport range labels (real and fake candles), the number of labels is dynamic
85
+ }
86
+ else {
87
+ this.addRxSubscription(merge(this.scale.xChanged, this.chartResizeHandler.canvasResized)
88
+ .pipe(throttleTime(150, animationFrameScheduler, { trailing: true, leading: true }))
89
+ .subscribe(() => this.xAxisLabelsGenerator.generateLabels(undefined, true)));
90
+ }
84
91
  this.addRxSubscription(this.chartComponent.chartModel.candlesUpdatedSubject
85
92
  .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
93
  .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); }));
@@ -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 { YAxisConfig } from '../../chart.config';
6
+ import { YAxisConfig, YAxisConfigTreasuryFormat } from '../../chart.config';
7
7
  import { DataSeriesModel } from '../../model/data-series.model';
8
8
  import { ViewportModel } from '../../model/scaling/viewport.model';
9
9
  import { NumericAxisLabelsGenerator, PriceAxisType } from '../labels_generator/numeric-axis-labels.generator';
@@ -14,6 +14,7 @@ export declare class NumericYAxisLabelsGenerator extends NumericAxisLabelsGenera
14
14
  private dataSeriesProvider;
15
15
  constructor(increment: number | null, dataSeriesProvider: () => DataSeriesModel | undefined, viewportModel: ViewportModel, valueFormatter: (value: number) => string, axisTypeProvider: (() => PriceAxisType) | undefined, singleLabelHeightPixels: number | undefined, config: YAxisConfig);
16
16
  getLargestLabel(): string;
17
+ updateTreasuryFormat(treasuryFormat: YAxisConfigTreasuryFormat): void;
17
18
  /**
18
19
  * Calculates the increment to be used on the chart axis based on the length of the value and the instrument's price increments.
19
20
  * @param {number} valueLength - The length of the value.
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { lastOf } from '../../utils/array.utils';
7
7
  import { precisionsToIncrement } from '../../utils/price-increments.utils';
8
+ import { TREASURY_32ND } from '../chart/price-formatters/treasury-price.formatter';
8
9
  import { NumericAxisLabelsGenerator } from '../labels_generator/numeric-axis-labels.generator';
9
10
  /**
10
11
  * Y axis labels generator for prices. Respects price increment from instrument.
@@ -18,19 +19,23 @@ export class NumericYAxisLabelsGenerator extends NumericAxisLabelsGenerator {
18
19
  var _a;
19
20
  return ((_a = this.labelsCache.getLastCachedValue()) !== null && _a !== void 0 ? _a : []).reduce((maxLengthText, label) => (label.text.length > maxLengthText.length ? label.text : maxLengthText), '');
20
21
  }
22
+ updateTreasuryFormat(treasuryFormat) {
23
+ this.treasuryFormat = treasuryFormat;
24
+ }
21
25
  /**
22
26
  * Calculates the increment to be used on the chart axis based on the length of the value and the instrument's price increments.
23
27
  * @param {number} valueLength - The length of the value.
24
28
  * @returns {number} - The calculated increment.
25
29
  */
26
30
  calculateIncrement(valueLength) {
27
- var _a;
31
+ var _a, _b;
28
32
  const dataSeries = this.dataSeriesProvider();
29
33
  if (dataSeries) {
30
34
  const lastCandle = lastOf(dataSeries.dataPoints);
31
35
  const priceIncrementBasis = (_a = lastCandle === null || lastCandle === void 0 ? void 0 : lastCandle.close) !== null && _a !== void 0 ? _a : 0;
32
36
  const increment = precisionsToIncrement(priceIncrementBasis, dataSeries.pricePrecisions);
33
- return this.adjustIncrementOnAxisType(increment);
37
+ const calculatedIncrement = ((_b = this.treasuryFormat) === null || _b === void 0 ? void 0 : _b.enabled) ? TREASURY_32ND : increment;
38
+ return this.adjustIncrementOnAxisType(calculatedIncrement);
34
39
  }
35
40
  // auto-generated increment
36
41
  return super.calculateIncrement(valueLength);
@@ -21,4 +21,4 @@ export declare class DifferenceCloudDrawer implements SeriesDrawer {
21
21
  protected fillCloud(ctx: CanvasRenderingContext2D, color: string, linePoints: Point[], nextLinePoints: Point[], hitTestDrawerConfig: HTSeriesDrawerConfig): void;
22
22
  protected mapDataSeriesDiffPointsIntoPoints(points: VisualSeriesPoint[], view: Viewable): Point[];
23
23
  }
24
- export declare const isDifferenceTool: (type: string) => boolean;
24
+ export declare const isDifferenceTool: (type: string) => type is "DIFFERENCE";
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 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 { DataSeriesModel, VisualSeriesPoint } from '../../model/data-series.model';
7
+ import { HTSeriesDrawerConfig, SeriesDrawer } from '../data-series.drawer';
8
+ export declare class LinearTrendDrawer implements SeriesDrawer {
9
+ constructor();
10
+ draw(ctx: CanvasRenderingContext2D, allPoints: VisualSeriesPoint[][], model: DataSeriesModel, hitTestDrawerConfig: HTSeriesDrawerConfig): void;
11
+ }
12
+ export declare const getPreviousValue: (arr: VisualSeriesPoint[], idx: number) => VisualSeriesPoint | undefined;
@@ -0,0 +1,42 @@
1
+ /*
2
+ * Copyright (C) 2019 - 2025 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 { flat } from '../../utils/array.utils';
7
+ import { setLineWidth } from '../data-series.drawer';
8
+ export class LinearTrendDrawer {
9
+ constructor() { }
10
+ draw(ctx, allPoints, model, hitTestDrawerConfig) {
11
+ const allPointsFlat = flat(allPoints);
12
+ const config = model.getPaintConfig(0);
13
+ setLineWidth(ctx, config.lineWidth, model, hitTestDrawerConfig, config.hoveredLineWidth);
14
+ ctx.lineCap = 'round';
15
+ allPointsFlat.forEach((point, idx) => {
16
+ var _a, _b;
17
+ const previousValue = getPreviousValue(allPointsFlat, idx) || allPointsFlat[0];
18
+ const isNegativeTrend = previousValue && point.close < previousValue.close;
19
+ if (((_a = config.multiplyColors) === null || _a === void 0 ? void 0 : _a.length) === 2) {
20
+ ctx.strokeStyle =
21
+ (_b = hitTestDrawerConfig.color) !== null && _b !== void 0 ? _b : ((isNegativeTrend ? config.multiplyColors[1] : config.multiplyColors[0]) ||
22
+ config.color ||
23
+ '#FF00FF');
24
+ const x = model.view.toX(point.centerUnit);
25
+ const y = model.view.toY(point.close);
26
+ const prevX = model.view.toX(previousValue.centerUnit);
27
+ const prevY = model.view.toY(previousValue.close);
28
+ ctx.beginPath();
29
+ ctx.moveTo(prevX, prevY);
30
+ ctx.lineTo(x, y);
31
+ ctx.stroke();
32
+ return;
33
+ }
34
+ });
35
+ }
36
+ }
37
+ export const getPreviousValue = (arr, idx) => {
38
+ do {
39
+ idx--;
40
+ } while (idx >= 0 && !isFinite(arr[idx] && arr[idx].close));
41
+ return arr[idx] ? arr[idx] : undefined;
42
+ };
@@ -27,7 +27,7 @@ export interface BaseHover {
27
27
  }
28
28
  export interface HoverParts {
29
29
  readonly candleHover: CandleHover | undefined;
30
- readonly compareSeriesHover: CompareSeriesHover[];
30
+ readonly compareSeriesHover: CompareSeriesHover[] | undefined;
31
31
  [key: string]: unknown;
32
32
  }
33
33
  export interface Hover extends BaseHover, HoverParts {
@@ -19,7 +19,7 @@ import { deviceDetector } from '../utils/device/device-detector.utils';
19
19
  * - zooming (wheel event)
20
20
  * - touch start and move
21
21
  */
22
- class CanvasInputListenerComponent extends ChartBaseElement {
22
+ export class CanvasInputListenerComponent extends ChartBaseElement {
23
23
  constructor(eventBus, element) {
24
24
  super();
25
25
  this.eventBus = eventBus;
@@ -652,4 +652,3 @@ class CanvasInputListenerComponent extends ChartBaseElement {
652
652
  CanvasInputListenerComponent.DRAG_START_EVENTS = ['mousedown', 'touchstart'];
653
653
  CanvasInputListenerComponent.DRAG_EVENTS = ['mousemove', 'touchmove'];
654
654
  CanvasInputListenerComponent.DRAG_END_EVENTS = ['mouseup', 'touchend', 'touchcancel'];
655
- export { CanvasInputListenerComponent };
@@ -31,7 +31,7 @@ export declare class DataSeriesView implements Viewable {
31
31
  * @param getBaseline - A function that returns the baseline for percent.
32
32
  * @returns - The converted value in the corresponding unit.
33
33
  */
34
- toAxisUnits(value: Price, getBaseline?: (idx?: number | undefined) => number): Unit;
34
+ toAxisUnits(value: Price, getBaseline?: (idx?: Index) => Unit): Unit;
35
35
  /**
36
36
  * Convert the input unit to its corresponding x-pixel coordinate based on the scale model.
37
37
  * @param unit - The unit to be converted to x-pixel coordinate.