@devexperts/dxcharts-lite 2.5.7 → 2.6.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 (52) hide show
  1. package/dist/chart/__tests__/chart.test.js +5 -5
  2. package/dist/chart/__tests__/env.js +1 -1
  3. package/dist/chart/bootstrap.js +2 -2
  4. package/dist/chart/canvas/canvas-bounds-container.js +24 -3
  5. package/dist/chart/chart.config.d.ts +2 -0
  6. package/dist/chart/chart.config.js +2 -1
  7. package/dist/chart/components/chart/basic-scale.d.ts +5 -1
  8. package/dist/chart/components/chart/basic-scale.js +10 -6
  9. package/dist/chart/components/chart/candle-transformer.functions.js +1 -1
  10. package/dist/chart/components/chart/candle.functions.d.ts +1 -1
  11. package/dist/chart/components/chart/candle.functions.js +3 -2
  12. package/dist/chart/components/chart/chart.component.d.ts +29 -8
  13. package/dist/chart/components/chart/chart.component.js +33 -4
  14. package/dist/chart/components/chart/chart.model.d.ts +42 -5
  15. package/dist/chart/components/chart/chart.model.js +99 -19
  16. package/dist/chart/components/chart/fake-candles.js +2 -0
  17. package/dist/chart/components/chart/fake-visual-candle.d.ts +4 -4
  18. package/dist/chart/components/chart/fake-visual-candle.js +4 -4
  19. package/dist/chart/components/pane/pane.component.js +3 -3
  20. package/dist/chart/components/volumes/separate-volumes.component.d.ts +1 -3
  21. package/dist/chart/components/volumes/separate-volumes.component.js +1 -3
  22. package/dist/chart/components/volumes/volumes.component.js +1 -1
  23. package/dist/chart/components/volumes/volumes.drawer.js +3 -3
  24. package/dist/chart/components/watermark/water-mark.component.d.ts +3 -12
  25. package/dist/chart/components/watermark/water-mark.component.js +1 -1
  26. package/dist/chart/components/x_axis/time/parser/time-formats-parser.functions.js +1 -1
  27. package/dist/chart/components/x_axis/x-axis-labels.generator.d.ts +2 -2
  28. package/dist/chart/components/x_axis/x-axis-labels.generator.js +6 -6
  29. package/dist/chart/components/x_axis/x-axis-scale.handler.js +2 -2
  30. package/dist/chart/components/x_axis/x-axis.component.js +1 -1
  31. package/dist/chart/components/y_axis/y-axis-scale.handler.js +3 -3
  32. package/dist/chart/drawers/drawing-manager.d.ts +1 -1
  33. package/dist/chart/drawers/drawing-manager.js +0 -1
  34. package/dist/chart/inputhandlers/hover-producer.component.js +8 -2
  35. package/dist/chart/inputhandlers/main-canvas-touch.handler.js +1 -1
  36. package/dist/chart/model/candle.model.d.ts +3 -0
  37. package/dist/chart/model/candle.model.js +7 -1
  38. package/dist/chart/model/data-series.model.d.ts +3 -3
  39. package/dist/chart/model/data-series.model.js +1 -1
  40. package/dist/chart/model/scale.model.js +1 -1
  41. package/dist/chart/model/scaling/viewport.model.d.ts +2 -1
  42. package/dist/chart/model/scaling/viewport.model.js +6 -1
  43. package/dist/chart/model/time-zone.model.js +1 -3
  44. package/dist/chart/utils/candles-generator-ts.utils.d.ts +1 -0
  45. package/dist/chart/utils/candles-generator.utils.d.ts +1 -0
  46. package/dist/chart/utils/candles-generator.utils.js +2 -0
  47. package/dist/chart/utils/string.utils.d.ts +6 -0
  48. package/dist/chart/utils/string.utils.js +19 -0
  49. package/dist/chart/utils/types.utils.d.ts +9 -0
  50. package/dist/chart/utils/types.utils.js +6 -0
  51. package/dist/dxchart.min.js +4 -4
  52. package/package.json +1 -1
