@pipsend/charts 2.3.10 → 2.3.11

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.10
3
+ * Pipsend Charts v2.3.11
4
4
  * Copyright (c) 2026 Pipsend
5
5
  * Licensed under MIT License
6
6
  * Built on TradingView Lightweight Charts™ (Apache 2.0)
@@ -19327,6 +19327,8 @@ class TradingLineController {
19327
19327
  this._private__pointerId = null;
19328
19328
  this._private__pressOrigin = null;
19329
19329
  this._private__pressedLine = null;
19330
+ /** Whether the gesture in flight came from a finger rather than a mouse. */
19331
+ this._private__pressWasTouch = false;
19330
19332
  /** Distance from the pointer to the dragged line when the press landed. */
19331
19333
  this._private__grabOffset = 0;
19332
19334
  /** Latest pointer position in pane coordinates, or null when off the panes. */
@@ -19391,8 +19393,18 @@ class TradingLineController {
19391
19393
  this._private__applyCursor();
19392
19394
  }
19393
19395
  _private__onPointerDown(event) {
19394
- const line = this._private__hoveredId === null ? null : this._private__lines.get(this._private__hoveredId) ?? null;
19396
+ // Hover belongs to the mouse. Touch leaves whatever the last press marked
19397
+ // still marked, so trusting it here grabbed that line again wherever the
19398
+ // next tap landed: every press resolves itself instead.
19399
+ this._private__pressWasTouch = event.pointerType !== 'mouse';
19400
+ let line = this._private__pressWasTouch || this._private__hoveredId === null
19401
+ ? null
19402
+ : this._private__lines.get(this._private__hoveredId) ?? null;
19403
+ if (line === null) {
19404
+ line = this._private__resolveHitAt(event);
19405
+ }
19395
19406
  if (!line) {
19407
+ this._private__clearTouchHover();
19396
19408
  return;
19397
19409
  }
19398
19410
  this._private__pressOrigin = { _internal_x: event.clientX, _internal_y: event.clientY };
@@ -19431,6 +19443,7 @@ class TradingLineController {
19431
19443
  }
19432
19444
  _private__onPointerUp(event) {
19433
19445
  const dragged = this._private__dragging;
19446
+ const wasTouch = this._private__pressWasTouch;
19434
19447
  const pressed = this._private__pressedLine;
19435
19448
  const origin = this._private__pressOrigin;
19436
19449
  this._private__releasePointer();
@@ -19452,12 +19465,24 @@ class TradingLineController {
19452
19465
  dragged.click();
19453
19466
  }
19454
19467
  }
19468
+ this._private__clearTouchHover(wasTouch);
19455
19469
  this._private__applyCursor();
19456
19470
  return;
19457
19471
  }
19458
19472
  if (pressed !== null && !moved && pressed.isClickable()) {
19459
19473
  pressed.click();
19460
19474
  }
19475
+ this._private__clearTouchHover(wasTouch);
19476
+ }
19477
+ /** A finger leaves nothing hovered behind it, the way lifting a mouse does. */
19478
+ _private__clearTouchHover(wasTouch = this._private__pressWasTouch) {
19479
+ if (!wasTouch || this._private__hoveredId === null) {
19480
+ return;
19481
+ }
19482
+ const line = this._private__lines.get(this._private__hoveredId) ?? null;
19483
+ this._private__setHovered(null);
19484
+ this._private__setHoveredPart(line, null);
19485
+ this._private__applyCursor();
19461
19486
  }
19462
19487
  /**
19463
19488
  * Abort an in-flight gesture: the line goes back to where it was and no
@@ -19503,9 +19528,38 @@ class TradingLineController {
19503
19528
  return paneY === null ? null : line.priceAt(paneY - this._private__grabOffset);
19504
19529
  }
19505
19530
  /** The pointer's position inside the line's pane, in pane coordinates. */
