@pipsend/charts 2.3.15 → 2.3.17

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.15
3
+ * Pipsend Charts v2.3.17-dev+202610130113
4
4
  * Copyright (c) 2026 Pipsend
5
5
  * Licensed under MIT License
6
6
  * Built on TradingView Lightweight Charts™ (Apache 2.0)
@@ -4575,18 +4575,16 @@
4575
4575
  this._private__invalidateInternalHeightCache();
4576
4576
  }
4577
4577
  if (priceRange !== null) {
4578
- // keep current range is new is empty
4579
- if (priceRange._internal_minValue() === priceRange._internal_maxValue()) {
4580
- // if price range is degenerated to 1 point let's extend it by 10 min move values
4581
- // to avoid incorrect range and empty (blank) scale (in case of min tick much greater than 1)
4582
- const extendValue = 5 * this._internal_minMove();
4583
- if (this._internal_isLog()) {
4584
- priceRange = convertPriceRangeFromLog(priceRange, this._private__logFormula);
4585
- }
4586
- priceRange = new PriceRangeImpl(priceRange._internal_minValue() - extendValue, priceRange._internal_maxValue() + extendValue);
4587
- if (this._internal_isLog()) {
4588
- priceRange = convertPriceRangeToLog(priceRange, this._private__logFormula);
4589
- }
4578
+ // a range flat or narrower than 10 min moves leaves room for one tick mark at most,
4579
+ // so widen it around its center to keep a readable scale
4580
+ const isLog = this._internal_isLog();
4581
+ const rawRange = isLog ? convertPriceRangeFromLog(priceRange, this._private__logFormula) : priceRange;
4582
+ const minimumLength = this._internal_isPercentage() || this._internal_isIndexedTo100() ? 0 : 10 * this._internal_minMove();
4583
+ if (rawRange._internal_minValue() === rawRange._internal_maxValue() || rawRange._internal_length() < minimumLength) {
4584
+ const extendValue = Math.max(5 * this._internal_minMove(), minimumLength / 2);
4585
+ const center = (rawRange._internal_minValue() + rawRange._internal_maxValue()) / 2;
4586
+ const widened = new PriceRangeImpl(center - extendValue, center + extendValue);
4587
+ priceRange = isLog ? convertPriceRangeToLog(widened, this._private__logFormula) : widened;
4590
4588
  }
4591
4589
  if (this._internal_isLog()) {
4592
4590
  const rawRange = convertPriceRangeFromLog(priceRange, this._private__logFormula);
@@ -20614,8 +20612,11 @@
20614
20612
  * move — which is invisible, and cheaper than forcing a second pass.
20615
20613
  */
20616
20614
  _internal_setClaims(ownerId, claims) {
20615
+ const previous = this._private__claims.get(ownerId);
20617
20616
  this._private__claims.set(ownerId, claims);
20618
- this._private__invalidated = true;
20617
+ if (previous === undefined || !sameClaims(previous, claims)) {
20618
+ this._private__invalidated = true;
20619
+ }
20619
20620
  }
20620
20621
  /** How far down a label has to move to clear the ones already placed. */
20621
20622
  _internal_offsetFor(ownerId, level) {
@@ -20636,7 +20637,10 @@
20636
20637
  // them only need the few pixels they are short of — stepping by a
20637
20638
  // full gap each time is what made the fan look flung open.
20638
20639
  let y = claim._internal_y;
20639
- for (const other of [...placed].sort(byY)) {
20640
+ for (const other of placed) {
20641
+ if (other._internal_y >= y + gap) {
20642
+ break;
20643
+ }
20640
20644
  if (Math.abs(y - other._internal_y) < gap) {
20641
20645
  y = other._internal_y + gap;
20642
20646
  }
@@ -20647,7 +20651,7 @@
20647
20651
  // no worse than before and keeps the pile from running off.
20648
20652
  offset = 0;
20649
20653
  }
20650
- placed.push({ _internal_y: claim._internal_y + offset, _internal_height: claim._internal_height });
20654
+ insertByY(placed, { _internal_y: claim._internal_y + offset, _internal_height: claim._internal_height });
20651
20655
  offsets.set(key(ownerId, claim._internal_level), offset);
20652
20656
  }
20653
20657
  }
@@ -20665,8 +20669,30 @@
20665
20669
  function minGap(height) {
20666
20670
  return Math.max(9, Math.round(height * 0.4));
20667
20671
  }
20668
- function byY(a, b) {
20669
- return a._internal_y - b._internal_y;
20672
+ function insertByY(placed, claim) {
20673
+ let low = 0;
20674
+ let high = placed.length;
20675
+ while (low < high) {
20676
+ const middle = (low + high) >> 1;
20677
+ if (placed[middle]._internal_y <= claim._internal_y) {
20678
+ low = middle + 1;
20679
+ }
20680
+ else {
20681
+ high = middle;
20682
+ }
20683
+ }
20684
+ placed.splice(low, 0, claim);
20685
+ }
20686
+ function sameClaims(a, b) {
20687
+ if (a.length !== b.length) {
20688
+ return false;
20689
+ }
20690
+ for (let i = 0; i < a.length; i++) {
20691
+ if (a[i]._internal_level !== b[i]._internal_level || a[i]._internal_y !== b[i]._internal_y || a[i]._internal_height !== b[i]._internal_height) {
20692
+ return false;
20693
+ }
20694
+ }
20695
+ return true;
20670
20696
  }
20671
20697
  const layouts = new WeakMap();
20672
20698
  /** The layout is shared by every position line on the same chart. */
@@ -21021,6 +21047,7 @@
21021
21047
  constructor(chart, series, options) {
21022
21048
  this._private__paneView = new PositionLinePaneView();
21023
21049
  this._private__colorParser = new ColorParser([]);
21050
+ this._private__axisLabels = new Map();
21024
21051
  this._private__attached = false;
21025
21052
  this._private__hoveredLevel = null;
21026
21053
  this._private__hoveredPart = null;
@@ -21312,12 +21339,22 @@
21312
21339
  return null;
21313
21340
  }
21314
21341
  const color = options.color ?? positionLineDefaultColors[level];
21315
- return {
21342
+ const formatter = this._private__series.priceFormatter();
21343
+ const cached = this._private__axisLabels.get(level);
21344
+ if (cached !== undefined && cached._internal_price === options.price && cached._internal_color === color && cached._internal_formatter === formatter) {
21345
+ if (cached._internal_label._internal_coordinate !== y) {
21346
+ cached._internal_label = { ...cached._internal_label, _internal_coordinate: y };
21347
+ }
21348
+ return cached._internal_label;
21349
+ }
21350
+ const label = {
21316
21351
  _internal_coordinate: y,
21317
- _internal_text: this._private__series.priceFormatter().format(options.price),
21352
+ _internal_text: formatter.format(options.price),
21318
21353
  _internal_color: color,
21319
21354
  _internal_textColor: this._private__colorParser._internal_generateContrastColors(color)._internal_foreground,
21320
21355
  };
21356
+ this._private__axisLabels.set(level, { _internal_price: options.price, _internal_color: color, _internal_formatter: formatter, _internal_label: label });
21357
+ return label;
21321
21358
  }
21322
21359
  _private__levelOptions(level) {
21323
21360
  const options = level === 'entry' ? this._private__options.entry : this._private__options[level];
@@ -31448,7 +31485,7 @@
31448
31485
  * Returns the current version as a string. For example `'1.0.0'`.
31449
31486
  */
31450
31487
  function version() {
31451
- return "2.3.15";
31488
+ return "2.3.17-dev+202610130113";
31452
31489
  }
31453
31490
 
31454
31491
  var PipsendChartsModule = /*#__PURE__*/Object.freeze({
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @license
3
- * Pipsend Charts v2.3.15
3
+ * Pipsend Charts v2.3.17-dev+202610130113
4
4
  * Copyright (c) 2026 Pipsend
5
5
  * Licensed under MIT License
6
6
  * Built on TradingView Lightweight Charts™ (Apache 2.0)
@@ -4572,18 +4572,16 @@ class PriceScale {
4572
4572
  this._private__invalidateInternalHeightCache();
4573
4573
  }
4574
4574
  if (priceRange !== null) {
4575
- // keep current range is new is empty
4576
- if (priceRange._internal_minValue() === priceRange._internal_maxValue()) {
4577
- // if price range is degenerated to 1 point let's extend it by 10 min move values
4578
- // to avoid incorrect range and empty (blank) scale (in case of min tick much greater than 1)
4579
- const extendValue = 5 * this._internal_minMove();
4580
- if (this._internal_isLog()) {
4581
- priceRange = convertPriceRangeFromLog(priceRange, this._private__logFormula);
4582
- }
4583
- priceRange = new PriceRangeImpl(priceRange._internal_minValue() - extendValue, priceRange._internal_maxValue() + extendValue);
4584
- if (this._internal_isLog()) {
4585
- priceRange = convertPriceRangeToLog(priceRange, this._private__logFormula);
4586
- }
4575
+ // a range flat or narrower than 10 min moves leaves room for one tick mark at most,
4576
+ // so widen it around its center to keep a readable scale
4577
+ const isLog = this._internal_isLog();
4578
+ const rawRange = isLog ? convertPriceRangeFromLog(priceRange, this._private__logFormula) : priceRange;
4579
+ const minimumLength = this._internal_isPercentage() || this._internal_isIndexedTo100() ? 0 : 10 * this._internal_minMove();
4580
+ if (rawRange._internal_minValue() === rawRange._internal_maxValue() || rawRange._internal_length() < minimumLength) {
4581
+ const extendValue = Math.max(5 * this._internal_minMove(), minimumLength / 2);
4582
+ const center = (rawRange._internal_minValue() + rawRange._internal_maxValue()) / 2;
4583
+ const widened = new PriceRangeImpl(center - extendValue, center + extendValue);
4584
+ priceRange = isLog ? convertPriceRangeToLog(widened, this._private__logFormula) : widened;
4587
4585
  }
4588
4586
  if (this._internal_isLog()) {
4589
4587
  const rawRange = convertPriceRangeFromLog(priceRange, this._private__logFormula);
@@ -20611,8 +20609,11 @@ class PositionLineLabelLayout {
20611
20609
  * move — which is invisible, and cheaper than forcing a second pass.
20612
20610
  */
20613
20611
  _internal_setClaims(ownerId, claims) {
20612
+ const previous = this._private__claims.get(ownerId);
20614
20613
  this._private__claims.set(ownerId, claims);
20615
- this._private__invalidated = true;
20614
+ if (previous === undefined || !sameClaims(previous, claims)) {
20615
+ this._private__invalidated = true;
20616
+ }
20616
20617
  }
20617
20618
  /** How far down a label has to move to clear the ones already placed. */
20618
20619
  _internal_offsetFor(ownerId, level) {
@@ -20633,7 +20634,10 @@ class PositionLineLabelLayout {
20633
20634
  // them only need the few pixels they are short of — stepping by a
20634
20635
  // full gap each time is what made the fan look flung open.
20635
20636
  let y = claim._internal_y;
20636
- for (const other of [...placed].sort(byY)) {
20637
+ for (const other of placed) {
20638
+ if (other._internal_y >= y + gap) {
20639
+ break;
20640
+ }
20637
20641
  if (Math.abs(y - other._internal_y) < gap) {
20638
20642
  y = other._internal_y + gap;
20639
20643
  }
@@ -20644,7 +20648,7 @@ class PositionLineLabelLayout {
20644
20648
  // no worse than before and keeps the pile from running off.
20645
20649
  offset = 0;
20646
20650
  }
20647
- placed.push({ _internal_y: claim._internal_y + offset, _internal_height: claim._internal_height });
20651
+ insertByY(placed, { _internal_y: claim._internal_y + offset, _internal_height: claim._internal_height });
20648
20652
  offsets.set(key(ownerId, claim._internal_level), offset);
20649
20653
  }
20650
20654
  }
@@ -20662,8 +20666,30 @@ function key(ownerId, level) {
20662
20666
  function minGap(height) {
20663
20667
  return Math.max(9, Math.round(height * 0.4));
20664
20668
  }
20665
- function byY(a, b) {
20666
- return a._internal_y - b._internal_y;
20669
+ function insertByY(placed, claim) {
20670
+ let low = 0;
20671
+ let high = placed.length;
20672
+ while (low < high) {
20673
+ const middle = (low + high) >> 1;
20674
+ if (placed[middle]._internal_y <= claim._internal_y) {
20675
+ low = middle + 1;
20676
+ }
20677
+ else {
20678
+ high = middle;
20679
+ }
20680
+ }
20681
+ placed.splice(low, 0, claim);
20682
+ }
20683
+ function sameClaims(a, b) {
20684
+ if (a.length !== b.length) {
20685
+ return false;
20686
+ }
20687
+ for (let i = 0; i < a.length; i++) {
20688
+ if (a[i]._internal_level !== b[i]._internal_level || a[i]._internal_y !== b[i]._internal_y || a[i]._internal_height !== b[i]._internal_height) {
20689
+ return false;
20690
+ }
20691
+ }
20692
+ return true;
20667
20693
  }
20668
20694
  const layouts = new WeakMap();
20669
20695
  /** The layout is shared by every position line on the same chart. */
@@ -21018,6 +21044,7 @@ class PositionLine {
21018
21044
  constructor(chart, series, options) {
21019
21045
  this._private__paneView = new PositionLinePaneView();
21020
21046
  this._private__colorParser = new ColorParser([]);
21047
+ this._private__axisLabels = new Map();
21021
21048
  this._private__attached = false;
21022
21049
  this._private__hoveredLevel = null;
21023
21050
  this._private__hoveredPart = null;
@@ -21309,12 +21336,22 @@ class PositionLine {
21309
21336
  return null;
21310
21337
  }
21311
21338
  const color = options.color ?? positionLineDefaultColors[level];
21312
- return {
21339
+ const formatter = this._private__series.priceFormatter();
21340
+ const cached = this._private__axisLabels.get(level);
21341
+ if (cached !== undefined && cached._internal_price === options.price && cached._internal_color === color && cached._internal_formatter === formatter) {
21342
+ if (cached._internal_label._internal_coordinate !== y) {
21343
+ cached._internal_label = { ...cached._internal_label, _internal_coordinate: y };
21344
+ }
21345
+ return cached._internal_label;
21346
+ }
21347
+ const label = {
21313
21348
  _internal_coordinate: y,
21314
- _internal_text: this._private__series.priceFormatter().format(options.price),
21349
+ _internal_text: formatter.format(options.price),
21315
21350
  _internal_color: color,
21316
21351
  _internal_textColor: this._private__colorParser._internal_generateContrastColors(color)._internal_foreground,
21317
21352
  };
21353
+ this._private__axisLabels.set(level, { _internal_price: options.price, _internal_color: color, _internal_formatter: formatter, _internal_label: label });
21354
+ return label;
21318
21355
  }
21319
21356
  _private__levelOptions(level) {
21320
21357
  const options = level === 'entry' ? this._private__options.entry : this._private__options[level];
@@ -31445,7 +31482,7 @@ const customSeriesDefaultOptions = {
31445
31482
  * Returns the current version as a string. For example `'1.0.0'`.
31446
31483
  */
31447
31484
  function version() {
31448
- return "2.3.15";
31485
+ return "2.3.17-dev+202610130113";
31449
31486
  }
31450
31487
 
31451
31488
  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 };