@@ -59,12 +59,19 @@ export class ChartModel extends ChartBaseElement {
59
59
  this.toY = (value) => {
60
60
  return this.mainCandleSeries.view.toY(value);
61
61
  };
62
+ this.prepareCandles = (candles) => {
63
+ const prepared = candles.map(prepareCandle).filter(isCandle);
64
+ const { sortCandles } = this.config.components.chart;
65
+ return sortCandles ? sortCandles(prepared) : prepared;
66
+ };
62
67
  this.chartTypeChanged.next(this.config.components.chart.type);
63
68
  this.secondaryChartColors = new SecondaryChartColorsPool(this.config);
64
69
  const candleSeries = new MainCandleSeriesModel(this.chartBaseModel, this.paneManager.panes[CHART_UUID].mainExtent, uuid(), this.paneManager.hitTestController.getNewDataSeriesHitTestId(), this.bus, this.scale, new ChartInstrument(), this.candlesTransformersByChartType, this.candleWidthByChartType, Object.assign({}, this.config.colors));
65
70
  candleSeries.config.type = this.config.components.chart.type;
66
71
  this.candleSeries.push(candleSeries);
67
- scale.addXConstraint((_, state) => candleEdgesConstrait(state, this.mainCandleSeries.visualPoints, this.config.components.chart.minCandlesOffset, scale.getBounds()));
72
+ if (this.config.components.chart.minCandlesOffset > 0) {
73
+ scale.addXConstraint((_, state) => candleEdgesConstrait(state, this.mainCandleSeries.visualPoints, this.config.components.chart.minCandlesOffset, scale.getBounds()));
74
+ }
68
75
  this.basicScaleViewportTransformer = createBasicScaleViewportTransformer(scale);
69
76
  this.timeFrameViewportTransformer = createTimeFrameViewportTransformer(scale, this);
70
77
  this.pane = this.paneManager.panes[CHART_UUID];
@@ -162,7 +169,7 @@ export class ChartModel extends ChartBaseElement {
162
169
  * @returns {CandleSeriesModel | undefined} - The newly created secondary candle series model or undefined if it could not be created.
163
170
  */
164
171
  setSecondaryCandleSeries(candles, instrument = this.mainCandleSeries.instrument, recalculateAndUpdate = true) {
165
- const preparedCandles = prepareCandles(candles);
172
+ const preparedCandles = this.prepareCandles(candles);
166
173
  // set correct indexes based on main candles timestamp
167
174
  const reindexCandles = this.reindexCandlesBasedOnSeries(this.mainCandleSeries.dataPoints, preparedCandles);
168
175
  // ensure there are no gaps in new candles
@@ -198,7 +205,7 @@ export class ChartModel extends ChartBaseElement {
198
205
  this.mainInstrumentChangedSubject.next(mainSeries.instrument);
199
206
  }
200
207
  this.rememberCurrentTimeframe();
201
- const preparedCandles = prepareCandles(mainSeries.candles);
208
+ const preparedCandles = this.prepareCandles(mainSeries.candles);
202
209
  this.mainCandleSeries.clearData();
203
210
  reindexCandles(preparedCandles);
204
211
  this.mainCandleSeries.dataPoints = preparedCandles;
@@ -217,7 +224,9 @@ export class ChartModel extends ChartBaseElement {
217
224
  });
218
225
  this.chartBaseModel.recalculatePeriod();
219
226
  this.autoScaleOnCandles();
220
- this.scale.doAutoScale();
227
+ if (this.config.scale.auto) {
228
+ this.scale.doAutoScale();
229
+ }
221
230
  this.candlesSetSubject.next();
222
231
  this.canvasModel.fireDraw();
223
232
  }
@@ -282,7 +291,7 @@ export class ChartModel extends ChartBaseElement {
282
291
  console.error('All series update failed. Instruments for series are different.');
283
292
  return;
284
293
  }
285
- const preparedCandles = prepareCandles(mainSeries.candles);
294
+ const preparedCandles = this.prepareCandles(mainSeries.candles);
286
295
  const updateResult = updateCandles(this.mainCandleSeries.dataPoints, preparedCandles);
287
296
  const updatedCandles = updateResult.candles;
288
297
  reindexCandles(updatedCandles);
@@ -290,7 +299,7 @@ export class ChartModel extends ChartBaseElement {
290
299
  // re-create series
291
300
  secondarySeries.map(series => {
292
301
  var _a, _b, _c, _d;
293
- const preparedCandles = prepareCandles(series.candles);
302
+ const preparedCandles = this.prepareCandles(series.candles);
294
303
  const updatedCandles = updateCandles((_d = (_c = this.findSecondarySeriesBySymbol((_b = (_a = series.instrument) === null || _a === void 0 ? void 0 : _a.symbol) !== null && _b !== void 0 ? _b : '')) === null || _c === void 0 ? void 0 : _c.dataPoints) !== null && _d !== void 0 ? _d : [], preparedCandles).candles;
295
304
  return this.setSecondaryCandleSeries(updatedCandles, series.instrument, false);
296
305
  });
@@ -325,9 +334,7 @@ export class ChartModel extends ChartBaseElement {
325
334
  series.dataPoints = series.dataPoints.slice(0, index);
326
335
  });
327
336
  });
328
- this.candlesRemovedSubject.next();
329
- this.candlesUpdatedSubject.next();
330
- this.canvasModel.fireDraw();
337
+ this.candlesChangedRedraw();
331
338
  }