19506
- _private__paneY(line, event) {
19531
+ /**
19532
+ * The hovered id comes from the crosshair, which touch never moves before it
19533
+ * presses, so the press resolves the target itself.
19534
+ */
19535
+ _private__resolveHitAt(event) {
19536
+ for (const line of this._private__lines.values()) {
19537
+ if (!line.hitTestAt) {
19538
+ continue;
19539
+ }
19540
+ const paneElement = this._private__paneElementOf(line);
19541
+ if (paneElement === null) {
19542
+ continue;
19543
+ }
19544
+ const rect = paneElement.getBoundingClientRect();
19545
+ // A fingertip is far coarser than a pointer, so its targets are widened.
19546
+ const slop = event.pointerType === 'mouse' ? 0 : 12 /* Constants.TouchSlopPx */;
19547
+ const hit = this._private__splitHit(line.hitTestAt(event.clientX - rect.left, event.clientY - rect.top, slop));
19548
+ if (hit === null) {
19549
+ continue;
19550
+ }
19551
+ this._private__setHovered(line.id());
19552
+ this._private__setHoveredPart(line, hit._internal_part);
19553
+ return line;
19554
+ }
19555
+ return null;
19556
+ }
19557
+ _private__paneElementOf(line) {
19507
19558
  const pane = this._private__chart.panes()[line.paneIndex()];
19508
- const paneElement = pane ? pane.getHTMLElement() : null;
19559
+ return pane ? pane.getHTMLElement() : null;
19560
+ }
19561
+ _private__paneY(line, event) {
19562
+ const paneElement = this._private__paneElementOf(line);
19509
19563
  if (paneElement) {
19510
19564
  return event.clientY - paneElement.getBoundingClientRect().top;
19511
19565
  }
@@ -19622,6 +19676,7 @@ let nextLineId = 0;
19622
19676
  * line. Hit testing comes from the engine — the line's id travels as the price
19623
19677
  * line's `externalId` — so the hit area matches what is drawn.
19624
19678
  */
19679
+ const HIT_TOLERANCE_PX$1 = 8;
19625
19680
  class DraggablePriceLine {
19626
19681
  constructor(chart, series, options) {
19627
19682
  this._private__priceLine = null;
@@ -19674,6 +19729,14 @@ class DraggablePriceLine {
19674
19729
  color: hovered ? this._private__options.hoverColor : this._private__originalColor,
19675
19730
  });
19676
19731
  }
19732
+ /**
19733
+ * The engine draws this one, so there is no pane view to ask: a press within
19734
+ * the line's own grab strip counts as a hit.
19735
+ */
19736
+ hitTestAt(x, y, slop = 0) {
19737
+ const coord = this._private__series.priceToCoordinate(this._private__options.price);
19738
+ return coord !== null && Math.abs(y - coord) <= HIT_TOLERANCE_PX$1 + slop ? this._private__id : null;
19739
+ }
19677
19740
  priceAt(paneY) {
19678
19741
  const price = this._private__series.coordinateToPrice(paneY);
19679
19742
  return price === null ? null : price;
@@ -20216,22 +20279,27 @@ class PositionLineRenderer {
20216
20279
  _internal_setData(data) {
20217
20280
  this._private__data = data;
20218
20281
  }
20219
- _internal_hitTest(x, y) {
20282
+ /**
20283
+ * `slop` widens every target by the same amount, for input coarser than a
20284
+ * mouse pointer.
20285
+ */
20286
+ _internal_hitTest(x, y, slop = 0) {
20220
20287
  // The close button sits on top of the label, which sits on top of the
20221
20288
  // line, so the narrowest target is tested first.
20222
20289
  for (const layout of this._private__layouts) {
20223
- if (layout._internal_closable && x >= layout._internal_closeLeft && x <= layout._internal_closeRight &&
20224
- Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2) {
20290
+ if (layout._internal_closable && x >= layout._internal_closeLeft - slop && x <= layout._internal_closeRight + slop &&
20291
+ Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2 + slop) {
20225
20292
  return { _internal_level: layout._internal_level, _internal_part: 'close' };
20226
20293
  }
20227
20294
  }
20228
20295
  for (const layout of this._private__layouts) {
20229
- if (x >= layout._internal_pillLeft && x <= layout._internal_pillRight && Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2) {
20296
+ if (x >= layout._internal_pillLeft - slop && x <= layout._internal_pillRight + slop &&
20297
+ Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2 + slop) {
20230
20298
  return { _internal_level: layout._internal_level, _internal_part: 'body' };
20231
20299
  }
20232
20300
  }
20233
20301
  for (const layout of this._private__layouts) {
20234
- if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */) {
20302
+ if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */ + slop) {
20235
20303
  return { _internal_level: layout._internal_level, _internal_part: 'line' };
20236
20304
  }
20237
20305
  }
@@ -20468,8 +20536,8 @@ class PositionLinePaneView {
20468
20536
  zOrder() {
20469
20537
  return 'top';
20470
20538
  }
20471
- _internal_hitTest(x, y) {
20472
- return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y);
20539
+ _internal_hitTest(x, y, slop = 0) {
20540
+ return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y, slop);
20473
20541
  }
20474
20542
  }
20475
20543
 
@@ -20620,6 +20688,13 @@ class PositionLine {
20620
20688
  * of jumping to sit under it — which matters most when the label has been
20621
20689
  * fanned away from its own line.
20622
20690
  */
20691
+ hitTestAt(x, y, slop = 0) {
20692
+ const hit = this._private__paneView._internal_hitTest(x, y, slop);
20693
+ if (hit === null) {
20694
+ return null;
20695
+ }
20696
+ return this._private__levelOptions(hit._internal_level) === null ? null : `${this._private__id}#${hit._internal_level}:${hit._internal_part}`;
20697
+ }
20623
20698
  dragAnchorY() {
20624
20699
  if (this._private__dragLevel === null) {
20625
20700
  return null;
@@ -29690,6 +29765,7 @@ class DrawingToolsManager {
29690
29765
  this._private__mouseMoveHandler = null;
29691
29766
  this._private__pointerDownHandler = null;
29692
29767
  this._private__pointerUpHandler = null;
29768
+ this._private__pointerMoveHandler = null;
29693
29769
  this._private__pointerCancelHandler = null;
29694
29770
  this._private__lostCaptureHandler = null;
29695
29771
  this._private__windowPointerUpHandler = null;
@@ -30264,10 +30340,12 @@ class DrawingToolsManager {
30264
30340
  if (chartElement) {
30265
30341
  this._private__pointerDownHandler = (event) => this._private__handlePointerDown(event);
30266
30342
  this._private__pointerUpHandler = (event) => this._private__handlePointerUp(event);
30343
+ this._private__pointerMoveHandler = (event) => this._private__handlePointerMove(event);
30267
30344
  this._private__pointerCancelHandler = (event) => this._private__handlePointerUp(event);
30268
30345
  this._private__lostCaptureHandler = (event) => this._private__handleLostPointerCapture(event);
30269
30346
  chartElement.addEventListener('pointerdown', this._private__pointerDownHandler);
30270
30347
  chartElement.addEventListener('pointerup', this._private__pointerUpHandler);
30348
+ chartElement.addEventListener('pointermove', this._private__pointerMoveHandler);
30271
30349
  chartElement.addEventListener('pointercancel', this._private__pointerCancelHandler);
30272
30350
  chartElement.addEventListener('lostpointercapture', this._private__lostCaptureHandler);
30273
30351
  }
@@ -30302,6 +30380,10 @@ class DrawingToolsManager {
30302
30380
  chartElement.removeEventListener('pointerup', this._private__pointerUpHandler);
30303
30381
  this._private__pointerUpHandler = null;
30304
30382
  }
30383
+ if (this._private__pointerMoveHandler) {
30384
+ chartElement.removeEventListener('pointermove', this._private__pointerMoveHandler);
30385
+ this._private__pointerMoveHandler = null;
30386
+ }
30305
30387
  if (this._private__pointerCancelHandler) {
30306
30388
  chartElement.removeEventListener('pointercancel', this._private__pointerCancelHandler);
30307
30389
  this._private__pointerCancelHandler = null;
@@ -30451,6 +30533,36 @@ class DrawingToolsManager {
30451
30533
  // mouse events, and those are what drive the crosshair the drag reads.
30452
30534
  this._private__disableChartInteractions();
30453
30535
  }
30536
+ /**
30537
+ * The drag reads the crosshair, which touch never moves: its move handler
30538
+ * only tries to pan, and the drag has just turned panning off. So touch is
30539
+ * driven straight from the pointer instead.
30540
+ */
30541
+ _private__handlePointerMove(event) {
30542
+ if (!this._private__isDragging || this._private__draggedToolId === null || event.pointerType === 'mouse') {
30543
+ return;
30544
+ }
30545
+ if (this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
30546
+ return;
30547
+ }
30548
+ const tool = this._private__tools.get(this._private__draggedToolId);
30549
+ if (!tool) {
30550
+ return;
30551
+ }
30552
+ const paneElement = this._private__paneElementOf(tool);
30553
+ if (paneElement === null) {
30554
+ return;
30555
+ }
30556
+ const rect = paneElement.getBoundingClientRect();
30557
+ const series = tool.series();
30558
+ const price = series.coordinateToPrice((event.clientY - rect.top));
30559
+ const time = timeFromCoordinate(this._private__chart, series, event.clientX - rect.left);
30560
+ if (price === null || time === null) {
30561
+ return;
30562
+ }
30563
+ tool.updateDrag(time, price);
30564
+ event.preventDefault();
30565
+ }
30454
30566
  _private__handlePointerUp(event) {
30455
30567
  if (!this._private__isDragging || this._private__draggedToolId === null) {
30456
30568
  return;
@@ -30624,7 +30736,7 @@ const customSeriesDefaultOptions = {
30624
30736
  * Returns the current version as a string. For example `'1.0.0'`.
30625
30737
  */
30626
30738
  function version() {
30627
- return "2.3.10";
30739
+ return "2.3.11";
30628
30740
  }
30629
30741
 
30630
30742
  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 };