@pipsend/charts 2.3.4 → 2.3.10

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.
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * Pipsend Charts v2.3.4
3
+ * Pipsend Charts v2.3.10
4
4
  * Copyright (c) 2026 Pipsend
5
5
  * Licensed under MIT License
6
6
  * Built on TradingView Lightweight Charts™ (Apache 2.0)
@@ -2486,14 +2486,8 @@
2486
2486
  return this._private__styleGetter(this._private__findBar, this._private__series._internal_options(), barIndex, precomputedBars);
2487
2487
  }
2488
2488
  /**
2489
- * Like `barStyle`, but returns null instead of throwing when the bar is
2490
- * gone.
2491
- *
2492
- * Recolouring walks items that were laid out against the data as it was. A
2493
- * bar that has since disappeared is not an error there: the view is about
2494
- * to be rebuilt from the new data anyway. Letting it throw took down
2495
- * whatever asked for the repaint — including `setData`, which left the
2496
- * series without its data and the pane empty until the page was reloaded.
2489
+ * Like `barStyle`, but null instead of throwing when the bar is gone, which
2490
+ * a recolour of items laid out against older data can hit.
2497
2491
  */
2498
2492
  _internal_barStyleOrNull(barIndex, precomputedBars) {
2499
2493
  if (precomputedBars === undefined && this._private__series._internal_bars()._internal_valueAt(barIndex) === null) {
@@ -2895,7 +2889,10 @@
2895
2889
  commonRendererData._internal_additionalPaddingTop = additionalPadding;
2896
2890
  commonRendererData._internal_additionalPaddingBottom = additionalPadding;
2897
2891
  commonRendererData._internal_coordinate = data._internal_coordinate;
2898
- commonRendererData._internal_fixedCoordinate = data._internal_fixedCoordinate;
2892
+ // Re-runs at draw time, after the axis has moved the label clear of overlaps.
2893
+ if (data._internal_fixedCoordinate !== undefined) {
2894
+ commonRendererData._internal_fixedCoordinate = data._internal_fixedCoordinate;
2895
+ }
2899
2896
  axisRendererData._internal_text = data._internal_text;
2900
2897
  axisRendererData._internal_visible = data._internal_visible;
2901
2898
  axisRendererData._internal_tickVisible = data._internal_tickVisible;
@@ -3772,7 +3769,6 @@
3772
3769
  }
3773
3770
  }
3774
3771
 
3775
- const TICK_DENSITY = 2.5;
3776
3772
  class PriceTickMarkBuilder {
3777
3773
  constructor(priceScale, base, coordinateToLogicalFunc, logicalToCoordinateFunc) {
3778
3774
  this._private__marks = [];
@@ -3833,7 +3829,7 @@
3833
3829
  return this._private__priceScale._internal_fontSize();
3834
3830
  }
3835
3831
  _private__tickMarkHeight() {
3836
- return Math.ceil(this._private__fontHeight() * TICK_DENSITY);
3832
+ return Math.max(1, Math.ceil(this._private__fontHeight() * this._private__priceScale._internal_options().tickMarkSpacing));
3837
3833
  }
3838
3834
  _private__updateMarks(firstValue, span, high, low, minCoord, maxCoord) {
3839
3835
  const marks = this._private__marks;
@@ -3998,6 +3994,9 @@
3998
3994
  this._private__invalidateInternalHeightCache();
3999
3995
  this._private__marksCache = null;
4000
3996
  }
3997
+ if (options.tickMarkSpacing !== undefined) {
3998
+ this._private__marksCache = null;
3999
+ }
4001
4000
  }
4002
4001
  _internal_isAutoScale() {
4003
4002
  return this._private__options.autoScale;
@@ -5175,6 +5174,9 @@
5175
5174
  this._private__uniformDistribution = val;
5176
5175
  this._private__cache = null;
5177
5176
  }
5177
+ _internal_invalidate() {
5178
+ this._private__cache = null;
5179
+ }
5178
5180
  _internal_setTimeScalePoints(newPoints, firstChangedPointIndex) {
5179
5181
  this._private__removeMarksSinceIndex(firstChangedPointIndex);
5180
5182
  this._private__cache = null;
@@ -5193,7 +5195,7 @@
5193
5195
  });
