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