332
339
  /**
333
340
  * Creates a secondary candle series model for a given instrument.
@@ -373,8 +380,8 @@ export class ChartModel extends ChartBaseElement {
373
380
  secondarySeriesAdjustments(mainSeries, secondarySeries) {
374
381
  const result = [];
375
382
  mainSeries.forEach(mainCandle => {
376
- var _a;
377
- const idx = (_a = mainCandle.idx) !== null && _a !== void 0 ? _a : 0;
383
+ const candleIdx = this.candleIdxFromId(mainCandle.id);
384
+ const idx = candleIdx > 0 ? candleIdx : 0;
378
385
  const compareCandle = secondarySeries[idx];
379
386
  if (!compareCandle) {
380
387
  // take first candle to left or right
@@ -521,6 +528,23 @@ export class ChartModel extends ChartBaseElement {
521
528
  const dataPointsSource = selectedCandleSeries.dataPoints;
522
529
  return this.chartBaseModel.dataFromTimestamp(timestamp, extrapolate, dataPointsSource);
523
530
  }
531
+ /**
532
+ * For given id finds the target candle
533
+ * @param id
534
+ * @param selectedCandleSeries
535
+ */
536
+ candleFromId(id, selectedCandleSeries = this.mainCandleSeries) {
537
+ return selectedCandleSeries.visualPoints.find(vc => vc.candle.id === id);
538
+ }
539
+ /**
540
+ * For given id finds the target candle index
541
+ * @param id
542
+ * @param selectedCandleSeries
543
+ * @returns candle index, -1 if not found
544
+ */
545
+ candleIdxFromId(id, selectedCandleSeries = this.mainCandleSeries) {
546
+ return selectedCandleSeries.visualPoints.findIndex(vc => vc.candle.id === id);
547
+ }
524
548
  /**
525
549
  * For given index returns the closest visual candle, or fake candle with correct X coordinate.
526
550
  * @param idx - index of candle
@@ -722,7 +746,7 @@ export class ChartModel extends ChartBaseElement {
722
746
  * Updates candles in series. Default is main series.
723
747
  * Any number of candles may be provided - they would be matched by their index and updated.
724
748
  * @param candles - any list of new (updated) candles
725
- * @param instrument - name of instrument to update
749
+ * @param instrumentSymbol - name of instrument to update
726
750
  */
727
751
  // I'd like to keep this method, for me one generic method is more convenient than 3 (updateLastCandle, addLastCandle, prepend...)
728
752
  updateCandles(candles, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
@@ -779,7 +803,9 @@ export class ChartModel extends ChartBaseElement {
779
803
  series.recalculateVisualPoints();
780
804
  }
781
805
  });
782
- this.scale.doAutoScale();
806
+ if (this.config.scale.auto) {
807
+ this.scale.doAutoScale();
808
+ }
783
809
  this.candlesUpdatedSubject.next();
784
810
  }
785
811
  /**
@@ -852,7 +878,7 @@ export class ChartModel extends ChartBaseElement {
852
878
  if (idx < 0) {
853
879
  prepend.push(c);
854
880
  }
855
- else if (target[idx].timestamp === c.timestamp) {
881
+ else if (target[idx].id === c.id) {
856
882
  targetCopy[idx] = c;
857
883
  }
858
884
  else {
@@ -867,7 +893,7 @@ export class ChartModel extends ChartBaseElement {
867
893
  /**
868
894
  * Adds new candle to the chart
869
895
  * @param candle - new candle
870
- * @param instrument - name of the instrument to update
896
+ * @param instrumentSymbol - name of the instrument to update
871
897
  */