5194
5196
  }
5195
5197
  }
5196
- _internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId) {
5198
+ _internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId, allows = () => true) {
5197
5199
  const maxIndexesPerMark = Math.ceil(maxWidth / spacing);
5198
5200
  if (this._private__cache === null ||
5199
5201
  this._private__cache._internal_maxIndexesPerMark !== maxIndexesPerMark ||
@@ -5202,7 +5204,7 @@
5202
5204
  this._private__cache = {
5203
5205
  _internal_indicesWithDataId: indicesWithDataId,
5204
5206
  _internal_checkIndicesForData: checkIndicesForData,
5205
- _internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap),
5207
+ _internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows),
5206
5208
  _internal_maxIndexesPerMark: maxIndexesPerMark,
5207
5209
  };
5208
5210
  }
@@ -5226,7 +5228,7 @@
5226
5228
  this._private__marksByWeight.delete(weight);
5227
5229
  }
5228
5230
  }
5229
- _private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap) {
5231
+ _private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows) {
5230
5232
  let marks = [];
5231
5233
  const canBeIncluded = (mark) => !checkIndicesForData || indicesWithDataMap.has(mark.index);
5232
5234
  for (const weight of Array.from(this._private__marksByWeight.keys()).sort((a, b) => b - a)) {
@@ -5244,6 +5246,11 @@
5244
5246
  let leftIndex = -Infinity;
5245
5247
  for (let i = 0; i < currentWeightLength; i++) {
5246
5248
  const mark = currentWeight[i];
5249
+ // Skipped before the fit check: a rejected mark must not count as one
5250
+ // that did not fit, which with uniform distribution drops its whole weight.
5251
+ if (!allows(mark, maxIndexesPerMark)) {
5252
+ continue;
5253
+ }
5247
5254
  const currentIndex = mark.index;
5248
5255
  // Determine indexes with which current index will be compared
5249
5256
  // All marks to the right is moved to new array
@@ -5550,7 +5557,7 @@
5550
5557
  const visibleBars = ensureNotNull(this._internal_visibleStrictRange());
5551
5558
  const firstBar = Math.max(visibleBars._internal_left(), visibleBars._internal_left() - indexPerLabel);
5552
5559
  const lastBar = Math.max(visibleBars._internal_right(), visibleBars._internal_right() - indexPerLabel);
5553
- const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId);
5560
+ const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId, (mark, barsPerMark) => this._private__horzScaleBehavior.allowsTickMark?.(mark, barsPerMark) ?? true);
5554
5561
  // according to indexPerLabel value this value means "earliest index which _might be_ used as the second label on time scale"
5555
5562
  const earliestIndexOfSecondLabel = this._private__firstIndex() + indexPerLabel;
5556
5563
  // according to indexPerLabel value this value means "earliest index which _might be_ used as the second last label on time scale"
@@ -5928,6 +5935,7 @@
5928
5935
  _private__invalidateTickMarks() {
5929
5936
  this._private__resetTimeMarksCache();
5930
5937
  this._private__formattedByWeight.clear();
5938
+ this._private__tickMarks._internal_invalidate();
5931
5939
  }
5932
5940
  _private__updateDateTimeFormatter() {
5933
5941
  this._private__horzScaleBehavior.updateFormatter(this._private__localizationOptions);
@@ -7042,6 +7050,14 @@
7042
7050
  const tp = item;
7043
7051
  return this._private__dateTimeFormatter._internal_format(new Date(tp._internal_timestamp * 1000));
7044
7052
  }
7053
+ allowsTickMark(tickMark, barsPerMark) {
7054
+ const filter = this._private__options.timeScale.tickMarkFilter;
7055
+ if (filter === undefined) {
7056
+ return true;
7057
+ }
7058
+ const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
7059
+ return filter(tickMark.originalTime, tickMarkType, barsPerMark);
7060
+ }
7045
7061
  formatTickmark(tickMark, localizationOptions) {
7046
7062
  const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
7047
7063
  const options = this._private__options.timeScale;
@@ -11446,9 +11462,6 @@
11446
11462
  _internal__updateOptions() {
11447
11463
  const colorer = this._internal__series._internal_barColorer();
11448
11464
  this._internal__items = this._internal__items.map((item) => {
11449
- // An item whose bar is gone keeps the colour it had. Throwing here
11450
- // took down whatever asked for the repaint — `setData` among them,
11451
- // which left the series without its data and the pane empty.
11452
11465
  const style = colorer._internal_barStyleOrNull(item._internal_time);
11453
11466
  return style === null ? item : { ...item, ...style };
11454
11467
  });
@@ -11751,6 +11764,7 @@
11751
11764
  },
11752
11765
  minimumWidth: 0,
11753
11766
  ensureEdgeTickMarksVisible: false,
11767
+ tickMarkSpacing: 2.5,
11754
11768
  };
11755
11769
 
11756
11770
  const timeScaleOptionsDefaults = {
@@ -12846,8 +12860,6 @@
12846
12860
  const colorer = this._internal__series._internal_barColorer();
12847
12861
  this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => {
12848
12862
  const value = row._internal_value[3 /* PlotRowValueIndex.Close */];
12849
- // The row travels with the point: without it the colorer looks it up
12850
- // again by index, and that lookup could fail and take the repaint down.
12851
12863
  return this._internal__createRawItem(row._internal_index, value, colorer, row);
12852
12864
  });
12853
12865
  }
