@pipsend/charts 2.3.12 → 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.12
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
  }
@@ -25731,17 +25759,19 @@ class RectangleTool extends DrawingToolBase {
25731
25759
  // Draw border
25732
25760
  const borderColor = this._private__rectOptions.borderColor;
25733
25761
  const borderWidth = this._private__isSelected ? this._private__rectOptions.borderWidth + 1 : this._private__rectOptions.borderWidth;
25734
- ctx.strokeStyle = borderColor;
25735
- ctx.lineWidth = borderWidth * horizontalPixelRatio;
25736
- // Set border style
25737
- if (this._private__rectOptions.borderStyle === 'dashed') {
25738
- ctx.setLineDash([10 * horizontalPixelRatio, 5 * horizontalPixelRatio]);
25739
- }
25740
- else if (this._private__rectOptions.borderStyle === 'dotted') {
25741
- 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([]);
25742
25774
  }
25743
- ctx.strokeRect(minX, minY, width, height);
25744
- ctx.setLineDash([]);
25745
25775
  // Draw corner handles if selected
25746
25776
  if ((this._private__isSelected || this._private__isHovered) && !this._private__isDrawing && !this.isLocked()) {
25747
25777
  this._private__drawCornerHandles(ctx, minX, minY, maxX, maxY, horizontalPixelRatio, borderColor);
@@ -25769,17 +25799,20 @@ class RectangleTool extends DrawingToolBase {
25769
25799
  }
25770
25800
  _private__drawLabel(ctx, minX, minY, maxX, maxY, horizontalPixelRatio, verticalPixelRatio, color) {
25771
25801
  const padding = 6 * horizontalPixelRatio;
25772
- const fontSize = 12 * horizontalPixelRatio;
25802
+ const fontSize = (this._private__rectOptions.labelFontSize ?? 12) * horizontalPixelRatio;
25773
25803
  ctx.font = `${fontSize}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
25774
25804
  const textMetrics = ctx.measureText(this._private__rectOptions.labelText);
25775
25805
  const textWidth = textMetrics.width;
25776
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);
25777
25810
  // Calculate label position based on labelPosition option
25778
25811
  let labelX = minX + padding;
25779
25812
  let labelY = minY + padding;
25780
25813
  switch (this._private__rectOptions.labelPosition) {
25781
25814
  case 'top-right':
25782
- labelX = maxX - textWidth - padding * 2;
25815
+ labelX = visibleMaxX - textWidth - padding * 2;
25783
25816
  labelY = minY + padding;
25784
25817
  break;
25785
25818
  case 'bottom-left':
@@ -25787,19 +25820,27 @@ class RectangleTool extends DrawingToolBase {
25787
25820
  labelY = maxY - textHeight - padding * 2;
25788
25821
  break;
25789
25822
  case 'bottom-right':
25790
- labelX = maxX - textWidth - padding * 2;
25823
+ labelX = visibleMaxX - textWidth - padding * 2;
25791
25824
  labelY = maxY - textHeight - padding * 2;
25792
25825
  break;
25793
25826
  case 'center':
25794
- labelX = (minX + maxX) / 2 - textWidth / 2 - padding;
25795
- 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;
25796
25837
  break;
25797
25838
  }
25798
25839
  // Draw background
25799
- ctx.fillStyle = color;
25840
+ ctx.fillStyle = this._private__rectOptions.labelBackgroundColor ?? color;
25800
25841
  ctx.fillRect(labelX, labelY, textWidth + padding * 2, textHeight + padding * 2);
25801
25842
  // Draw text
25802
- ctx.fillStyle = '#ffffff';
25843
+ ctx.fillStyle = this._private__rectOptions.labelColor ?? '#ffffff';
25803
25844
  ctx.textBaseline = 'top';
25804
25845
  ctx.fillText(this._private__rectOptions.labelText, labelX + padding, labelY + padding);
25805
25846
  }
@@ -26037,6 +26078,9 @@ class RectangleTool extends DrawingToolBase {
26037
26078
  showLabel: this._private__rectOptions.showLabel,
26038
26079
  labelText: this._private__rectOptions.labelText,
26039
26080
  labelPosition: this._private__rectOptions.labelPosition,
26081
+ labelColor: this._private__rectOptions.labelColor,
26082
+ labelBackgroundColor: this._private__rectOptions.labelBackgroundColor,
26083
+ labelFontSize: this._private__rectOptions.labelFontSize,
26040
26084
  },
26041
26085
  };
26042
26086
  }
@@ -27641,6 +27685,9 @@ class TextTool extends DrawingToolBase {
27641
27685
  borderWidth: 1,
27642
27686
  textAlign: 'left',
27643
27687
  maxWidth: 200,
27688
+ anchor: 'top-left',
27689
+ pointer: false,
27690
+ borderRadius: 0,
27644
27691
  ...options,
27645
27692
  };
27646
27693
  this._registerOptions(this._private__textOptions);
@@ -27792,18 +27839,59 @@ class TextTool extends DrawingToolBase {
27792
27839
  const py = this._series.priceToCoordinate(price) ?? 0;
27793
27840
  // Calculate text box dimensions
27794
27841
  const fontSize = this._private__textOptions.fontSize || 14;
27795
- const padding = this._private__textOptions.padding || 8;
27842
+ const padding = this._private__textOptions.padding ?? 8;
27796
27843
  const text = this._private__textOptions.text || '';
27797
27844
  // Rough estimate of text width (will be more accurate in canvas)
27798
27845
  const charWidth = fontSize * 0.6;
27799
27846
  const textWidth = Math.min(text.length * charWidth, this._private__textOptions.maxWidth || 200);
27800
- const textHeight = fontSize + padding * 2;
27801
- // Check if click is within text box bounds
27802
- const left = px;
27803
- const right = px + textWidth + padding * 2;
27804
- const top = py;
27805
- const bottom = py + textHeight;
27806
- 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();
27807
27895
  }
27808
27896
  hitTestEndpoint(x, y) {
27809
27897
  if (!this.isComplete())
@@ -27855,7 +27943,7 @@ class TextTool extends DrawingToolBase {
27855
27943
  const x = (coordinateFromTime(this._chart, this._series, time) ?? 0) * horizontalPixelRatio;
27856
27944
  const y = (this._series.priceToCoordinate(price) ?? 0) * verticalPixelRatio;
27857
27945
  const fontSize = (this._private__textOptions.fontSize || 14) * horizontalPixelRatio;
27858
- const padding = (this._private__textOptions.padding || 8) * horizontalPixelRatio;
27946
+ const padding = (this._private__textOptions.padding ?? 8) * horizontalPixelRatio;
27859
27947
  const maxWidth = (this._private__textOptions.maxWidth || 200) * horizontalPixelRatio;
27860
27948
  // Set font
27861
27949
  ctx.font = `${fontSize}px ${this._private__textOptions.fontFamily || 'Arial'}`;
@@ -27887,32 +27975,39 @@ class TextTool extends DrawingToolBase {
27887
27975
  const boxWidth = maxLineWidth + padding * 2;
27888
27976
  const lineHeight = fontSize * 1.2;
27889
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;
27890
27981
  // Draw background
27891
- const bgOpacity = this._private__textOptions.backgroundOpacity || 0.8;
27982
+ const bgOpacity = this._private__textOptions.backgroundOpacity ?? 0.8;
27892
27983
  const bgColor = this._private__textOptions.backgroundColor || '#2962FF';
27893
- ctx.fillStyle = this._private__hexToRgba(bgColor, bgOpacity);
27894
- 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
+ }
27895
27989
  // Draw border
27896
27990
  if (this._private__isSelected || this._private__isHovered) {
27897
27991
  ctx.strokeStyle = this._private__textOptions.borderColor ?? '#FFFFFF';
27898
27992
  ctx.lineWidth = (this._private__textOptions.borderWidth || 1) * horizontalPixelRatio * (this._private__isSelected ? 2 : 1);
27899
- ctx.strokeRect(x, y, boxWidth, boxHeight);
27993
+ this._private__traceBox(ctx, left, top, boxWidth, boxHeight, tail, x, y, radius);
27994
+ ctx.stroke();
27900
27995
  }
27901
27996
  // Draw text
27902
27997
  ctx.fillStyle = this._private__textOptions.textColor || '#FFFFFF';
27903
27998
  for (let i = 0; i < lines.length; i++) {
27904
27999
  const line = lines[i];
27905
- let textX = x + padding;
28000
+ let textX = left + padding;
27906
28001
  // Handle text alignment
27907
28002
  if (this._private__textOptions.textAlign === 'center') {
27908
28003
  const metrics = ctx.measureText(line);
27909
- textX = x + (boxWidth - metrics.width) / 2;
28004
+ textX = left + (boxWidth - metrics.width) / 2;
27910
28005
  }
27911
28006
  else if (this._private__textOptions.textAlign === 'right') {
27912
28007
  const metrics = ctx.measureText(line);
27913
- textX = x + boxWidth - metrics.width - padding;
28008
+ textX = left + boxWidth - metrics.width - padding;
27914
28009
  }
27915
- const textY = y + padding + i * lineHeight;
28010
+ const textY = top + padding + i * lineHeight;
27916
28011
  ctx.fillText(line, textX, textY);
27917
28012
  }
27918
28013
  // Draw anchor point if selected
@@ -27956,6 +28051,9 @@ class TextTool extends DrawingToolBase {
27956
28051
  borderWidth: this._private__textOptions.borderWidth,
27957
28052
  textAlign: this._private__textOptions.textAlign,
27958
28053
  maxWidth: this._private__textOptions.maxWidth,
28054
+ anchor: this._private__textOptions.anchor,
28055
+ pointer: this._private__textOptions.pointer,
28056
+ borderRadius: this._private__textOptions.borderRadius,
27959
28057
  },
27960
28058
  extra: {
27961
28059
  text: this._private__textOptions.text,
@@ -30743,7 +30841,7 @@ const customSeriesDefaultOptions = {
30743
30841
  * Returns the current version as a string. For example `'1.0.0'`.
30744
30842
  */
30745
30843
  function version() {
30746
- return "2.3.12";
30844
+ return "2.3.13-dev+202609280001";
30747
30845
  }
30748
30846
 
30749
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 };