@devexperts/dxcharts-lite 2.5.8 → 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 (45) 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/canvas/canvas-bounds-container.js +24 -3
  4. package/dist/chart/chart.config.d.ts +2 -0
  5. package/dist/chart/chart.config.js +2 -1
  6. package/dist/chart/components/chart/candle-transformer.functions.js +1 -1
  7. package/dist/chart/components/chart/candle.functions.d.ts +1 -1
  8. package/dist/chart/components/chart/candle.functions.js +3 -2
  9. package/dist/chart/components/chart/chart.component.d.ts +29 -8
  10. package/dist/chart/components/chart/chart.component.js +33 -4
  11. package/dist/chart/components/chart/chart.model.d.ts +41 -4
  12. package/dist/chart/components/chart/chart.model.js +90 -16
  13. package/dist/chart/components/chart/fake-candles.js +2 -0
  14. package/dist/chart/components/chart/fake-visual-candle.d.ts +4 -4
  15. package/dist/chart/components/chart/fake-visual-candle.js +4 -4
  16. package/dist/chart/components/volumes/separate-volumes.component.d.ts +1 -3
  17. package/dist/chart/components/volumes/separate-volumes.component.js +1 -3
  18. package/dist/chart/components/volumes/volumes.component.js +1 -1
  19. package/dist/chart/components/volumes/volumes.drawer.js +3 -3
  20. package/dist/chart/components/watermark/water-mark.component.d.ts +3 -12
  21. package/dist/chart/components/watermark/water-mark.component.js +1 -1
  22. package/dist/chart/components/x_axis/time/parser/time-formats-parser.functions.js +1 -1
  23. package/dist/chart/components/x_axis/x-axis-scale.handler.js +2 -2
  24. package/dist/chart/components/x_axis/x-axis.component.js +1 -1
  25. package/dist/chart/components/y_axis/y-axis-scale.handler.js +3 -3
  26. package/dist/chart/drawers/drawing-manager.d.ts +1 -1
  27. package/dist/chart/drawers/drawing-manager.js +0 -1
  28. package/dist/chart/inputhandlers/hover-producer.component.js +8 -2
  29. package/dist/chart/model/candle.model.d.ts +3 -0
  30. package/dist/chart/model/candle.model.js +7 -1
  31. package/dist/chart/model/data-series.model.d.ts +3 -3
  32. package/dist/chart/model/data-series.model.js +1 -1
  33. package/dist/chart/model/scale.model.js +1 -1
  34. package/dist/chart/model/scaling/viewport.model.d.ts +2 -1
  35. package/dist/chart/model/scaling/viewport.model.js +6 -1
  36. package/dist/chart/model/time-zone.model.js +1 -3
  37. package/dist/chart/utils/candles-generator-ts.utils.d.ts +1 -0
  38. package/dist/chart/utils/candles-generator.utils.d.ts +1 -0
  39. package/dist/chart/utils/candles-generator.utils.js +2 -0
  40. package/dist/chart/utils/string.utils.d.ts +6 -0
  41. package/dist/chart/utils/string.utils.js +19 -0
  42. package/dist/chart/utils/types.utils.d.ts +9 -0
  43. package/dist/chart/utils/types.utils.js +6 -0
  44. package/dist/dxchart.min.js +4 -4
  45. package/package.json +1 -1
@@ -1,8 +1,3 @@
1
- /*
2
- * Copyright (C) 2019 - 2024 Devexperts Solutions IE Limited
3
- * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
- * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
5
- */
6
1
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7
2
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
8
3
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -12,6 +7,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
12
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13
8
  });
14
9
  };
10
+ /*
11
+ * Copyright (C) 2019 - 2024 Devexperts Solutions IE Limited
12
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
13
+ * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
14
+ */
15
15
  import './env';
16
16
  import { createChart } from '../../index';
17
17
  import { generateCandlesDataTS } from '../utils/candles-generator-ts.utils';
@@ -1,9 +1,9 @@
1
+ "use strict";
1
2
  /*
2
3
  * Copyright (C) 2019 - 2024 Devexperts Solutions IE Limited
3
4
  * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
5
  * 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
  */