@@ -12870,10 +12882,10 @@
12870
12882
  if (point) {
12871
12883
  const style = styleGetter(renderingScope, point);
12872
12884
  if (style !== prevStyle) {
12873
- context.beginPath();
12874
12885
  if (prevStyle !== null) {
12875
12886
  context.fill();
12876
12887
  }
12888
+ context.beginPath();
12877
12889
  context.fillStyle = style;
12878
12890
  prevStyle = style;
12879
12891
  }
@@ -13812,9 +13824,6 @@
13812
13824
  }
13813
13825
  _internal__fillRawPoints() {
13814
13826
  const colorer = this._internal__series._internal_barColorer();
13815
- // The row goes to the colorer as it is. Asking for the style by index
13816
- // alone made it look the row up again, and that second lookup could come
13817
- // back empty and throw, taking the whole repaint down with it.
13818
13827
  this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => this._internal__createRawItem(row._internal_index, row, colorer));
13819
13828
  }
13820
13829
  }
@@ -17885,7 +17894,7 @@
17885
17894
  hideSource: options.hideSource ?? true,
17886
17895
  };
17887
17896
  const sourceOptions = series.options();
17888
- // Same price scale and the same formatting as the source: the candles are a
17897
+ // Same price scale, formatting and axis labels as the source: the candles are a
17889
17898
  // restatement of that series, not a second instrument, so they must not
17890
17899
  // autoscale on their own axis or round to a different precision.
17891
17900
  const haSeries = chart.addSeries(candlestickSeries, {
@@ -17899,6 +17908,8 @@
17899
17908
  wickDownColor: resolved.wickDownColor,
17900
17909
  priceScaleId: sourceOptions.priceScaleId,
17901
17910
  priceFormat: sourceOptions.priceFormat,
17911
+ lastValueVisible: sourceOptions.lastValueVisible,
17912
+ priceLineVisible: sourceOptions.priceLineVisible,
17902
17913
  }, resolved.paneIndex);
17903
17914
  let restoreSourcePaint = null;
17904
17915
  const blankSource = (blank) => {
@@ -18100,12 +18111,14 @@
18100
18111
  const macdSeries = chart.addSeries(lineSeries, {
18101
18112
  color: resolved.colorMACD,
18102
18113
  }, paneIndex);
18114
+ // An index past the last pane opens a new one, so the rest follow MACD to where it landed.
18115
+ const macdPane = paneIndexOf(chart, macdSeries, paneIndex);
18103
18116
  const signalSeries = chart.addSeries(lineSeries, {
18104
18117
  color: resolved.colorSignal,
18105
- }, paneIndex);
18118
+ }, macdPane);
18106
18119
  const histogramSeries$1 = chart.addSeries(histogramSeries, {
18107
18120
  color: resolved.colorHistogramUp,
18108
- }, paneIndex);
18121
+ }, macdPane);
18109
18122
  // Calculate EMA
