@devexperts/dxcharts-lite 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chart/bootstrap.js +4 -3
- package/dist/chart/canvas/canvas-bounds-container.js +5 -3
- package/dist/chart/canvas/cursor.handler.js +2 -2
- package/dist/chart/components/chart/chart-area-pan.handler.js +3 -3
- package/dist/chart/components/chart/chart.component.d.ts +6 -3
- package/dist/chart/components/chart/chart.component.js +18 -7
- package/dist/chart/components/chart/chart.model.d.ts +1 -2
- package/dist/chart/components/chart/chart.model.js +2 -3
- package/dist/chart/components/cross_tool/types/cross-and-labels.drawer.js +4 -2
- package/dist/chart/components/high_low/high-low.drawer.js +9 -2
- package/dist/chart/components/highlights/highlights.drawer.js +1 -1
- package/dist/chart/components/pane/pane.component.js +6 -3
- package/dist/chart/components/volumes/volumes.drawer.js +1 -1
- package/dist/chart/components/x_axis/time/parser/time-formats-matchers.functions.js +1 -1
- package/dist/chart/components/x_axis/time/parser/time-formats.model.d.ts +1 -1
- package/dist/chart/components/x_axis/time/x-axis-weights.functions.js +2 -2
- package/dist/chart/components/x_axis/time/x-axis-weights.generator.js +6 -7
- package/dist/chart/components/x_axis/x-axis-labels.generator.d.ts +11 -3
- package/dist/chart/components/x_axis/x-axis-labels.generator.js +47 -19
- package/dist/chart/components/x_axis/x-axis-time-labels.drawer.js +0 -4
- package/dist/chart/components/x_axis/x-axis.component.js +7 -11
- package/dist/chart/components/y_axis/price_labels/last-candle-labels.provider.js +5 -5
- package/dist/chart/components/y_axis/price_labels/price-label.drawer.js +21 -22
- package/dist/chart/components/y_axis/y-axis-labels.drawer.d.ts +18 -6
- package/dist/chart/components/y_axis/y-axis-labels.drawer.js +23 -12
- package/dist/chart/components/y_axis/y-axis-scale.handler.d.ts +4 -0
- package/dist/chart/components/y_axis/y-axis-scale.handler.js +13 -6
- package/dist/chart/components/y_axis/y-axis.drawer.js +1 -1
- package/dist/chart/drawers/chart-background.drawer.d.ts +2 -3
- package/dist/chart/drawers/chart-background.drawer.js +16 -22
- package/dist/chart/drawers/data-series-drawers/candle-series-wrapper.js +1 -1
- package/dist/chart/drawers/data-series.drawer.d.ts +0 -2
- package/dist/chart/drawers/data-series.drawer.js +1 -6
- package/dist/chart/drawers/ht-data-series.drawer.js +1 -1
- package/dist/chart/inputhandlers/hover-producer.component.d.ts +1 -1
- package/dist/chart/model/compare-series-hover.d.ts +1 -1
- package/dist/chart/model/compare-series-hover.js +5 -0
- package/dist/chart/model/data-series.model.js +1 -1
- package/dist/chart/model/hit-test-canvas.model.js +2 -2
- package/dist/chart/model/scale.model.d.ts +3 -1
- package/dist/chart/model/scale.model.js +23 -4
- package/dist/chart/model/scaling/viewport.model.d.ts +2 -0
- package/dist/chart/model/scaling/viewport.model.js +13 -4
- package/dist/chart/model/time-zone.model.d.ts +0 -14
- package/dist/chart/model/time-zone.model.js +13 -33
- package/dist/chart/utils/canvas/canvas-drawing-functions.utils.d.ts +12 -1
- package/dist/chart/utils/canvas/canvas-drawing-functions.utils.js +16 -1
- package/dist/chart/utils/canvas/canvas-text-functions.utils.d.ts +3 -2
- package/dist/chart/utils/canvas/canvas-text-functions.utils.js +8 -3
- package/dist/chart/utils/math.utils.d.ts +1 -0
- package/dist/chart/utils/math.utils.js +3 -0
- package/dist/chart/utils/timezone.utils.d.ts +13 -0
- package/dist/chart/utils/timezone.utils.js +48 -0
- package/dist/dxchart.min.js +6 -6
- package/package.json +1 -2
package/dist/chart/bootstrap.js
CHANGED
|
@@ -106,8 +106,9 @@ export default class ChartBootstrap {
|
|
|
106
106
|
// canvas animation container
|
|
107
107
|
const canvasAnimation = new CanvasAnimation(eventBus);
|
|
108
108
|
this.canvasAnimation = canvasAnimation;
|
|
109
|
+
const chartPaneId = CanvasElement.PANE_UUID(CHART_UUID);
|
|
109
110
|
//#region ScaleModel init
|
|
110
|
-
const scaleModel = new ScaleModel(config, () => canvasBoundsContainer.getBounds(
|
|
111
|
+
const scaleModel = new ScaleModel(config, () => canvasBoundsContainer.getBounds(chartPaneId), canvasAnimation);
|
|
111
112
|
this.scaleModel = scaleModel;
|
|
112
113
|
//#endregion
|
|
113
114
|
const backgroundCanvasModel = createCanvasModel(eventBus, elements.backgroundCanvas, config, drawingManager, this.canvasModels, elements.chartResizer, {
|
|
@@ -135,7 +136,7 @@ export default class ChartBootstrap {
|
|
|
135
136
|
this.chartComponents.push(this.dynamicObjects);
|
|
136
137
|
this.chartModel = new ChartModel(chartBaseModel, paneManager, eventBus, this.dynamicObjectsCanvasModel, config, scaleModel, formatterFactory, mainCanvasParent, canvasBoundsContainer, chartResizeHandler);
|
|
137
138
|
//#region main chart component init
|
|
138
|
-
const chartComponent = new ChartComponent(this.chartModel, this.dynamicObjectsCanvasModel, config, scaleModel, canvasBoundsContainer, drawingManager, hitTestCanvasModel, canvasInputListener, backgroundCanvasModel, chartPanComponent, paneManager, this.cursorHandler, this.dynamicObjects);
|
|
139
|
+
const chartComponent = new ChartComponent(this.chartModel, this.dynamicObjectsCanvasModel, config, scaleModel, canvasBoundsContainer, drawingManager, hitTestCanvasModel, canvasInputListener, backgroundCanvasModel, chartPanComponent, paneManager, this.cursorHandler, this.dynamicObjects, this.chartResizeHandler);
|
|
139
140
|
this.chartComponents.push(chartComponent);
|
|
140
141
|
this.chartComponent = chartComponent;
|
|
141
142
|
const chartModel = this.chartComponent.chartModel;
|
|
@@ -175,7 +176,7 @@ export default class ChartBootstrap {
|
|
|
175
176
|
this.volumesComponent = new VolumesComponent(this.dynamicObjectsCanvasModel, chartComponent, scaleModel, canvasBoundsContainer, drawingManager, config, paneManager, this.dynamicObjects);
|
|
176
177
|
this.chartComponents.push(this.volumesComponent);
|
|
177
178
|
// grid component
|
|
178
|
-
const mainChartGridComponent = new GridComponent(mainCanvasModel, scaleModel, config, this.yAxisComponent.state, 'GRID', drawingManager, () => this.canvasBoundsContainer.getBounds(CanvasElement.ALL_PANES), () => this.canvasBoundsContainer.getBounds(
|
|
179
|
+
const mainChartGridComponent = new GridComponent(mainCanvasModel, scaleModel, config, this.yAxisComponent.state, 'GRID', drawingManager, () => this.canvasBoundsContainer.getBounds(CanvasElement.ALL_PANES), () => this.canvasBoundsContainer.getBounds(chartPaneId), () => this.xAxisComponent.xAxisLabelsGenerator.labels, () => this.yAxisComponent.model.baseLabelsModel.labels, () => mainPane.mainExtent.toY(mainPane.mainExtent.getBaseline()), () => config.components.grid.visible);
|
|
179
180
|
this.chartComponents.push(mainChartGridComponent);
|
|
180
181
|
this.hoverProducer = new HoverProducerComponent(this.crossEventProducer, scaleModel, config, chartModel, canvasInputListener, this.canvasBoundsContainer, this.paneManager, timeZoneModel, formatterFactory);
|
|
181
182
|
this.chartComponents.push(this.hoverProducer);
|
|
@@ -565,10 +565,12 @@ export class CanvasBoundsContainer {
|
|
|
565
565
|
* @return {Bounds} bounds of element
|
|
566
566
|
*/
|
|
567
567
|
getBounds(el) {
|
|
568
|
-
|
|
569
|
-
|
|
568
|
+
let bounds = this.bounds[el];
|
|
569
|
+
if (bounds === undefined) {
|
|
570
|
+
bounds = this.copyOf(DEFAULT_BOUNDS);
|
|
571
|
+
this.bounds[el] = bounds;
|
|
570
572
|
}
|
|
571
|
-
return
|
|
573
|
+
return bounds;
|
|
572
574
|
}
|
|
573
575
|
/**
|
|
574
576
|
* Returns the position of CANVAS on whole page.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
4
4
|
* If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
5
|
*/
|
|
6
|
-
import { Subject } from 'rxjs';
|
|
6
|
+
import { Subject, animationFrameScheduler } from 'rxjs';
|
|
7
7
|
import { distinctUntilChanged, throttleTime } from 'rxjs/operators';
|
|
8
8
|
import { ChartBaseElement } from '../model/chart-base-element';
|
|
9
9
|
import { CanvasBoundsContainer } from './canvas-bounds-container';
|
|
@@ -29,7 +29,7 @@ export class CursorHandler extends ChartBaseElement {
|
|
|
29
29
|
super.doActivate();
|
|
30
30
|
this.canvasInputListener
|
|
31
31
|
.observeMouseMoveNoDrag()
|
|
32
|
-
.pipe(throttleTime(100,
|
|
32
|
+
.pipe(throttleTime(100, animationFrameScheduler, { trailing: true }))
|
|
33
33
|
.subscribe(point => {
|
|
34
34
|
const cursorFromHT = this.hitTestCanvasModel.resolveCursor(point);
|
|
35
35
|
if (cursorFromHT !== undefined) {
|
|
@@ -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 } from 'rxjs';
|
|
6
|
+
import { merge, animationFrameScheduler } from 'rxjs';
|
|
7
7
|
import { throttleTime } from 'rxjs/operators';
|
|
8
8
|
import { VIEWPORT_ANIMATION_ID } from '../../animation/canvas-animation';
|
|
9
9
|
import { CanvasElement } from '../../canvas/canvas-bounds-container';
|
|
@@ -112,7 +112,7 @@ export class ChartAreaPanHandler extends ChartBaseElement {
|
|
|
112
112
|
const allPanesHitTest = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.ALL_PANES);
|
|
113
113
|
//#endregion
|
|
114
114
|
this.addRxSubscription(merge(this.canvasInputListener.observeWheel(allPanesHitTest), this.canvasInputListener.observePinch(allPanesHitTest))
|
|
115
|
-
.pipe(throttleTime(this.wheelTrottleTime,
|
|
115
|
+
.pipe(throttleTime(this.wheelTrottleTime, animationFrameScheduler, { trailing: true, leading: true }))
|
|
116
116
|
.subscribe(e => {
|
|
117
117
|
const isTouchpad = touchpadDetector(e);
|
|
118
118
|
const zoomSensitivity = isTouchpad
|
|
@@ -122,7 +122,7 @@ export class ChartAreaPanHandler extends ChartBaseElement {
|
|
|
122
122
|
}));
|
|
123
123
|
this.addRxSubscription(this.canvasInputListener
|
|
124
124
|
.observeScrollGesture()
|
|
125
|
-
.pipe(throttleTime(this.wheelTrottleTime,
|
|
125
|
+
.pipe(throttleTime(this.wheelTrottleTime, animationFrameScheduler, { trailing: true, leading: true }))
|
|
126
126
|
.subscribe((e) => {
|
|
127
127
|
let direction = -1;
|
|
128
128
|
const device = deviceDetector();
|
|
@@ -24,6 +24,7 @@ import { PaneManager } from '../pane/pane-manager.component';
|
|
|
24
24
|
import { CandleWidthCalculator, ChartModel, LastCandleLabelHandler, VisualCandleCalculator } from './chart.model';
|
|
25
25
|
import { PrependedCandlesData } from './chart-base.model';
|
|
26
26
|
import { DynamicObjectsComponent } from '../dynamic-objects/dynamic-objects.component';
|
|
27
|
+
import { ChartResizeHandler } from '../../inputhandlers/chart-resize.handler';
|
|
27
28
|
/**
|
|
28
29
|
* Represents a financial instrument to be displayed on a chart
|
|
29
30
|
* @class
|
|
@@ -59,11 +60,13 @@ export declare class ChartComponent extends ChartBaseElement {
|
|
|
59
60
|
private canvasInputListener;
|
|
60
61
|
private paneManager;
|
|
61
62
|
private dynamicObjects;
|
|
63
|
+
private chartResizeHandler;
|
|
62
64
|
readonly baselineModel: BaselineModel;
|
|
63
65
|
private readonly backgroundDrawer;
|
|
64
66
|
private readonly _dataSeriesDrawers;
|
|
65
67
|
private readonly dataSeriesDrawer;
|
|
66
|
-
|
|
68
|
+
private backgroundDrawPredicateSubj;
|
|
69
|
+
constructor(chartModel: ChartModel, canvasModel: CanvasModel, config: FullChartConfig, scale: ScaleModel, canvasBoundsContainer: CanvasBoundsContainer, drawingManager: DrawingManager, hitTestCanvasModel: HitTestCanvasModel, canvasInputListener: CanvasInputListenerComponent, backgroundCanvasModel: CanvasModel, chartPanComponent: ChartPanComponent, paneManager: PaneManager, cursorHandler: CursorHandler, dynamicObjects: DynamicObjectsComponent, chartResizeHandler: ChartResizeHandler);
|
|
67
70
|
/**
|
|
68
71
|
* This method overrides the doActivate method of the parent class and calls it.
|
|
69
72
|
* It does not take any parameters and does not return anything.
|
|
@@ -118,13 +121,13 @@ export declare class ChartComponent extends ChartBaseElement {
|
|
|
118
121
|
* @param {Timestamp} end - The end timestamp of the range.
|
|
119
122
|
* @returns {void}
|
|
120
123
|
*/
|
|
121
|
-
setTimestampRange(start: Timestamp, end: Timestamp): void;
|
|
124
|
+
setTimestampRange(start: Timestamp, end: Timestamp, forceNoAnimation?: boolean): void;
|
|
122
125
|
/**
|
|
123
126
|
* Moves the viewport to exactly xStart..xEnd place.
|
|
124
127
|
* @param xStart - viewport start in units
|
|
125
128
|
* @param xEnd - viewport end in units
|
|
126
129
|
*/
|
|
127
|
-
setXScale(xStart: Unit, xEnd: Unit): void;
|
|
130
|
+
setXScale(xStart: Unit, xEnd: Unit, forceNoAnimation?: boolean): void;
|
|
128
131
|
/**
|
|
129
132
|
* Sets the visibility of the wicks in the chart.
|
|
130
133
|
* @param {boolean} isShow - A boolean value indicating whether to show or hide the wicks.
|
|
@@ -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 { BehaviorSubject } from 'rxjs';
|
|
6
7
|
import { CHART_UUID, CanvasElement } from '../../canvas/canvas-bounds-container';
|
|
7
8
|
import { ChartBaseElement } from '../../model/chart-base-element';
|
|
8
9
|
import { BackgroundDrawer } from '../../drawers/chart-background.drawer';
|
|
@@ -48,7 +49,7 @@ export class ChartInstrument {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
export class ChartComponent extends ChartBaseElement {
|
|
51
|
-
constructor(chartModel, canvasModel, config, scale, canvasBoundsContainer, drawingManager, hitTestCanvasModel, canvasInputListener, backgroundCanvasModel, chartPanComponent, paneManager, cursorHandler, dynamicObjects) {
|
|
52
|
+
constructor(chartModel, canvasModel, config, scale, canvasBoundsContainer, drawingManager, hitTestCanvasModel, canvasInputListener, backgroundCanvasModel, chartPanComponent, paneManager, cursorHandler, dynamicObjects, chartResizeHandler) {
|
|
52
53
|
super();
|
|
53
54
|
this.chartModel = chartModel;
|
|
54
55
|
this.canvasModel = canvasModel;
|
|
@@ -60,7 +61,9 @@ export class ChartComponent extends ChartBaseElement {
|
|
|
60
61
|
this.canvasInputListener = canvasInputListener;
|
|
61
62
|
this.paneManager = paneManager;
|
|
62
63
|
this.dynamicObjects = dynamicObjects;
|
|
64
|
+
this.chartResizeHandler = chartResizeHandler;
|
|
63
65
|
this._dataSeriesDrawers = {};
|
|
66
|
+
this.backgroundDrawPredicateSubj = new BehaviorSubject(true);
|
|
64
67
|
this.strToBarType = (str) => { var _a; return (_a = this.barTypeValues.find(t => t === str)) !== null && _a !== void 0 ? _a : 'candle'; };
|
|
65
68
|
this.addChildEntity(this.chartModel);
|
|
66
69
|
this.registerDefaultCandlesTransformers();
|
|
@@ -73,7 +76,7 @@ export class ChartComponent extends ChartBaseElement {
|
|
|
73
76
|
//#region data series drawers
|
|
74
77
|
this.registerDefaultDataSeriesDrawers();
|
|
75
78
|
//#endregion
|
|
76
|
-
this.backgroundDrawer = new BackgroundDrawer(backgroundCanvasModel, this.config);
|
|
79
|
+
this.backgroundDrawer = new BackgroundDrawer(backgroundCanvasModel, this.config, () => this.backgroundDrawPredicateSubj.getValue());
|
|
77
80
|
drawingManager.addDrawer(this.backgroundDrawer, 'MAIN_BACKGROUND');
|
|
78
81
|
cursorHandler.setCursorForCanvasEl(CanvasElement.PANE_UUID(CHART_UUID), config.components.chart.cursor);
|
|
79
82
|
this.dataSeriesDrawer = new DataSeriesDrawer(paneManager, this.dataSeriesDrawers);
|
|
@@ -104,6 +107,13 @@ export class ChartComponent extends ChartBaseElement {
|
|
|
104
107
|
this.addRxSubscription(this.paneManager.dataSeriesRemovedSubject.subscribe(series => {
|
|
105
108
|
this.dynamicObjects.model.removeObject(series.id);
|
|
106
109
|
}));
|
|
110
|
+
// redraw background only when chart is resized
|
|
111
|
+
this.addRxSubscription(this.canvasBoundsContainer.observeAnyBoundsChanged().subscribe(() => {
|
|
112
|
+
this.backgroundDrawPredicateSubj.next(false);
|
|
113
|
+
}));
|
|
114
|
+
this.addRxSubscription(this.chartResizeHandler.canvasResized.subscribe(() => {
|
|
115
|
+
this.backgroundDrawPredicateSubj.next(true);
|
|
116
|
+
}));
|
|
107
117
|
}
|
|
108
118
|
/**
|
|
109
119
|
* Registers default candle transformers.
|
|
@@ -162,7 +172,8 @@ export class ChartComponent extends ChartBaseElement {
|
|
|
162
172
|
this.registerDataSeriesTypeDrawer('area', new AreaDrawer(this.config.components.chart));
|
|
163
173
|
this.registerDataSeriesTypeDrawer('baseline', new BaselineDrawer(this.baselineModel, this.canvasBoundsContainer));
|
|
164
174
|
this.registerDataSeriesTypeDrawer('histogram', new MainChartHistogramDrawer(this.config.components.chart.histogram));
|
|
165
|
-
const
|
|
175
|
+
const chartPaneId = CanvasElement.PANE_UUID(CHART_UUID);
|
|
176
|
+
const mainChartBoundsProvider = () => this.canvasBoundsContainer.getBounds(chartPaneId);
|
|
166
177
|
this.registerDataSeriesTypeDrawer('LINEAR', new LinearDrawer());
|
|
167
178
|
this.registerDataSeriesTypeDrawer('HISTOGRAM', new HistogramDrawer());
|
|
168
179
|
this.registerDataSeriesTypeDrawer('TREND_HISTOGRAM', new TrendHistogramDrawer());
|
|
@@ -196,16 +207,16 @@ export class ChartComponent extends ChartBaseElement {
|
|
|
196
207
|
* @param {Timestamp} end - The end timestamp of the range.
|
|
197
208
|
* @returns {void}
|
|
198
209
|
*/
|
|
199
|
-
setTimestampRange(start, end) {
|
|
200
|
-
return this.chartModel.setTimestampRange(start, end);
|
|
210
|
+
setTimestampRange(start, end, forceNoAnimation = true) {
|
|
211
|
+
return this.chartModel.setTimestampRange(start, end, forceNoAnimation);
|
|
201
212
|
}
|
|
202
213
|
/**
|
|
203
214
|
* Moves the viewport to exactly xStart..xEnd place.
|
|
204
215
|
* @param xStart - viewport start in units
|
|
205
216
|
* @param xEnd - viewport end in units
|
|
206
217
|
*/
|
|
207
|
-
setXScale(xStart, xEnd) {
|
|
208
|
-
return this.scale.setXScale(xStart, xEnd);
|
|
218
|
+
setXScale(xStart, xEnd, forceNoAnimation = true) {
|
|
219
|
+
return this.scale.setXScale(xStart, xEnd, forceNoAnimation);
|
|
209
220
|
}
|
|
210
221
|
/**
|
|
211
222
|
* Sets the visibility of the wicks in the chart.
|
|
@@ -49,7 +49,6 @@ export declare class ChartModel extends ChartBaseElement {
|
|
|
49
49
|
readonly nextCandleTimeStampSubject: Subject<void>;
|
|
50
50
|
readonly chartTypeChanged: Subject<BarType>;
|
|
51
51
|
readonly mainInstrumentChangedSubject: Subject<ChartInstrument>;
|
|
52
|
-
readonly scaleInversedSubject: Subject<void>;
|
|
53
52
|
readonly offsetsChanged: Subject<void>;
|
|
54
53
|
private candlesTransformersByChartType;
|
|
55
54
|
lastCandleLabelsByChartType: Partial<Record<BarType, LastCandleLabelHandler>>;
|
|
@@ -319,7 +318,7 @@ export declare class ChartModel extends ChartBaseElement {
|
|
|
319
318
|
* @param {Timestamp} end - The end timestamp of the range.
|
|
320
319
|
* @returns {void}
|
|
321
320
|
*/
|
|
322
|
-
setTimestampRange(start: Timestamp, end: Timestamp): void;
|
|
321
|
+
setTimestampRange(start: Timestamp, end: Timestamp, forceNoAnimation?: boolean): void;
|
|
323
322
|
/**
|
|
324
323
|
* Returns the last candle of the main candle series.
|
|
325
324
|
* @returns {Candle | undefined} The last candle of the main candle series or undefined if the series is empty.
|
|
@@ -50,7 +50,6 @@ export class ChartModel extends ChartBaseElement {
|
|
|
50
50
|
this.nextCandleTimeStampSubject = new Subject();
|
|
51
51
|
this.chartTypeChanged = new Subject();
|
|
52
52
|
this.mainInstrumentChangedSubject = new Subject();
|
|
53
|
-
this.scaleInversedSubject = new Subject();
|
|
54
53
|
this.offsetsChanged = new Subject();
|
|
55
54
|
this.candlesTransformersByChartType = {};
|
|
56
55
|
this.lastCandleLabelsByChartType = {};
|
|
@@ -656,11 +655,11 @@ export class ChartModel extends ChartBaseElement {
|
|
|
656
655
|
* @param {Timestamp} end - The end timestamp of the range.
|
|
657
656
|
* @returns {void}
|
|
658
657
|
*/
|
|
659
|
-
setTimestampRange(start, end) {
|
|
658
|
+
setTimestampRange(start, end, forceNoAnimation = true) {
|
|
660
659
|
const startUnit = this.candleFromTimestamp(start).startUnit;
|
|
661
660
|
const endCandle = this.candleFromTimestamp(end);
|
|
662
661
|
const endUnit = endCandle.startUnit + endCandle.width;
|
|
663
|
-
return this.scale.setXScale(startUnit, endUnit);
|
|
662
|
+
return this.scale.setXScale(startUnit, endUnit, forceNoAnimation);
|
|
664
663
|
}
|
|
665
664
|
/**
|
|
666
665
|
* Returns the last candle of the main candle series.
|
|
@@ -122,6 +122,7 @@ export class CrossAndLabelsDrawerType {
|
|
|
122
122
|
if (this.config.components.yAxis.visible) {
|
|
123
123
|
const pane = this.paneManager.panes[point.paneId];
|
|
124
124
|
const y = point.y;
|
|
125
|
+
const type = this.config.components.crossTool.yLabel.type;
|
|
125
126
|
if (!pane) {
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
@@ -129,9 +130,10 @@ export class CrossAndLabelsDrawerType {
|
|
|
129
130
|
const price = extent.regularValueFromY(y);
|
|
130
131
|
const label = extent.valueFormatter(price);
|
|
131
132
|
const bounds = this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID_Y_AXIS(pane.uuid, extent.idx));
|
|
132
|
-
const drawYLabel = priceLabelDrawersMap[
|
|
133
|
+
const drawYLabel = priceLabelDrawersMap[type];
|
|
134
|
+
const textColor = type === 'plain' ? crossToolColors.lineColor : crossToolColors.labelTextColor;
|
|
133
135
|
drawYLabel(ctx, bounds, label, y, {
|
|
134
|
-
textColor
|
|
136
|
+
textColor,
|
|
135
137
|
bgColor: crossToolColors.labelBoxColor,
|
|
136
138
|
paddingBottom: yLabelPadding === null || yLabelPadding === void 0 ? void 0 : yLabelPadding.bottom,
|
|
137
139
|
paddingEnd: yLabelPadding === null || yLabelPadding === void 0 ? void 0 : yLabelPadding.end,
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { CanvasElement } from '../../canvas/canvas-bounds-container';
|
|
7
7
|
import { getTextLineHeight } from '../../utils/canvas/canvas-text-functions.utils';
|
|
8
|
+
import { clipToBounds } from '../../utils/canvas/canvas-drawing-functions.utils';
|
|
8
9
|
export class HighLowDrawer {
|
|
9
10
|
constructor(canvasModel, chartModel, config, canvasBoundsContainer) {
|
|
10
11
|
this.canvasModel = canvasModel;
|
|
@@ -34,7 +35,10 @@ export class HighLowDrawer {
|
|
|
34
35
|
ctx.font = this.config.components.highLow.font;
|
|
35
36
|
this.drawMarkerLabel(ctx, finalHighIdx, high, 'high');
|
|
36
37
|
this.drawMarkerLabel(ctx, finalLowIdx, low, 'low');
|
|
38
|
+
const chartBounds = this.canvasBoundsContainer.getBounds('PANE_CHART');
|
|
37
39
|
ctx.restore();
|
|
40
|
+
// We need clip here so lowLabel won't overlap other panes
|
|
41
|
+
clipToBounds(ctx, chartBounds);
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
44
|
/**
|
|
@@ -47,7 +51,10 @@ export class HighLowDrawer {
|
|
|
47
51
|
*/
|
|
48
52
|
drawMarkerLabel(ctx, candleIdx, yValue, type) {
|
|
49
53
|
const y = this.getMarkerY(ctx, yValue, type === 'low');
|
|
50
|
-
|
|
54
|
+
const fontSize = getTextLineHeight(ctx, false);
|
|
55
|
+
// we need to measure fit into the bounds for low label by its top point
|
|
56
|
+
const yForBoundsTrack = type === 'low' ? y - fontSize : y;
|
|
57
|
+
if (!this.checkMarkerInBounds(yForBoundsTrack)) {
|
|
51
58
|
return;
|
|
52
59
|
}
|
|
53
60
|
const text = this.getMarkerText(yValue, type);
|
|
@@ -79,7 +86,7 @@ export class HighLowDrawer {
|
|
|
79
86
|
getMarkerY(ctx, yValue, offset = false) {
|
|
80
87
|
const y = this.chartModel.toY(yValue);
|
|
81
88
|
if (offset) {
|
|
82
|
-
const fontSize = getTextLineHeight(ctx);
|
|
89
|
+
const fontSize = getTextLineHeight(ctx, false);
|
|
83
90
|
return y + fontSize;
|
|
84
91
|
}
|
|
85
92
|
return y;
|
|
@@ -7,7 +7,7 @@ import { calculateTextWidth } from '../../utils/canvas/canvas-font-measure-tool.
|
|
|
7
7
|
import { HIGHLIGHTS_TYPES } from './highlights.model';
|
|
8
8
|
import { CanvasElement } from '../../canvas/canvas-bounds-container';
|
|
9
9
|
import { unitToPixels } from '../../model/scaling/viewport.model';
|
|
10
|
-
import { clipToBounds } from '../../
|
|
10
|
+
import { clipToBounds } from '../../utils/canvas/canvas-drawing-functions.utils';
|
|
11
11
|
const LABEL_PADDINGS = [20, 10];
|
|
12
12
|
export class HighlightsDrawer {
|
|
13
13
|
constructor(highlightsModel, chartModel, canvasModel, canvasBoundsContainer, config) {
|
|
@@ -85,7 +85,8 @@ export class PaneComponent extends ChartBaseElement {
|
|
|
85
85
|
* @returns {GridComponent} - The newly created GridComponent instance.
|
|
86
86
|
*/
|
|
87
87
|
createGridComponent(uuid, scale, yAxisLabelsGenerator, yAxisState) {
|
|
88
|
-
const
|
|
88
|
+
const chartPaneId = CanvasElement.PANE_UUID(uuid);
|
|
89
|
+
const gridComponent = new GridComponent(this.mainCanvasModel, scale, this.config, yAxisState, `PANE_${uuid}_grid_drawer`, this.drawingManager, () => this.canvasBoundsContainer.getBounds(chartPaneId), () => this.canvasBoundsContainer.getBounds(chartPaneId), () => [], () => yAxisLabelsGenerator.generateNumericLabels());
|
|
89
90
|
return gridComponent;
|
|
90
91
|
}
|
|
91
92
|
/**
|
|
@@ -96,7 +97,8 @@ export class PaneComponent extends ChartBaseElement {
|
|
|
96
97
|
* @returns {Unsubscriber}
|
|
97
98
|
*/
|
|
98
99
|
createYPanHandler(uuid, scale) {
|
|
99
|
-
const
|
|
100
|
+
const chartPaneId = CanvasElement.PANE_UUID(uuid);
|
|
101
|
+
const dragNDropComponent = this.chartPanComponent.chartAreaPanHandler.registerChartYPanHandler(scale, this.canvasBoundsContainer.getBoundsHitTest(chartPaneId));
|
|
100
102
|
return [
|
|
101
103
|
() => {
|
|
102
104
|
this.chartPanComponent.chartAreaPanHandler.removeChildEntity(dragNDropComponent);
|
|
@@ -113,7 +115,8 @@ export class PaneComponent extends ChartBaseElement {
|
|
|
113
115
|
createExtentComponent(options) {
|
|
114
116
|
var _a, _b;
|
|
115
117
|
const extentIdx = this.yExtentComponents.length;
|
|
116
|
-
const
|
|
118
|
+
const chartPaneId = CanvasElement.PANE_UUID(this.uuid);
|
|
119
|
+
const getBounds = () => this.canvasBoundsContainer.getBounds(chartPaneId);
|
|
117
120
|
const scaleModel = (_a = options === null || options === void 0 ? void 0 : options.scale) !== null && _a !== void 0 ? _a : new SyncedByXScaleModel(this.mainScale, this.config, getBounds, this.canvasAnimation);
|
|
118
121
|
const [unsub, dragNDrop] = this.createYPanHandler(this.uuid, scaleModel);
|
|
119
122
|
// creating partially resolved constructor except formatter & dataSeriesProvider - bcs it's not possible to provide formatter
|
|
@@ -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 '../../
|
|
6
|
+
import { clipToBounds } from '../../utils/canvas/canvas-drawing-functions.utils';
|
|
7
7
|
import { unitToPixels } from '../../model/scaling/viewport.model';
|
|
8
8
|
import { flat } from '../../utils/array.utils';
|
|
9
9
|
import { ceilToDPR, floorToDPR } from '../../utils/device/device-pixel-ratio.utils';
|
|
@@ -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 { eachDayOfInterval, isSameDay, isMonday, isTuesday, isWednesday, isThursday, isFriday, isSaturday, isSunday, startOfMonth, endOfMonth, } from 'date-fns
|
|
6
|
+
import { eachDayOfInterval, isSameDay, isMonday, isTuesday, isWednesday, isThursday, isFriday, isSaturday, isSunday, startOfMonth, endOfMonth, } from 'date-fns';
|
|
7
7
|
/**
|
|
8
8
|
* Factory that return a {@link TimeFormatMatcher} function for a given {@link ParsedTimeFormats}
|
|
9
9
|
* @see
|
|
@@ -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 "
|
|
30
|
+
export declare const timeFormatConfirugableGuard: (key: string) => key is "year" | "month" | "day" | "hour" | "minute" | "second";
|
|
31
31
|
export declare const weekWeekdayGuard: (key: string) => key is "week-weekday";
|
|
32
32
|
export declare const timeFormatNoNConfirugableGuard: (key: string) => key is "lessThanSecond";
|
|
33
33
|
export {};
|
|
@@ -51,7 +51,7 @@ export const getWeightFromTimeFormat = (format) => {
|
|
|
51
51
|
*/
|
|
52
52
|
export const groupLabelsByWeight = (weightedLabels) => {
|
|
53
53
|
const labelsGroupedByWeight = {};
|
|
54
|
-
|
|
54
|
+
for (const weightedLabel of weightedLabels) {
|
|
55
55
|
const labelsByWeight = labelsGroupedByWeight[weightedLabel.weight];
|
|
56
56
|
if (labelsByWeight === undefined) {
|
|
57
57
|
labelsGroupedByWeight[weightedLabel.weight] = [weightedLabel];
|
|
@@ -59,7 +59,7 @@ export const groupLabelsByWeight = (weightedLabels) => {
|
|
|
59
59
|
else {
|
|
60
60
|
labelsByWeight.push(weightedLabel);
|
|
61
61
|
}
|
|
62
|
-
}
|
|
62
|
+
}
|
|
63
63
|
return labelsGroupedByWeight;
|
|
64
64
|
};
|
|
65
65
|
/**
|
|
@@ -18,12 +18,10 @@ import { getWeightFromTimeFormat } from './x-axis-weights.functions';
|
|
|
18
18
|
* @see
|
|
19
19
|
* returns `null` if date doesn't match any condition
|
|
20
20
|
*/
|
|
21
|
-
const getWeightByDate = (currentDate, previousDate, sortedWeights
|
|
21
|
+
const getWeightByDate = (currentDate, previousDate, sortedWeights) => {
|
|
22
22
|
var _a, _b;
|
|
23
|
-
const offsetCurrentDate = tzOffset(currentDate.getTime());
|
|
24
|
-
const offsetPrevDate = tzOffset(previousDate.getTime());
|
|
25
23
|
for (const [weight, timeMatcher] of sortedWeights) {
|
|
26
|
-
if (timeMatcher(
|
|
24
|
+
if (timeMatcher(currentDate, previousDate)) {
|
|
27
25
|
return weight;
|
|
28
26
|
}
|
|
29
27
|
}
|
|
@@ -36,12 +34,13 @@ const getWeightByDate = (currentDate, previousDate, sortedWeights, tzOffset) =>
|
|
|
36
34
|
export function mapCandlesToWeightedPoints(visualCandles, sortedWeights, tzOffset) {
|
|
37
35
|
const result = new Array(visualCandles.length);
|
|
38
36
|
// assume that candles` timestamp before the first visual candle is unreachable
|
|
39
|
-
let prevDate =
|
|
37
|
+
let prevDate = tzOffset(0);
|
|
40
38
|
for (let i = 0; i < visualCandles.length; i++) {
|
|
41
39
|
const currentCandle = visualCandles[i];
|
|
42
|
-
|
|
40
|
+
// calculate timstamp to Date in acordance with provided timezone and time
|
|
41
|
+
const currentDate = tzOffset(currentCandle.candle.timestamp);
|
|
43
42
|
const currentWeightedPoint = {
|
|
44
|
-
weight: getWeightByDate(currentDate, prevDate, sortedWeights
|
|
43
|
+
weight: getWeightByDate(currentDate, prevDate, sortedWeights),
|
|
45
44
|
};
|
|
46
45
|
result[i] = currentWeightedPoint;
|
|
47
46
|
prevDate = currentDate;
|
|
@@ -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 { CanvasBoundsContainer } from '../../canvas/canvas-bounds-container';
|
|
6
7
|
import { FullChartConfig } from '../../chart.config';
|
|
7
8
|
import EventBus from '../../events/event-bus';
|
|
8
9
|
import { CanvasModel } from '../../model/canvas.model';
|
|
@@ -48,6 +49,7 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
|
|
|
48
49
|
private scale;
|
|
49
50
|
private timeZoneModel;
|
|
50
51
|
private canvasModel;
|
|
52
|
+
private canvasBoundsContainer;
|
|
51
53
|
private labelsGroupedByWeight;
|
|
52
54
|
private weightedCache?;
|
|
53
55
|
private levelsCache;
|
|
@@ -56,7 +58,8 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
|
|
|
56
58
|
private weightToTimeFormatMatcherArray;
|
|
57
59
|
private weightToTimeFormatsDict;
|
|
58
60
|
private extendedLabelsFilterConfig;
|
|
59
|
-
constructor(eventBus: EventBus, config: FullChartConfig, chartModel: ChartModel, scale: ScaleModel, timeZoneModel: TimeZoneModel, canvasModel: CanvasModel);
|
|
61
|
+
constructor(eventBus: EventBus, config: FullChartConfig, chartModel: ChartModel, scale: ScaleModel, timeZoneModel: TimeZoneModel, canvasModel: CanvasModel, canvasBoundsContainer: CanvasBoundsContainer);
|
|
62
|
+
private filterLabelsInViewport;
|
|
60
63
|
private getLabelsFromChartType;
|
|
61
64
|
/**
|
|
62
65
|
* Make a prediction(750) about how many candles we need to fake to fill all X axis by labels
|
|
@@ -110,11 +113,16 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
|
|
|
110
113
|
* @returns {void}
|
|
111
114
|
*/
|
|
112
115
|
recalculateLabels(): void;
|
|
116
|
+
/**
|
|
117
|
+
* Calculates the cover up level based on the maximum label width and the mean candle width.
|
|
118
|
+
* Cover up level is based on maximum label width, which is based on the font size and the maximum format length.
|
|
119
|
+
* Used to group labels.
|
|
120
|
+
*/
|
|
121
|
+
private calculateCoverUpLevel;
|
|
113
122
|
/**
|
|
114
123
|
* Recalculates cached labels based on the current configuration and zoom level.
|
|
115
124
|
* If there are no grouped labels, the cache is not set.
|
|
116
|
-
*
|
|
117
|
-
* Calculates the cover up level based on the maximum label width and the mean candle width.
|
|
125
|
+
* Recalculating depends on cover up level.
|
|
118
126
|
* If the cover up level is negative, the cache is not updated.
|
|
119
127
|
* If the cover up level has not changed, the cached labels are returned.
|
|
120
128
|
* Otherwise, the labels are filtered by extended rules and grouped by cover up level.
|
|
@@ -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 { CanvasElement } from '../../canvas/canvas-bounds-container';
|
|
6
7
|
import { unitToPixels } from '../../model/scaling/viewport.model';
|
|
7
8
|
import { cloneUnsafe, typedEntries_UNSAFE } from '../../utils/object.utils';
|
|
8
9
|
import { fakeVisualCandle } from '../chart/fake-candles';
|
|
@@ -11,15 +12,16 @@ import { filterMapGroupedLabelsByCoverUpLevel, getWeightFromTimeFormat, groupLab
|
|
|
11
12
|
import { generateWeightsMapForConfig, mapCandlesToWeightedPoints, } from './time/x-axis-weights.generator';
|
|
12
13
|
export class XAxisTimeLabelsGenerator {
|
|
13
14
|
get labels() {
|
|
14
|
-
return this.getLabelsFromChartType();
|
|
15
|
+
return this.filterLabelsInViewport(this.getLabelsFromChartType());
|
|
15
16
|
}
|
|
16
|
-
constructor(eventBus, config, chartModel, scale, timeZoneModel, canvasModel) {
|
|
17
|
+
constructor(eventBus, config, chartModel, scale, timeZoneModel, canvasModel, canvasBoundsContainer) {
|
|
17
18
|
this.eventBus = eventBus;
|
|
18
19
|
this.config = config;
|
|
19
20
|
this.chartModel = chartModel;
|
|
20
21
|
this.scale = scale;
|
|
21
22
|
this.timeZoneModel = timeZoneModel;
|
|
22
23
|
this.canvasModel = canvasModel;
|
|
24
|
+
this.canvasBoundsContainer = canvasBoundsContainer;
|
|
23
25
|
this.labelsGroupedByWeight = {};
|
|
24
26
|
this.levelsCache = {};
|
|
25
27
|
this.weightToTimeFormatMatcherArray = [];
|
|
@@ -27,6 +29,29 @@ export class XAxisTimeLabelsGenerator {
|
|
|
27
29
|
this.extendedLabelsFilterConfig = {
|
|
28
30
|
minute_1: (coverUpLevel) => coverUpLevel >= 2,
|
|
29
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Calculates the cover up level based on the maximum label width and the mean candle width.
|
|
34
|
+
* Cover up level is based on maximum label width, which is based on the font size and the maximum format length.
|
|
35
|
+
* Used to group labels.
|
|
36
|
+
*/
|
|
37
|
+
this.calculateCoverUpLevel = () => {
|
|
38
|
+
const animation = this.scale.currentAnimation;
|
|
39
|
+
const meanCandleWidthInUnits = this.chartModel.mainCandleSeries.meanCandleWidth;
|
|
40
|
+
if (Object.getOwnPropertyNames(this.labelsGroupedByWeight).length === 0) {
|
|
41
|
+
return -1;
|
|
42
|
+
}
|
|
43
|
+
// calculate coverUpLevel for target zoomX to prevent extra labels calculations on every animation tick
|
|
44
|
+
const meanCandleWidthInPixels = (animation === null || animation === void 0 ? void 0 : animation.animationInProgress)
|
|
45
|
+
? unitToPixels(meanCandleWidthInUnits, animation.animationConfig.targetZoomX)
|
|
46
|
+
: unitToPixels(meanCandleWidthInUnits, this.scale.zoomX);
|
|
47
|
+
if (!isFinite(meanCandleWidthInPixels)) {
|
|
48
|
+
return -1;
|
|
49
|
+
}
|
|
50
|
+
const fontSize = this.config.components.xAxis.fontSize;
|
|
51
|
+
const maxFormatLength = Object.values(this.formatsByWeightMap).reduce((max, item) => Math.max(item.length, max), 1);
|
|
52
|
+
const maxLabelWidth = fontSize * maxFormatLength;
|
|
53
|
+
return Math.round(maxLabelWidth / meanCandleWidthInPixels);
|
|
54
|
+
};
|
|
30
55
|
this.formatsByWeightMap = config.components.xAxis.formatsForLabelsConfig;
|
|
31
56
|
const { weightToTimeFormatsDict, weightToTimeFormatMatcherDict } = generateWeightsMapForConfig(this.formatsByWeightMap);
|
|
32
57
|
this.weightToTimeFormatMatcherArray = Object.entries(weightToTimeFormatMatcherDict)
|
|
@@ -34,6 +59,19 @@ export class XAxisTimeLabelsGenerator {
|
|
|
34
59
|
.sort(([a], [b]) => b - a);
|
|
35
60
|
this.weightToTimeFormatsDict = weightToTimeFormatsDict;
|
|
36
61
|
}
|
|
62
|
+
filterLabelsInViewport(labels) {
|
|
63
|
+
const bounds = this.canvasBoundsContainer.getBounds(CanvasElement.X_AXIS);
|
|
64
|
+
const filteredLabels = [];
|
|
65
|
+
for (const label of labels) {
|
|
66
|
+
const x = this.scale.toX(label.value);
|
|
67
|
+
// skip labels outside viewport
|
|
68
|
+
if (x < 0 || x > bounds.width) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
filteredLabels.push(label);
|
|
72
|
+
}
|
|
73
|
+
return filteredLabels;
|
|
74
|
+
}
|
|
37
75
|
getLabelsFromChartType() {
|
|
38
76
|
var _a, _b;
|
|
39
77
|
const labels = (_b = (_a = this.weightedCache) === null || _a === void 0 ? void 0 : _a.labels) !== null && _b !== void 0 ? _b : [];
|
|
@@ -64,9 +102,10 @@ export class XAxisTimeLabelsGenerator {
|
|
|
64
102
|
* @returns {XAxisLabelWeighted[]} An array of XAxisLabelWeighted objects.
|
|
65
103
|
*/
|
|
66
104
|
mapWeightedPointsToLabels(weightedPoints, allCandlesWithFake) {
|
|
105
|
+
var _a;
|
|
67
106
|
const arr = new Array(weightedPoints.length);
|
|
68
|
-
weightedPoints.
|
|
69
|
-
|
|
107
|
+
for (let index = 0; index < weightedPoints.length; ++index) {
|
|
108
|
+
const point = weightedPoints[index];
|
|
70
109
|
const visualCandle = allCandlesWithFake[index];
|
|
71
110
|
const labelFormat = this.weightToTimeFormatsDict[point.weight];
|
|
72
111
|
const formattedLabel = this.timeZoneModel.getDateTimeFormatter(labelFormat)(visualCandle.candle.timestamp);
|
|
@@ -77,7 +116,7 @@ export class XAxisTimeLabelsGenerator {
|
|
|
77
116
|
time: visualCandle.candle.timestamp,
|
|
78
117
|
text: formattedLabel,
|
|
79
118
|
};
|
|
80
|
-
}
|
|
119
|
+
}
|
|
81
120
|
return arr;
|
|
82
121
|
}
|
|
83
122
|
/**
|
|
@@ -227,27 +266,16 @@ export class XAxisTimeLabelsGenerator {
|
|
|
227
266
|
/**
|
|
228
267
|
* Recalculates cached labels based on the current configuration and zoom level.
|
|
229
268
|
* If there are no grouped labels, the cache is not set.
|
|
230
|
-
*
|
|
231
|
-
* Calculates the cover up level based on the maximum label width and the mean candle width.
|
|
269
|
+
* Recalculating depends on cover up level.
|
|
232
270
|
* If the cover up level is negative, the cache is not updated.
|
|
233
271
|
* If the cover up level has not changed, the cached labels are returned.
|
|
234
272
|
* Otherwise, the labels are filtered by extended rules and grouped by cover up level.
|
|
235
273
|
* The filtered labels are then cached and returned.
|
|
236
274
|
*/
|
|
237
275
|
recalculateCachedLabels() {
|
|
238
|
-
|
|
239
|
-
if (Object.getOwnPropertyNames(this.labelsGroupedByWeight).length === 0) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
const fontSize = this.config.components.xAxis.fontSize;
|
|
243
|
-
const maxFormatLength = Object.values(this.formatsByWeightMap).reduce((max, item) => {
|
|
244
|
-
return Math.max(item.length, max);
|
|
245
|
-
}, 1);
|
|
246
|
-
const maxLabelWidth = fontSize * maxFormatLength;
|
|
247
|
-
const meanCandleWidthPx = unitToPixels(this.chartModel.mainCandleSeries.meanCandleWidth, this.scale.zoomX);
|
|
248
|
-
const coverUpLevel = Math.round(maxLabelWidth / meanCandleWidthPx);
|
|
276
|
+
const coverUpLevel = this.calculateCoverUpLevel();
|
|
249
277
|
// for some reason sometimes `this.scale.zoomX` is negative so we dont want to update labels
|
|
250
|
-
if (coverUpLevel < 0
|
|
278
|
+
if (coverUpLevel < 0) {
|
|
251
279
|
return;
|
|
252
280
|
}
|
|
253
281
|
if (this.weightedCache === undefined || coverUpLevel !== this.weightedCache.coverUpLevel) {
|
|
@@ -58,10 +58,6 @@ export class XAxisTimeLabelsDrawer {
|
|
|
58
58
|
ctx.fillStyle = color;
|
|
59
59
|
for (const label of labels) {
|
|
60
60
|
const x = this.viewportModel.toX(label.value) - calculateTextWidth(label.text, ctx, font) / 2;
|
|
61
|
-
// skip labels outside viewport
|
|
62
|
-
if (x < 0 || x > bounds.width) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
61
|
const y = bounds.y + fontHeight - 1 + offsetTop; // -1 for font drawing inconsistency
|
|
66
62
|
const labelText = label.text;
|
|
67
63
|
ctx.font = font;
|