@pipsend/charts 2.3.3 → 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.3
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
  });
@@ -11528,7 +11541,7 @@
11528
11541
  return {
11529
11542
  _internal_time: row._internal_index,
11530
11543
  _internal_x: NaN,
11531
- ...colorer._internal_barStyle(row._internal_index),
11544
+ ...colorer._internal_barStyle(row._internal_index, { _internal_value: row }),
11532
11545
  _internal_originalData: row._internal_data,
11533
11546
  };
11534
11547
  });
@@ -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,7 +12860,7 @@
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
- return this._internal__createRawItem(row._internal_index, value, colorer);
12863
+ return this._internal__createRawItem(row._internal_index, value, colorer, row);
12850
12864
  });
12851
12865
  }
12852
12866
  }
@@ -12868,10 +12882,10 @@
12868
12882
  if (point) {
12869
12883
  const style = styleGetter(renderingScope, point);
12870
12884
  if (style !== prevStyle) {
12871
- context.beginPath();
12872
12885
  if (prevStyle !== null) {
12873
12886
  context.fill();
12874
12887
  }
12888
+ context.beginPath();
12875
12889
  context.fillStyle = style;
12876
12890
  prevStyle = style;
12877
12891
  }
@@ -13014,10 +13028,10 @@
13014
13028
  super(...arguments);
13015
13029
  this._internal__renderer = new PaneRendererLine();
13016
13030
  }
