@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)
@@ -4574,18 +4574,16 @@ class PriceScale {
4574
4574
  this._private__invalidateInternalHeightCache();
4575
4575
  }
4576
4576
  if (priceRange !== null) {
4577
- // keep current range is new is empty
4578
- if (priceRange._internal_minValue() === priceRange._internal_maxValue()) {
4579
- // if price range is degenerated to 1 point let's extend it by 10 min move values
4580
- // to avoid incorrect range and empty (blank) scale (in case of min tick much greater than 1)
4581
- const extendValue = 5 * this._internal_minMove();
4582
- if (this._internal_isLog()) {
4583
- priceRange = convertPriceRangeFromLog(priceRange, this._private__logFormula);
4584
- }
4585
- priceRange = new PriceRangeImpl(priceRange._internal_minValue() - extendValue, priceRange._internal_maxValue() + extendValue);
4586
- if (this._internal_isLog()) {
4587
- priceRange = convertPriceRangeToLog(priceRange, this._private__logFormula);
4588
- }
4577
+ // a range flat or narrower than 10 min moves leaves room for one tick mark at most,
4578
+ // so widen it around its center to keep a readable scale
4579
+ const isLog = this._internal_isLog();
4580
+ const rawRange = isLog ? convertPriceRangeFromLog(priceRange, this._private__logFormula) : priceRange;
4581
+ const minimumLength = this._internal_isPercentage() || this._internal_isIndexedTo100() ? 0 : 10 * this._internal_minMove();
4582
+ if (rawRange._internal_minValue() === rawRange._internal_maxValue() || rawRange._internal_length() < minimumLength) {
4583
+ const extendValue = Math.max(5 * this._internal_minMove(), minimumLength / 2);
4584
+ const center = (rawRange._internal_minValue() + rawRange._internal_maxValue()) / 2;
4585
+ const widened = new PriceRangeImpl(center - extendValue, center + extendValue);
4586
+ priceRange = isLog ? convertPriceRangeToLog(widened, this._private__logFormula) : widened;
4589
4587
  }
4590
4588
  if (this._internal_isLog()) {
4591
4589
  const rawRange = convertPriceRangeFromLog(priceRange, this._private__logFormula);
@@ -20218,8 +20216,11 @@ class PositionLineLabelLayout {
20218
20216
  * move — which is invisible, and cheaper than forcing a second pass.
20219
20217
  */
20220
20218
  _internal_setClaims(ownerId, claims) {
20219
+ const previous = this._private__claims.get(ownerId);
20221
20220
  this._private__claims.set(ownerId, claims);
20222
- this._private__invalidated = true;
20221
+ if (previous === undefined || !sameClaims(previous, claims)) {
20222
+ this._private__invalidated = true;
20223
+ }
20223
20224
  }
20224
20225
  /** How far down a label has to move to clear the ones already placed. */
20225
20226
  _internal_offsetFor(ownerId, level) {
@@ -20240,7 +20241,10 @@ class PositionLineLabelLayout {
20240
20241
  // them only need the few pixels they are short of — stepping by a
20241
20242
  // full gap each time is what made the fan look flung open.
20242
20243
  let y = claim._internal_y;
20243
- for (const other of [...placed].sort(byY)) {
20244
+ for (const other of placed) {
20245
+ if (other._internal_y >= y + gap) {
20246
+ break;
20247
+ }
20244
20248
  if (Math.abs(y - other._internal_y) < gap) {
20245
20249
  y = other._internal_y + gap;
20246
20250
  }
@@ -20251,7 +20255,7 @@ class PositionLineLabelLayout {
20251
20255
  // no worse than before and keeps the pile from running off.
20252
20256
  offset = 0;
20253
20257
  }
20254
- placed.push({ _internal_y: claim._internal_y + offset, _internal_height: claim._internal_height });
20258
+ insertByY(placed, { _internal_y: claim._internal_y + offset, _internal_height: claim._internal_height });
20255
20259
  offsets.set(key(ownerId, claim._internal_level), offset);
20256
20260
  }
20257
20261
  }
@@ -20269,8 +20273,30 @@ function key(ownerId, level) {
20269
20273
  function minGap(height) {
20270
20274
  return Math.max(9, Math.round(height * 0.4));
20271
20275
  }
20272
- function byY(a, b) {
20273
- return a._internal_y - b._internal_y;
20276
+ function insertByY(placed, claim) {
20277
+ let low = 0;
20278
+ let high = placed.length;
20279
+ while (low < high) {
20280
+ const middle = (low + high) >> 1;
20281
+ if (placed[middle]._internal_y <= claim._internal_y) {
20282
+ low = middle + 1;
20283
+ }
20284
+ else {
20285
+ high = middle;
20286
+ }
20287
+ }
20288
+ placed.splice(low, 0, claim);
20289
+ }
20290
+ function sameClaims(a, b) {
20291
+ if (a.length !== b.length) {
20292
+ return false;
20293
+ }
20294
+ for (let i = 0; i < a.length; i++) {
20295
+ 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) {
20296
+ return false;
20297
+ }
20298
+ }
20299
+ return true;
20274
20300
  }
20275
20301
  const layouts = new WeakMap();
20276
20302
  /** The layout is shared by every position line on the same chart. */
@@ -20625,6 +20651,7 @@ class PositionLine {
20625
20651
  constructor(chart, series, options) {
20626
20652
  this._private__paneView = new PositionLinePaneView();
20627
20653
  this._private__colorParser = new ColorParser([]);
20654
+ this._private__axisLabels = new Map();
20628
20655
  this._private__attached = false;
20629
20656
  this._private__hoveredLevel = null;
20630
20657
  this._private__hoveredPart = null;
@@ -20916,12 +20943,22 @@ class PositionLine {
20916
20943
  return null;
20917
20944
  }
20918
20945
  const color = options.color ?? positionLineDefaultColors[level];
20919
- return {
20946
+ const formatter = this._private__series.priceFormatter();
20947
+ const cached = this._private__axisLabels.get(level);
20948
+ if (cached !== undefined && cached._internal_price === options.price && cached._internal_color === color && cached._internal_formatter === formatter) {
20949
+ if (cached._internal_label._internal_coordinate !== y) {
20950
+ cached._internal_label = { ...cached._internal_label, _internal_coordinate: y };
20951
+ }
20952
+ return cached._internal_label;
20953
+ }
20954
+ const label = {
20920
20955
  _internal_coordinate: y,
20921
- _internal_text: this._private__series.priceFormatter().format(options.price),
20956
+ _internal_text: formatter.format(options.price),
20922
20957
  _internal_color: color,
20923
20958
  _internal_textColor: this._private__colorParser._internal_generateContrastColors(color)._internal_foreground,
20924
20959
  };
20960
+ this._private__axisLabels.set(level, { _internal_price: options.price, _internal_color: color, _internal_formatter: formatter, _internal_label: label });
20961
+ return label;
20925
20962
  }
20926
20963
  _private__levelOptions(level) {
20927
20964
  const options = level === 'entry' ? this._private__options.entry : this._private__options[level];
@@ -31052,7 +31089,7 @@ const customSeriesDefaultOptions = {
31052
31089
  * Returns the current version as a string. For example `'1.0.0'`.
31053
31090
  */
31054
31091
  function version() {
31055
- return "2.3.15";
31092
+ return "2.3.17-dev+202610130113";
31056
31093
  }
31057
31094
 
31058
31095
  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 };