@pipsend/charts 2.2.1 → 2.3.0

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.2.1
3
+ * Pipsend Charts v2.3.0-dev+202609220108
4
4
  * Copyright (c) 2026 Pipsend
5
5
  * Licensed under MIT License
6
6
  * Built on TradingView Lightweight Charts™ (Apache 2.0)
@@ -14245,6 +14245,8 @@ function shapeSize(shape, originalSize) {
14245
14245
  return size(originalSize, 0.8);
14246
14246
  case 'square':
14247
14247
  return size(originalSize, 0.7);
14248
+ case 'tag':
14249
+ return size(originalSize, 1);
14248
14250
  }
14249
14251
  }
14250
14252
  function calculateShapeHeight(barSpacing) {
@@ -14354,6 +14356,85 @@ function hitTestSquare(centerX, centerY, size, x, y) {
14354
14356
  y >= top && y <= top + squareSize;
14355
14357
  }
14356
14358
 
14359
+ const TAIL_HALF_WIDTH_RATIO = 0.62;
14360
+ /**
14361
+ * Lays the pointer into the edge the path is already travelling along, so the
14362
+ * bubble and its tail are a single outline. Two subpaths would leave a stroked
14363
+ * seam where they meet.
14364
+ */
14365
+ // eslint-disable-next-line max-params
14366
+ function tailPath(ctx, xCenter, edgeY, tailHeight, halfWidth, up) {
14367
+ // A tip with a small radius reads as drawn rather than as an artefact of the
14368
+ // rasteriser, which a bare triangle does at these sizes.
14369
+ const tipRadius = Math.min(halfWidth / 3, tailHeight / 3);
14370
+ const sign = up ? -1 : 1;
14371
+ const tipY = edgeY + sign * tailHeight;
14372
+ const shoulderY = tipY - sign * tipRadius;
14373
+ // The top edge is travelled left to right, the bottom edge right to left.
14374
+ const entry = up ? -halfWidth : halfWidth;
14375
+ ctx.lineTo(xCenter + entry, edgeY);
14376
+ ctx.lineTo(xCenter + (up ? -tipRadius : tipRadius), shoulderY);
14377
+ ctx.quadraticCurveTo(xCenter, tipY, xCenter + (up ? tipRadius : -tipRadius), shoulderY);
14378
+ ctx.lineTo(xCenter - entry, edgeY);
14379
+ }
14380
+ /**
14381
+ * Draws a rounded speech-bubble tag with an optional pointer towards its anchor.
14382
+ */
14383
+ function drawTag(ctx, params) {
14384
+ const hpr = params._internal_horizontalPixelRatio;
14385
+ const vpr = params._internal_verticalPixelRatio;
14386
+ const left = Math.round((params._internal_x - params._internal_width / 2) * hpr);
14387
+ const right = Math.round((params._internal_x + params._internal_width / 2) * hpr);
14388
+ const top = Math.round((params._internal_centerY - params._internal_height / 2) * vpr);
14389
+ const bottom = Math.round((params._internal_centerY + params._internal_height / 2) * vpr);
14390
+ const xCenter = Math.round(params._internal_x * hpr);
14391
+ const radius = Math.min(params._internal_radius * hpr, (right - left) / 2, (bottom - top) / 2);
14392
+ const tailHeight = params._internal_tailHeight * vpr;
14393
+ const tailHalfWidth = Math.min(tailHeight * TAIL_HALF_WIDTH_RATIO, Math.max(0, (right - left) / 2 - radius));
14394
+ const hasTail = params._internal_tailDirection !== 'none' && tailHalfWidth > 0 && tailHeight > 0;
14395
+ ctx.save();
14396
+ ctx.beginPath();
14397
+ if (!hasTail) {
14398
+ drawRoundRect(ctx, left, top, right - left, bottom - top, [radius, radius, radius, radius]);
14399
+ }
14400
+ else {
14401
+ ctx.moveTo(left + radius, top);
14402
+ if (params._internal_tailDirection === 'up') {
14403
+ tailPath(ctx, xCenter, top, tailHeight, tailHalfWidth, true);
14404
+ }
14405
+ ctx.lineTo(right - radius, top);
14406
+ ctx.arcTo(right, top, right, top + radius, radius);
14407
+ ctx.lineTo(right, bottom - radius);
14408
+ ctx.arcTo(right, bottom, right - radius, bottom, radius);
14409
+ if (params._internal_tailDirection === 'down') {
14410
+ tailPath(ctx, xCenter, bottom, tailHeight, tailHalfWidth, false);
14411
+ }
14412
+ ctx.lineTo(left + radius, bottom);
14413
+ ctx.arcTo(left, bottom, left, bottom - radius, radius);
14414
+ ctx.lineTo(left, top + radius);
14415
+ ctx.arcTo(left, top, left + radius, top, radius);
14416
+ }
14417
+ ctx.closePath();
14418
+ ctx.fillStyle = params._internal_fillColor;
14419
+ ctx.fill();
14420
+ if (params._internal_borderColor !== undefined && params._internal_borderWidth > 0) {
14421
+ ctx.lineWidth = Math.max(1, Math.round(params._internal_borderWidth * hpr));
14422
+ ctx.strokeStyle = params._internal_borderColor;
14423
+ ctx.stroke();
14424
+ }
14425
+ ctx.restore();
14426
+ }
14427
+ function hitTestTag(centerX, centerY, tag, x, y) {
14428
+ if (tag._internal_width <= 0) {
14429
+ return false;
14430
+ }
14431
+ const halfHeight = tag._internal_height / 2;
14432
+ const top = tag._internal_tailDirection === 'up' ? centerY - halfHeight - tag._internal_tailHeight : centerY - halfHeight;
14433
+ const bottom = tag._internal_tailDirection === 'down' ? centerY + halfHeight + tag._internal_tailHeight : centerY + halfHeight;
14434
+ const left = centerX - tag._internal_width / 2;
14435
+ return x >= left && x <= left + tag._internal_width && y >= top && y <= bottom;
14436
+ }
14437
+
14357
14438
  function drawText(ctx, text, x, y, horizontalPixelRatio, verticalPixelRatio) {
14358
14439
  ctx.save();
14359
14440
  ctx.scale(horizontalPixelRatio, verticalPixelRatio);
@@ -14370,9 +14451,11 @@ class SeriesMarkersRenderer {
14370
14451
  constructor() {
14371
14452
  this._private__data = null;
14372
14453
  this._private__textWidthCache = new TextWidthCache();
14454
+ this._private__tagTextWidthCache = new TextWidthCache();
14373
14455
  this._private__fontSize = -1;
14374
14456
  this._private__fontFamily = '';
14375
14457
  this._private__font = '';
14458
+ this._private__tagFont = '';
14376
14459
  this._private__zOrder = 'normal';
14377
14460
  }
14378
14461
  _internal_setData(data) {
@@ -14383,7 +14466,11 @@ class SeriesMarkersRenderer {
14383
14466
  this._private__fontSize = fontSize;
14384
14467
  this._private__fontFamily = fontFamily;
14385
14468
  this._private__font = makeFont(fontSize, fontFamily);
14469
+ // Tags carry a label rather than an annotation, so they get the heavier
14470
+ // weight — and their own cache, since widths differ per font.
14471
+ this._private__tagFont = makeFont(fontSize, fontFamily, '600');
14386
14472
  this._private__textWidthCache._internal_reset();
14473
+ this._private__tagTextWidthCache._internal_reset();
14387
14474
  }
14388
14475
  this._private__zOrder = zOrder;
14389
14476
  }
@@ -14423,14 +14510,21 @@ class SeriesMarkersRenderer {
14423
14510
  return;
14424
14511
  }
14425
14512
  ctx.textBaseline = 'middle';
14426
- ctx.font = this._private__font;
14427
14513
  for (let index = this._private__data._internal_visibleRange.from; index < this._private__data._internal_visibleRange.to; index++) {
14428
14514
  const item = this._private__data._internal_items[index];
14515
+ const isTag = item._internal_tag !== undefined;
14516
+ ctx.font = isTag ? this._private__tagFont : this._private__font;
14429
14517
  if (item._internal_text !== undefined) {
14430
- item._internal_text._internal_width = this._private__textWidthCache._internal_measureText(ctx, item._internal_text._internal_content);
14518
+ const cache = isTag ? this._private__tagTextWidthCache : this._private__textWidthCache;
14519
+ item._internal_text._internal_width = cache._internal_measureText(ctx, item._internal_text._internal_content);
14431
14520
  item._internal_text._internal_height = this._private__fontSize;
14432
14521
  item._internal_text._internal_x = item._internal_x - item._internal_text._internal_width / 2;
14433
14522
  }
14523
+ if (item._internal_tag !== undefined) {
14524
+ const textWidth = item._internal_text !== undefined ? item._internal_text._internal_width : 0;
14525
+ item._internal_tag._internal_width = Math.max(textWidth + item._internal_tag._internal_paddingX * 2, item._internal_tag._internal_height);
14526
+ item._internal_tag._internal_left = item._internal_x - item._internal_tag._internal_width / 2;
14527
+ }
14434
14528
  drawItem(item, ctx, horizontalPixelRatio, verticalPixelRatio);
14435
14529
  }
14436
14530
  }
@@ -14445,12 +14539,40 @@ function bitmapShapeItemCoordinates(item, horizontalPixelRatio, verticalPixelRat
14445
14539
  };
14446
14540
  }
14447
14541
  function drawItem(item, ctx, horizontalPixelRatio, verticalPixelRatio) {
14542
+ if (item._internal_tag !== undefined) {
14543
+ drawTagItem(item, item._internal_tag, ctx, horizontalPixelRatio, verticalPixelRatio);
14544
+ return;
14545
+ }
14448
14546
  ctx.fillStyle = item._internal_color;
14449
14547
  if (item._internal_text !== undefined) {
14450
14548
  drawText(ctx, item._internal_text._internal_content, item._internal_text._internal_x, item._internal_text._internal_y, horizontalPixelRatio, verticalPixelRatio);
14451
14549
  }
14452
14550
  drawShape(item, ctx, bitmapShapeItemCoordinates(item, horizontalPixelRatio, verticalPixelRatio));
14453
14551
  }
14552
+ // eslint-disable-next-line max-params
14553
+ function drawTagItem(item, tag, ctx, horizontalPixelRatio, verticalPixelRatio) {
14554
+ if (item._internal_size === 0) {
14555
+ return;
14556
+ }
14557
+ drawTag(ctx, {
14558
+ _internal_x: item._internal_x,
14559
+ _internal_centerY: item._internal_y,
14560
+ _internal_width: tag._internal_width,
14561
+ _internal_height: tag._internal_height,
14562
+ _internal_tailHeight: tag._internal_tailHeight,
14563
+ _internal_tailDirection: tag._internal_tailDirection,
14564
+ _internal_radius: tag._internal_radius,
14565
+ _internal_fillColor: item._internal_color,
14566
+ _internal_borderColor: item._internal_borderColor,
14567
+ _internal_borderWidth: item._internal_borderWidth ?? 1,
14568
+ _internal_horizontalPixelRatio: horizontalPixelRatio,
14569
+ _internal_verticalPixelRatio: verticalPixelRatio,
14570
+ });
14571
+ if (item._internal_text !== undefined) {
14572
+ ctx.fillStyle = item._internal_textColor ?? '#FFFFFF';
14573
+ drawText(ctx, item._internal_text._internal_content, item._internal_text._internal_x, item._internal_text._internal_y, horizontalPixelRatio, verticalPixelRatio);
14574
+ }
14575
+ }
14454
14576
  function drawShape(item, ctx, coordinates) {
14455
14577
  if (item._internal_size === 0) {
14456
14578
  return;
@@ -14468,10 +14590,16 @@ function drawShape(item, ctx, coordinates) {
14468
14590
  case 'square':
14469
14591
  drawSquare(ctx, coordinates, item._internal_size);
14470
14592
  return;
14593
+ case 'tag':
14594
+ // Handled by drawTagItem, which needs both pixel ratios and the text.
14595
+ return;
14471
14596
  }
14472
14597
  ensureNever(item._internal_shape);
14473
14598
  }
14474
14599
  function hitTestItem(item, x, y) {
14600
+ if (item._internal_tag !== undefined) {
14601
+ return item._internal_size !== 0 && hitTestTag(item._internal_x, item._internal_y, item._internal_tag, x, y);
14602
+ }
14475
14603
  if (item._internal_text !== undefined && hitTestText(item._internal_text._internal_x, item._internal_text._internal_y, item._internal_text._internal_width, item._internal_text._internal_height, x, y)) {
14476
14604
  return true;
14477
14605
  }
@@ -14490,6 +14618,8 @@ function hitTestShape(item, x, y) {
14490
14618
  return hitTestCircle(item._internal_x, item._internal_y, item._internal_size, x, y);
14491
14619
  case 'square':
14492
14620
  return hitTestSquare(item._internal_x, item._internal_y, item._internal_size, x, y);
14621
+ case 'tag':
14622
+ return false;
14493
14623
  }
14494
14624
  }
14495
14625
 
@@ -14522,15 +14652,71 @@ function getPrice(seriesData, marker, isInverted) {
14522
14652
  }
14523
14653
  return;
14524
14654
  }
14655
+ /**
14656
+ * Lays out a `tag` marker: the bubble carries the text, so it is measured from
14657
+ * the font rather than from the bar spacing, and its pointer is aimed back at
14658
+ * the anchor price.
14659
+ */
14660
+ // eslint-disable-next-line max-params
14661
+ function fillTagSizeAndY(rendererItem, marker, anchorY, offsets, textHeight, shapeMargin, sizeMultiplier) {
14662
+ const height = Math.round((textHeight + 5 /* Constants.TagPaddingY */ * 2) * sizeMultiplier);
14663
+ const tailHeight = Math.round(7 /* Constants.TagTailHeight */ * sizeMultiplier);
14664
+ const ignoreOffset = isPriceMarker(marker.position);
14665
+ const halfHeight = height / 2;
14666
+ let tailDirection = 'none';
14667
+ let centerY = anchorY;
14668
+ switch (marker.position) {
14669
+ case 'aboveBar':
14670
+ case 'atPriceTop': {
14671
+ const offset = ignoreOffset ? 0 : offsets._internal_aboveBar;
14672
+ tailDirection = 'down';
14673
+ centerY = (anchorY - offset - tailHeight - halfHeight);
14674
+ if (!ignoreOffset) {
14675
+ offsets._internal_aboveBar += height + tailHeight + shapeMargin;
14676
+ }
14677
+ break;
14678
+ }
14679
+ case 'belowBar':
14680
+ case 'atPriceBottom': {
14681
+ const offset = ignoreOffset ? 0 : offsets._internal_belowBar;
14682
+ tailDirection = 'up';
14683
+ centerY = (anchorY + offset + tailHeight + halfHeight);
14684
+ if (!ignoreOffset) {
14685
+ offsets._internal_belowBar += height + tailHeight + shapeMargin;
14686
+ }
14687
+ break;
14688
+ }
14689
+ }
14690
+ const tag = {
14691
+ _internal_height: height,
14692
+ _internal_tailHeight: tailHeight,
14693
+ _internal_tailDirection: tailDirection,
14694
+ _internal_radius: marker.borderRadius ?? 6 /* Constants.TagRadius */,
14695
+ _internal_paddingX: 9 /* Constants.TagPaddingX */ * sizeMultiplier,
14696
+ _internal_left: 0,
14697
+ _internal_width: 0,
14698
+ };
14699
+ rendererItem._internal_size = height;
14700
+ rendererItem._internal_y = centerY;
14701
+ rendererItem._internal_tag = tag;
14702
+ if (rendererItem._internal_text !== undefined) {
14703
+ rendererItem._internal_text._internal_y = centerY;
14704
+ }
14705
+ }
14525
14706
  // eslint-disable-next-line max-params, complexity
14526
- function fillSizeAndY(rendererItem, marker, seriesData, offsets, textHeight, shapeMargin, series, chart) {
14527
- const price = getPrice(seriesData, marker, series.priceScale().options().invertScale);
14707
+ function fillSizeAndY(rendererItem, marker, seriesData, offsets, textHeight, shapeMargin, series, chart, invertScale) {
14708
+ const price = getPrice(seriesData, marker, invertScale);
14528
14709
  if (price === undefined) {
14529
14710
  return;
14530
14711
  }
14531
14712
  const ignoreOffset = isPriceMarker(marker.position);
14532
14713
  const timeScale = chart.timeScale();
14533
14714
  const sizeMultiplier = isNumber(marker.size) ? Math.max(marker.size, 0) : 1;
14715
+ if (marker.shape === 'tag') {
14716
+ const anchorY = ensureNotNull(series.priceToCoordinate(price));
14717
+ fillTagSizeAndY(rendererItem, marker, anchorY, offsets, textHeight, shapeMargin, sizeMultiplier);
14718
+ return;
14719
+ }
14534
14720
  const shapeSize = calculateShapeHeight(timeScale.options().barSpacing) * sizeMultiplier;
14535
14721
  const halfSize = shapeSize / 2;
14536
14722
  rendererItem._internal_size = shapeSize;
@@ -14637,6 +14823,10 @@ class SeriesMarkersPaneView {
14637
14823
  _internal_externalId: marker.id,
14638
14824
  _internal_internalId: marker._internal_internalId,
14639
14825
  _internal_text: undefined,
14826
+ _internal_textColor: marker.textColor,
14827
+ _internal_borderColor: marker.borderColor,
14828
+ _internal_borderWidth: marker.borderWidth,
14829
+ _internal_tag: undefined,
14640
14830
  }));
14641
14831
  this._private__dataInvalidated = false;
14642
14832
  }
