@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)
@@ -14674,6 +14674,8 @@ function shapeSize(shape, originalSize) {
14674
14674
  return size(originalSize, 0.7);
14675
14675
  case 'tag':
14676
14676
  return size(originalSize, 1);
14677
+ case 'xcross':
14678
+ return size(originalSize, 0.7);
14677
14679
  }
14678
14680
  }
14679
14681
  function calculateShapeHeight(barSpacing) {
@@ -14874,6 +14876,27 @@ function hitTestText(textX, textY, textWidth, textHeight, x, y) {
14874
14876
  y >= textY - halfHeight && y <= textY + halfHeight;
14875
14877
  }
14876
14878
 
14879
+ function drawXCross(ctx, coords, size) {
14880
+ const crossSize = shapeSize('xcross', size);
14881
+ const halfSize = ((crossSize - 1) / 2) * coords._internal_pixelRatio;
14882
+ ctx.save();
14883
+ ctx.strokeStyle = ctx.fillStyle;
14884
+ ctx.lineWidth = Math.max(1, Math.round(1.5 * coords._internal_pixelRatio));
14885
+ ctx.lineCap = 'round';
14886
+ ctx.beginPath();
14887
+ ctx.moveTo(coords._internal_x - halfSize, coords._internal_y - halfSize);
14888
+ ctx.lineTo(coords._internal_x + halfSize, coords._internal_y + halfSize);
14889
+ ctx.moveTo(coords._internal_x + halfSize, coords._internal_y - halfSize);
14890
+ ctx.lineTo(coords._internal_x - halfSize, coords._internal_y + halfSize);
14891
+ ctx.stroke();
14892
+ ctx.restore();
14893
+ }
14894
+ function hitTestXCross(centerX, centerY, size, x, y) {
14895
+ const crossSize = shapeSize('xcross', size);
14896
+ const tolerance = 2 + crossSize / 2;
14897
+ return Math.abs(x - centerX) <= tolerance && Math.abs(y - centerY) <= tolerance;
14898
+ }
14899
+
14877
14900
  class SeriesMarkersRenderer {
14878
14901
  constructor() {
14879
14902
  this._private__data = null;
@@ -15017,6 +15040,9 @@ function drawShape(item, ctx, coordinates) {
15017
15040
  case 'square':
15018
15041
  drawSquare(ctx, coordinates, item._internal_size);
15019
15042
  return;
15043
+ case 'xcross':
15044
+ drawXCross(ctx, coordinates, item._internal_size);
15045
+ return;
15020
15046
  case 'tag':
15021
15047
  // Handled by drawTagItem, which needs both pixel ratios and the text.
15022
15048
  return;
@@ -15045,6 +15071,8 @@ function hitTestShape(item, x, y) {
15045
15071
  return hitTestCircle(item._internal_x, item._internal_y, item._internal_size, x, y);
15046
15072
  case 'square':
15047
15073
  return hitTestSquare(item._internal_x, item._internal_y, item._internal_size, x, y);
15074
+ case 'xcross':
15075
+ return hitTestXCross(item._internal_x, item._internal_y, item._internal_size, x, y);
15048
15076
  case 'tag':
15049
15077
  return false;
15050
15078
  }
@@ -19702,6 +19730,12 @@ function setVolumeProfileData(indicator, data) {
19702
19730
  }
19703
19731
 
19704
19732
  const CLICK_TOLERANCE_PX = 4;
19733
+ /**
19734
+ * A fingertip never holds still: every tap travels further than a pointer
19735
+ * does, and judging it by the mouse's few pixels turned each one into a tiny
19736
+ * drag, so the tap never arrived.
19737
+ */
19738
+ const TOUCH_CLICK_TOLERANCE_PX = 12;
19705
19739
  /**
19706
19740
  * Single input owner for every trading line on a chart.
19707
19741
  *
@@ -19842,9 +19876,10 @@ class TradingLineController {
19842
19876
  this._private__releasePointer();
19843
19877
  this._private__pressedLine = null;
19844
19878
  this._private__pressOrigin = null;
19879
+ const tolerance = wasTouch ? TOUCH_CLICK_TOLERANCE_PX : CLICK_TOLERANCE_PX;
19845
19880
  const moved = origin !== null &&
19846
- (Math.abs(event.clientX - origin._internal_x) > CLICK_TOLERANCE_PX ||
19847
- Math.abs(event.clientY - origin._internal_y) > CLICK_TOLERANCE_PX);
19881
+ (Math.abs(event.clientX - origin._internal_x) > tolerance ||
19882
+ Math.abs(event.clientY - origin._internal_y) > tolerance);
19848
19883
  if (dragged !== null) {
19849
19884
  this._private__dragging = null;
19850
19885
  this._private__grabOffset = 0;
@@ -26117,17 +26152,19 @@ class RectangleTool extends DrawingToolBase {
26117
26152
  // Draw border
26118
26153
  const borderColor = this._private__rectOptions.borderColor;
26119
26154
  const borderWidth = this._private__isSelected ? this._private__rectOptions.borderWidth + 1 : this._private__rectOptions.borderWidth;
26120
- ctx.strokeStyle = borderColor;
26121
- ctx.lineWidth = borderWidth * horizontalPixelRatio;
26122
- // Set border style
26123
- if (this._private__rectOptions.borderStyle === 'dashed') {
26124
- ctx.setLineDash([10 * horizontalPixelRatio, 5 * horizontalPixelRatio]);
26125
- }
26126
- else if (this._private__rectOptions.borderStyle === 'dotted') {
26127
- ctx.setLineDash([2 * horizontalPixelRatio, 3 * horizontalPixelRatio]);
26155
+ if (borderWidth > 0) {
26156
+ ctx.strokeStyle = borderColor;
26157
+ ctx.lineWidth = borderWidth * horizontalPixelRatio;
26158
+ // Set border style
26159
+ if (this._private__rectOptions.borderStyle === 'dashed') {
26160
+ ctx.setLineDash([10 * horizontalPixelRatio, 5 * horizontalPixelRatio]);
26161
+ }
26162
+ else if (this._private__rectOptions.borderStyle === 'dotted') {
26163
+ ctx.setLineDash([2 * horizontalPixelRatio, 3 * horizontalPixelRatio]);
26164
+ }
26165
+ ctx.strokeRect(minX, minY, width, height);
26166
+ ctx.setLineDash([]);
26128
26167
  }
26129
- ctx.strokeRect(minX, minY, width, height);
26130
- ctx.setLineDash([]);
26131
26168
  // Draw corner handles if selected
26132
26169
  if ((this._private__isSelected || this._private__isHovered) && !this._private__isDrawing && !this.isLocked()) {
26133
26170
  this._private__drawCornerHandles(ctx, minX, minY, maxX, maxY, horizontalPixelRatio, borderColor);
@@ -26155,17 +26192,20 @@ class RectangleTool extends DrawingToolBase {
26155
26192
  }
26156
26193
  _private__drawLabel(ctx, minX, minY, maxX, maxY, horizontalPixelRatio, verticalPixelRatio, color) {
26157
26194
  const padding = 6 * horizontalPixelRatio;
26158
- const fontSize = 12 * horizontalPixelRatio;
26195
+ const fontSize = (this._private__rectOptions.labelFontSize ?? 12) * horizontalPixelRatio;
26159
26196
  ctx.font = `${fontSize}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
26160
26197
  const textMetrics = ctx.measureText(this._private__rectOptions.labelText);
26161
26198
  const textWidth = textMetrics.width;
26162
26199
  const textHeight = fontSize;
26200
+ const middleY = (minY + maxY) / 2 - textHeight / 2 - padding;
26201
+ // A box extended far past the pane keeps right-hand and centred labels on screen.
26202
+ const visibleMaxX = Math.min(maxX, ctx.canvas.width);
26163
26203
  // Calculate label position based on labelPosition option
26164
26204
  let labelX = minX + padding;
26165
26205
  let labelY = minY + padding;
26166
26206
  switch (this._private__rectOptions.labelPosition) {
26167
26207
  case 'top-right':
26168
- labelX = maxX - textWidth - padding * 2;
26208
+ labelX = visibleMaxX - textWidth - padding * 2;
26169
26209
  labelY = minY + padding;
26170
26210
  break;
26171
26211
  case 'bottom-left':
@@ -26173,19 +26213,27 @@ class RectangleTool extends DrawingToolBase {
26173
26213
  labelY = maxY - textHeight - padding * 2;
26174
26214
  break;
26175
26215
  case 'bottom-right':
26176
- labelX = maxX - textWidth - padding * 2;
26216
+ labelX = visibleMaxX - textWidth - padding * 2;
26177
26217
  labelY = maxY - textHeight - padding * 2;
26178
26218
  break;
26179
26219
  case 'center':
26180
- labelX = (minX + maxX) / 2 - textWidth / 2 - padding;
26181
- labelY = (minY + maxY) / 2 - textHeight / 2 - padding;
26220
+ labelX = (Math.max(minX, 0) + visibleMaxX) / 2 - textWidth / 2 - padding;
26221
+ labelY = middleY;
26222
+ break;
26223
+ case 'left':
26224
+ labelX = minX + padding;
26225
+ labelY = middleY;
26226
+ break;
26227
+ case 'right':
26228
+ labelX = visibleMaxX - textWidth - padding * 2;
26229
+ labelY = middleY;
26182
26230
  break;
26183
26231
  }
26184
26232
  // Draw background
26185
- ctx.fillStyle = color;
26233
+ ctx.fillStyle = this._private__rectOptions.labelBackgroundColor ?? color;
26186
26234
  ctx.fillRect(labelX, labelY, textWidth + padding * 2, textHeight + padding * 2);
26187
26235
  // Draw text
26188
- ctx.fillStyle = '#ffffff';
26236
+ ctx.fillStyle = this._private__rectOptions.labelColor ?? '#ffffff';
26189
26237
  ctx.textBaseline = 'top';
26190
26238
  ctx.fillText(this._private__rectOptions.labelText, labelX + padding, labelY + padding);
26191
26239
  }
@@ -26423,6 +26471,9 @@ class RectangleTool extends DrawingToolBase {
26423
26471
  showLabel: this._private__rectOptions.showLabel,
26424
26472
  labelText: this._private__rectOptions.labelText,
26425
26473
  labelPosition: this._private__rectOptions.labelPosition,
26474
+ labelColor: this._private__rectOptions.labelColor,
26475
+ labelBackgroundColor: this._private__rectOptions.labelBackgroundColor,
26476
+ labelFontSize: this._private__rectOptions.labelFontSize,
26426
26477
  },
26427
26478
  };
26428
26479
  }
@@ -28027,6 +28078,9 @@ class TextTool extends DrawingToolBase {
28027
28078
  borderWidth: 1,
28028
28079
  textAlign: 'left',
28029
28080
  maxWidth: 200,
28081
+ anchor: 'top-left',
28082
+ pointer: false,
28083
+ borderRadius: 0,
28030
28084
  ...options,
28031
28085
  };
28032
28086
  this._registerOptions(this._private__textOptions);
@@ -28178,18 +28232,59 @@ class TextTool extends DrawingToolBase {
28178
28232
  const py = this._series.priceToCoordinate(price) ?? 0;
28179
28233
  // Calculate text box dimensions
28180
28234
  const fontSize = this._private__textOptions.fontSize || 14;
28181
- const padding = this._private__textOptions.padding || 8;
28235
+ const padding = this._private__textOptions.padding ?? 8;
28182
28236
  const text = this._private__textOptions.text || '';
28183
28237
  // Rough estimate of text width (will be more accurate in canvas)
28184
28238
  const charWidth = fontSize * 0.6;
28185
28239
  const textWidth = Math.min(text.length * charWidth, this._private__textOptions.maxWidth || 200);
28186
- const textHeight = fontSize + padding * 2;
28187
- // Check if click is within text box bounds
28188
- const left = px;
28189
- const right = px + textWidth + padding * 2;
28190
- const top = py;
28191
- const bottom = py + textHeight;
28192
- return x >= left && x <= right && y >= top && y <= bottom;
28240
+ const boxWidth = textWidth + padding * 2;
28241
+ const boxHeight = fontSize + padding * 2;
28242
+ const tail = this._private__tailSize(boxHeight);
28243
+ const box = this._private__boxOrigin(px, py, boxWidth, boxHeight, tail);
28244
+ const left = box._internal_left - (this._private__textOptions.anchor === 'left' ? tail : 0);
28245
+ const right = box._internal_left + boxWidth + (this._private__textOptions.anchor === 'right' ? tail : 0);
28246
+ return x >= left && x <= right && y >= box._internal_top && y <= box._internal_top + boxHeight;
28247
+ }
28248
+ _private__tailSize(boxHeight) {
28249
+ const anchor = this._private__textOptions.anchor;
28250
+ return this._private__textOptions.pointer && (anchor === 'left' || anchor === 'right') ? Math.round(boxHeight * 0.35) : 0;
28251
+ }
28252
+ _private__boxOrigin(x, y, width, height, tail) {
28253
+ switch (this._private__textOptions.anchor) {
28254
+ case 'left':
28255
+ return { _internal_left: x + tail, _internal_top: y - height / 2 };
28256
+ case 'right':
28257
+ return { _internal_left: x - tail - width, _internal_top: y - height / 2 };
28258
+ case 'center':
28259
+ return { _internal_left: x - width / 2, _internal_top: y - height / 2 };
28260
+ default:
28261
+ return { _internal_left: x, _internal_top: y };
28262
+ }
28263
+ }
28264
+ // eslint-disable-next-line max-params
28265
+ _private__traceBox(ctx, left, top, width, height, tail, anchorX, anchorY, radius) {
28266
+ const r = Math.max(0, Math.min(radius, width / 2, height / 2));
28267
+ ctx.beginPath();
28268
+ ctx.moveTo(left + r, top);
28269
+ ctx.lineTo(left + width - r, top);
28270
+ ctx.arcTo(left + width, top, left + width, top + r, r);
28271
+ if (tail > 0 && this._private__textOptions.anchor === 'right') {
28272
+ ctx.lineTo(left + width, anchorY - tail);
28273
+ ctx.lineTo(anchorX, anchorY);
28274
+ ctx.lineTo(left + width, anchorY + tail);
28275
+ }
28276
+ ctx.lineTo(left + width, top + height - r);
28277
+ ctx.arcTo(left + width, top + height, left + width - r, top + height, r);
28278
+ ctx.lineTo(left + r, top + height);
28279
+ ctx.arcTo(left, top + height, left, top + height - r, r);
28280
+ if (tail > 0 && this._private__textOptions.anchor === 'left') {
28281
+ ctx.lineTo(left, anchorY + tail);
28282
+ ctx.lineTo(anchorX, anchorY);
28283
+ ctx.lineTo(left, anchorY - tail);
28284
+ }
28285
+ ctx.lineTo(left, top + r);
28286
+ ctx.arcTo(left, top, left + r, top, r);
28287
+ ctx.closePath();
28193
28288
  }
28194
28289
  hitTestEndpoint(x, y) {
28195
28290
  if (!this.isComplete())
@@ -28241,7 +28336,7 @@ class TextTool extends DrawingToolBase {
28241
28336
  const x = (coordinateFromTime(this._chart, this._series, time) ?? 0) * horizontalPixelRatio;
28242
28337
  const y = (this._series.priceToCoordinate(price) ?? 0) * verticalPixelRatio;
28243
28338
  const fontSize = (this._private__textOptions.fontSize || 14) * horizontalPixelRatio;
28244
- const padding = (this._private__textOptions.padding || 8) * horizontalPixelRatio;
28339
+ const padding = (this._private__textOptions.padding ?? 8) * horizontalPixelRatio;
28245
28340
  const maxWidth = (this._private__textOptions.maxWidth || 200) * horizontalPixelRatio;
28246
28341
  // Set font
28247
28342
  ctx.font = `${fontSize}px ${this._private__textOptions.fontFamily || 'Arial'}`;
@@ -28273,32 +28368,39 @@ class TextTool extends DrawingToolBase {
28273
28368
  const boxWidth = maxLineWidth + padding * 2;
28274
28369
  const lineHeight = fontSize * 1.2;
28275
28370
  const boxHeight = lines.length * lineHeight + padding * 2;
28371
+ const tail = this._private__tailSize(boxHeight);
28372
+ const { _internal_left: left, _internal_top: top } = this._private__boxOrigin(x, y, boxWidth, boxHeight, tail);
28373
+ const radius = (this._private__textOptions.borderRadius ?? 0) * horizontalPixelRatio;
28276
28374
  // Draw background
28277
- const bgOpacity = this._private__textOptions.backgroundOpacity || 0.8;
28375
+ const bgOpacity = this._private__textOptions.backgroundOpacity ?? 0.8;
28278
28376
  const bgColor = this._private__textOptions.backgroundColor || '#2962FF';
28279
- ctx.fillStyle = this._private__hexToRgba(bgColor, bgOpacity);
28280
- ctx.fillRect(x, y, boxWidth, boxHeight);
28377
+ if (bgOpacity > 0) {
28378
+ ctx.fillStyle = this._private__hexToRgba(bgColor, bgOpacity);
28379
+ this._private__traceBox(ctx, left, top, boxWidth, boxHeight, tail, x, y, radius);
28380
+ ctx.fill();
28381
+ }
28281
28382
  // Draw border
28282
28383
  if (this._private__isSelected || this._private__isHovered) {
28283
28384
  ctx.strokeStyle = this._private__textOptions.borderColor ?? '#FFFFFF';
28284
28385
  ctx.lineWidth = (this._private__textOptions.borderWidth || 1) * horizontalPixelRatio * (this._private__isSelected ? 2 : 1);
28285
- ctx.strokeRect(x, y, boxWidth, boxHeight);
28386
+ this._private__traceBox(ctx, left, top, boxWidth, boxHeight, tail, x, y, radius);
28387
+ ctx.stroke();
28286
28388
  }
28287
28389
  // Draw text
28288
28390
  ctx.fillStyle = this._private__textOptions.textColor || '#FFFFFF';
28289
28391
  for (let i = 0; i < lines.length; i++) {
28290
28392
  const line = lines[i];
28291
- let textX = x + padding;
28393
+ let textX = left + padding;
28292
28394
  // Handle text alignment
28293
28395
  if (this._private__textOptions.textAlign === 'center') {
28294
28396
  const metrics = ctx.measureText(line);
28295
- textX = x + (boxWidth - metrics.width) / 2;
28397
+ textX = left + (boxWidth - metrics.width) / 2;
28296
28398
  }
28297
28399
  else if (this._private__textOptions.textAlign === 'right') {
28298
28400
  const metrics = ctx.measureText(line);
28299
- textX = x + boxWidth - metrics.width - padding;
28401
+ textX = left + boxWidth - metrics.width - padding;
28300
28402
  }
28301
- const textY = y + padding + i * lineHeight;
28403
+ const textY = top + padding + i * lineHeight;
28302
28404
  ctx.fillText(line, textX, textY);
28303
28405
  }
28304
28406
  // Draw anchor point if selected
@@ -28342,6 +28444,9 @@ class TextTool extends DrawingToolBase {
28342
28444
  borderWidth: this._private__textOptions.borderWidth,
28343
28445
  textAlign: this._private__textOptions.textAlign,
28344
28446
  maxWidth: this._private__textOptions.maxWidth,
28447
+ anchor: this._private__textOptions.anchor,
28448
+ pointer: this._private__textOptions.pointer,
28449
+ borderRadius: this._private__textOptions.borderRadius,
28345
28450
  },
28346
28451
  extra: {
28347
28452
  text: this._private__textOptions.text,
@@ -31129,7 +31234,7 @@ const customSeriesDefaultOptions = {
31129
31234
  * Returns the current version as a string. For example `'1.0.0'`.
31130
31235
  */
31131
31236
  function version() {
31132
- return "2.3.11";
31237
+ return "2.3.13-dev+202609280001";
31133
31238
  }
31134
31239
 
31135
31240
  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 };