@pipsend/charts 2.3.11 → 2.3.13

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.11
3
+ * Pipsend Charts v2.3.13-dev+202609280001
4
4
  * Copyright (c) 2026 Pipsend
5
5
  * Licensed under MIT License
6
6
  * Built on TradingView Lightweight Charts™ (Apache 2.0)
@@ -14281,6 +14281,8 @@ function shapeSize(shape, originalSize) {
14281
14281
  return size(originalSize, 0.7);
14282
14282
  case 'tag':
14283
14283
  return size(originalSize, 1);
14284
+ case 'xcross':
14285
+ return size(originalSize, 0.7);
14284
14286
  }
14285
14287
  }
14286
14288
  function calculateShapeHeight(barSpacing) {
@@ -14481,6 +14483,27 @@ function hitTestText(textX, textY, textWidth, textHeight, x, y) {
14481
14483
  y >= textY - halfHeight && y <= textY + halfHeight;
14482
14484
  }
14483
14485
 
14486
+ function drawXCross(ctx, coords, size) {
14487
+ const crossSize = shapeSize('xcross', size);
14488
+ const halfSize = ((crossSize - 1) / 2) * coords._internal_pixelRatio;
14489
+ ctx.save();
14490
+ ctx.strokeStyle = ctx.fillStyle;
14491
+ ctx.lineWidth = Math.max(1, Math.round(1.5 * coords._internal_pixelRatio));
14492
+ ctx.lineCap = 'round';
14493
+ ctx.beginPath();
14494
+ ctx.moveTo(coords._internal_x - halfSize, coords._internal_y - halfSize);
14495
+ ctx.lineTo(coords._internal_x + halfSize, coords._internal_y + halfSize);
14496
+ ctx.moveTo(coords._internal_x + halfSize, coords._internal_y - halfSize);
14497
+ ctx.lineTo(coords._internal_x - halfSize, coords._internal_y + halfSize);
14498
+ ctx.stroke();
14499
+ ctx.restore();
14500
+ }
14501
+ function hitTestXCross(centerX, centerY, size, x, y) {
14502
+ const crossSize = shapeSize('xcross', size);
14503
+ const tolerance = 2 + crossSize / 2;
14504
+ return Math.abs(x - centerX) <= tolerance && Math.abs(y - centerY) <= tolerance;
14505
+ }
14506
+
14484
14507
  class SeriesMarkersRenderer {
14485
14508
  constructor() {
14486
14509
  this._private__data = null;
@@ -14624,6 +14647,9 @@ function drawShape(item, ctx, coordinates) {
14624
14647
  case 'square':
14625
14648
  drawSquare(ctx, coordinates, item._internal_size);
14626
14649
  return;
14650
+ case 'xcross':
14651
+ drawXCross(ctx, coordinates, item._internal_size);
14652
+ return;
14627
14653
  case 'tag':
14628
14654
  // Handled by drawTagItem, which needs both pixel ratios and the text.
14629
14655
  return;
@@ -14652,6 +14678,8 @@ function hitTestShape(item, x, y) {
14652
14678
  return hitTestCircle(item._internal_x, item._internal_y, item._internal_size, x, y);
14653
14679
  case 'square':
14654
14680
  return hitTestSquare(item._internal_x, item._internal_y, item._internal_size, x, y);
14681
+ case 'xcross':
14682
+ return hitTestXCross(item._internal_x, item._internal_y, item._internal_size, x, y);
14655
14683
  case 'tag':
14656
14684
  return false;
14657
14685
  }
@@ -19309,6 +19337,12 @@ function setVolumeProfileData(indicator, data) {
19309
19337
  }
19310
19338
 
19311
19339
  const CLICK_TOLERANCE_PX = 4;
19340
+ /**
19341
+ * A fingertip never holds still: every tap travels further than a pointer
19342
+ * does, and judging it by the mouse's few pixels turned each one into a tiny
19343
+ * drag, so the tap never arrived.
19344
+ */
19345
+ const TOUCH_CLICK_TOLERANCE_PX = 12;
19312
19346
  /**
19313
19347
  * Single input owner for every trading line on a chart.
19314
19348
  *
@@ -19449,9 +19483,10 @@ class TradingLineController {
19449
19483
  this._private__releasePointer();
19450
19484
  this._private__pressedLine = null;
19451
19485
  this._private__pressOrigin = null;
19486
+ const tolerance = wasTouch ? TOUCH_CLICK_TOLERANCE_PX : CLICK_TOLERANCE_PX;
19452
19487
  const moved = origin !== null &&
19453
- (Math.abs(event.clientX - origin._internal_x) > CLICK_TOLERANCE_PX ||
19454
- Math.abs(event.clientY - origin._internal_y) > CLICK_TOLERANCE_PX);
19488
+ (Math.abs(event.clientX - origin._internal_x) > tolerance ||
19489
+ Math.abs(event.clientY - origin._internal_y) > tolerance);
19455
19490
  if (dragged !== null) {
19456
19491
  this._private__dragging = null;
19457
19492
  this._private__grabOffset = 0;
@@ -25724,17 +25759,19 @@ class RectangleTool extends DrawingToolBase {
25724
25759
  // Draw border
25725
25760
  const borderColor = this._private__rectOptions.borderColor;
25726
25761
  const borderWidth = this._private__isSelected ? this._private__rectOptions.borderWidth + 1 : this._private__rectOptions.borderWidth;
25727
- ctx.strokeStyle = borderColor;
25728
- ctx.lineWidth = borderWidth * horizontalPixelRatio;
25729
- // Set border style
25730
- if (this._private__rectOptions.borderStyle === 'dashed') {
25731
- ctx.setLineDash([10 * horizontalPixelRatio, 5 * horizontalPixelRatio]);
25732
- }
25733
- else if (this._private__rectOptions.borderStyle === 'dotted') {
25734
- ctx.setLineDash([2 * horizontalPixelRatio, 3 * horizontalPixelRatio]);
25762
+ if (borderWidth > 0) {
25763
+ ctx.strokeStyle = borderColor;
25764
+ ctx.lineWidth = borderWidth * horizontalPixelRatio;
25765
+ // Set border style
25766
+ if (this._private__rectOptions.borderStyle === 'dashed') {
25767
+ ctx.setLineDash([10 * horizontalPixelRatio, 5 * horizontalPixelRatio]);
25768
+ }
25769
+ else if (this._private__rectOptions.borderStyle === 'dotted') {
25770
+ ctx.setLineDash([2 * horizontalPixelRatio, 3 * horizontalPixelRatio]);
25771
+ }
25772
+ ctx.strokeRect(minX, minY, width, height);
25773
+ ctx.setLineDash([]);
25735
25774
  }
25736
- ctx.strokeRect(minX, minY, width, height);
25737
- ctx.setLineDash([]);
25738
25775
  // Draw corner handles if selected
25739
25776
  if ((this._private__isSelected || this._private__isHovered) && !this._private__isDrawing && !this.isLocked()) {
25740
25777
  this._private__drawCornerHandles(ctx, minX, minY, maxX, maxY, horizontalPixelRatio, borderColor);
@@ -25762,17 +25799,20 @@ class RectangleTool extends DrawingToolBase {
25762
25799
  }
25763
25800
  _private__drawLabel(ctx, minX, minY, maxX, maxY, horizontalPixelRatio, verticalPixelRatio, color) {
25764
25801
  const padding = 6 * horizontalPixelRatio;
25765
- const fontSize = 12 * horizontalPixelRatio;
25802
+ const fontSize = (this._private__rectOptions.labelFontSize ?? 12) * horizontalPixelRatio;
25766
25803
  ctx.font = `${fontSize}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
25767
25804
  const textMetrics = ctx.measureText(this._private__rectOptions.labelText);
25768
25805
  const textWidth = textMetrics.width;
25769
25806
  const textHeight = fontSize;
25807
+ const middleY = (minY + maxY) / 2 - textHeight / 2 - padding;
25808
+ // A box extended far past the pane keeps right-hand and centred labels on screen.
25809
+ const visibleMaxX = Math.min(maxX, ctx.canvas.width);
25770
25810
  // Calculate label position based on labelPosition option
25771
25811
  let labelX = minX + padding;
25772
25812
  let labelY = minY + padding;
25773
25813
  switch (this._private__rectOptions.labelPosition) {
25774
25814
  case 'top-right':
25775
- labelX = maxX - textWidth - padding * 2;
25815
+ labelX = visibleMaxX - textWidth - padding * 2;
25776
25816
  labelY = minY + padding;
25777
25817
  break;
25778
25818
  case 'bottom-left':
@@ -25780,19 +25820,27 @@ class RectangleTool extends DrawingToolBase {
25780
25820
  labelY = maxY - textHeight - padding * 2;
25781
25821
  break;
25782
25822
  case 'bottom-right':
25783
- labelX = maxX - textWidth - padding * 2;
25823
+ labelX = visibleMaxX - textWidth - padding * 2;
25784
25824
  labelY = maxY - textHeight - padding * 2;
25785
25825
  break;
25786
25826
  case 'center':
25787
- labelX = (minX + maxX) / 2 - textWidth / 2 - padding;
25788
- labelY = (minY + maxY) / 2 - textHeight / 2 - padding;
25827
+ labelX = (Math.max(minX, 0) + visibleMaxX) / 2 - textWidth / 2 - padding;
25828
+ labelY = middleY;
25829
+ break;
25830
+ case 'left':
25831
+ labelX = minX + padding;
25832
+ labelY = middleY;
25833
+ break;
25834
+ case 'right':
25835
+ labelX = visibleMaxX - textWidth - padding * 2;
25836
+ labelY = middleY;
25789
25837
  break;
25790
25838
  }
25791
25839
  // Draw background
25792
- ctx.fillStyle = color;
25840
+ ctx.fillStyle = this._private__rectOptions.labelBackgroundColor ?? color;
25793
25841
  ctx.fillRect(labelX, labelY, textWidth + padding * 2, textHeight + padding * 2);
25794
25842
  // Draw text
25795
- ctx.fillStyle = '#ffffff';
25843
+ ctx.fillStyle = this._private__rectOptions.labelColor ?? '#ffffff';
25796
25844
  ctx.textBaseline = 'top';
25797
25845
  ctx.fillText(this._private__rectOptions.labelText, labelX + padding, labelY + padding);
25798
25846
  }
@@ -26030,6 +26078,9 @@ class RectangleTool extends DrawingToolBase {
26030
26078
  showLabel: this._private__rectOptions.showLabel,
26031
26079
  labelText: this._private__rectOptions.labelText,
26032
26080
  labelPosition: this._private__rectOptions.labelPosition,
26081
+ labelColor: this._private__rectOptions.labelColor,
26082
+ labelBackgroundColor: this._private__rectOptions.labelBackgroundColor,
26083
+ labelFontSize: this._private__rectOptions.labelFontSize,
26033
26084
  },
26034
26085
  };
26035
26086
  }
@@ -27634,6 +27685,9 @@ class TextTool extends DrawingToolBase {
27634
27685
  borderWidth: 1,
27635
27686
  textAlign: 'left',
27636
27687
  maxWidth: 200,
27688
+ anchor: 'top-left',
27689
+ pointer: false,
27690
+ borderRadius: 0,
27637
27691
  ...options,
27638
27692
  };
27639
27693
  this._registerOptions(this._private__textOptions);
@@ -27785,18 +27839,59 @@ class TextTool extends DrawingToolBase {
27785
27839
  const py = this._series.priceToCoordinate(price) ?? 0;
27786
27840
  // Calculate text box dimensions
27787
27841
  const fontSize = this._private__textOptions.fontSize || 14;
27788
- const padding = this._private__textOptions.padding || 8;
27842
+ const padding = this._private__textOptions.padding ?? 8;
27789
27843
  const text = this._private__textOptions.text || '';
27790
27844
  // Rough estimate of text width (will be more accurate in canvas)
27791
27845
  const charWidth = fontSize * 0.6;
27792
27846
  const textWidth = Math.min(text.length * charWidth, this._private__textOptions.maxWidth || 200);
27793
- const textHeight = fontSize + padding * 2;
27794
- // Check if click is within text box bounds
27795
- const left = px;
27796
- const right = px + textWidth + padding * 2;
27797
- const top = py;
27798
- const bottom = py + textHeight;
27799
- return x >= left && x <= right && y >= top && y <= bottom;
27847
+ const boxWidth = textWidth + padding * 2;
27848
+ const boxHeight = fontSize + padding * 2;
27849
+ const tail = this._private__tailSize(boxHeight);
27850
+ const box = this._private__boxOrigin(px, py, boxWidth, boxHeight, tail);
27851
+ const left = box._internal_left - (this._private__textOptions.anchor === 'left' ? tail : 0);
27852
+ const right = box._internal_left + boxWidth + (this._private__textOptions.anchor === 'right' ? tail : 0);
27853
+ return x >= left && x <= right && y >= box._internal_top && y <= box._internal_top + boxHeight;
27854
+ }
27855
+ _private__tailSize(boxHeight) {
27856
+ const anchor = this._private__textOptions.anchor;
27857
+ return this._private__textOptions.pointer && (anchor === 'left' || anchor === 'right') ? Math.round(boxHeight * 0.35) : 0;
27858
+ }
27859
+ _private__boxOrigin(x, y, width, height, tail) {
27860
+ switch (this._private__textOptions.anchor) {
27861
+ case 'left':
27862
+ return { _internal_left: x + tail, _internal_top: y - height / 2 };
27863
+ case 'right':
27864
+ return { _internal_left: x - tail - width, _internal_top: y - height / 2 };
27865
+ case 'center':
27866
+ return { _internal_left: x - width / 2, _internal_top: y - height / 2 };
27867
+ default:
27868
+ return { _internal_left: x, _internal_top: y };
27869
+ }
27870
+ }
27871
+ // eslint-disable-next-line max-params
27872
+ _private__traceBox(ctx, left, top, width, height, tail, anchorX, anchorY, radius) {
27873
+ const r = Math.max(0, Math.min(radius, width / 2, height / 2));
27874
+ ctx.beginPath();
27875
+ ctx.moveTo(left + r, top);
27876
+ ctx.lineTo(left + width - r, top);
27877
+ ctx.arcTo(left + width, top, left + width, top + r, r);
27878
+ if (tail > 0 && this._private__textOptions.anchor === 'right') {
27879
+ ctx.lineTo(left + width, anchorY - tail);
27880
+ ctx.lineTo(anchorX, anchorY);
27881
+ ctx.lineTo(left + width, anchorY + tail);
27882
+ }
27883
+ ctx.lineTo(left + width, top + height - r);
27884
+ ctx.arcTo(left + width, top + height, left + width - r, top + height, r);
27885
+ ctx.lineTo(left + r, top + height);
27886
+ ctx.arcTo(left, top + height, left, top + height - r, r);
27887
+ if (tail > 0 && this._private__textOptions.anchor === 'left') {
27888
+ ctx.lineTo(left, anchorY + tail);
27889
+ ctx.lineTo(anchorX, anchorY);
27890
+ ctx.lineTo(left, anchorY - tail);
27891
+ }
27892
+ ctx.lineTo(left, top + r);
27893
+ ctx.arcTo(left, top, left + r, top, r);
27894
+ ctx.closePath();
27800
27895
  }
27801
27896
  hitTestEndpoint(x, y) {
27802
27897
  if (!this.isComplete())
@@ -27848,7 +27943,7 @@ class TextTool extends DrawingToolBase {
27848
27943
  const x = (coordinateFromTime(this._chart, this._series, time) ?? 0) * horizontalPixelRatio;
27849
27944
  const y = (this._series.priceToCoordinate(price) ?? 0) * verticalPixelRatio;
27850
27945
  const fontSize = (this._private__textOptions.fontSize || 14) * horizontalPixelRatio;
27851
- const padding = (this._private__textOptions.padding || 8) * horizontalPixelRatio;
27946
+ const padding = (this._private__textOptions.padding ?? 8) * horizontalPixelRatio;
27852
27947
  const maxWidth = (this._private__textOptions.maxWidth || 200) * horizontalPixelRatio;
27853
27948
  // Set font
27854
27949
  ctx.font = `${fontSize}px ${this._private__textOptions.fontFamily || 'Arial'}`;
@@ -27880,32 +27975,39 @@ class TextTool extends DrawingToolBase {
27880
27975
  const boxWidth = maxLineWidth + padding * 2;
27881
27976
  const lineHeight = fontSize * 1.2;
27882
27977
  const boxHeight = lines.length * lineHeight + padding * 2;
27978
+ const tail = this._private__tailSize(boxHeight);
27979
+ const { _internal_left: left, _internal_top: top } = this._private__boxOrigin(x, y, boxWidth, boxHeight, tail);
27980
+ const radius = (this._private__textOptions.borderRadius ?? 0) * horizontalPixelRatio;
27883
27981
  // Draw background
27884
- const bgOpacity = this._private__textOptions.backgroundOpacity || 0.8;
27982
+ const bgOpacity = this._private__textOptions.backgroundOpacity ?? 0.8;
27885
27983
  const bgColor = this._private__textOptions.backgroundColor || '#2962FF';
27886
- ctx.fillStyle = this._private__hexToRgba(bgColor, bgOpacity);
27887
- ctx.fillRect(x, y, boxWidth, boxHeight);
27984
+ if (bgOpacity > 0) {
27985
+ ctx.fillStyle = this._private__hexToRgba(bgColor, bgOpacity);
27986
+ this._private__traceBox(ctx, left, top, boxWidth, boxHeight, tail, x, y, radius);
27987
+ ctx.fill();
27988
+ }
27888
27989
  // Draw border
27889
27990
  if (this._private__isSelected || this._private__isHovered) {
27890
27991
  ctx.strokeStyle = this._private__textOptions.borderColor ?? '#FFFFFF';
27891
27992
  ctx.lineWidth = (this._private__textOptions.borderWidth || 1) * horizontalPixelRatio * (this._private__isSelected ? 2 : 1);
27892
- ctx.strokeRect(x, y, boxWidth, boxHeight);
27993
+ this._private__traceBox(ctx, left, top, boxWidth, boxHeight, tail, x, y, radius);
27994
+ ctx.stroke();
27893
27995
  }
27894
27996
  // Draw text
27895
27997
  ctx.fillStyle = this._private__textOptions.textColor || '#FFFFFF';
27896
27998
  for (let i = 0; i < lines.length; i++) {
27897
27999
  const line = lines[i];
27898
- let textX = x + padding;
28000
+ let textX = left + padding;
27899
28001
  // Handle text alignment
27900
28002
  if (this._private__textOptions.textAlign === 'center') {
27901
28003
  const metrics = ctx.measureText(line);
27902
- textX = x + (boxWidth - metrics.width) / 2;
28004
+ textX = left + (boxWidth - metrics.width) / 2;
27903
28005
  }
27904
28006
  else if (this._private__textOptions.textAlign === 'right') {
27905
28007
  const metrics = ctx.measureText(line);
27906
- textX = x + boxWidth - metrics.width - padding;
28008
+ textX = left + boxWidth - metrics.width - padding;
27907
28009
  }
27908
- const textY = y + padding + i * lineHeight;
28010
+ const textY = top + padding + i * lineHeight;
27909
28011
  ctx.fillText(line, textX, textY);
27910
28012
  }
27911
28013
  // Draw anchor point if selected
@@ -27949,6 +28051,9 @@ class TextTool extends DrawingToolBase {
27949
28051
  borderWidth: this._private__textOptions.borderWidth,
27950
28052
  textAlign: this._private__textOptions.textAlign,
27951
28053
  maxWidth: this._private__textOptions.maxWidth,
28054
+ anchor: this._private__textOptions.anchor,
28055
+ pointer: this._private__textOptions.pointer,
28056
+ borderRadius: this._private__textOptions.borderRadius,
27952
28057
  },
27953
28058
  extra: {
27954
28059
  text: this._private__textOptions.text,
@@ -30736,7 +30841,7 @@ const customSeriesDefaultOptions = {
30736
30841
  * Returns the current version as a string. For example `'1.0.0'`.
30737
30842
  */
30738
30843
  function version() {
30739
- return "2.3.11";
30844
+ return "2.3.13-dev+202609280001";
30740
30845
  }
30741
30846
 
30742
30847
  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 };