18110
18123
  const calculateEMA = (prices, period) => {
18111
18124
  const ema = [];
@@ -18237,13 +18250,13 @@
18237
18250
  // Stochastic is bounded to 0-100; pinning it keeps the pane readable
18238
18251
  autoscaleInfoProvider: boundedScale,
18239
18252
  }, paneIndex);
18253
+ // An index past the last pane opens a new one, so %D follows %K to where it landed.
18254
+ const scalePane = paneIndexOf(chart, kSeries, paneIndex);
18240
18255
  // Create %D line (slow - signal)
18241
18256
  const dSeries = chart.addSeries(lineSeries, {
18242
18257
  color: resolved.colorD,
18243
18258
  autoscaleInfoProvider: boundedScale,
18244
- }, paneIndex);
18245
- // The pane the series landed in, which is not always the one asked for.
18246
- const scalePane = paneIndexOf(chart, kSeries, paneIndex);
18259
+ }, scalePane);
18247
18260
  chart.priceScale(kSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
18248
18261
  scaleMargins: {
18249
18262
  top: 0.1,
@@ -18585,15 +18598,16 @@
18585
18598
  color: resolved.colorADX,
18586
18599
  autoscaleInfoProvider: boundedScale,
18587
18600
  }, paneIndex);
18601
+ // An index past the last pane opens a new one, so the DI lines follow ADX to where it landed.
18602
+ const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
18588
18603
  const plusSeries = chart.addSeries(lineSeries, {
18589
18604
  color: resolved.colorPlusDI,
18590
18605
  autoscaleInfoProvider: boundedScale,
18591
- }, paneIndex);
18606
+ }, scalePane);
18592
18607
  const minusSeries = chart.addSeries(lineSeries, {
18593
18608
  color: resolved.colorMinusDI,
18594
18609
  autoscaleInfoProvider: boundedScale,
18595
- }, paneIndex);
18596
- const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
18610
+ }, scalePane);
18597
18611
  chart.priceScale(adxSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
18598
18612
  scaleMargins: {
18599
18613
  top: 0.1,
@@ -31006,7 +31020,7 @@
31006
31020
  * Returns the current version as a string. For example `'1.0.0'`.
31007
31021
  */
31008
31022
  function version() {
31009
- return "2.3.4";
31023
+ return "2.3.10";
31010
31024
  }
31011
31025
 
31012
31026
  var PipsendChartsModule = /*#__PURE__*/Object.freeze({
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * Pipsend Charts v2.3.4
3
+ * Pipsend Charts v2.3.10
4
4
  * Copyright (c) 2026 Pipsend
5
5
  * Licensed under MIT License
6
6
  * Built on TradingView Lightweight Charts™ (Apache 2.0)
@@ -2483,14 +2483,8 @@ class SeriesBarColorer {
2483
2483
  return this._private__styleGetter(this._private__findBar, this._private__series._internal_options(), barIndex, precomputedBars);
2484
2484
  }
2485
2485
  /**
2486
- * Like `barStyle`, but returns null instead of throwing when the bar is
2487
- * gone.
2488
- *
2489
- * Recolouring walks items that were laid out against the data as it was. A
2490
- * bar that has since disappeared is not an error there: the view is about
2491
- * to be rebuilt from the new data anyway. Letting it throw took down
2492
- * whatever asked for the repaint — including `setData`, which left the
2493
- * series without its data and the pane empty until the page was reloaded.
2486
+ * Like `barStyle`, but null instead of throwing when the bar is gone, which
2487
+ * a recolour of items laid out against older data can hit.
2494
2488
  */
2495
2489
  _internal_barStyleOrNull(barIndex, precomputedBars) {
2496
2490
  if (precomputedBars === undefined && this._private__series._internal_bars()._internal_valueAt(barIndex) === null) {
@@ -2892,7 +2886,10 @@ class SeriesPrimitivePriceAxisViewWrapper extends PriceAxisView {
2892
2886
  commonRendererData._internal_additionalPaddingTop = additionalPadding;
2893
2887
  commonRendererData._internal_additionalPaddingBottom = additionalPadding;
2894
2888
  commonRendererData._internal_coordinate = data._internal_coordinate;
2895
- commonRendererData._internal_fixedCoordinate = data._internal_fixedCoordinate;
2889
+ // Re-runs at draw time, after the axis has moved the label clear of overlaps.
2890
+ if (data._internal_fixedCoordinate !== undefined) {
2891
+ commonRendererData._internal_fixedCoordinate = data._internal_fixedCoordinate;
2892
+ }
2896
2893
  axisRendererData._internal_text = data._internal_text;
2897
2894
  axisRendererData._internal_visible = data._internal_visible;
2898
2895
  axisRendererData._internal_tickVisible = data._internal_tickVisible;
@@ -3769,7 +3766,6 @@ class PriceTickSpanCalculator {
3769
3766
  }
3770
3767
  }
3771
3768
 
3772
- const TICK_DENSITY = 2.5;
3773
3769
  class PriceTickMarkBuilder {
3774
3770
  constructor(priceScale, base, coordinateToLogicalFunc, logicalToCoordinateFunc) {
3775
3771
  this._private__marks = [];
@@ -3830,7 +3826,7 @@ class PriceTickMarkBuilder {
3830
3826
  return this._private__priceScale._internal_fontSize();
3831
3827
  }
3832
3828
  _private__tickMarkHeight() {
3833
- return Math.ceil(this._private__fontHeight() * TICK_DENSITY);
3829
+ return Math.max(1, Math.ceil(this._private__fontHeight() * this._private__priceScale._internal_options().tickMarkSpacing));
3834
3830
  }
3835
3831
  _private__updateMarks(firstValue, span, high, low, minCoord, maxCoord) {
3836
3832
  const marks = this._private__marks;
@@ -3995,6 +3991,9 @@ class PriceScale {
3995
3991
  this._private__invalidateInternalHeightCache();
3996
3992
  this._private__marksCache = null;
3997
3993
  }
3994
+ if (options.tickMarkSpacing !== undefined) {
3995
+ this._private__marksCache = null;
3996
+ }
3998
3997
  }
3999
3998
  _internal_isAutoScale() {
4000
3999
  return this._private__options.autoScale;
@@ -5172,6 +5171,9 @@ class TickMarks {
5172
5171
  this._private__uniformDistribution = val;
5173
5172
  this._private__cache = null;
5174
5173
  }
5174
+ _internal_invalidate() {
5175
+ this._private__cache = null;
5176
+ }
5175
5177
  _internal_setTimeScalePoints(newPoints, firstChangedPointIndex) {
5176
5178
  this._private__removeMarksSinceIndex(firstChangedPointIndex);
5177
5179
  this._private__cache = null;
@@ -5190,7 +5192,7 @@ class TickMarks {
5190
5192
  });
5191
5193
  }
5192
5194
  }
5193
- _internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId) {
5195
+ _internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId, allows = () => true) {
5194
5196
  const maxIndexesPerMark = Math.ceil(maxWidth / spacing);
5195
5197
  if (this._private__cache === null ||
5196
5198
  this._private__cache._internal_maxIndexesPerMark !== maxIndexesPerMark ||
@@ -5199,7 +5201,7 @@ class TickMarks {
5199
5201
  this._private__cache = {
5200
5202
  _internal_indicesWithDataId: indicesWithDataId,
5201
5203
  _internal_checkIndicesForData: checkIndicesForData,
5202
- _internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap),
5204
+ _internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows),
5203
5205
  _internal_maxIndexesPerMark: maxIndexesPerMark,
5204
5206
  };
5205
5207
  }
@@ -5223,7 +5225,7 @@ class TickMarks {
5223
5225
  this._private__marksByWeight.delete(weight);
5224
5226
  }
5225
5227
  }
5226
- _private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap) {
5228
+ _private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows) {
5227
5229
  let marks = [];
5228
5230
  const canBeIncluded = (mark) => !checkIndicesForData || indicesWithDataMap.has(mark.index);
5229
5231
  for (const weight of Array.from(this._private__marksByWeight.keys()).sort((a, b) => b - a)) {
@@ -5241,6 +5243,11 @@ class TickMarks {
5241
5243
  let leftIndex = -Infinity;
5242
5244
  for (let i = 0; i < currentWeightLength; i++) {
5243
5245
  const mark = currentWeight[i];
5246
+ // Skipped before the fit check: a rejected mark must not count as one
5247
+ // that did not fit, which with uniform distribution drops its whole weight.
5248
+ if (!allows(mark, maxIndexesPerMark)) {
5249
+ continue;
5250
+ }
5244
5251
  const currentIndex = mark.index;
5245
5252
  // Determine indexes with which current index will be compared
5246
5253
  // All marks to the right is moved to new array
@@ -5547,7 +5554,7 @@ class TimeScale {
5547
5554
  const visibleBars = ensureNotNull(this._internal_visibleStrictRange());
5548
5555
  const firstBar = Math.max(visibleBars._internal_left(), visibleBars._internal_left() - indexPerLabel);
5549
5556
  const lastBar = Math.max(visibleBars._internal_right(), visibleBars._internal_right() - indexPerLabel);
5550
- const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId);
5557
+ const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId, (mark, barsPerMark) => this._private__horzScaleBehavior.allowsTickMark?.(mark, barsPerMark) ?? true);
5551
5558
  // according to indexPerLabel value this value means "earliest index which _might be_ used as the second label on time scale"
5552
5559
  const earliestIndexOfSecondLabel = this._private__firstIndex() + indexPerLabel;
5553
5560
  // according to indexPerLabel value this value means "earliest index which _might be_ used as the second last label on time scale"
@@ -5925,6 +5932,7 @@ class TimeScale {
5925
5932
  _private__invalidateTickMarks() {
5926
5933
  this._private__resetTimeMarksCache();
5927
5934
  this._private__formattedByWeight.clear();
5935
+ this._private__tickMarks._internal_invalidate();
5928
5936
  }
5929
5937
  _private__updateDateTimeFormatter() {
5930
5938
  this._private__horzScaleBehavior.updateFormatter(this._private__localizationOptions);
@@ -7039,6 +7047,14 @@ class HorzScaleBehaviorTime {
7039
7047
  const tp = item;
7040
7048
  return this._private__dateTimeFormatter._internal_format(new Date(tp._internal_timestamp * 1000));
7041
7049
  }
7050
+ allowsTickMark(tickMark, barsPerMark) {
7051
+ const filter = this._private__options.timeScale.tickMarkFilter;
7052
+ if (filter === undefined) {
7053
+ return true;
7054
+ }
7055
+ const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
7056
+ return filter(tickMark.originalTime, tickMarkType, barsPerMark);
7057
+ }
7042
7058
  formatTickmark(tickMark, localizationOptions) {
7043
7059
  const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
7044
7060
  const options = this._private__options.timeScale;
@@ -11443,9 +11459,6 @@ class SeriesPaneViewBase {
11443
11459
  _internal__updateOptions() {
11444
11460
  const colorer = this._internal__series._internal_barColorer();
11445
11461
  this._internal__items = this._internal__items.map((item) => {
11446
- // An item whose bar is gone keeps the colour it had. Throwing here
11447
- // took down whatever asked for the repaint — `setData` among them,
11448
- // which left the series without its data and the pane empty.
11449
11462
  const style = colorer._internal_barStyleOrNull(item._internal_time);
11450
11463
  return style === null ? item : { ...item, ...style };
11451
11464
  });
@@ -11748,6 +11761,7 @@ const priceScaleOptionsDefaults = {
11748
11761
  },
11749
11762
  minimumWidth: 0,
11750
11763
  ensureEdgeTickMarksVisible: false,
11764
+ tickMarkSpacing: 2.5,
11751
11765
  };
11752
11766
 
11753
11767
  const timeScaleOptionsDefaults = {
@@ -12843,8 +12857,6 @@ class LinePaneViewBase extends SeriesPaneViewBase {
12843
12857
  const colorer = this._internal__series._internal_barColorer();
12844
12858
  this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => {
12845
12859
  const value = row._internal_value[3 /* PlotRowValueIndex.Close */];
12846
- // The row travels with the point: without it the colorer looks it up
12847
- // again by index, and that lookup could fail and take the repaint down.
12848
12860
  return this._internal__createRawItem(row._internal_index, value, colorer, row);
12849
12861
  });
12850
12862
  }
@@ -12867,10 +12879,10 @@ styleGetter) {
12867
12879
  if (point) {
12868
12880
  const style = styleGetter(renderingScope, point);
12869
12881
  if (style !== prevStyle) {
12870
- context.beginPath();
12871
12882
  if (prevStyle !== null) {
12872
12883
  context.fill();
12873
12884
  }
12885
+ context.beginPath();
12874
12886
  context.fillStyle = style;
12875
12887
  prevStyle = style;
12876
12888
  }
@@ -13809,9 +13821,6 @@ class BarsPaneViewBase extends SeriesPaneViewBase {
13809
13821
  }
13810
13822
  _internal__fillRawPoints() {
13811
13823
  const colorer = this._internal__series._internal_barColorer();
13812
- // The row goes to the colorer as it is. Asking for the style by index
13813
- // alone made it look the row up again, and that second lookup could come
13814
- // back empty and throw, taking the whole repaint down with it.
13815
13824
  this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => this._internal__createRawItem(row._internal_index, row, colorer));
13816
13825
  }
13817
13826
  }
@@ -17882,7 +17891,7 @@ function applyHeikinAshi(series, chart, options = {}) {
17882
17891
  hideSource: options.hideSource ?? true,
17883
17892
  };
17884
17893
  const sourceOptions = series.options();
17885
- // Same price scale and the same formatting as the source: the candles are a
17894
+ // Same price scale, formatting and axis labels as the source: the candles are a
17886
17895
  // restatement of that series, not a second instrument, so they must not
17887
17896
  // autoscale on their own axis or round to a different precision.
17888
17897
  const haSeries = chart.addSeries(candlestickSeries, {
@@ -17896,6 +17905,8 @@ function applyHeikinAshi(series, chart, options = {}) {
17896
17905
  wickDownColor: resolved.wickDownColor,
17897
17906
  priceScaleId: sourceOptions.priceScaleId,
17898
17907
  priceFormat: sourceOptions.priceFormat,
17908
+ lastValueVisible: sourceOptions.lastValueVisible,
17909
+ priceLineVisible: sourceOptions.priceLineVisible,
17899
17910
  }, resolved.paneIndex);
17900
17911
  let restoreSourcePaint = null;
17901
17912
  const blankSource = (blank) => {
@@ -18097,12 +18108,14 @@ function applyMACD(series, chart, options = {}) {
18097
18108
  const macdSeries = chart.addSeries(lineSeries, {
18098
18109
  color: resolved.colorMACD,
18099
18110
  }, paneIndex);
18111
+ // An index past the last pane opens a new one, so the rest follow MACD to where it landed.
18112
+ const macdPane = paneIndexOf(chart, macdSeries, paneIndex);
18100
18113
  const signalSeries = chart.addSeries(lineSeries, {
18101
18114
  color: resolved.colorSignal,
18102
- }, paneIndex);
18115
+ }, macdPane);
18103
18116
  const histogramSeries$1 = chart.addSeries(histogramSeries, {
18104
18117
  color: resolved.colorHistogramUp,
18105
- }, paneIndex);
18118
+ }, macdPane);
18106
18119
  // Calculate EMA
18107
18120
  const calculateEMA = (prices, period) => {
18108
18121
  const ema = [];
@@ -18234,13 +18247,13 @@ function applyStochastic(series, chart, options = {}) {
18234
18247
  // Stochastic is bounded to 0-100; pinning it keeps the pane readable
18235
18248
  autoscaleInfoProvider: boundedScale,
18236
18249
  }, paneIndex);
18250
+ // An index past the last pane opens a new one, so %D follows %K to where it landed.
18251
+ const scalePane = paneIndexOf(chart, kSeries, paneIndex);
18237
18252
  // Create %D line (slow - signal)
18238
18253
  const dSeries = chart.addSeries(lineSeries, {
18239
18254
  color: resolved.colorD,
18240
18255
  autoscaleInfoProvider: boundedScale,
18241
- }, paneIndex);
18242
- // The pane the series landed in, which is not always the one asked for.
18243
- const scalePane = paneIndexOf(chart, kSeries, paneIndex);
18256
+ }, scalePane);
18244
18257
  chart.priceScale(kSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
18245
18258
  scaleMargins: {
18246
18259
  top: 0.1,
@@ -18582,15 +18595,16 @@ function applyADX(series, chart, options = {}) {
18582
18595
  color: resolved.colorADX,
18583
18596
  autoscaleInfoProvider: boundedScale,
18584
18597
  }, paneIndex);
18598
+ // An index past the last pane opens a new one, so the DI lines follow ADX to where it landed.
18599
+ const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
18585
18600
  const plusSeries = chart.addSeries(lineSeries, {
18586
18601
  color: resolved.colorPlusDI,
18587
18602
  autoscaleInfoProvider: boundedScale,
18588
- }, paneIndex);
18603
+ }, scalePane);
18589
18604
  const minusSeries = chart.addSeries(lineSeries, {
18590
18605
  color: resolved.colorMinusDI,
18591
18606
  autoscaleInfoProvider: boundedScale,
18592
- }, paneIndex);
18593
- const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
18607
+ }, scalePane);
18594
18608
  chart.priceScale(adxSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
18595
18609
  scaleMargins: {
18596
18610
  top: 0.1,
@@ -31003,7 +31017,7 @@ const customSeriesDefaultOptions = {
31003
31017
  * Returns the current version as a string. For example `'1.0.0'`.
31004
31018
  */
31005
31019
  function version() {
31006
- return "2.3.4";
31020
+ return "2.3.10";
31007
31021
  }
31008
31022
 
31009
31023
  export { areaSeries as AreaSeries, ArrowTool, barSeries as BarSeries, baselineSeries as BaselineSeries, BrushTool, candlestickSeries as CandlestickSeries, CircleTool, ColorType, CrossLineTool, CrosshairMode, DEFAULT_SESSIONS, DraggablePriceLine, DrawingToolsManager, EXTENDED_FIBONACCI_RATIOS, FibonacciCalculator, FibonacciExtensionTool, FibonacciFanTool, FibonacciTool, GanttTool, histogramSeries as HistogramSeries, HorizontalLineTool, InteractiveLineManager, LastPriceAnimationMode, lineSeries as LineSeries, LineStyle, LineType, MismatchDirection, ParallelChannelTool, PitchforkTool, PolygonTool, PositionCalculator, PositionLine, PositionMarkersManager, PositionTool, PriceLineSource, PriceScaleMode, RectangleTool, RulerCalculator, RulerTool, STANDARD_FIBONACCI_RATIOS, TextTool, TickMarkType, TrackingModeExitMode, TradingSessionsIndicator, TrendLineTool, VerticalLineTool, VolumeProfileIndicator, applyADX, applyATR, applyBollingerBands, applyCCI, applyDonchianChannels, applyEMA, applyHeikinAshi, applyIchimoku, applyKeltnerChannels, applyMACD, applyMFI, applyOBV, applyParabolicSAR, applyPivotPoints, applyRSI, applySMA, applyStochastic, applySuperTrend, applyVWAP, applyVolume, applyWMA, applyWilliamsR, calculateHeikinAshi, calculatePipConfig, coordinateFromTime, createArrowTool, createBrushTool, createChart, createChartEx, createCircleTool, createCrossLineTool, createFibonacciExtensionTool, createFibonacciFanTool, createFibonacciTool, createGanttTool, createHorizontalLineTool, createImageWatermark, createInteractiveLineManager, createOptionsChart, createParallelChannelTool, createPitchforkTool, createPolygonTool, createPositionLine, createPositionMarkers, createPositionTool, createRectangleTool, createRulerTool, createSeriesMarkers, createTextTool, createTextWatermark, createTradingLine, createTradingSessionsIndicator, createTrendLineTool, createUpDownMarkers, createVerticalLineTool, createVolumeProfileIndicator, createYieldCurveChart, customSeriesDefaultOptions, defaultHorzScaleBehavior, getPipConfig, hideSeriesPaint, isBusinessDay, isUTCTimestamp, setSeriesVolumes, setVolumeProfileData, timeFromCoordinate, version };