13017
- _internal__createRawItem(time, price, colorer) {
13031
+ _internal__createRawItem(time, price, colorer, row) {
13018
13032
  return {
13019
13033
  ...this._internal__createRawItemBase(time, price),
13020
- ...colorer._internal_barStyle(time),
13034
+ ...colorer._internal_barStyle(time, { _internal_value: row }),
13021
13035
  };
13022
13036
  }
13023
13037
  _internal__prepareRendererData() {
@@ -13491,10 +13505,10 @@
13491
13505
  this._private__baselineLineRenderer = new PaneRendererBaselineLine();
13492
13506
  this._internal__renderer._internal_setRenderers([this._private__baselineAreaRenderer, this._private__baselineLineRenderer]);
13493
13507
  }
13494
- _internal__createRawItem(time, price, colorer) {
13508
+ _internal__createRawItem(time, price, colorer, row) {
13495
13509
  return {
13496
13510
  ...this._internal__createRawItemBase(time, price),
13497
- ...colorer._internal_barStyle(time),
13511
+ ...colorer._internal_barStyle(time, { _internal_value: row }),
13498
13512
  };
13499
13513
  }
13500
13514
  _internal__prepareRendererData() {
@@ -13614,10 +13628,10 @@
13614
13628
  this._private__lineRenderer = new PaneRendererLine();
13615
13629
  this._internal__renderer._internal_setRenderers([this._private__areaRenderer, this._private__lineRenderer]);
13616
13630
  }
13617
- _internal__createRawItem(time, price, colorer) {
13631
+ _internal__createRawItem(time, price, colorer, row) {
13618
13632
  return {
13619
13633
  ...this._internal__createRawItemBase(time, price),
13620
- ...colorer._internal_barStyle(time),
13634
+ ...colorer._internal_barStyle(time, { _internal_value: row }),
13621
13635
  };
13622
13636
  }
13623
13637
  _internal__prepareRendererData() {
@@ -13822,7 +13836,7 @@
13822
13836
  _internal__createRawItem(time, bar, colorer) {
13823
13837
  return {
13824
13838
  ...this._internal__createDefaultItem(time, bar, colorer),
13825
- ...colorer._internal_barStyle(time),
13839
+ ...colorer._internal_barStyle(time, { _internal_value: bar }),
13826
13840
  };
13827
13841
  }
13828
13842
  _internal__prepareRendererData() {
@@ -14015,7 +14029,7 @@
14015
14029
  _internal__createRawItem(time, bar, colorer) {
14016
14030
  return {
14017
14031
  ...this._internal__createDefaultItem(time, bar, colorer),
14018
- ...colorer._internal_barStyle(time),
14032
+ ...colorer._internal_barStyle(time, { _internal_value: bar }),
14019
14033
  };
14020
14034
  }
14021
14035
  _internal__prepareRendererData() {
@@ -14183,10 +14197,10 @@
14183
14197
  super(...arguments);
14184
14198
  this._internal__renderer = new PaneRendererHistogram();
14185
14199
  }
14186
- _internal__createRawItem(time, price, colorer) {
14200
+ _internal__createRawItem(time, price, colorer, row) {
14187
14201
  return {
14188
14202
  ...this._internal__createRawItemBase(time, price),
14189
- ...colorer._internal_barStyle(time),
14203
+ ...colorer._internal_barStyle(time, { _internal_value: row }),
14190
14204
  };
14191
14205
  }
14192
14206
  _internal__prepareRendererData() {
@@ -17880,7 +17894,7 @@
17880
17894
  hideSource: options.hideSource ?? true,
17881
17895
  };
17882
17896
  const sourceOptions = series.options();
17883
- // 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
17884
17898
  // restatement of that series, not a second instrument, so they must not
17885
17899
  // autoscale on their own axis or round to a different precision.
17886
17900
  const haSeries = chart.addSeries(candlestickSeries, {
@@ -17894,6 +17908,8 @@
17894
17908
  wickDownColor: resolved.wickDownColor,
17895
17909
  priceScaleId: sourceOptions.priceScaleId,
17896
17910
  priceFormat: sourceOptions.priceFormat,
17911
+ lastValueVisible: sourceOptions.lastValueVisible,
17912
+ priceLineVisible: sourceOptions.priceLineVisible,
17897
17913
  }, resolved.paneIndex);
17898
17914
  let restoreSourcePaint = null;
17899
17915
  const blankSource = (blank) => {
@@ -18095,12 +18111,14 @@
18095
18111
  const macdSeries = chart.addSeries(lineSeries, {
18096
18112
  color: resolved.colorMACD,
18097
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);
18098
18116
  const signalSeries = chart.addSeries(lineSeries, {
18099
18117
  color: resolved.colorSignal,
18100
- }, paneIndex);
18118
+ }, macdPane);
18101
18119
  const histogramSeries$1 = chart.addSeries(histogramSeries, {
18102
18120
  color: resolved.colorHistogramUp,
18103
- }, paneIndex);
18121
+ }, macdPane);
18104
18122
  // Calculate EMA
18105
18123
  const calculateEMA = (prices, period) => {
18106
18124
  const ema = [];
@@ -18232,13 +18250,13 @@
18232
18250
  // Stochastic is bounded to 0-100; pinning it keeps the pane readable
18233
18251
  autoscaleInfoProvider: boundedScale,
18234
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);
18235
18255
  // Create %D line (slow - signal)
18236
18256
  const dSeries = chart.addSeries(lineSeries, {
18237
18257
  color: resolved.colorD,
18238
18258
  autoscaleInfoProvider: boundedScale,
18239
- }, paneIndex);
18240
- // The pane the series landed in, which is not always the one asked for.
18241
- const scalePane = paneIndexOf(chart, kSeries, paneIndex);
18259
+ }, scalePane);
18242
18260
  chart.priceScale(kSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
18243
18261
  scaleMargins: {
18244
18262
  top: 0.1,
@@ -18580,15 +18598,16 @@
18580
18598
  color: resolved.colorADX,
18581
18599
  autoscaleInfoProvider: boundedScale,
18582
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);
18583
18603
  const plusSeries = chart.addSeries(lineSeries, {
18584
18604
  color: resolved.colorPlusDI,
18585
18605
  autoscaleInfoProvider: boundedScale,
18586
- }, paneIndex);
18606
+ }, scalePane);
18587
18607
  const minusSeries = chart.addSeries(lineSeries, {
18588
18608
  color: resolved.colorMinusDI,
18589
18609
  autoscaleInfoProvider: boundedScale,
18590
- }, paneIndex);
18591
- const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
18610
+ }, scalePane);
18592
18611
  chart.priceScale(adxSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
18593
18612
  scaleMargins: {
18594
18613
  top: 0.1,
@@ -31001,7 +31020,7 @@
31001
31020
  * Returns the current version as a string. For example `'1.0.0'`.
31002
31021
  */
31003
31022
  function version() {
31004
- return "2.3.3";
31023
+ return "2.3.10";
31005
31024
  }
31006
31025
 
31007
31026
  var PipsendChartsModule = /*#__PURE__*/Object.freeze({