872
898
  addLastCandle(candle, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
873
899
  this.updateCandles([candle], instrumentSymbol);
@@ -875,7 +901,7 @@ export class ChartModel extends ChartBaseElement {
875
901
  /**
876
902
  * Updates last candle value
877
903
  * @param candle - updated candle
878
- * @param instrument - name of the instrument to update
904
+ * @param instrumentSymbol - name of the instrument to update
879
905
  */
880
906
  updateLastCandle(candle, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
881
907
  this.updateCandles([candle], instrumentSymbol);
@@ -883,9 +909,12 @@ export class ChartModel extends ChartBaseElement {
883
909
  /**
884
910
  * Remove candle by idx and recaculate indexes
885
911
  * @param candle - new candle
886
- * @param instrument - name of the instrument to update
912
+ * @param instrumentSymbol - name of the instrument to update
887
913
  */
888
914
  removeCandleByIdx(idx, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
915
+ if (idx < 0) {
916
+ return;
917
+ }
889
918
  const seriesList = this.findSeriesBySymbol(instrumentSymbol);
890
919
  if (seriesList.length === 0) {
891
920
  console.warn("removeCandle by id failed. Can't find series", instrumentSymbol);
@@ -896,13 +925,64 @@ export class ChartModel extends ChartBaseElement {
896
925
  reindexCandles(series.dataPoints);
897
926
  series.recalculateVisualPoints();
898
927
  });
928
+ this.candlesChangedRedraw();
929
+ }
930
+ /**
931
+ * Remove candles by ids and recalculate indexes, candles should be as a sequence, follow one by one
932
+ * Works faster than removeCandlesByIds
933
+ *
934
+ * @param ids - candles ids to remove
935
+ * @param selectedCandleSeries - candle series to remove candles from
936
+ */
937
+ removeCandlesByIdsSequence(ids, selectedCandleSeries) {
938
+ const firstIdx = this.candleIdxFromId(ids[0], selectedCandleSeries);
939
+ const lastIdx = this.candleIdxFromId(ids[ids.length - 1], selectedCandleSeries);
940
+ if (firstIdx < 0 || lastIdx < 0) {
941
+ console.warn('Candle is not found');
942
+ return;
943
+ }
944
+ // if array is a sequence the removal process should be faster because reindex and recalculate visual points would call only once
945
+ selectedCandleSeries.dataPoints = selectedCandleSeries.dataPoints
946
+ .slice(0, firstIdx)
947
+ .concat(selectedCandleSeries.dataPoints.slice(lastIdx + 1));
948
+ reindexCandles(selectedCandleSeries.dataPoints, lastIdx);
949
+ selectedCandleSeries.recalculateVisualPoints();
950
+ this.candlesChangedRedraw();
951
+ }
952
+ /**
953
+ * Remove candles by ids and recalculate indexes
954
+ * @param ids - candles ids to remove
955
+ * @param selectedCandleSeries - candle series to remove candles from
956
+ */
957
+ removeCandlesByIds(ids, selectedCandleSeries) {
958
+ ids.forEach(id => this.removeCandleByIdx(this.candleIdxFromId(id, selectedCandleSeries)));
959
+ }
960
+ /**
961
+ * Add candles by id and recalculate indexes
962
+ *
963
+ * @param candles - candles to add
964
+ * @param startId - target candle to start adding candles from
965
+ * @param selectedCandleSeries - candle series to add candles to
966
+ */
967
+ addCandlesById(candles, startId, selectedCandleSeries) {
968
+ const targetCandleIdx = this.candleIdxFromId(startId);
969
+ if (targetCandleIdx < 0) {
970
+ console.warn('Selected start candle is not found');
971
+ return;
972
+ }
973
+ const candlesBefore = selectedCandleSeries.dataPoints.slice(0, targetCandleIdx);
974
+ const candlesAfter = selectedCandleSeries.dataPoints.slice(targetCandleIdx);
975
+ selectedCandleSeries.dataPoints = candlesBefore.concat(candles).concat(candlesAfter);
976
+ reindexCandles(selectedCandleSeries.dataPoints);
977
+ selectedCandleSeries.recalculateVisualPoints();
978
+ this.candlesChangedRedraw();
979
+ }
980
+ candlesChangedRedraw() {
899
981
  this.candlesRemovedSubject.next();
900
982
  this.candlesUpdatedSubject.next();
901
983
  this.canvasModel.fireDraw();
902
984
  }
903
985
  }
904
- const sortCandles = (candles) => candles.slice().sort((a, b) => (a.timestamp === b.timestamp ? 0 : a.timestamp > b.timestamp ? 1 : -1));
905
- const prepareCandles = (candles) => sortCandles(candles.map(prepareCandle).filter(isCandle));
906
986
  const findFirstNotEmptyCandle = (candles, startIdx, iterateStep) => {
907
987
  if (startIdx >= candles.length) {
908
988
  return candles[candles.length - 1];
@@ -3,12 +3,14 @@
3
3
  * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
4
  * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
5
  */
6
+ import { generateCandleId } from '../../model/candle.model';
6
7
  import { firstOf, lastOf } from '../../utils/array.utils';
7
8
  import { round } from '../../utils/math.utils';
8
9
  export const DEFAULT_PERIOD = 60; // 1 minute
9
10
  export const fakeCandle = (candles, index, period = DEFAULT_PERIOD) => {
10
11
  const t = getTimestampOfIndex(candles, index, period);
11
12
  return {
13
+ id: generateCandleId(t, t),
12
14
  hi: NaN,
13
15
  lo: NaN,
14
16
  open: NaN,
@@ -3,10 +3,10 @@
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 { Candle } from "../../model/candle.model";
7
- import { DataSeriesPoint, VisualSeriesPoint } from "../../model/data-series.model";
8
- import { Index } from "../../model/scaling/viewport.model";
9
- import VisualCandle from "../../model/visual-candle";
6
+ import { Candle } from '../../model/candle.model';
7
+ import { DataSeriesPoint, VisualSeriesPoint } from '../../model/data-series.model';
8
+ import { Index } from '../../model/scaling/viewport.model';
9
+ import VisualCandle from '../../model/visual-candle';
10
10
  /**
11
11
  * Generates fake candle for left and right "out of data range" zones.
12
12
  * Requires period to calculate the fake timestamp.
@@ -3,10 +3,10 @@
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 { nameDirection } from "../../model/candle.model";
7
- import { VisualSeriesPoint } from "../../model/data-series.model";
8
- import VisualCandle from "../../model/visual-candle";
9
- import { DEFAULT_PERIOD, fakeCandle, fakeDataPoint } from "./fake-candles";
6
+ import { nameDirection } from '../../model/candle.model';
7
+ import { VisualSeriesPoint } from '../../model/data-series.model';
8
+ import VisualCandle from '../../model/visual-candle';
9
+ import { DEFAULT_PERIOD, fakeCandle, fakeDataPoint } from './fake-candles';
10
10
  /**
11
11
  * Generates fake candle for left and right "out of data range" zones.
12
12
  * Requires period to calculate the fake timestamp.
@@ -88,9 +88,9 @@ export class PaneComponent extends ChartBaseElement {
88
88
  * @param {NumericYAxisLabelsGenerator} yAxisLabelsGenerator - The generator used to create the labels for the y-axis.
89
89
  * @returns {GridComponent} - The newly created GridComponent instance.
90
90
  */
91
- createGridComponent(uuid, scale, yAxisLabelsGenerator, yAxisState) {
91
+ createGridComponent(uuid, scale, yAxisState, yAxisLabelsGetter, yAxisBaselineGetter) {
92
92
  const chartPaneId = CanvasElement.PANE_UUID(uuid);
93
- 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());
93
+ const gridComponent = new GridComponent(this.mainCanvasModel, scale, this.config, yAxisState, `PANE_${uuid}_grid_drawer`, this.drawingManager, () => this.canvasBoundsContainer.getBounds(chartPaneId), () => this.canvasBoundsContainer.getBounds(chartPaneId), () => [], yAxisLabelsGetter, yAxisBaselineGetter, () => this.config.components.grid.visible);
94
94
  return gridComponent;
95
95
  }
96
96
  /**
@@ -135,7 +135,7 @@ export class PaneComponent extends ChartBaseElement {
135
135
  if (useDefaultHighLow) {
136
136
  scaleModel.autoScaleModel.setHighLowProvider('default', createCandlesOffsetProvider(() => ({ top: 10, bottom: 10, left: 0, right: 0, visible: true }), createDefaultYExtentHighLowProvider(yExtentComponent)));
137
137
  }
138
- const gridComponent = this.createGridComponent(this.uuid, scaleModel, yExtentComponent.yAxis.model.labelsGenerator, yExtentComponent.yAxis.state);
138
+ const gridComponent = this.createGridComponent(this.uuid, scaleModel, yExtentComponent.yAxis.state, () => yExtentComponent.yAxis.model.baseLabelsModel.labels, () => yExtentComponent.toY(yExtentComponent.getBaseline()));
139
139
  yExtentComponent.addChildEntity(gridComponent);
140
140
  yExtentComponent.activate();
141
141
  this.yExtentComponents.push(yExtentComponent);
@@ -4,7 +4,6 @@
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 { FullChartConfig } from '../../chart.config';
7
- import { DrawingManager } from '../../drawers/drawing-manager';
8
7
  import { ChartBaseElement } from '../../model/chart-base-element';
9
8
  import { Pixel, Unit } from '../../model/scaling/viewport.model';
10
9
  import { ChartComponent } from '../chart/chart.component';
@@ -13,13 +12,12 @@ import { PaneComponent } from '../pane/pane.component';
13
12
  import { VolumesModel } from './volumes.model';
14
13
  export declare class SeparateVolumesComponent extends ChartBaseElement {
15
14
  private chartComponent;
16
- private drawingManager;
17
15
  config: FullChartConfig;
18
16
  private volumesModel;
19
17
  private paneManager;
20
18
  static UUID: string;
21
19
  pane: PaneComponent | undefined;
22
- constructor(chartComponent: ChartComponent, drawingManager: DrawingManager, config: FullChartConfig, volumesModel: VolumesModel, paneManager: PaneManager);
20
+ constructor(chartComponent: ChartComponent, config: FullChartConfig, volumesModel: VolumesModel, paneManager: PaneManager);
23
21
  protected doActivate(): void;
24
22
  /**
25
23
  * Activates the separate volumes feature.
@@ -7,10 +7,9 @@ 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
9
  class SeparateVolumesComponent extends ChartBaseElement {
10
- constructor(chartComponent, drawingManager, config, volumesModel, paneManager) {
10
+ constructor(chartComponent, config, volumesModel, paneManager) {
11
11
  super();
12
12
  this.chartComponent = chartComponent;
13
- this.drawingManager = drawingManager;
14
13
  this.config = config;
15
14
  this.volumesModel = volumesModel;
16
15
  this.paneManager = paneManager;
@@ -53,7 +52,6 @@ class SeparateVolumesComponent extends ChartBaseElement {
53
52
  deactiveSeparateVolumes() {
54
53
  this.paneManager.removePane(SeparateVolumesComponent.UUID);
55
54
  delete this.pane;
56
- this.drawingManager.removeDrawerByName('UNDERLAY_VOLUMES_AREA');
57
55
  }
58
56
  /**
59
57
  * Converts a pixel value from the Y-axis of the scale model to the corresponding data value.
@@ -23,7 +23,7 @@ export class VolumesComponent extends ChartBaseElement {
23
23
  const volumesModel = new VolumesModel(chartComponent, scale);
24
24
  this.volumesModel = volumesModel;
25
25
  this.addChildEntity(volumesModel);
26
- this.separateVolumes = new SeparateVolumesComponent(chartComponent, drawingManager, config, volumesModel, paneManager);
26
+ this.separateVolumes = new SeparateVolumesComponent(chartComponent, config, volumesModel, paneManager);
27
27
  this.volumesDrawer = new VolumesDrawer(config, this.volumesModel, chartComponent.chartModel, () => { var _a, _b; return (this.config.components.volumes.showSeparately ? (_b = (_a = this.separateVolumes.pane) === null || _a === void 0 ? void 0 : _a.scale) !== null && _b !== void 0 ? _b : scale : scale); }, this.volumesColorByChartTypeMap, () => true);
28
28
  config.components.volumes.visible && this.syncVolumesDynamicObject();
29
29
  this.addChildEntity(this.separateVolumes);
@@ -101,12 +101,12 @@ export class VolumesDrawer {
101
101
  const width = nextX !== undefined ? nextX - x : floorToDPR(unitToPixels(vCandle.width, viewportModel.zoomX));
102
102
  if (this.config.components.volumes.showSeparately) {
103
103
  const y = floorToDPR(viewportModel.toY(vCandle.candle.volume));
104
- const height = floorToDPR(viewportModel.toY(0)) - y;
104
+ const height = ceilToDPR(viewportModel.toY(0)) - y;
105
105
  this.drawVolume(canvasModel, vCandle, x, y, width, height);
106
106
  }
107
107
  else {
108
108
  const zoomY = volumeMax / (fullVHeight / OVERLAY_VOLUME_TOTAL_HEIGHT_DIVISOR);
109
- const height = Math.max(unitToPixels(vCandle.candle.volume, zoomY), 2);
109
+ const height = Math.max(ceilToDPR(unitToPixels(vCandle.candle.volume, zoomY)), 2);
110
110
  const y = floorToDPR(bounds.y + fullVHeight - height);
111
111
  this.drawVolume(canvasModel, vCandle, x, y, width, height);
112
112
  }
@@ -139,7 +139,7 @@ export class VolumesDrawer {
139
139
  ctx.stroke();
140
140
  }
141
141
  else {
142
- ctx.fillRect(x, y, width, ceilToDPR(height));
142
+ ctx.fillRect(x, y, width, height);
143
143
  }
144
144
  }
145
145
  }
@@ -5,21 +5,12 @@
5
5
  */
6
6
  import { CanvasBoundsContainer } from '../../canvas/canvas-bounds-container';
7
7
  import { ChartBaseElement } from '../../model/chart-base-element';
8
- import { FullChartConfig } from '../../chart.config';
8
+ import { ChartConfigComponentsWaterMark, FullChartConfig } from '../../chart.config';
9
9
  import { CanvasModel } from '../../model/canvas.model';
10
10
  import { DrawingManager } from '../../drawers/drawing-manager';
11
11
  import EventBus from '../../events/event-bus';
12
12
  import { ChartModel } from '../chart/chart.model';
13
13
  import { PaneManager } from '../pane/pane-manager.component';
14
- export interface WaterMarkConfig {
15
- isVisible?: boolean;
16
- fontFamily?: string;
17
- firstRowFontSize?: number;
18
- firstRowBottomPadding?: number;
19
- secondRowFontSize?: number;
20
- secondRowBottomPadding?: number;
21
- thirdRowFontSize?: number;
22
- }
23
14
  export interface WaterMarkData {
24
15
  firstRow?: string;
25
16
  secondRow?: string;
@@ -55,11 +46,11 @@ export declare class WaterMarkComponent extends ChartBaseElement {
55
46
  private getWaterMarkData;
56
47
  /**
57
48
  * Sets the watermark configuration for the chart.
58
- * @param {WaterMarkConfig} watermarkConfig - The configuration object for the watermark.
49
+ * @param {ChartConfigComponentsWaterMark} watermarkConfig - The configuration object for the watermark.
59
50
  * @returns {void}
60
51
 
61
52
  */
62
- setWaterMarkConfig(watermarkConfig: WaterMarkConfig): void;
53
+ setWaterMarkConfig(watermarkConfig: ChartConfigComponentsWaterMark): void;
63
54
  /**
64
55
  * Sets the logo image to be used as a watermark.
65
56
  * @param {CanvasImageSource} img - The image to be used as a watermark.
@@ -56,7 +56,7 @@ export class WaterMarkComponent extends ChartBaseElement {
56
56
  }
57
57
  /**
58
58
  * Sets the watermark configuration for the chart.
59
- * @param {WaterMarkConfig} watermarkConfig - The configuration object for the watermark.
59
+ * @param {ChartConfigComponentsWaterMark} watermarkConfig - The configuration object for the watermark.
60
60
  * @returns {void}
61
61
 
62
62
  */
@@ -75,7 +75,7 @@ export const parseTimeFormatsFromKey = (format) => {
75
75
  };
76
76
  }
77
77
  else {
78
- console.warn(`${format} is not fit, check the documentation to see available formats https://webdev.prosp.devexperts.com:8095/docs/chart/x-axis`);
78
+ console.warn(`${format} is not fit, check the documentation to see available formats in dxchart-lite documentation.`);
79
79
  return null;
80
80
  }
81
81
  };
@@ -18,7 +18,7 @@ export interface XAxisLabelsGenerator {
18
18
  /**
19
19
  * Generates x-axis labels from scratch. Heavy operation.
20
20
  */
21
- generateLabels(): void;
21
+ generateLabels(prependedCandles?: VisualCandle[]): void;
22
22
  /**
23
23
  * Updates current labels state (x-position). Lightweight operation.
24
24
  */
@@ -107,7 +107,7 @@ export declare class XAxisTimeLabelsGenerator implements XAxisLabelsGenerator {
107
107
  * Calls the method generateWeightedLabels to generate labels.
108
108
  * @returns {void}
109
109
  */
110
- generateLabels(): void;
110
+ generateLabels(prependedCandles?: VisualCandle[]): void;
111
111
  /**
112
112
  * Recalculates the labels by calling the method recalculateCachedLabels.
113
113
  * @returns {void}
@@ -86,14 +86,14 @@ export class XAxisTimeLabelsGenerator {
86
86
  /**
87
87
  * Make a prediction(750) about how many candles we need to fake to fill all X axis by labels
88
88
  */
89
- getAllCandlesWithFake() {
89
+ getAllCandlesWithFake(prependedCandles = []) {
90
90
  const visualCandles = this.chartModel.mainCandleSeries.visualPoints;
91
91
  if (visualCandles.length === 0) {
92
92
  return [];
93
93
  }
94
94
  const fakeCandlesForSides = Array.from({ length: 750 });
95
95
  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
- return [...visualCandles, ...appendFakeCandle];
96
+ return [...prependedCandles, ...visualCandles, ...appendFakeCandle];
97
97
  }
98
98
  /**
99
99
  * Maps an array of weighted points to an array of XAxisLabelWeighted objects.
@@ -139,8 +139,8 @@ export class XAxisTimeLabelsGenerator {
139
139
  * @function
140
140
  * @returns {void}
141
141
  */
142
- generateWeightedLabels() {
143
- const allCandlesWithFake = this.getAllCandlesWithFake();
142
+ generateWeightedLabels(prependedCandles = []) {
143
+ const allCandlesWithFake = this.getAllCandlesWithFake(prependedCandles);
144
144
  const weightedPoints = mapCandlesToWeightedPoints(allCandlesWithFake, this.weightToTimeFormatMatcherArray, this.timeZoneModel.tzOffset(this.config.timezone));
145
145
  const weightedLabels = this.mapWeightedPointsToLabels(weightedPoints, allCandlesWithFake);
146
146
  this.labelsGroupedByWeight = groupLabelsByWeight(weightedLabels);
@@ -253,8 +253,8 @@ export class XAxisTimeLabelsGenerator {
253
253
  * Calls the method generateWeightedLabels to generate labels.
254
254
  * @returns {void}
255
255
  */
256
- generateLabels() {
257
- this.generateWeightedLabels();
256
+ generateLabels(prependedCandles) {
257
+ this.generateWeightedLabels(prependedCandles);
258
258
  }
259
259
  /**
260
260
  * Recalculates the labels by calling the method recalculateCachedLabels.
@@ -47,8 +47,8 @@ export class XAxisScaleHandler extends ChartBaseElement {
47
47
  // Continue redrawing hit test
48
48
  this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(true);
49
49
  };
50
- this.setDblTapCallback = (cb) => this.dblTapCallback = cb;
51
- this.setDblClickCallback = (cb) => this.dblClickCallback = cb;
50
+ this.setDblTapCallback = (cb) => (this.dblTapCallback = cb);
51
+ this.setDblClickCallback = (cb) => (this.dblClickCallback = cb);
52
52
  this.dblClickCallback = () => chartModel.doBasicScale();
53
53
  this.dblTapCallback = () => chartModel.doBasicScale();
54
54
  const dragNDropXComponent = new DragNDropXComponent(hitTest, {
@@ -82,7 +82,7 @@ export class XAxisComponent extends ChartBaseElement {
82
82
  this.xAxisLabelsGenerator.recalculateLabels();
83
83
  }));
84
84
  this.addRxSubscription(this.chartComponent.chartModel.candlesUpdatedSubject
85
- .pipe(map(() => lastOf(this.chartComponent.chartModel.mainCandleSeries.visualPoints)), distinctUntilChanged((a, b) => { var _a, _b; return ((_a = a === null || a === void 0 ? void 0 : a.candle) === null || _a === void 0 ? void 0 : _a.timestamp) === ((_b = b === null || b === void 0 ? void 0 : b.candle) === null || _b === void 0 ? void 0 : _b.timestamp); }), filter(notEmpty))
85
+ .pipe(map(() => lastOf(this.chartComponent.chartModel.mainCandleSeries.visualPoints)), distinctUntilChanged((a, b) => { var _a, _b; return ((_a = a === null || a === void 0 ? void 0 : a.candle) === null || _a === void 0 ? void 0 : _a.id) === ((_b = b === null || b === void 0 ? void 0 : b.candle) === null || _b === void 0 ? void 0 : _b.id); }), filter(notEmpty))
86
86
  .subscribe(x => { var _a, _b; return (_b = (_a = this.xAxisLabelsGenerator) === null || _a === void 0 ? void 0 : _a.updateLastLabel) === null || _b === void 0 ? void 0 : _b.call(_a, x); }));
87
87
  }
88
88
  /**
@@ -4,7 +4,7 @@
4
4
  * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
5
  */
6
6
  import { Subject } from 'rxjs';
7
- import { CanvasElement, DEFAULT_MIN_PANE_HEIGHT } from '../../canvas/canvas-bounds-container';
7
+ import { CanvasElement, DEFAULT_MIN_PANE_HEIGHT, } from '../../canvas/canvas-bounds-container';
8
8
  import { ChartBaseElement } from '../../model/chart-base-element';
9
9
  import { DragNDropYComponent } from '../dran-n-drop_helper/drag-n-drop-y.component';
10
10
  // if you drag full Y height from top to bottom - you will have x3 zoom, and vice-versa
@@ -73,8 +73,8 @@ export class YAxisScaleHandler extends ChartBaseElement {
73
73
  // Continue redrawing hit test
74
74
  this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(true);
75
75
  };
76
- this.setDblTapCallback = (cb) => this.dblTapCallback = cb;
77
- this.setDblClickCallback = (cb) => this.dblClickCallback = cb;
76
+ this.setDblTapCallback = (cb) => (this.dblTapCallback = cb);
77
+ this.setDblClickCallback = (cb) => (this.dblClickCallback = cb);
78
78
  this.dblClickCallback = () => scale.autoScale(true);
79
79
  this.dblTapCallback = () => scale.autoScale(true);
80
80
  // drag to Y-scale and double click to auto scale
@@ -6,7 +6,7 @@
6
6
  import EventBus from '../events/event-bus';
7
7
  import { ChartResizeHandler } from '../inputhandlers/chart-resize.handler';
8
8
  export declare const HIT_TEST_PREFIX = "HIT_TEST_";
9
- declare const drawerTypes: readonly ["MAIN_BACKGROUND", "MAIN_CLEAR", "HIT_TEST_CLEAR", "YAXIS_CLEAR", "SERIES_CLEAR", "OVER_SERIES_CLEAR", "HIT_TEST_DRAWINGS", "GRID", "UNDERLAY_VOLUMES_AREA", "X_AXIS", "Y_AXIS", "HIGH_LOW", "DYNAMIC_OBJECTS", "N_MAP_CHART", "PL_CHART", "WATERMARK", "EMPTY_CHART", "OFFLINE_CHART", "LABELS", "EVENTS", "HIT_TEST_EVENTS", "ZERO_LINE", "PL_ZERO_LINE_BACKGROUND", "CROSS_TOOL"];
9
+ declare const drawerTypes: readonly ["MAIN_BACKGROUND", "MAIN_CLEAR", "HIT_TEST_CLEAR", "YAXIS_CLEAR", "SERIES_CLEAR", "OVER_SERIES_CLEAR", "HIT_TEST_DRAWINGS", "GRID", "X_AXIS", "Y_AXIS", "HIGH_LOW", "DYNAMIC_OBJECTS", "N_MAP_CHART", "PL_CHART", "WATERMARK", "EMPTY_CHART", "OFFLINE_CHART", "LABELS", "EVENTS", "HIT_TEST_EVENTS", "ZERO_LINE", "PL_ZERO_LINE_BACKGROUND", "CROSS_TOOL"];
10
10
  export type DrawerType = typeof drawerTypes[number];
11
11
  /**
12
12
  * Manages the drawing process.
@@ -18,7 +18,6 @@ const drawerTypes = [
18
18
  'OVER_SERIES_CLEAR',
19
19
  'HIT_TEST_DRAWINGS',
20
20
  'GRID',
21
- 'UNDERLAY_VOLUMES_AREA',
22
21
  'X_AXIS',
23
22
  'Y_AXIS',
24
23
  'HIGH_LOW',
@@ -4,6 +4,7 @@
4
4
  * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
5
  */
6
6
  import { BehaviorSubject, merge } from 'rxjs';
7
+ import { filter, switchMap } from 'rxjs/operators';
7
8
  import { CHART_UUID, CanvasElement } from '../canvas/canvas-bounds-container';
8
9
  import { CandleHoverProducerPart } from '../model/candle-hover';
9
10
  import { ChartBaseElement } from '../model/chart-base-element';
@@ -50,8 +51,13 @@ export class HoverProducerComponent extends ChartBaseElement {
50
51
  */
51
52
  doActivate() {
52
53
  super.doActivate();
53
- this.addRxSubscription(this.chartModel.candlesSetSubject.subscribe(() => {
54
- // required for initial legend initialization, do not show cross tool
54
+ this.addRxSubscription(
55
+ // required for initial legend initialization, do not show cross tool
56
+ this.chartModel.candlesSetSubject
57
+ .pipe(
58
+ // check the scale is valid before doing candle-based hover event
59
+ switchMap(() => this.scale.initialViewportValidSubject.pipe(filter(Boolean))))
60
+ .subscribe(() => {
55
61
  const lastCandle = this.chartModel.getLastVisualCandle();
56
62
  lastCandle && this.createAndFireHoverFromCandle(lastCandle);
57
63
  }));
@@ -89,7 +89,7 @@ export class MainCanvasTouchHandler extends ChartBaseElement {
89
89
  const last = first +
90
90
  ((candleIndexes[0] - candleIndexes[1]) / (touchPositions[0] - touchPositions[1])) *
91
91
  this.scale.getBounds().width;
92
- if (first >= last) {
92
+ if (first >= last || touchPositions[0] === touchPositions[1]) {
93
93
  return;
94
94
  }
95
95
  this.scale.setXScale(first, last);
@@ -11,6 +11,7 @@ export declare const BASIC_CANDLE_WIDTH: Unit;
11
11
  * @doc-tags-name Candle
12
12
  */
13
13
  export interface Candle {
14
+ readonly id: string;
14
15
  readonly hi: number;
15
16
  readonly lo: number;
16
17
  readonly open: number;
@@ -22,6 +23,8 @@ export interface Candle {
22
23
  readonly impVolatility?: number;
23
24
  readonly vwap?: number;
24
25
  }
26
+ export declare const defaultSortCandles: (candles: Candle[]) => Candle[];
27
+ export declare const generateCandleId: (timestamp: number, hashValue: number | string) => string;
25
28
  /**
26
29
  * Provides the name of candle difference
27
30
  * @param {Number} open