6
- "use strict";
7
7
  /* @see https://jestjs.io/docs/29.4/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom */
8
8
  Object.defineProperty(window, 'matchMedia', {
9
9
  writable: true,
@@ -455,14 +455,33 @@ export class CanvasBoundsContainer {
455
455
  const oldPecNumber = visiblePecRatios.filter(ratio => ratio !== undefined).length;
456
456
  // if ratio in undefined for a given pane it means that it's a new pane
457
457
  const newPecNumber = pecRatios.filter(ratio => ratio === undefined).length;
458
+ const paneIsAdded = newPecNumber > 0;
458
459
  let freeRatioForPec = 0;
459
460
  let freeRatio = 0;
460
461
  let ratioForOldPec = 1;
461
462
  let ratioForNewPec = 0;
462
- if (newPecNumber > 0) {
463
+ if (paneIsAdded) {
463
464
  [ratioForOldPec, ratioForNewPec] = getHeightRatios(visiblePecNumber);
464
- chartRatio *= ratioForOldPec;
465
465
  }
466
+ //#region chart height ratio logic
467
+ if (this.graphsHeightRatio[CHART_UUID] === 0) {
468
+ chartRatio = 0;
469
+ }
470
+ if (this.graphsHeightRatio[CHART_UUID] !== 0) {
471
+ if (paneIsAdded) {
472
+ chartRatio = 1 * ratioForOldPec;
473
+ }
474
+ else {
475
+ // pec ratio values before recalculating and new chart ratio
476
+ const currentHeightRatioValues = Object.values(this.graphsHeightRatio).reduce((prev, curr) => (curr += prev));
477
+ // chart is hidden and one of the pec is removed
478
+ // since the chart height ratio is new, the currentHeightRatioValues could be > 1, it happens if make chart visible again
479
+ if (currentHeightRatioValues < 1 && this.graphsHeightRatio[CHART_UUID] !== 0) {
480
+ chartRatio += 1 - currentHeightRatioValues;
481
+ }
482
+ }
483
+ }
484
+ //#endregion
466
485
  // this means we should keep in mind only new panes
467
486
  if (oldPecNumber === 0) {
468
487
  chartRatio = 1 - ratioForNewPec * newPecNumber;
@@ -856,13 +875,15 @@ export class CanvasBoundsContainer {
856
875
  }
857
876
  }
858
877
  // paneCounter=chartHeightRatio: 0=1, 1=0.8, 2=0.6, 3=0.5, 4=0.4, 5=0.4
878
+ // ratios requirements table: https://confluence.in.devexperts.com/display/UI/Chart+Navigation#ChartNavigation-2Graphsadjustablesizes
859
879
  const DEFAULT_RATIOS = {
860
880
  0: 1,
861
881
  1: 0.8,
862
882
  2: 0.6,
863
883
  3: 0.5,
864
884
  4: 0.4,
865
- 5: 0.2,
885
+ 5: 0.4,
886
+ 6: 0.4,
866
887
  };
867
888
  // NOTE: pec stands for panes except main chart
868
889
  export const getHeightRatios = (pecLength) => {
@@ -14,6 +14,7 @@ import { DrawerType } from './drawers/drawing-manager';
14
14
  import { DateTimeFormatter, TimeFormatterConfig } from './model/date-time.formatter';
15
15
  import { MergeOptions } from './utils/merge.utils';
16
16
  import { DeepPartial } from './utils/object.utils';
17
+ import { Candle } from './model/candle.model';
17
18
  export declare const MAIN_FONT = "Open Sans Semibold, sans-serif";
18
19
  export interface DateTimeFormatConfig {
19
20
  format: string;
@@ -321,6 +322,7 @@ export interface ChartConfigComponentsChart {
321
322
  selectedWidth: number;
322
323
  minCandlesOffset: number;
323
324
  histogram: ChartConfigComponentsHistogram;
325
+ sortCandles?: (candles: Candle[]) => Candle[];
324
326
  }
325
327
  export interface ChartConfigComponentsEvents {
326
328
  /**
@@ -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 { DEFAULT_MERGE_OPTIONS, merge } from './utils/merge.utils';
7
+ import { defaultSortCandles } from './model/candle.model';
7
8
  export const MAIN_FONT = 'Open Sans Semibold, sans-serif';
8
9
  export const LastBarRedrawableBarTypes = ['candle', 'bar', 'scatterPlot', 'trend', 'hollow', 'histogram'];
9
10
  export const availableBarTypes = [
@@ -70,6 +71,7 @@ export const getDefaultConfig = () => ({
70
71
  histogram: {
71
72
  barCapSize: 1,
72
73
  },
74
+ sortCandles: defaultSortCandles,
73
75
  },
74
76
  yAxis: {
75
77
  type: 'regular',
@@ -537,7 +539,6 @@ export const getDefaultConfig = () => ({
537
539
  'GRID',
538
540
  'X_AXIS',
539
541
  'Y_AXIS',
540
- 'UNDERLAY_VOLUMES_AREA',
541
542
  'DYNAMIC_OBJECTS',
542
543
  'WATERMARK',
543
544
  'N_MAP_CHART',
@@ -16,6 +16,6 @@ export const trendCandleTransformer = (candle, { x, width, activeCandle, prevCan
16
16
  };
17
17
  export const lineCandleTransformer = trendCandleTransformer;
18
18
  export const getCandleIsActive = (candle, activeCandle) => {
19
- const isActive = activeCandle && activeCandle.idx === candle.idx;
19
+ const isActive = activeCandle && activeCandle.id === candle.id;
20
20
  return isActive !== null && isActive !== void 0 ? isActive : false;
21
21
  };
@@ -15,6 +15,6 @@ export declare const prepareCandle: (candle: PartialCandle) => Candle | undefine
15
15
  * Adds index to candles according to their array index.
16
16
  * @param candles
17
17
  */
18
- export declare const reindexCandles: (candles: Array<Candle>) => void;
18
+ export declare const reindexCandles: (candles: Array<Candle>, startIdx?: number) => void;
19
19
  export declare const deleteCandlesIndex: (candles: Array<Candle>) => void;
20
20
  export declare const isCandle: (value: Candle | undefined) => value is Candle;
@@ -23,6 +23,7 @@ export const prepareCandle = (candle) => {
23
23
  const preparedCandleOpen = finite(candle.open, candle.lo, settlementPrice);
24
24
  const preparedCandleClose = finite(candle.close, candle.hi, settlementPrice);
25
25
  return {
26
+ id: candle.id,
26
27
  hi: preparedCandleHi,
27
28
  lo: preparedCandleLo,
28
29
  open: preparedCandleOpen,
@@ -43,8 +44,8 @@ export const prepareCandle = (candle) => {
43
44
  * Adds index to candles according to their array index.
44
45
  * @param candles
45
46
  */
46
- export const reindexCandles = (candles) => {
47
- for (let i = 0; i < candles.length; ++i) {
47
+ export const reindexCandles = (candles, startIdx = 0) => {
48
+ for (let i = startIdx; i < candles.length; ++i) {
48
49
  candles[i].idx = i;
49
50
  }
50
51
  };
@@ -25,6 +25,7 @@ import { CandleWidthCalculator, ChartModel, LastCandleLabelHandler, VisualCandle
25
25
  import { PrependedCandlesData } from './chart-base.model';
26
26
  import { DynamicObjectsComponent } from '../dynamic-objects/dynamic-objects.component';
27
27
  import { ChartResizeHandler } from '../../inputhandlers/chart-resize.handler';
28
+ import { PartialExcept } from '../../utils/types.utils';
28
29
  /**
29
30
  * Represents a financial instrument to be displayed on a chart
30
31
  * @class
@@ -41,10 +42,7 @@ export declare class ChartInstrument {
41
42
  */
42
43
  priceIncrements?: Array<number>;
43
44
  }
44
- export type PartialCandle = Partial<Candle> & {
45
- timestamp: Timestamp;
46
- close: number;
47
- };
45
+ export type PartialCandle = PartialExcept<Candle, 'id' | 'timestamp' | 'close'>;
48
46
  export interface CandleSeries {
49
47
  candles: PartialCandle[];
50
48
  instrument?: ChartInstrument;
@@ -190,19 +188,42 @@ export declare class ChartComponent extends ChartBaseElement {
190
188
  /**
191
189
  * Adds new candle to the chart
192
190
  * @param candle - new candle
193
- * @param instrument - name of the instrument to update
191
+ * @param instrumentSymbol - name of the instrument to update
194
192
  */
195
193
  addLastCandle(candle: Candle, instrumentSymbol?: string): void;
196
194
  /**
197
- * Remove candle by idx and recaculate indexes
195
+ * Remove candle by idx and recalculate indexes
198
196
  * @param idx - candle index
199
- * @param instrument - name of the instrument to update
197
+ * @param instrumentSymbol - name of the instrument to update
200
198
  */
201
199
  removeCandleByIdx(idx: number, instrumentSymbol?: string): void;
200
+ /**
201
+ * Remove candles by ids and recalculate indexes, candles should be as a sequence, follow one by one
202
+ * Works faster than removeCandlesByIds
203
+ *
204
+ * @param ids - candles ids to remove
205
+ * @param selectedCandleSeries - candle series to remove candles from
206
+ */
207
+ removeCandlesByIdsSequence(ids: Candle['id'][], selectedCandleSeries?: CandleSeriesModel): void;
208
+ /**
209
+ * Remove candles by ids and recalculate indexes
210
+ *
211
+ * @param ids - candles ids to remove
212
+ * @param selectedCandleSeries - candle series to remove candles from
213
+ */
214
+ removeCandlesByIds(ids: Candle['id'][], selectedCandleSeries?: CandleSeriesModel): void;
215
+ /**
216
+ * Add candles by id and recalculate indexes
217
+ *
218
+ * @param candles - candles to add
219
+ * @param startId - target candle to start adding candles from
220
+ * @param selectedCandleSeries - candle series to add candles to
221
+ */
222
+ addCandlesById(candles: Candle[], startId: string, selectedCandleSeries?: CandleSeriesModel): void;
202
223
  /**
203
224
  * Updates last candle value
204
225
  * @param candle - updated candle
205
- * @param instrument - name of the instrument to update
226
+ * @param instrumentSymbol - name of the instrument to update
206
227
  */
207
228
  updateLastCandle(candle: Candle, instrumentSymbol?: string): void;
208
229
  /**
@@ -337,23 +337,52 @@ export class ChartComponent extends ChartBaseElement {
337
337
  /**
338
338
  * Adds new candle to the chart
339
339
  * @param candle - new candle
340
- * @param instrument - name of the instrument to update
340
+ * @param instrumentSymbol - name of the instrument to update
341
341
  */
342
342
  addLastCandle(candle, instrumentSymbol) {
343
343
  this.chartModel.addLastCandle(candle, instrumentSymbol);
344
344
  }
345
345
  /**
346
- * Remove candle by idx and recaculate indexes
346
+ * Remove candle by idx and recalculate indexes
347
347
  * @param idx - candle index
348
- * @param instrument - name of the instrument to update
348
+ * @param instrumentSymbol - name of the instrument to update
349
349
  */
350
350
  removeCandleByIdx(idx, instrumentSymbol) {
351
351
  this.chartModel.removeCandleByIdx(idx, instrumentSymbol);
352
352
  }
353
+ /**
354
+ * Remove candles by ids and recalculate indexes, candles should be as a sequence, follow one by one
355
+ * Works faster than removeCandlesByIds
356
+ *
357
+ * @param ids - candles ids to remove
358
+ * @param selectedCandleSeries - candle series to remove candles from
359
+ */
360
+ removeCandlesByIdsSequence(ids, selectedCandleSeries = this.chartModel.mainCandleSeries) {
361
+ this.chartModel.removeCandlesByIdsSequence(ids, selectedCandleSeries);
362
+ }
363
+ /**
364
+ * Remove candles by ids and recalculate indexes
365
+ *
366
+ * @param ids - candles ids to remove
367
+ * @param selectedCandleSeries - candle series to remove candles from
368
+ */
369
+ removeCandlesByIds(ids, selectedCandleSeries = this.chartModel.mainCandleSeries) {
370
+ this.chartModel.removeCandlesByIds(ids, selectedCandleSeries);
371
+ }
372
+ /**
373
+ * Add candles by id and recalculate indexes
374
+ *
375
+ * @param candles - candles to add
376
+ * @param startId - target candle to start adding candles from
377
+ * @param selectedCandleSeries - candle series to add candles to
378
+ */
379
+ addCandlesById(candles, startId, selectedCandleSeries = this.chartModel.mainCandleSeries) {
380
+ this.chartModel.addCandlesById(candles, startId, selectedCandleSeries);
381
+ }
353
382
  /**
354
383
  * Updates last candle value
355
384
  * @param candle - updated candle
356
- * @param instrument - name of the instrument to update
385
+ * @param instrumentSymbol - name of the instrument to update
357
386
  */
358
387
  updateLastCandle(candle, instrumentSymbol) {
359
388
  this.chartModel.updateLastCandle(candle, instrumentSymbol);
@@ -228,6 +228,19 @@ export declare class ChartModel extends ChartBaseElement {
228
228
  * @param timestamp
229
229
  */
230
230
  candleFromTimestamp(timestamp: Timestamp, extrapolate?: boolean, selectedCandleSeries?: CandleSeriesModel): VisualCandle;
231
+ /**
232
+ * For given id finds the target candle
233
+ * @param id
234
+ * @param selectedCandleSeries
235
+ */
236
+ candleFromId(id: Candle['id'], selectedCandleSeries?: CandleSeriesModel): VisualCandle | undefined;
237
+ /**
238
+ * For given id finds the target candle index
239
+ * @param id
240
+ * @param selectedCandleSeries
241
+ * @returns candle index, -1 if not found
242
+ */
243
+ candleIdxFromId(id: Candle['id'], selectedCandleSeries?: CandleSeriesModel): number;
231
244
  /**
232
245
  * For given index returns the closest visual candle, or fake candle with correct X coordinate.
233
246
  * @param idx - index of candle
@@ -358,7 +371,7 @@ export declare class ChartModel extends ChartBaseElement {
358
371
  * Updates candles in series. Default is main series.
359
372
  * Any number of candles may be provided - they would be matched by their index and updated.
360
373
  * @param candles - any list of new (updated) candles
361
- * @param instrument - name of instrument to update
374
+ * @param instrumentSymbol - name of instrument to update
362
375
  */
363
376
  updateCandles(candles: Array<Candle>, instrumentSymbol?: string): void;
364
377
  /**
@@ -400,21 +413,45 @@ export declare class ChartModel extends ChartBaseElement {
400
413
  /**
401
414
  * Adds new candle to the chart
402
415
  * @param candle - new candle
403
- * @param instrument - name of the instrument to update
416
+ * @param instrumentSymbol - name of the instrument to update
404
417
  */
405
418
  addLastCandle(candle: Candle, instrumentSymbol?: string): void;
406
419
  /**
407
420
  * Updates last candle value
408
421
  * @param candle - updated candle
409
- * @param instrument - name of the instrument to update
422
+ * @param instrumentSymbol - name of the instrument to update
410
423
  */
411
424
  updateLastCandle(candle: Candle, instrumentSymbol?: string): void;
412
425
  /**
413
426
  * Remove candle by idx and recaculate indexes
414
427
  * @param candle - new candle
415
- * @param instrument - name of the instrument to update
428
+ * @param instrumentSymbol - name of the instrument to update
416
429
  */
417
430
  removeCandleByIdx(idx: number, instrumentSymbol?: string): void;
431
+ /**
432
+ * Remove candles by ids and recalculate indexes, candles should be as a sequence, follow one by one
433
+ * Works faster than removeCandlesByIds
434
+ *
435
+ * @param ids - candles ids to remove
436
+ * @param selectedCandleSeries - candle series to remove candles from
437
+ */
438
+ removeCandlesByIdsSequence(ids: Candle['id'][], selectedCandleSeries: CandleSeriesModel): void;
439
+ /**
440
+ * Remove candles by ids and recalculate indexes
441
+ * @param ids - candles ids to remove
442
+ * @param selectedCandleSeries - candle series to remove candles from
443
+ */
444
+ removeCandlesByIds(ids: Candle['id'][], selectedCandleSeries: CandleSeriesModel): void;
445
+ /**
446
+ * Add candles by id and recalculate indexes
447
+ *
448
+ * @param candles - candles to add
449
+ * @param startId - target candle to start adding candles from
450
+ * @param selectedCandleSeries - candle series to add candles to
451
+ */
452
+ addCandlesById(candles: Candle[], startId: string, selectedCandleSeries: CandleSeriesModel): void;
453
+ private candlesChangedRedraw;
454
+ private prepareCandles;
418
455
  }
419
456
  export interface UpdateCandlesResult {
420
457
  prepended: Candle[];
@@ -59,6 +59,11 @@ 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));
@@ -164,7 +169,7 @@ export class ChartModel extends ChartBaseElement {
164
169
  * @returns {CandleSeriesModel | undefined} - The newly created secondary candle series model or undefined if it could not be created.
165
170
  */
166
171
  setSecondaryCandleSeries(candles, instrument = this.mainCandleSeries.instrument, recalculateAndUpdate = true) {
167
- const preparedCandles = prepareCandles(candles);
172
+ const preparedCandles = this.prepareCandles(candles);
168
173
  // set correct indexes based on main candles timestamp
169
174
  const reindexCandles = this.reindexCandlesBasedOnSeries(this.mainCandleSeries.dataPoints, preparedCandles);
170
175
  // ensure there are no gaps in new candles
@@ -200,7 +205,7 @@ export class ChartModel extends ChartBaseElement {
200
205
  this.mainInstrumentChangedSubject.next(mainSeries.instrument);
201
206
  }
202
207
  this.rememberCurrentTimeframe();
203
- const preparedCandles = prepareCandles(mainSeries.candles);
208
+ const preparedCandles = this.prepareCandles(mainSeries.candles);
204
209
  this.mainCandleSeries.clearData();
205
210
  reindexCandles(preparedCandles);
206
211
  this.mainCandleSeries.dataPoints = preparedCandles;
@@ -286,7 +291,7 @@ export class ChartModel extends ChartBaseElement {
286
291
  console.error('All series update failed. Instruments for series are different.');
287
292
  return;
288
293
  }
289
- const preparedCandles = prepareCandles(mainSeries.candles);
294
+ const preparedCandles = this.prepareCandles(mainSeries.candles);
290
295
  const updateResult = updateCandles(this.mainCandleSeries.dataPoints, preparedCandles);
291
296
  const updatedCandles = updateResult.candles;
292
297
  reindexCandles(updatedCandles);
@@ -294,7 +299,7 @@ export class ChartModel extends ChartBaseElement {
294
299
  // re-create series
295
300
  secondarySeries.map(series => {
296
301
  var _a, _b, _c, _d;
297
- const preparedCandles = prepareCandles(series.candles);
302
+ const preparedCandles = this.prepareCandles(series.candles);
298
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;
299
304
  return this.setSecondaryCandleSeries(updatedCandles, series.instrument, false);
300
305
  });
@@ -329,9 +334,7 @@ export class ChartModel extends ChartBaseElement {
329
334
  series.dataPoints = series.dataPoints.slice(0, index);
330
335
  });
331
336
  });
332
- this.candlesRemovedSubject.next();
333
- this.candlesUpdatedSubject.next();
334
- this.canvasModel.fireDraw();
337
+ this.candlesChangedRedraw();
335
338
  }
336
339
  /**
337
340
  * Creates a secondary candle series model for a given instrument.
@@ -377,8 +380,8 @@ export class ChartModel extends ChartBaseElement {
377
380
  secondarySeriesAdjustments(mainSeries, secondarySeries) {
378
381
  const result = [];
379
382
  mainSeries.forEach(mainCandle => {
380
- var _a;
381
- 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;
382
385
  const compareCandle = secondarySeries[idx];
383
386
  if (!compareCandle) {
384
387
  // take first candle to left or right
@@ -525,6 +528,23 @@ export class ChartModel extends ChartBaseElement {
525
528
  const dataPointsSource = selectedCandleSeries.dataPoints;
526
529
  return this.chartBaseModel.dataFromTimestamp(timestamp, extrapolate, dataPointsSource);
527
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
+ }
528
548
  /**
529
549
  * For given index returns the closest visual candle, or fake candle with correct X coordinate.
530
550
  * @param idx - index of candle
@@ -726,7 +746,7 @@ export class ChartModel extends ChartBaseElement {
726
746
  * Updates candles in series. Default is main series.
727
747
  * Any number of candles may be provided - they would be matched by their index and updated.
728
748
  * @param candles - any list of new (updated) candles
729
- * @param instrument - name of instrument to update
749
+ * @param instrumentSymbol - name of instrument to update
730
750
  */
731
751
  // I'd like to keep this method, for me one generic method is more convenient than 3 (updateLastCandle, addLastCandle, prepend...)
732
752
  updateCandles(candles, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
@@ -858,7 +878,7 @@ export class ChartModel extends ChartBaseElement {
858
878
  if (idx < 0) {
859
879
  prepend.push(c);
860
880
  }
861
- else if (target[idx].timestamp === c.timestamp) {
881
+ else if (target[idx].id === c.id) {
862
882
  targetCopy[idx] = c;
863
883
  }
864
884
  else {
@@ -873,7 +893,7 @@ export class ChartModel extends ChartBaseElement {
873
893
  /**
874
894
  * Adds new candle to the chart
875
895
  * @param candle - new candle
876
- * @param instrument - name of the instrument to update
896
+ * @param instrumentSymbol - name of the instrument to update
877
897
  */
878
898
  addLastCandle(candle, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
879
899
  this.updateCandles([candle], instrumentSymbol);
@@ -881,7 +901,7 @@ export class ChartModel extends ChartBaseElement {
881
901
  /**
882
902
  * Updates last candle value
883
903
  * @param candle - updated candle
884
- * @param instrument - name of the instrument to update
904
+ * @param instrumentSymbol - name of the instrument to update
885
905
  */
886
906
  updateLastCandle(candle, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
887
907
  this.updateCandles([candle], instrumentSymbol);
@@ -889,9 +909,12 @@ export class ChartModel extends ChartBaseElement {
889
909
  /**
890
910
  * Remove candle by idx and recaculate indexes
891
911
  * @param candle - new candle
892
- * @param instrument - name of the instrument to update
912
+ * @param instrumentSymbol - name of the instrument to update
893
913
  */
894
914
  removeCandleByIdx(idx, instrumentSymbol = this.mainCandleSeries.instrument.symbol) {
915
+ if (idx < 0) {
916
+ return;
917
+ }
895
918
  const seriesList = this.findSeriesBySymbol(instrumentSymbol);
896
919
  if (seriesList.length === 0) {
897
920
  console.warn("removeCandle by id failed. Can't find series", instrumentSymbol);
@@ -902,13 +925,64 @@ export class ChartModel extends ChartBaseElement {
902
925
  reindexCandles(series.dataPoints);
903
926
  series.recalculateVisualPoints();
904
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() {
905
981
  this.candlesRemovedSubject.next();
906
982
  this.candlesUpdatedSubject.next();
907
983
  this.canvasModel.fireDraw();
908
984
  }
909
985
  }
910
- const sortCandles = (candles) => candles.slice().sort((a, b) => (a.timestamp === b.timestamp ? 0 : a.timestamp > b.timestamp ? 1 : -1));
911
- const prepareCandles = (candles) => sortCandles(candles.map(prepareCandle).filter(isCandle));
912
986
  const findFirstNotEmptyCandle = (candles, startIdx, iterateStep) => {
913
987
  if (startIdx >= candles.length) {
914
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.
@@ -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.