@@ -14647,13 +14837,22 @@ class SeriesMarkersPaneView {
14647
14837
  return;
14648
14838
  }
14649
14839
  const visibleBarsRange = new RangeImpl(Math.floor(visibleBars.from), Math.ceil(visibleBars.to));
14650
- const firstValue = this._private__series.data()[0];
14840
+ const firstValue = this._private__series.dataByIndex(0, 1 /* MismatchDirection.NearestRight */);
14651
14841
  if (firstValue === null) {
14652
14842
  return;
14653
14843
  }
14654
14844
  if (this._private__data._internal_items.length === 0) {
14655
14845
  return;
14656
14846
  }
14847
+ // This runs inside the hit-test and paint loops, where a throw costs the
14848
+ // rest of the frame.
14849
+ let invertScale = false;
14850
+ try {
14851
+ invertScale = this._private__series.priceScale().options().invertScale;
14852
+ }
14853
+ catch (error) {
14854
+ invertScale = false;
14855
+ }
14657
14856
  let prevTimeIndex = NaN;
14658
14857
  const shapeMargin$1 = shapeMargin(timeScale.options().barSpacing);
14659
14858
  const offsets = {
@@ -14684,7 +14883,7 @@ class SeriesMarkersPaneView {
14684
14883
  if (dataAt === null) {
14685
14884
  continue;
14686
14885
  }
14687
- fillSizeAndY(rendererItem, marker, dataAt, offsets, layoutOptions.fontSize, shapeMargin$1, this._private__series, this._private__chart);
14886
+ fillSizeAndY(rendererItem, marker, dataAt, offsets, layoutOptions.fontSize, shapeMargin$1, this._private__series, this._private__chart, invertScale);
14688
14887
  }
14689
14888
  this._private__invalidated = false;
14690
14889
  }
@@ -14842,6 +15041,10 @@ class SeriesMarkersPrimitive {
14842
15041
  text: marker.text,
14843
15042
  size: marker.size,
14844
15043
  price: marker.price,
15044
+ textColor: marker.textColor,
15045
+ borderColor: marker.borderColor,
15046
+ borderWidth: marker.borderWidth,
15047
+ borderRadius: marker.borderRadius,
14845
15048
  _internal_originalTime: marker.time,
14846
15049
  };
14847
15050
  if (marker.position === 'atPriceTop' ||
@@ -19143,6 +19346,7 @@ class TradingLineController {
19143
19346
  constructor(chart, element) {
19144
19347
  this._private__lines = new Map();
19145
19348
  this._private__hoveredId = null;
19349
+ this._private__hoveredPart = null;
19146
19350
  this._private__dragging = null;
19147
19351
  this._private__pointerId = null;
19148
19352
  this._private__pressOrigin = null;
@@ -19200,8 +19404,12 @@ class TradingLineController {
19200
19404
  if (this._private__dragging !== null) {
19201
19405
  return;
19202
19406
  }
19203
- const hovered = this._private__lineFromHit(param.hoveredObjectId);
19407
+ const hit = this._private__splitHit(param.hoveredObjectId);
19408
+ const hovered = hit === null ? null : this._private__lines.get(hit._internal_id) ?? null;
19204
19409
  this._private__setHovered(hovered ? hovered.id() : null);
19410
+ // The part is updated after the id, and separately from it: moving from a
19411
+ // label onto its close button keeps the same line hovered.
19412
+ this._private__setHoveredPart(hovered, hovered === null ? null : hit?._internal_part ?? null);
19205
19413
  this._private__applyCursor();
19206
19414
  }
19207
19415
  _private__onPointerDown(event) {
@@ -19305,24 +19513,43 @@ class TradingLineController {
19305
19513
  if (line === null) {
19306
19514
  return null;
19307
19515
  }
19308
- // While the pointer is over the panes the engine gives pane coordinates.
19309
- // Once it leaves them — during a captured drag — fall back to the pane
19310
- // element, which still excludes the price axis.
19516
+ // The pointer event is the gesture's own position, so it is the source of
19517
+ // truth. The crosshair is only a mirror of it: it stops updating as soon
19518
+ // as the pointer leaves the pane canvas — over the price axis, past the
19519
+ // chart's edge — and a drag driven from it freezes there while the user
19520
+ // is still moving.
19521
+ const pane = this._private__chart.panes()[line.paneIndex()];
19522
+ const paneElement = pane ? pane.getHTMLElement() : null;
19523
+ if (paneElement) {
19524
+ return line.priceAt(event.clientY - paneElement.getBoundingClientRect().top);
19525
+ }
19311
19526
  if (this._private__point !== null && this._private__paneIndex === line.paneIndex()) {
19312
19527
  return line.priceAt(this._private__point._internal_y);
19313
19528
  }
19314
- const pane = this._private__chart.panes()[line.paneIndex()];
19315
- const paneElement = pane ? pane.getHTMLElement() : null;
19316
- if (!paneElement) {
19529
+ return null;
19530
+ }
19531
+ /**
19532
+ * Hit ids are either a bare line id or `id#part`, which is how a line with
19533
+ * several targets reports which one was hit.
19534
+ */
19535
+ _private__splitHit(externalId) {
19536
+ if (typeof externalId !== 'string' || externalId.length === 0) {
19317
19537
  return null;
19318
19538
  }
19319
- return line.priceAt(event.clientY - paneElement.getBoundingClientRect().top);
19539
+ const separator = externalId.indexOf('#');
19540
+ if (separator === -1) {
19541
+ return { _internal_id: externalId, _internal_part: null };
19542
+ }
19543
+ return { _internal_id: externalId.slice(0, separator), _internal_part: externalId.slice(separator + 1) };
19320
19544
  }
19321
- _private__lineFromHit(externalId) {
19322
- if (typeof externalId !== 'string') {
19323
- return null;
19545
+ _private__setHoveredPart(line, part) {
19546
+ if (this._private__hoveredPart === part) {
19547
+ return;
19548
+ }
19549
+ this._private__hoveredPart = part;
19550
+ if (line && line.setHoveredPart) {
19551
+ line.setHoveredPart(part);
19324
19552
  }
19325
- return this._private__lines.get(externalId) ?? null;
19326
19553
  }
19327
19554
  _private__setHovered(id) {
19328
19555
  if (this._private__hoveredId === id) {
@@ -19332,6 +19559,7 @@ class TradingLineController {
19332
19559
  this._private__lines.get(this._private__hoveredId)?.setHovered(false);
19333
19560
  }
19334
19561
  this._private__hoveredId = id;
19562
+ this._private__hoveredPart = null;
19335
19563
  if (id !== null) {
19336
19564
  this._private__lines.get(id)?.setHovered(true);
19337
19565
  }
@@ -19855,6 +20083,702 @@ function createInteractiveLineManager(chart, series) {
19855
20083
  return new InteractiveLineManager(chart, series);
19856
20084
  }
19857
20085
 
20086
+ const positionLineDefaultColors = {
20087
+ entry: '#2962FF',
20088
+ takeProfit: '#26A17B',
20089
+ stopLoss: '#D9A23B',
20090
+ };
20091
+ const positionLineThemeDefaults = {
20092
+ badgeTextColor: '#FFFFFF',
20093
+ borderRadius: 4,
20094
+ borderWidth: 1,
20095
+ paddingX: 8,
20096
+ paddingY: 6,
20097
+ backgroundOpacity: 1,
20098
+ };
20099
+ const positionLineLevels = ['takeProfit', 'entry', 'stopLoss'];
20100
+
20101
+ class PositionLineRenderer {
20102
+ constructor() {
20103
+ this._private__data = null;
20104
+ this._private__layouts = [];
20105
+ this._private__connectorX = 0;
20106
+ this._private__font = '';
20107
+ this._private__colorParser = new ColorParser([]);
20108
+ this._private__textWidthCache = new TextWidthCache(50);
20109
+ }
20110
+ _internal_setData(data) {
20111
+ this._private__data = data;
20112
+ }
20113
+ _internal_hitTest(x, y) {
20114
+ // The close button sits on top of the label, which sits on top of the
20115
+ // line, so the narrowest target is tested first.
20116
+ for (const layout of this._private__layouts) {
20117
+ if (layout._internal_closable && x >= layout._internal_closeLeft && x <= layout._internal_closeRight &&
20118
+ Math.abs(y - layout._internal_y) <= layout._internal_height / 2) {
20119
+ return { _internal_level: layout._internal_level, _internal_part: 'close' };
20120
+ }
20121
+ }
20122
+ for (const layout of this._private__layouts) {
20123
+ if (x >= layout._internal_pillLeft && x <= layout._internal_pillRight && Math.abs(y - layout._internal_y) <= layout._internal_height / 2) {
20124
+ return { _internal_level: layout._internal_level, _internal_part: 'body' };
20125
+ }
20126
+ }
20127
+ for (const layout of this._private__layouts) {
20128
+ if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */) {
20129
+ return { _internal_level: layout._internal_level, _internal_part: 'line' };
20130
+ }
20131
+ }
20132
+ return null;
20133
+ }
20134
+ draw(target) {
20135
+ target.useBitmapCoordinateSpace((scope) => this._private__drawImpl(scope));
20136
+ }
20137
+ _private__drawImpl(scope) {
20138
+ const data = this._private__data;
20139
+ this._private__layouts = [];
20140
+ if (data === null || data._internal_levels.length === 0) {
20141
+ return;
20142
+ }
20143
+ const { context: ctx, mediaSize } = scope;
20144
+ ctx.save();
20145
+ if (this._private__font !== data._internal_font) {
20146
+ this._private__font = data._internal_font;
20147
+ this._private__textWidthCache._internal_reset();
20148
+ }
20149
+ ctx.font = data._internal_font;
20150
+ ctx.textBaseline = 'middle';
20151
+ this._private__connectorX = Math.max(0, mediaSize.width - data._internal_rightOffset);
20152
+ const lineEnd = data._internal_connectorVisible ? this._private__connectorX : mediaSize.width;
20153
+ for (const level of data._internal_levels) {
20154
+ this._private__layouts.push(this._private__drawLevel(scope, data, level, lineEnd));
20155
+ }
20156
+ if (data._internal_connectorVisible && data._internal_levels.length > 1) {
20157
+ this._private__drawConnector(scope, data);
20158
+ }
20159
+ ctx.restore();
20160
+ }
20161
+ // eslint-disable-next-line max-params
20162
+ _private__drawLevel(scope, data, level, lineEnd) {
20163
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20164
+ const height = data._internal_fontSize + data._internal_paddingY * 2;
20165
+ const badgeWidth = level._internal_badge.length === 0
20166
+ ? 0
20167
+ : Math.max(this._private__textWidthCache._internal_measureText(ctx, level._internal_badge) + data._internal_paddingX * 2, height * 0.85 /* Constants.BadgeMinWidthRatio */);
20168
+ const labelWidth = this._private__textWidthCache._internal_measureText(ctx, level._internal_text) + data._internal_paddingX * 2;
20169
+ const closeWidth = level._internal_closable ? height : 0;
20170
+ const pillWidth = badgeWidth + labelWidth + closeWidth;
20171
+ const pillRight = Math.max(pillWidth, lineEnd - 8 /* Constants.LabelGap */);
20172
+ const pillLeft = pillRight - pillWidth;
20173
+ const top = level._internal_y - height / 2;
20174
+ this._private__drawLineSegments(scope, level, pillLeft, pillRight, lineEnd);
20175
+ this._private__drawPill(scope, data, level, { _internal_left: pillLeft, _internal_top: top, _internal_width: pillWidth, _internal_height: height });
20176
+ let cellLeft = pillLeft;
20177
+ if (badgeWidth > 0) {
20178
+ this._private__drawBadge(scope, data, level, { _internal_left: cellLeft, _internal_top: top, _internal_width: badgeWidth, _internal_height: height });
20179
+ cellLeft += badgeWidth;
20180
+ this._private__drawSeparator(ctx, level._internal_color, cellLeft, top, height, hpr, vpr);
20181
+ }
20182
+ ctx.save();
20183
+ ctx.scale(hpr, vpr);
20184
+ ctx.textAlign = 'center';
20185
+ ctx.fillStyle = data._internal_textColor ?? level._internal_color;
20186
+ ctx.fillText(level._internal_text, cellLeft + labelWidth / 2, level._internal_y);
20187
+ ctx.restore();
20188
+ cellLeft += labelWidth;
20189
+ if (level._internal_closable) {
20190
+ this._private__drawSeparator(ctx, level._internal_color, cellLeft, top, height, hpr, vpr);
20191
+ this._private__drawCloseButton(scope, data, level, { _internal_left: cellLeft, _internal_top: top, _internal_width: closeWidth, _internal_height: height });
20192
+ }
20193
+ return {
20194
+ _internal_level: level._internal_level,
20195
+ _internal_y: level._internal_y,
20196
+ _internal_height: height,
20197
+ _internal_pillLeft: pillLeft,
20198
+ _internal_pillRight: pillRight,
20199
+ _internal_closeLeft: cellLeft,
20200
+ _internal_closeRight: cellLeft + closeWidth,
20201
+ _internal_closable: level._internal_closable,
20202
+ };
20203
+ }
20204
+ // eslint-disable-next-line max-params
20205
+ _private__drawLineSegments(scope, level, pillLeft, pillRight, lineEnd) {
20206
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20207
+ const lineWidth = Math.max(1, Math.round(level._internal_lineWidth * vpr));
20208
+ const y = Math.round(level._internal_y * vpr) - Math.floor(lineWidth / 2);
20209
+ ctx.save();
20210
+ ctx.strokeStyle = level._internal_color;
20211
+ ctx.lineWidth = lineWidth;
20212
+ setLineStyle(ctx, level._internal_lineStyle);
20213
+ ctx.beginPath();
20214
+ ctx.moveTo(0, y);
20215
+ ctx.lineTo(Math.round(Math.max(0, pillLeft - 8 /* Constants.LabelGap */) * hpr), y);
20216
+ if (lineEnd > pillRight + 8 /* Constants.LabelGap */) {
20217
+ ctx.moveTo(Math.round((pillRight + 8 /* Constants.LabelGap */) * hpr), y);
20218
+ ctx.lineTo(Math.round(lineEnd * hpr), y);
20219
+ }
20220
+ ctx.stroke();
20221
+ ctx.restore();
20222
+ }
20223
+ // eslint-disable-next-line max-params
20224
+ _private__drawPill(scope, data, level, box) {
20225
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20226
+ const hovered = data._internal_hoveredLevel === level._internal_level;
20227
+ const borderWidth = Math.max(1, Math.round((hovered ? data._internal_borderWidth + 1 : data._internal_borderWidth) * hpr));
20228
+ ctx.save();
20229
+ ctx.setLineDash([]);
20230
+ bitmapRoundRect(ctx, box, data._internal_borderRadius, hpr, vpr);
20231
+ ctx.fillStyle = this._private__colorParser._internal_applyAlpha(data._internal_background, data._internal_backgroundOpacity);
20232
+ ctx.fill();
20233
+ ctx.lineWidth = borderWidth;
20234
+ ctx.strokeStyle = level._internal_color;
20235
+ ctx.stroke();
20236
+ ctx.restore();
20237
+ }
20238
+ // eslint-disable-next-line max-params
20239
+ _private__drawBadge(scope, data, level, box) {
20240
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20241
+ if (level._internal_badgeFilled) {
20242
+ // The badge shares the label's left corners, so its fill has to stop
20243
+ // short of the border instead of squaring it off.
20244
+ const inset = data._internal_borderWidth;
20245
+ ctx.save();
20246
+ bitmapRoundRect(ctx, { _internal_left: box._internal_left + inset, _internal_top: box._internal_top + inset, _internal_width: box._internal_width - inset, _internal_height: box._internal_height - inset * 2 }, Math.max(0, data._internal_borderRadius - inset), hpr, vpr, 'left');
20247
+ ctx.fillStyle = level._internal_color;
20248
+ ctx.fill();
20249
+ ctx.restore();
20250
+ }
20251
+ ctx.save();
20252
+ ctx.scale(hpr, vpr);
20253
+ ctx.textAlign = 'center';
20254
+ ctx.fillStyle = level._internal_badgeFilled ? data._internal_badgeTextColor : level._internal_color;
20255
+ ctx.fillText(level._internal_badge, box._internal_left + box._internal_width / 2, box._internal_top + box._internal_height / 2);
20256
+ ctx.restore();
20257
+ }
20258
+ // eslint-disable-next-line max-params
20259
+ _private__drawSeparator(ctx, color, x, top, height, hpr, vpr) {
20260
+ const width = Math.max(1, Math.floor(hpr));
20261
+ ctx.save();
20262
+ ctx.setLineDash([]);
20263
+ ctx.fillStyle = this._private__colorParser._internal_applyAlpha(color, 0.4 /* Constants.SeparatorAlpha */);
20264
+ ctx.fillRect(Math.round(x * hpr), Math.round(top * vpr), width, Math.round(height * vpr));
20265
+ ctx.restore();
20266
+ }
20267
+ // eslint-disable-next-line max-params
20268
+ _private__drawCloseButton(scope, data, level, box) {
20269
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20270
+ const hovered = data._internal_hoveredLevel === level._internal_level && data._internal_hoveredPart === 'close';
20271
+ if (hovered) {
20272
+ ctx.save();
20273
+ const inset = data._internal_borderWidth;
20274
+ bitmapRoundRect(ctx, { _internal_left: box._internal_left, _internal_top: box._internal_top + inset, _internal_width: box._internal_width - inset, _internal_height: box._internal_height - inset * 2 }, Math.max(0, data._internal_borderRadius - inset), hpr, vpr, 'right');
20275
+ ctx.fillStyle = this._private__colorParser._internal_applyAlpha(level._internal_color, 0.25);
20276
+ ctx.fill();
20277
+ ctx.restore();
20278
+ }
20279
+ const centerX = (box._internal_left + box._internal_width / 2) * hpr;
20280
+ const centerY = (box._internal_top + box._internal_height / 2) * vpr;
20281
+ const arm = (7 /* Constants.CloseGlyphSize */ / 2) * hpr;
20282
+ ctx.save();
20283
+ ctx.setLineDash([]);
20284
+ ctx.lineCap = 'round';
20285
+ ctx.lineWidth = Math.max(1, Math.round(1.4 * hpr));
20286
+ ctx.strokeStyle = level._internal_color;
20287
+ ctx.beginPath();
20288
+ ctx.moveTo(centerX - arm, centerY - arm);
20289
+ ctx.lineTo(centerX + arm, centerY + arm);
20290
+ ctx.moveTo(centerX + arm, centerY - arm);
20291
+ ctx.lineTo(centerX - arm, centerY + arm);
20292
+ ctx.stroke();
20293
+ ctx.restore();
20294
+ }
20295
+ _private__drawConnector(scope, data) {
20296
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20297
+ const entry = data._internal_levels.find((level) => level._internal_level === 'entry') ?? data._internal_levels[0];
20298
+ const ys = data._internal_levels.map((level) => level._internal_y);
20299
+ const x = Math.round(this._private__connectorX * hpr);
20300
+ ctx.save();
20301
+ ctx.setLineDash([]);
20302
+ ctx.strokeStyle = entry._internal_color;
20303
+ ctx.lineWidth = Math.max(1, Math.floor(hpr));
20304
+ ctx.beginPath();
20305
+ ctx.moveTo(x, Math.round(Math.min(...ys) * vpr));
20306
+ ctx.lineTo(x, Math.round(Math.max(...ys) * vpr));
20307
+ ctx.stroke();
20308
+ for (const level of data._internal_levels) {
20309
+ ctx.beginPath();
20310
+ ctx.arc(x, Math.round(level._internal_y * vpr), 4.5 /* Constants.HandleRadius */ * hpr, 0, 2 * Math.PI);
20311
+ ctx.fillStyle = level._internal_level === 'entry'
20312
+ ? entry._internal_color
20313
+ : this._private__colorParser._internal_applyAlpha(data._internal_background, data._internal_backgroundOpacity);
20314
+ ctx.fill();
20315
+ ctx.lineWidth = Math.max(1, Math.round(1.5 * hpr));
20316
+ ctx.strokeStyle = level._internal_color;
20317
+ ctx.stroke();
20318
+ }
20319
+ ctx.restore();
20320
+ }
20321
+ }
20322
+ // eslint-disable-next-line max-params
20323
+ function bitmapRoundRect(ctx, box, radius, hpr, vpr, side = 'all') {
20324
+ const left = Math.round(box._internal_left * hpr);
20325
+ const top = Math.round(box._internal_top * vpr);
20326
+ const width = Math.round(box._internal_width * hpr);
20327
+ const height = Math.round(box._internal_height * vpr);
20328
+ const r = Math.min(radius * hpr, width / 2, height / 2);
20329
+ const radii = side === 'left'
20330
+ ? [r, 0, 0, r]
20331
+ : side === 'right'
20332
+ ? [0, r, r, 0]
20333
+ : [r, r, r, r];
20334
+ drawRoundRect(ctx, left, top, width, height, radii);
20335
+ }
20336
+
20337
+ class PositionLinePaneView {
20338
+ constructor() {
20339
+ this._private__renderer = new PositionLineRenderer();
20340
+ this._private__data = null;
20341
+ }
20342
+ _internal_update(data) {
20343
+ this._private__data = data;
20344
+ }
20345
+ renderer() {
20346
+ if (this._private__data === null) {
20347
+ return null;
20348
+ }
20349
+ this._private__renderer._internal_setData(this._private__data);
20350
+ return this._private__renderer;
20351
+ }
20352
+ zOrder() {
20353
+ return 'top';
20354
+ }
20355
+ _internal_hitTest(x, y) {
20356
+ return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y);
20357
+ }
20358
+ }
20359
+
20360
+ class PositionLineAxisView {
20361
+ constructor(source) {
20362
+ this._private__source = source;
20363
+ }
20364
+ coordinate() {
20365
+ // A hidden label is pushed far off the axis so it cannot reserve a gap
20366
+ // between the labels that are shown.
20367
+ return this._private__label()?._internal_coordinate ?? -1e3;
20368
+ }
20369
+ text() {
20370
+ return this._private__label()?._internal_text ?? '';
20371
+ }
20372
+ textColor() {
20373
+ return this._private__label()?._internal_textColor ?? '#FFFFFF';
20374
+ }
20375
+ backColor() {
20376
+ return this._private__label()?._internal_color ?? '#000000';
20377
+ }
20378
+ visible() {
20379
+ return this._private__label() !== null;
20380
+ }
20381
+ _private__label() {
20382
+ return this._private__source();
20383
+ }
20384
+ }
20385
+
20386
+ let nextPositionId = 0;
20387
+ const DEFAULT_RIGHT_OFFSET = 56;
20388
+ /**
20389
+ * A group of trading levels — entry, take profit and stop loss — drawn as one
20390
+ * unit: a line per level, a label carrying size and P&L, and a connector that
20391
+ * ties the three together.
20392
+ *
20393
+ * Input is not handled here. Every trading line on a chart shares a single
20394
+ * TradingLineController, which is what guarantees that one gesture moves one
20395
+ * level, and that a position line and a plain draggable price line on the same
20396
+ * chart do not fight over the pointer.
20397
+ */
20398
+ class PositionLine {
20399
+ constructor(chart, series, options) {
20400
+ this._private__paneView = new PositionLinePaneView();
20401
+ this._private__colorParser = new ColorParser([]);
20402
+ this._private__attached = false;
20403
+ this._private__hoveredLevel = null;
20404
+ this._private__hoveredPart = null;
20405
+ this._private__dragLevel = null;
20406
+ this._private__priceBeforeDrag = null;
20407
+ this._private__chart = chart;
20408
+ this._private__series = series;
20409
+ this._private__id = `pipsend-position-line-${nextPositionId++}`;
20410
+ this._private__options = options;
20411
+ this._private__theme = { ...positionLineThemeDefaults, ...options.theme };
20412
+ this._private__paneViews = [this._private__paneView];
20413
+ this._private__axisViews = positionLineLevels.map((level) => new PositionLineAxisView(() => this._private__axisLabel(level)));
20414
+ this._private__series.attachPrimitive(this);
20415
+ acquireController(this._private__chart)?._internal_register(this);
20416
+ }
20417
+ // ---- ISeriesPrimitive ----
20418
+ attached(param) {
20419
+ this._private__requestUpdate = param.requestUpdate;
20420
+ this._private__attached = true;
20421
+ this.requestUpdate();
20422
+ }
20423
+ detached() {
20424
+ this._private__attached = false;
20425
+ this._private__requestUpdate = undefined;
20426
+ }
20427
+ paneViews() {
20428
+ return this._private__paneViews;
20429
+ }
20430
+ priceAxisViews() {
20431
+ return this._private__axisViews;
20432
+ }
20433
+ updateAllViews() {
20434
+ this._private__paneView._internal_update(this._private__buildRendererData());
20435
+ }
20436
+ hitTest(x, y) {
20437
+ const hit = this._private__paneView._internal_hitTest(x, y);
20438
+ if (hit === null) {
20439
+ return null;
20440
+ }
20441
+ const level = this._private__levelOptions(hit._internal_level);
20442
+ if (level === null) {
20443
+ return null;
20444
+ }
20445
+ return {
20446
+ externalId: `${this._private__id}#${hit._internal_level}:${hit._internal_part}`,
20447
+ zOrder: 'top',
20448
+ cursorStyle: hit._internal_part === 'close'
20449
+ ? 'pointer'
20450
+ : (level.draggable ?? true) ? 'ns-resize' : undefined,
20451
+ };
20452
+ }
20453
+ // ---- ControllableLine ----
20454
+ id() {
20455
+ return this._private__id;
20456
+ }
20457
+ paneIndex() {
20458
+ try {
20459
+ return this._private__series.getPane().paneIndex();
20460
+ }
20461
+ catch (error) {
20462
+ // The engine asserts the series belongs to a pane, and that lookup can
20463
+ // come back empty while panes are being rebuilt. The main pane is the
20464
+ // right guess and keeps the gesture alive instead of throwing mid-drag.
20465
+ return 0;
20466
+ }
20467
+ }
20468
+ setHoveredPart(part) {
20469
+ const [level, name] = part === null ? [null, null] : part.split(':');
20470
+ const nextLevel = level ?? null;
20471
+ const nextPart = name ?? null;
20472
+ if (this._private__hoveredLevel === nextLevel && this._private__hoveredPart === nextPart) {
20473
+ return;
20474
+ }
20475
+ this._private__hoveredLevel = nextLevel;
20476
+ this._private__hoveredPart = nextPart;
20477
+ this.requestUpdate();
20478
+ }
20479
+ setHovered(hovered) {
20480
+ if (!hovered) {
20481
+ this.setHoveredPart(null);
20482
+ }
20483
+ }
20484
+ isDraggable() {
20485
+ if (this._private__hoveredLevel === null || this._private__hoveredPart === 'close') {
20486
+ return false;
20487
+ }
20488
+ return this._private__levelOptions(this._private__hoveredLevel)?.draggable ?? true;
20489
+ }
20490
+ isClickable() {
20491
+ if (this._private__hoveredPart === 'close') {
20492
+ return true;
20493
+ }
20494
+ return this._private__options.onClick !== undefined;
20495
+ }
20496
+ priceAt(paneY) {
20497
+ const price = this._private__series.coordinateToPrice(paneY);
20498
+ return price === null ? null : price;
20499
+ }
20500
+ beginDrag() {
20501
+ this._private__dragLevel = this._private__hoveredLevel;
20502
+ if (this._private__dragLevel === null) {
20503
+ return;
20504
+ }
20505
+ const price = this._private__levelOptions(this._private__dragLevel)?.price ?? null;
20506
+ this._private__priceBeforeDrag = price;
20507
+ if (price !== null && this._private__options.onDragStart) {
20508
+ this._private__options.onDragStart(this._private__dragLevel, price);
20509
+ }
20510
+ }
20511
+ dragTo(price) {
20512
+ if (this._private__dragLevel === null) {
20513
+ return;
20514
+ }
20515
+ this._private__applyPrice(this._private__dragLevel, price);
20516
+ if (this._private__options.onDragMove) {
20517
+ this._private__options.onDragMove(this._private__dragLevel, price);
20518
+ }
20519
+ }
20520
+ commitDrag() {
20521
+ const level = this._private__dragLevel;
20522
+ this._private__dragLevel = null;
20523
+ this._private__priceBeforeDrag = null;
20524
+ if (level === null) {
20525
+ return;
20526
+ }
20527
+ const price = this._private__levelOptions(level)?.price;
20528
+ if (price !== undefined && this._private__options.onDragEnd) {
20529
+ this._private__options.onDragEnd(level, price);
20530
+ }
20531
+ }
20532
+ cancelDrag() {
20533
+ const level = this._private__dragLevel;
20534
+ const original = this._private__priceBeforeDrag;
20535
+ this._private__dragLevel = null;
20536
+ this._private__priceBeforeDrag = null;
20537
+ if (level === null) {
20538
+ return;
20539
+ }
20540
+ // Reported even when the price did not move, so a caller that pauses work
20541
+ // on `onDragStart` always gets the matching end of the gesture.
20542
+ const restored = original !== null && original !== this._private__levelOptions(level)?.price;
20543
+ if (restored) {
20544
+ this._private__applyPrice(level, original);
20545
+ if (this._private__options.onDragMove) {
20546
+ this._private__options.onDragMove(level, original);
20547
+ }
20548
+ }
20549
+ if (this._private__options.onDragCancel) {
20550
+ this._private__options.onDragCancel(level, this._private__levelOptions(level)?.price ?? 0);
20551
+ }
20552
+ }
20553
+ click() {
20554
+ const level = this._private__hoveredLevel;
20555
+ if (level === null) {
20556
+ return;
20557
+ }
20558
+ if (this._private__hoveredPart === 'close') {
20559
+ if (this._private__options.onClose) {
20560
+ this._private__options.onClose(level);
20561
+ }
20562
+ return;
20563
+ }
20564
+ const price = this._private__levelOptions(level)?.price;
20565
+ if (price !== undefined && this._private__options.onClick) {
20566
+ this._private__options.onClick(level, price);
20567
+ }
20568
+ }
20569
+ // ---- public API ----
20570
+ /**
20571
+ * Updates the group. Any subset of options can be passed; the levels given
20572
+ * are merged into the current ones, and a level set to `undefined` is
20573
+ * removed.
20574
+ */
20575
+ applyOptions(options) {
20576
+ // A level under an active gesture owns its price. Callers feeding the
20577
+ // group from a socket re-send the old price several times a second, and
20578
+ // letting that through would pull the level out from under the cursor.
20579
+ const dragged = this._private__dragLevel;
20580
+ const draggedPrice = dragged === null ? undefined : this._private__levelOptions(dragged)?.price;
20581
+ const merged = { ...this._private__options, ...options };
20582
+ merged.entry = { ...this._private__options.entry, ...options.entry };
20583
+ merged.takeProfit = mergeLevel(this._private__options.takeProfit, options, 'takeProfit');
20584
+ merged.stopLoss = mergeLevel(this._private__options.stopLoss, options, 'stopLoss');
20585
+ this._private__options = merged;
20586
+ if (dragged !== null && draggedPrice !== undefined) {
20587
+ const level = this._private__levelOptions(dragged);
20588
+ if (level !== null) {
20589
+ level.price = draggedPrice;
20590
+ }
20591
+ }
20592
+ if (options.theme) {
20593
+ // Merged onto what is already applied, so two partial theme updates do
20594
+ // not undo each other.
20595
+ this._private__theme = { ...this._private__theme, ...options.theme };
20596
+ }
20597
+ this.requestUpdate();
20598
+ }
20599
+ /**
20600
+ * Moves one level to a new price, recomputing its text when the level has a
20601
+ * `formatText`.
20602
+ *
20603
+ * Ignored for a level the user is currently dragging — the gesture owns the
20604
+ * price until it reports back through
20605
+ * {@link PositionLineOptions.onDragEnd} or
20606
+ * {@link PositionLineOptions.onDragCancel}.
20607
+ */
20608
+ setPrice(level, price) {
20609
+ if (this._private__dragLevel === level) {
20610
+ return;
20611
+ }
20612
+ this._private__applyPrice(level, price);
20613
+ }
20614
+ /**
20615
+ * Replaces one level's label text. Use this for text that changes on its own
20616
+ * — a ticking P&L on a fixed entry — rather than with the price.
20617
+ */
20618
+ setText(level, text) {
20619
+ const options = this._private__levelOptions(level);
20620
+ if (options === null) {
20621
+ return;
20622
+ }
20623
+ options.text = text;
20624
+ this.requestUpdate();
20625
+ }
20626
+ /**
20627
+ * The current price of each level that is present.
20628
+ */
20629
+ prices() {
20630
+ const result = {};
20631
+ for (const level of positionLineLevels) {
20632
+ const options = this._private__levelOptions(level);
20633
+ if (options !== null) {
20634
+ result[level] = options.price;
20635
+ }
20636
+ }
20637
+ return result;
20638
+ }
20639
+ options() {
20640
+ return this._private__options;
20641
+ }
20642
+ /**
20643
+ * Removes the group from the chart and releases its share of the input
20644
+ * controller.
20645
+ */
20646
+ remove() {
20647
+ releaseController(this._private__chart, this);
20648
+ this._private__series.detachPrimitive(this);
20649
+ }
20650
+ requestUpdate() {
20651
+ if (this._private__requestUpdate) {
20652
+ this._private__requestUpdate();
20653
+ }
20654
+ }
20655
+ /** Reads back the label the price axis should draw for a level. */
20656
+ _private__axisLabel(level) {
20657
+ const options = this._private__levelOptions(level);
20658
+ if (options === null || !isFinite(options.price) ||
20659
+ this._private__options.visible === false || options.axisLabelVisible === false) {
20660
+ return null;
20661
+ }
20662
+ const y = this._private__series.priceToCoordinate(options.price);
20663
+ if (y === null) {
20664
+ return null;
20665
+ }
20666
+ const color = options.color ?? positionLineDefaultColors[level];
20667
+ return {
20668
+ _internal_coordinate: y,
20669
+ _internal_text: this._private__series.priceFormatter().format(options.price),
20670
+ _internal_color: color,
20671
+ _internal_textColor: this._private__colorParser._internal_generateContrastColors(color)._internal_foreground,
20672
+ };
20673
+ }
20674
+ _private__levelOptions(level) {
20675
+ const options = level === 'entry' ? this._private__options.entry : this._private__options[level];
20676
+ return options ?? null;
20677
+ }
20678
+ _private__applyPrice(level, price) {
20679
+ const options = this._private__levelOptions(level);
20680
+ if (options === null) {
20681
+ return;
20682
+ }
20683
+ options.price = price;
20684
+ if (options.formatText) {
20685
+ options.text = options.formatText(price);
20686
+ }
20687
+ this.requestUpdate();
20688
+ }
20689
+ _private__buildRendererData() {
20690
+ if (!this._private__attached || this._private__options.visible === false) {
20691
+ return null;
20692
+ }
20693
+ const levels = [];
20694
+ for (const level of positionLineLevels) {
20695
+ const options = this._private__levelOptions(level);
20696
+ // A level added through a patch can be missing its price until the
20697
+ // caller supplies one; drawing it would put it at NaN.
20698
+ if (options === null || !isFinite(options.price)) {
20699
+ continue;
20700
+ }
20701
+ const y = this._private__series.priceToCoordinate(options.price);
20702
+ if (y === null) {
20703
+ continue;
20704
+ }
20705
+ const isEntry = level === 'entry';
20706
+ levels.push({
20707
+ _internal_level: level,
20708
+ _internal_y: y,
20709
+ _internal_color: options.color ?? positionLineDefaultColors[level],
20710
+ _internal_text: options.formatText ? options.formatText(options.price) : options.text ?? '',
20711
+ _internal_badge: options.badge ?? '',
20712
+ _internal_badgeFilled: options.badgeFilled ?? isEntry,
20713
+ _internal_lineWidth: options.lineWidth ?? 1,
20714
+ _internal_lineStyle: options.lineStyle ?? (isEntry ? 0 /* LineStyle.Solid */ : 2 /* LineStyle.Dashed */),
20715
+ _internal_closable: options.closable ?? true,
20716
+ _internal_draggable: options.draggable ?? true,
20717
+ });
20718
+ }
20719
+ if (levels.length === 0) {
20720
+ return null;
20721
+ }
20722
+ const layout = this._private__chart.options()['layout'];
20723
+ const fontSize = this._private__theme.fontSize ?? layout.fontSize;
20724
+ return {
20725
+ _internal_levels: levels,
20726
+ _internal_background: this._private__theme.background ?? resolveBackgroundColor(layout.background),
20727
+ _internal_textColor: this._private__theme.textColor,
20728
+ _internal_badgeTextColor: this._private__theme.badgeTextColor,
20729
+ _internal_borderRadius: this._private__theme.borderRadius,
20730
+ _internal_borderWidth: this._private__theme.borderWidth,
20731
+ _internal_paddingX: this._private__theme.paddingX,
20732
+ _internal_paddingY: this._private__theme.paddingY,
20733
+ _internal_backgroundOpacity: this._private__theme.backgroundOpacity,
20734
+ _internal_font: makeFont(fontSize, this._private__theme.fontFamily ?? layout.fontFamily),
20735
+ _internal_fontSize: fontSize,
20736
+ _internal_connectorVisible: this._private__options.connectorVisible !== false && levels.length > 1,
20737
+ _internal_rightOffset: this._private__options.rightOffset ?? DEFAULT_RIGHT_OFFSET,
20738
+ _internal_hoveredLevel: this._private__hoveredLevel,
20739
+ _internal_hoveredPart: this._private__hoveredPart,
20740
+ };
20741
+ }
20742
+ }
20743
+ function mergeLevel(current, options, key) {
20744
+ if (!(key in options)) {
20745
+ return current;
20746
+ }
20747
+ const next = options[key];
20748
+ return next === undefined ? undefined : { ...current, ...next };
20749
+ }
20750
+ /**
20751
+ * Reads the chart's own background so the label sits on a solid surface. The
20752
+ * parameter is typed as the public {@link Background}: the production build
20753
+ * renames the members of structural types it does not see in the public API,
20754
+ * and an anonymous `{ color: string }` here resolved to nothing at runtime.
20755
+ */
20756
+ function resolveBackgroundColor(background) {
20757
+ return background.type === "solid" /* ColorType.Solid */ ? background.color : background.topColor;
20758
+ }
20759
+ /**
20760
+ * Creates a position line group: entry, take profit and stop loss drawn as one
20761
+ * interactive unit.
20762
+ *
20763
+ * @param series - The series the levels are priced against.
20764
+ * @param chart - The chart the series belongs to.
20765
+ * @param options - The levels and their style.
20766
+ *
20767
+ * @example
20768
+ * ```js
20769
+ * const position = createPositionLine(candleSeries, chart, {
20770
+ * entry: { price: 4306.79, badge: '1', formatText: () => '+ 2.32 USD' },
20771
+ * takeProfit: { price: 4349.58, badge: '1', text: '+ 42.79 USD' },
20772
+ * stopLoss: { price: 4266.06, badge: '1', text: '- 40.73 USD' },
20773
+ * onClose: (level) => console.log('close', level),
20774
+ * onDragEnd: (level, price) => console.log(level, 'moved to', price),
20775
+ * });
20776
+ * ```
20777
+ */
20778
+ function createPositionLine(series, chart, options) {
20779
+ return new PositionLine(chart, series, options);
20780
+ }
20781
+
19858
20782
  /** Hit parts that drag the whole object rather than a single handle. */
19859
20783
  const WHOLE_OBJECT_PARTS = new Set([
19860
20784
  'line',
@@ -20734,13 +21658,6 @@ class TrendLineTool extends DrawingToolBase {
20734
21658
  // Clean up references
20735
21659
  this._private__primitive = null;
20736
21660
  this._private__paneView = null;
20737
- // Force chart update by triggering a resize
20738
- const chartElement = this._chart.chartElement?.();
20739
- if (chartElement) {
20740
- const currentWidth = chartElement.clientWidth;
20741
- const currentHeight = chartElement.clientHeight;
20742
- this._chart.resize(currentWidth, currentHeight);
20743
- }
20744
21661
  }
20745
21662
  if (this._private__trendOptions.onRemove) {
20746
21663
  this._private__trendOptions.onRemove();
@@ -21013,12 +21930,6 @@ class HorizontalLineTool extends DrawingToolBase {
21013
21930
  this._series.detachPrimitive(this._private__primitive);
21014
21931
  this._private__primitive = null;
21015
21932
  this._private__paneView = null;
21016
- const chartElement = this._chart.chartElement?.();
21017
- if (chartElement) {
21018
- const currentWidth = chartElement.clientWidth;
21019
- const currentHeight = chartElement.clientHeight;
21020
- this._chart.resize(currentWidth, currentHeight);
21021
- }
21022
21933
  }
21023
21934
  if (this._private__hLineOptions.onRemove) {
21024
21935
  this._private__hLineOptions.onRemove();
@@ -22857,12 +23768,6 @@ class VerticalLineTool extends DrawingToolBase {
22857
23768
  this._series.detachPrimitive(this._private__primitive);
22858
23769
  this._private__primitive = null;
22859
23770
  this._private__paneView = null;
22860
- const chartElement = this._chart.chartElement?.();
22861
- if (chartElement) {
22862
- const currentWidth = chartElement.clientWidth;
22863
- const currentHeight = chartElement.clientHeight;
22864
- this._chart.resize(currentWidth, currentHeight);
22865
- }
22866
23771
  }
22867
23772
  if (this._private__vLineOptions.onRemove) {
22868
23773
  this._private__vLineOptions.onRemove();
@@ -23515,12 +24420,6 @@ class FibonacciTool extends DrawingToolBase {
23515
24420
  this._series.detachPrimitive(this._private__primitive);
23516
24421
  this._private__primitive = null;
23517
24422
  this._private__paneView = null;
23518
- const chartElement = this._chart.chartElement?.();
23519
- if (chartElement) {
23520
- const currentWidth = chartElement.clientWidth;
23521
- const currentHeight = chartElement.clientHeight;
23522
- this._chart.resize(currentWidth, currentHeight);
23523
- }
23524
24423
  }
23525
24424
  if (this._private__drawingManager) {
23526
24425
  this._private__drawingManager._internal_destroy();
@@ -23536,12 +24435,6 @@ class FibonacciTool extends DrawingToolBase {
23536
24435
  this._series.detachPrimitive(this._private__primitive);
23537
24436
  this._private__primitive = null;
23538
24437
  this._private__paneView = null;
23539
- const chartElement = this._chart.chartElement?.();
23540
- if (chartElement) {
23541
- const currentWidth = chartElement.clientWidth;
23542
- const currentHeight = chartElement.clientHeight;
23543
- this._chart.resize(currentWidth, currentHeight);
23544
- }
23545
24438
  }
23546
24439
  if (this._private__fibOptions.onRemove) {
23547
24440
  this._private__fibOptions.onRemove();
@@ -23969,12 +24862,6 @@ class FibonacciExtensionTool extends DrawingToolBase {
23969
24862
  this._series.detachPrimitive(this._private__primitive);
23970
24863
  this._private__primitive = null;
23971
24864
  this._private__paneView = null;
23972
- const chartElement = this._chart.chartElement?.();
23973
- if (chartElement) {
23974
- const currentWidth = chartElement.clientWidth;
23975
- const currentHeight = chartElement.clientHeight;
23976
- this._chart.resize(currentWidth, currentHeight);
23977
- }
23978
24865
  }
23979
24866
  }
23980
24867
  }
@@ -24416,12 +25303,6 @@ class FibonacciFanTool extends DrawingToolBase {
24416
25303
  this._series.detachPrimitive(this._private__primitive);
24417
25304
  this._private__primitive = null;
24418
25305
  this._private__paneView = null;
24419
- const chartElement = this._chart.chartElement?.();
24420
- if (chartElement) {
24421
- const currentWidth = chartElement.clientWidth;
24422
- const currentHeight = chartElement.clientHeight;
24423
- this._chart.resize(currentWidth, currentHeight);
24424
- }
24425
25306
  }
24426
25307
  if (this._private__fanOptions.onRemove) {
24427
25308
  this._private__fanOptions.onRemove();
@@ -24962,12 +25843,6 @@ class RectangleTool extends DrawingToolBase {
24962
25843
  this._series.detachPrimitive(this._private__primitive);
24963
25844
  this._private__primitive = null;
24964
25845
  this._private__paneView = null;
24965
- const chartElement = this._chart.chartElement?.();
24966
- if (chartElement) {
24967
- const currentWidth = chartElement.clientWidth;
24968
- const currentHeight = chartElement.clientHeight;
24969
- this._chart.resize(currentWidth, currentHeight);
24970
- }
24971
25846
  }
24972
25847
  if (this._private__rectOptions.onRemove) {
24973
25848
  this._private__rectOptions.onRemove();
@@ -25428,12 +26303,6 @@ class CircleTool extends DrawingToolBase {
25428
26303
  this._series.detachPrimitive(this._private__primitive);
25429
26304
  this._private__primitive = null;
25430
26305
  this._private__paneView = null;
25431
- const chartElement = this._chart.chartElement?.();
25432
- if (chartElement) {
25433
- const currentWidth = chartElement.clientWidth;
25434
- const currentHeight = chartElement.clientHeight;
25435
- this._chart.resize(currentWidth, currentHeight);
25436
- }
25437
26306
  }
25438
26307
  if (this._private__circleOptions.onRemove) {
25439
26308
  this._private__circleOptions.onRemove();
@@ -25983,12 +26852,6 @@ class ArrowTool extends DrawingToolBase {
25983
26852
  this._series.detachPrimitive(this._private__primitive);
25984
26853
  this._private__primitive = null;
25985
26854
  this._private__paneView = null;
25986
- const chartElement = this._chart.chartElement?.();
25987
- if (chartElement) {
25988
- const currentWidth = chartElement.clientWidth;
25989
- const currentHeight = chartElement.clientHeight;
25990
- this._chart.resize(currentWidth, currentHeight);
25991
- }
25992
26855
  }
25993
26856
  if (this._private__arrowOptions.onRemove) {
25994
26857
  this._private__arrowOptions.onRemove();
@@ -26849,12 +27712,6 @@ class TextTool extends DrawingToolBase {
26849
27712
  this._series.detachPrimitive(this._private__primitive);
26850
27713
  this._private__primitive = null;
26851
27714
  this._private__paneView = null;
26852
- const chartElement = this._chart.chartElement?.();
26853
- if (chartElement) {
26854
- const currentWidth = chartElement.clientWidth;
26855
- const currentHeight = chartElement.clientHeight;
26856
- this._chart.resize(currentWidth, currentHeight);
26857
- }
26858
27715
  }
26859
27716
  if (this._private__textOptions.onRemove) {
26860
27717
  this._private__textOptions.onRemove();
@@ -27437,12 +28294,6 @@ class RulerTool extends DrawingToolBase {
27437
28294
  this._series.detachPrimitive(this._private__primitive);
27438
28295
  this._private__primitive = null;
27439
28296
  this._private__paneView = null;
27440
- const chartElement = this._chart.chartElement?.();
27441
- if (chartElement) {
27442
- const currentWidth = chartElement.clientWidth;
27443
- const currentHeight = chartElement.clientHeight;
27444
- this._chart.resize(currentWidth, currentHeight);
27445
- }
27446
28297
  }
27447
28298
  if (this._private__drawingManager) {
27448
28299
  this._private__drawingManager._internal_destroy();
@@ -28298,12 +29149,6 @@ class PositionTool extends DrawingToolBase {
28298
29149
  this._series.detachPrimitive(this._private__primitive);
28299
29150
  this._private__primitive = null;
28300
29151
  this._private__paneView = null;
28301
- const chartElement = this._chart.chartElement?.();
28302
- if (chartElement) {
28303
- const currentWidth = chartElement.clientWidth;
28304
- const currentHeight = chartElement.clientHeight;
28305
- this._chart.resize(currentWidth, currentHeight);
28306
- }
28307
29152
  }
28308
29153
  if (this._private__positionOptions.onRemove) {
28309
29154
  this._private__positionOptions.onRemove();
@@ -28646,12 +29491,6 @@ class GanttTool extends DrawingToolBase {
28646
29491
  this._series.detachPrimitive(this._private__primitive);
28647
29492
  this._private__primitive = null;
28648
29493
  this._private__paneView = null;
28649
- const chartElement = this._chart.chartElement?.();
28650
- if (chartElement) {
28651
- const currentWidth = chartElement.clientWidth;
28652
- const currentHeight = chartElement.clientHeight;
28653
- this._chart.resize(currentWidth, currentHeight);
28654
- }
28655
29494
  }
28656
29495
  if (this._private__ganttOptions.onRemove) {
28657
29496
  this._private__ganttOptions.onRemove();
@@ -28662,6 +29501,8 @@ function createGanttTool(context, options) {
28662
29501
  return new GanttTool(context, options);
28663
29502
  }
28664
29503
 
29504
+ /** Undo steps kept, each a full snapshot of every drawing. */
29505
+ const UNDO_HISTORY_LIMIT = 100;
28665
29506
  /**
28666
29507
  * Central manager for all drawing tools - TradingView style
28667
29508
  * Handles multiple tools, selection, deletion, and keyboard shortcuts
@@ -28684,6 +29525,8 @@ class DrawingToolsManager {
28684
29525
  this._private__pointerDownHandler = null;
28685
29526
  this._private__pointerUpHandler = null;
28686
29527
  this._private__pointerCancelHandler = null;
29528
+ this._private__lostCaptureHandler = null;
29529
+ this._private__windowPointerUpHandler = null;
28687
29530
  this._private__pointerId = null;
28688
29531
  /** A press that grabbed a tool already selected it; its click must not undo that. */
28689
29532
  this._private__gestureHandled = false;
@@ -28849,6 +29692,9 @@ class DrawingToolsManager {
28849
29692
  return;
28850
29693
  }
28851
29694
  this._private__past.push(this._private__committed);
29695
+ if (this._private__past.length > UNDO_HISTORY_LIMIT) {
29696
+ this._private__past.shift();
29697
+ }
28852
29698
  this._private__future = [];
28853
29699
  this._private__committed = this.serializeAll();
28854
29700
  }
@@ -29228,8 +30074,12 @@ class DrawingToolsManager {
29228
30074
  this._private__completionCheck = null;
29229
30075
  }
29230
30076
  this._private__drawingCompleted._internal_destroy();
30077
+ this._private__selectionChanged._internal_destroy();
29231
30078
  this.clearAll();
29232
30079
  this._private__detachEventHandlers();
30080
+ this._private__past = [];
30081
+ this._private__future = [];
30082
+ this._private__committed = [];
29233
30083
  }
29234
30084
  _private__attachEventHandlers() {
29235
30085
  // Click handler for selection
@@ -29249,9 +30099,15 @@ class DrawingToolsManager {
29249
30099
  this._private__pointerDownHandler = (event) => this._private__handlePointerDown(event);
29250
30100
  this._private__pointerUpHandler = (event) => this._private__handlePointerUp(event);
29251
30101
  this._private__pointerCancelHandler = (event) => this._private__handlePointerUp(event);
30102
+ this._private__lostCaptureHandler = (event) => this._private__handleLostPointerCapture(event);
29252
30103
  chartElement.addEventListener('pointerdown', this._private__pointerDownHandler);
29253
30104
  chartElement.addEventListener('pointerup', this._private__pointerUpHandler);
29254
30105
  chartElement.addEventListener('pointercancel', this._private__pointerCancelHandler);
30106
+ chartElement.addEventListener('lostpointercapture', this._private__lostCaptureHandler);
30107
+ }
30108
+ if (isRunningOnClientSide) {
30109
+ this._private__windowPointerUpHandler = (event) => this._private__handlePointerUp(event);
30110
+ window.addEventListener('pointerup', this._private__windowPointerUpHandler);
29255
30111
  }
29256
30112
  // Keyboard handler for shortcuts
29257
30113
  if (this._private__options.enableKeyboardShortcuts) {
@@ -29284,6 +30140,14 @@ class DrawingToolsManager {
29284
30140
  chartElement.removeEventListener('pointercancel', this._private__pointerCancelHandler);
29285
30141
  this._private__pointerCancelHandler = null;
29286
30142
  }
30143
+ if (this._private__lostCaptureHandler) {
30144
+ chartElement.removeEventListener('lostpointercapture', this._private__lostCaptureHandler);
30145
+ this._private__lostCaptureHandler = null;
30146
+ }
30147
+ }
30148
+ if (this._private__windowPointerUpHandler) {
30149
+ window.removeEventListener('pointerup', this._private__windowPointerUpHandler);
30150
+ this._private__windowPointerUpHandler = null;
29287
30151
  }
29288
30152
  if (this._private__keyboardHandler) {
29289
30153
  document.removeEventListener('keydown', this._private__keyboardHandler);
@@ -29409,7 +30273,12 @@ class DrawingToolsManager {
29409
30273
  this._private__gestureHandled = true;
29410
30274
  this._private__draggedToolId = toolId;
29411
30275
  this._private__pointerId = event.pointerId;
29412
- chartElement.setPointerCapture(event.pointerId);
30276
+ try {
30277
+ chartElement.setPointerCapture(event.pointerId);
30278
+ }
30279
+ catch (error) {
30280
+ this._private__pointerId = null;
30281
+ }
29413
30282
  tool.startDrag(endpoint, anchor);
29414
30283
  // Panning is stopped by disabling it for the gesture, not by preventing
29415
30284
  // the event: preventDefault on pointerdown suppresses the compatibility
@@ -29423,17 +30292,32 @@ class DrawingToolsManager {
29423
30292
  if (event && this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
29424
30293
  return;
29425
30294
  }
29426
- const tool = this._private__tools.get(this._private__draggedToolId);
29427
- if (tool) {
29428
- tool.stopDrag();
29429
- }
29430
- this._private__releasePointer();
29431
- this._private__enableChartInteractions();
30295
+ const draggedToolId = this._private__draggedToolId;
30296
+ // Cleared first: anything below can throw, and a half-finished release
30297
+ // would leave the manager dragging forever.
29432
30298
  this._private__isDragging = false;
29433
30299
  this._private__draggedToolId = null;
30300
+ try {
30301
+ const tool = this._private__tools.get(draggedToolId);
30302
+ if (tool) {
30303
+ tool.stopDrag();
30304
+ }
30305
+ }
30306
+ finally {
30307
+ this._private__releasePointer();
30308
+ this._private__enableChartInteractions();
30309
+ }
29434
30310
  // A finished drag is one step, not one per frame
29435
30311
  this.recordChange();
29436
30312
  }
30313
+ /** Ends the drag when capture is lost without a pointerup ever arriving. */
30314
+ _private__handleLostPointerCapture(event) {
30315
+ if (this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
30316
+ return;
30317
+ }
30318
+ this._private__pointerId = null;
30319
+ this._private__handlePointerUp();
30320
+ }
29437
30321
  /**
29438
30322
  * Pane element of a tool's series. The engine asserts the series has a pane,
29439
30323
  * so the lookup is guarded.
@@ -29484,9 +30368,11 @@ class DrawingToolsManager {
29484
30368
  return;
29485
30369
  }
29486
30370
  const options = this._private__chart.options();
30371
+ // `options()` returns the live object and `applyOptions` merges into it
30372
+ // in place, so a snapshot by reference restores all-false.
29487
30373
  this._private__interactionsBeforeDrag = {
29488
- _internal_handleScroll: options.handleScroll,
29489
- _internal_handleScale: options.handleScale,
30374
+ _internal_handleScroll: clone(options.handleScroll),
30375
+ _internal_handleScale: clone(options.handleScale),
29490
30376
  };
29491
30377
  this._private__chart.applyOptions({
29492
30378
  handleScroll: false,
@@ -29572,7 +30458,7 @@ const customSeriesDefaultOptions = {
29572
30458
  * Returns the current version as a string. For example `'1.0.0'`.
29573
30459
  */
29574
30460
  function version() {
29575
- return "2.2.1";
30461
+ return "2.3.0-dev+202609220108";
29576
30462
  }
29577
30463
 
29578
- 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, 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, createPositionMarkers, createPositionTool, createRectangleTool, createRulerTool, createSeriesMarkers, createTextTool, createTextWatermark, createTradingLine, createTradingSessionsIndicator, createTrendLineTool, createUpDownMarkers, createVerticalLineTool, createVolumeProfileIndicator, createYieldCurveChart, customSeriesDefaultOptions, defaultHorzScaleBehavior, getPipConfig, hideSeriesPaint, isBusinessDay, isUTCTimestamp, setSeriesVolumes, setVolumeProfileData, timeFromCoordinate, version };
30464
+ 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 };