@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)
@@ -14638,6 +14638,8 @@ function shapeSize(shape, originalSize) {
14638
14638
  return size(originalSize, 0.8);
14639
14639
  case 'square':
14640
14640
  return size(originalSize, 0.7);
14641
+ case 'tag':
14642
+ return size(originalSize, 1);
14641
14643
  }
14642
14644
  }
14643
14645
  function calculateShapeHeight(barSpacing) {
@@ -14747,6 +14749,85 @@ function hitTestSquare(centerX, centerY, size, x, y) {
14747
14749
  y >= top && y <= top + squareSize;
14748
14750
  }
14749
14751
 
14752
+ const TAIL_HALF_WIDTH_RATIO = 0.62;
14753
+ /**
14754
+ * Lays the pointer into the edge the path is already travelling along, so the
14755
+ * bubble and its tail are a single outline. Two subpaths would leave a stroked
14756
+ * seam where they meet.
14757
+ */
14758
+ // eslint-disable-next-line max-params
14759
+ function tailPath(ctx, xCenter, edgeY, tailHeight, halfWidth, up) {
14760
+ // A tip with a small radius reads as drawn rather than as an artefact of the
14761
+ // rasteriser, which a bare triangle does at these sizes.
14762
+ const tipRadius = Math.min(halfWidth / 3, tailHeight / 3);
14763
+ const sign = up ? -1 : 1;
14764
+ const tipY = edgeY + sign * tailHeight;
14765
+ const shoulderY = tipY - sign * tipRadius;
14766
+ // The top edge is travelled left to right, the bottom edge right to left.
14767
+ const entry = up ? -halfWidth : halfWidth;
14768
+ ctx.lineTo(xCenter + entry, edgeY);
14769
+ ctx.lineTo(xCenter + (up ? -tipRadius : tipRadius), shoulderY);
14770
+ ctx.quadraticCurveTo(xCenter, tipY, xCenter + (up ? tipRadius : -tipRadius), shoulderY);
14771
+ ctx.lineTo(xCenter - entry, edgeY);
14772
+ }
14773
+ /**
14774
+ * Draws a rounded speech-bubble tag with an optional pointer towards its anchor.
14775
+ */
14776
+ function drawTag(ctx, params) {
14777
+ const hpr = params._internal_horizontalPixelRatio;
14778
+ const vpr = params._internal_verticalPixelRatio;
14779
+ const left = Math.round((params._internal_x - params._internal_width / 2) * hpr);
14780
+ const right = Math.round((params._internal_x + params._internal_width / 2) * hpr);
14781
+ const top = Math.round((params._internal_centerY - params._internal_height / 2) * vpr);
14782
+ const bottom = Math.round((params._internal_centerY + params._internal_height / 2) * vpr);
14783
+ const xCenter = Math.round(params._internal_x * hpr);
14784
+ const radius = Math.min(params._internal_radius * hpr, (right - left) / 2, (bottom - top) / 2);
14785
+ const tailHeight = params._internal_tailHeight * vpr;
14786
+ const tailHalfWidth = Math.min(tailHeight * TAIL_HALF_WIDTH_RATIO, Math.max(0, (right - left) / 2 - radius));
14787
+ const hasTail = params._internal_tailDirection !== 'none' && tailHalfWidth > 0 && tailHeight > 0;
14788
+ ctx.save();
14789
+ ctx.beginPath();
14790
+ if (!hasTail) {
14791
+ drawRoundRect(ctx, left, top, right - left, bottom - top, [radius, radius, radius, radius]);
14792
+ }
14793
+ else {
14794
+ ctx.moveTo(left + radius, top);
14795
+ if (params._internal_tailDirection === 'up') {
14796
+ tailPath(ctx, xCenter, top, tailHeight, tailHalfWidth, true);
14797
+ }
14798
+ ctx.lineTo(right - radius, top);
14799
+ ctx.arcTo(right, top, right, top + radius, radius);
14800
+ ctx.lineTo(right, bottom - radius);
14801
+ ctx.arcTo(right, bottom, right - radius, bottom, radius);
14802
+ if (params._internal_tailDirection === 'down') {
14803
+ tailPath(ctx, xCenter, bottom, tailHeight, tailHalfWidth, false);
14804
+ }
14805
+ ctx.lineTo(left + radius, bottom);
14806
+ ctx.arcTo(left, bottom, left, bottom - radius, radius);
14807
+ ctx.lineTo(left, top + radius);
14808
+ ctx.arcTo(left, top, left + radius, top, radius);
14809
+ }
14810
+ ctx.closePath();
14811
+ ctx.fillStyle = params._internal_fillColor;
14812
+ ctx.fill();
14813
+ if (params._internal_borderColor !== undefined && params._internal_borderWidth > 0) {
14814
+ ctx.lineWidth = Math.max(1, Math.round(params._internal_borderWidth * hpr));
14815
+ ctx.strokeStyle = params._internal_borderColor;
14816
+ ctx.stroke();
14817
+ }
14818
+ ctx.restore();
14819
+ }
14820
+ function hitTestTag(centerX, centerY, tag, x, y) {
14821
+ if (tag._internal_width <= 0) {
14822
+ return false;
14823
+ }
14824
+ const halfHeight = tag._internal_height / 2;
14825
+ const top = tag._internal_tailDirection === 'up' ? centerY - halfHeight - tag._internal_tailHeight : centerY - halfHeight;
14826
+ const bottom = tag._internal_tailDirection === 'down' ? centerY + halfHeight + tag._internal_tailHeight : centerY + halfHeight;
14827
+ const left = centerX - tag._internal_width / 2;
14828
+ return x >= left && x <= left + tag._internal_width && y >= top && y <= bottom;
14829
+ }
14830
+
14750
14831
  function drawText(ctx, text, x, y, horizontalPixelRatio, verticalPixelRatio) {
14751
14832
  ctx.save();
14752
14833
  ctx.scale(horizontalPixelRatio, verticalPixelRatio);
@@ -14763,9 +14844,11 @@ class SeriesMarkersRenderer {
14763
14844
  constructor() {
14764
14845
  this._private__data = null;
14765
14846
  this._private__textWidthCache = new TextWidthCache();
14847
+ this._private__tagTextWidthCache = new TextWidthCache();
14766
14848
  this._private__fontSize = -1;
14767
14849
  this._private__fontFamily = '';
14768
14850
  this._private__font = '';
14851
+ this._private__tagFont = '';
14769
14852
  this._private__zOrder = 'normal';
14770
14853
  }
14771
14854
  _internal_setData(data) {
@@ -14776,7 +14859,11 @@ class SeriesMarkersRenderer {
14776
14859
  this._private__fontSize = fontSize;
14777
14860
  this._private__fontFamily = fontFamily;
14778
14861
  this._private__font = makeFont(fontSize, fontFamily);
14862
+ // Tags carry a label rather than an annotation, so they get the heavier
14863
+ // weight — and their own cache, since widths differ per font.
14864
+ this._private__tagFont = makeFont(fontSize, fontFamily, '600');
14779
14865
  this._private__textWidthCache._internal_reset();
14866
+ this._private__tagTextWidthCache._internal_reset();
14780
14867
  }
14781
14868
  this._private__zOrder = zOrder;
14782
14869
  }
@@ -14816,14 +14903,21 @@ class SeriesMarkersRenderer {
14816
14903
  return;
14817
14904
  }
14818
14905
  ctx.textBaseline = 'middle';
14819
- ctx.font = this._private__font;
14820
14906
  for (let index = this._private__data._internal_visibleRange.from; index < this._private__data._internal_visibleRange.to; index++) {
14821
14907
  const item = this._private__data._internal_items[index];
14908
+ const isTag = item._internal_tag !== undefined;
14909
+ ctx.font = isTag ? this._private__tagFont : this._private__font;
14822
14910
  if (item._internal_text !== undefined) {
14823
- item._internal_text._internal_width = this._private__textWidthCache._internal_measureText(ctx, item._internal_text._internal_content);
14911
+ const cache = isTag ? this._private__tagTextWidthCache : this._private__textWidthCache;
14912
+ item._internal_text._internal_width = cache._internal_measureText(ctx, item._internal_text._internal_content);
14824
14913
  item._internal_text._internal_height = this._private__fontSize;
14825
14914
  item._internal_text._internal_x = item._internal_x - item._internal_text._internal_width / 2;
14826
14915
  }
14916
+ if (item._internal_tag !== undefined) {
14917
+ const textWidth = item._internal_text !== undefined ? item._internal_text._internal_width : 0;
14918
+ item._internal_tag._internal_width = Math.max(textWidth + item._internal_tag._internal_paddingX * 2, item._internal_tag._internal_height);
14919
+ item._internal_tag._internal_left = item._internal_x - item._internal_tag._internal_width / 2;
14920
+ }
14827
14921
  drawItem(item, ctx, horizontalPixelRatio, verticalPixelRatio);
14828
14922
  }
14829
14923
  }
@@ -14838,12 +14932,40 @@ function bitmapShapeItemCoordinates(item, horizontalPixelRatio, verticalPixelRat
14838
14932
  };
14839
14933
  }
14840
14934
  function drawItem(item, ctx, horizontalPixelRatio, verticalPixelRatio) {
14935
+ if (item._internal_tag !== undefined) {
14936
+ drawTagItem(item, item._internal_tag, ctx, horizontalPixelRatio, verticalPixelRatio);
14937
+ return;
14938
+ }
14841
14939
  ctx.fillStyle = item._internal_color;
14842
14940
  if (item._internal_text !== undefined) {
14843
14941
  drawText(ctx, item._internal_text._internal_content, item._internal_text._internal_x, item._internal_text._internal_y, horizontalPixelRatio, verticalPixelRatio);
14844
14942
  }
14845
14943
  drawShape(item, ctx, bitmapShapeItemCoordinates(item, horizontalPixelRatio, verticalPixelRatio));
14846
14944
  }
14945
+ // eslint-disable-next-line max-params
14946
+ function drawTagItem(item, tag, ctx, horizontalPixelRatio, verticalPixelRatio) {
14947
+ if (item._internal_size === 0) {
14948
+ return;
14949
+ }
14950
+ drawTag(ctx, {
14951
+ _internal_x: item._internal_x,
14952
+ _internal_centerY: item._internal_y,
14953
+ _internal_width: tag._internal_width,
14954
+ _internal_height: tag._internal_height,
14955
+ _internal_tailHeight: tag._internal_tailHeight,
14956
+ _internal_tailDirection: tag._internal_tailDirection,
14957
+ _internal_radius: tag._internal_radius,
14958
+ _internal_fillColor: item._internal_color,
14959
+ _internal_borderColor: item._internal_borderColor,
14960
+ _internal_borderWidth: item._internal_borderWidth ?? 1,
14961
+ _internal_horizontalPixelRatio: horizontalPixelRatio,
14962
+ _internal_verticalPixelRatio: verticalPixelRatio,
14963
+ });
14964
+ if (item._internal_text !== undefined) {
14965
+ ctx.fillStyle = item._internal_textColor ?? '#FFFFFF';
14966
+ drawText(ctx, item._internal_text._internal_content, item._internal_text._internal_x, item._internal_text._internal_y, horizontalPixelRatio, verticalPixelRatio);
14967
+ }
14968
+ }
14847
14969
  function drawShape(item, ctx, coordinates) {
14848
14970
  if (item._internal_size === 0) {
14849
14971
  return;
@@ -14861,10 +14983,16 @@ function drawShape(item, ctx, coordinates) {
14861
14983
  case 'square':
14862
14984
  drawSquare(ctx, coordinates, item._internal_size);
14863
14985
  return;
14986
+ case 'tag':
14987
+ // Handled by drawTagItem, which needs both pixel ratios and the text.
14988
+ return;
14864
14989
  }
14865
14990
  ensureNever(item._internal_shape);
14866
14991
  }
14867
14992
  function hitTestItem(item, x, y) {
14993
+ if (item._internal_tag !== undefined) {
14994
+ return item._internal_size !== 0 && hitTestTag(item._internal_x, item._internal_y, item._internal_tag, x, y);
14995
+ }
14868
14996
  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)) {
14869
14997
  return true;
14870
14998
  }
@@ -14883,6 +15011,8 @@ function hitTestShape(item, x, y) {
14883
15011
  return hitTestCircle(item._internal_x, item._internal_y, item._internal_size, x, y);
14884
15012
  case 'square':
14885
15013
  return hitTestSquare(item._internal_x, item._internal_y, item._internal_size, x, y);
15014
+ case 'tag':
15015
+ return false;
14886
15016
  }
14887
15017
  }
14888
15018
 
@@ -14915,15 +15045,71 @@ function getPrice(seriesData, marker, isInverted) {
14915
15045
  }
14916
15046
  return;
14917
15047
  }
15048
+ /**
15049
+ * Lays out a `tag` marker: the bubble carries the text, so it is measured from
15050
+ * the font rather than from the bar spacing, and its pointer is aimed back at
15051
+ * the anchor price.
15052
+ */
15053
+ // eslint-disable-next-line max-params
15054
+ function fillTagSizeAndY(rendererItem, marker, anchorY, offsets, textHeight, shapeMargin, sizeMultiplier) {
15055
+ const height = Math.round((textHeight + 5 /* Constants.TagPaddingY */ * 2) * sizeMultiplier);
15056
+ const tailHeight = Math.round(7 /* Constants.TagTailHeight */ * sizeMultiplier);
15057
+ const ignoreOffset = isPriceMarker(marker.position);
15058
+ const halfHeight = height / 2;
15059
+ let tailDirection = 'none';
15060
+ let centerY = anchorY;
15061
+ switch (marker.position) {
15062
+ case 'aboveBar':
15063
+ case 'atPriceTop': {
15064
+ const offset = ignoreOffset ? 0 : offsets._internal_aboveBar;
15065
+ tailDirection = 'down';
15066
+ centerY = (anchorY - offset - tailHeight - halfHeight);
15067
+ if (!ignoreOffset) {
15068
+ offsets._internal_aboveBar += height + tailHeight + shapeMargin;
15069
+ }
15070
+ break;
15071
+ }
15072
+ case 'belowBar':
15073
+ case 'atPriceBottom': {
15074
+ const offset = ignoreOffset ? 0 : offsets._internal_belowBar;
15075
+ tailDirection = 'up';
15076
+ centerY = (anchorY + offset + tailHeight + halfHeight);
15077
+ if (!ignoreOffset) {
15078
+ offsets._internal_belowBar += height + tailHeight + shapeMargin;
15079
+ }
15080
+ break;
15081
+ }
15082
+ }
15083
+ const tag = {
15084
+ _internal_height: height,
15085
+ _internal_tailHeight: tailHeight,
15086
+ _internal_tailDirection: tailDirection,
15087
+ _internal_radius: marker.borderRadius ?? 6 /* Constants.TagRadius */,
15088
+ _internal_paddingX: 9 /* Constants.TagPaddingX */ * sizeMultiplier,
15089
+ _internal_left: 0,
15090
+ _internal_width: 0,
15091
+ };
15092
+ rendererItem._internal_size = height;
15093
+ rendererItem._internal_y = centerY;
15094
+ rendererItem._internal_tag = tag;
15095
+ if (rendererItem._internal_text !== undefined) {
15096
+ rendererItem._internal_text._internal_y = centerY;
15097
+ }
15098
+ }
14918
15099
  // eslint-disable-next-line max-params, complexity
14919
- function fillSizeAndY(rendererItem, marker, seriesData, offsets, textHeight, shapeMargin, series, chart) {
14920
- const price = getPrice(seriesData, marker, series.priceScale().options().invertScale);
15100
+ function fillSizeAndY(rendererItem, marker, seriesData, offsets, textHeight, shapeMargin, series, chart, invertScale) {
15101
+ const price = getPrice(seriesData, marker, invertScale);
14921
15102
  if (price === undefined) {
14922
15103
  return;
14923
15104
  }
14924
15105
  const ignoreOffset = isPriceMarker(marker.position);
14925
15106
  const timeScale = chart.timeScale();
14926
15107
  const sizeMultiplier = isNumber(marker.size) ? Math.max(marker.size, 0) : 1;
15108
+ if (marker.shape === 'tag') {
15109
+ const anchorY = ensureNotNull(series.priceToCoordinate(price));
15110
+ fillTagSizeAndY(rendererItem, marker, anchorY, offsets, textHeight, shapeMargin, sizeMultiplier);
15111
+ return;
15112
+ }
14927
15113
  const shapeSize = calculateShapeHeight(timeScale.options().barSpacing) * sizeMultiplier;
14928
15114
  const halfSize = shapeSize / 2;
14929
15115
  rendererItem._internal_size = shapeSize;
@@ -15030,6 +15216,10 @@ class SeriesMarkersPaneView {
15030
15216
  _internal_externalId: marker.id,
15031
15217
  _internal_internalId: marker._internal_internalId,
15032
15218
  _internal_text: undefined,
15219
+ _internal_textColor: marker.textColor,
15220
+ _internal_borderColor: marker.borderColor,
15221
+ _internal_borderWidth: marker.borderWidth,
15222
+ _internal_tag: undefined,
15033
15223
  }));
15034
15224
  this._private__dataInvalidated = false;
15035
15225
  }
@@ -15040,13 +15230,22 @@ class SeriesMarkersPaneView {
15040
15230
  return;
15041
15231
  }
15042
15232
  const visibleBarsRange = new RangeImpl(Math.floor(visibleBars.from), Math.ceil(visibleBars.to));
15043
- const firstValue = this._private__series.data()[0];
15233
+ const firstValue = this._private__series.dataByIndex(0, 1 /* MismatchDirection.NearestRight */);
15044
15234
  if (firstValue === null) {
15045
15235
  return;
15046
15236
  }
15047
15237
  if (this._private__data._internal_items.length === 0) {
15048
15238
  return;
15049
15239
  }
15240
+ // This runs inside the hit-test and paint loops, where a throw costs the
15241
+ // rest of the frame.
15242
+ let invertScale = false;
15243
+ try {
15244
+ invertScale = this._private__series.priceScale().options().invertScale;
15245
+ }
15246
+ catch (error) {
15247
+ invertScale = false;
15248
+ }
15050
15249
  let prevTimeIndex = NaN;
15051
15250
  const shapeMargin$1 = shapeMargin(timeScale.options().barSpacing);
15052
15251
  const offsets = {
@@ -15077,7 +15276,7 @@ class SeriesMarkersPaneView {
15077
15276
  if (dataAt === null) {
15078
15277
  continue;
15079
15278
  }
15080
- fillSizeAndY(rendererItem, marker, dataAt, offsets, layoutOptions.fontSize, shapeMargin$1, this._private__series, this._private__chart);
15279
+ fillSizeAndY(rendererItem, marker, dataAt, offsets, layoutOptions.fontSize, shapeMargin$1, this._private__series, this._private__chart, invertScale);
15081
15280
  }
15082
15281
  this._private__invalidated = false;
15083
15282
  }
@@ -15235,6 +15434,10 @@ class SeriesMarkersPrimitive {
15235
15434
  text: marker.text,
15236
15435
  size: marker.size,
15237
15436
  price: marker.price,
15437
+ textColor: marker.textColor,
15438
+ borderColor: marker.borderColor,
15439
+ borderWidth: marker.borderWidth,
15440
+ borderRadius: marker.borderRadius,
15238
15441
  _internal_originalTime: marker.time,
15239
15442
  };
15240
15443
  if (marker.position === 'atPriceTop' ||
@@ -19536,6 +19739,7 @@ class TradingLineController {
19536
19739
  constructor(chart, element) {
19537
19740
  this._private__lines = new Map();
19538
19741
  this._private__hoveredId = null;
19742
+ this._private__hoveredPart = null;
19539
19743
  this._private__dragging = null;
19540
19744
  this._private__pointerId = null;
19541
19745
  this._private__pressOrigin = null;
@@ -19593,8 +19797,12 @@ class TradingLineController {
19593
19797
  if (this._private__dragging !== null) {
19594
19798
  return;
19595
19799
  }
19596
- const hovered = this._private__lineFromHit(param.hoveredObjectId);
19800
+ const hit = this._private__splitHit(param.hoveredObjectId);
19801
+ const hovered = hit === null ? null : this._private__lines.get(hit._internal_id) ?? null;
19597
19802
  this._private__setHovered(hovered ? hovered.id() : null);
19803
+ // The part is updated after the id, and separately from it: moving from a
19804
+ // label onto its close button keeps the same line hovered.
19805
+ this._private__setHoveredPart(hovered, hovered === null ? null : hit?._internal_part ?? null);
19598
19806
  this._private__applyCursor();
19599
19807
  }
19600
19808
  _private__onPointerDown(event) {
@@ -19698,24 +19906,43 @@ class TradingLineController {
19698
19906
  if (line === null) {
19699
19907
  return null;
19700
19908
  }
19701
- // While the pointer is over the panes the engine gives pane coordinates.
19702
- // Once it leaves them — during a captured drag — fall back to the pane
19703
- // element, which still excludes the price axis.
19909
+ // The pointer event is the gesture's own position, so it is the source of
19910
+ // truth. The crosshair is only a mirror of it: it stops updating as soon
19911
+ // as the pointer leaves the pane canvas — over the price axis, past the
19912
+ // chart's edge — and a drag driven from it freezes there while the user
19913
+ // is still moving.
19914
+ const pane = this._private__chart.panes()[line.paneIndex()];
19915
+ const paneElement = pane ? pane.getHTMLElement() : null;
19916
+ if (paneElement) {
19917
+ return line.priceAt(event.clientY - paneElement.getBoundingClientRect().top);
19918
+ }
19704
19919
  if (this._private__point !== null && this._private__paneIndex === line.paneIndex()) {
19705
19920
  return line.priceAt(this._private__point._internal_y);
19706
19921
  }
19707
- const pane = this._private__chart.panes()[line.paneIndex()];
19708
- const paneElement = pane ? pane.getHTMLElement() : null;
19709
- if (!paneElement) {
19922
+ return null;
19923
+ }
19924
+ /**
19925
+ * Hit ids are either a bare line id or `id#part`, which is how a line with
19926
+ * several targets reports which one was hit.
19927
+ */
19928
+ _private__splitHit(externalId) {
19929
+ if (typeof externalId !== 'string' || externalId.length === 0) {
19710
19930
  return null;
19711
19931
  }
19712
- return line.priceAt(event.clientY - paneElement.getBoundingClientRect().top);
19932
+ const separator = externalId.indexOf('#');
19933
+ if (separator === -1) {
19934
+ return { _internal_id: externalId, _internal_part: null };
19935
+ }
19936
+ return { _internal_id: externalId.slice(0, separator), _internal_part: externalId.slice(separator + 1) };
19713
19937
  }
19714
- _private__lineFromHit(externalId) {
19715
- if (typeof externalId !== 'string') {
19716
- return null;
19938
+ _private__setHoveredPart(line, part) {
19939
+ if (this._private__hoveredPart === part) {
19940
+ return;
19941
+ }
19942
+ this._private__hoveredPart = part;
19943
+ if (line && line.setHoveredPart) {
19944
+ line.setHoveredPart(part);
19717
19945
  }
19718
- return this._private__lines.get(externalId) ?? null;
19719
19946
  }
19720
19947
  _private__setHovered(id) {
19721
19948
  if (this._private__hoveredId === id) {
@@ -19725,6 +19952,7 @@ class TradingLineController {
19725
19952
  this._private__lines.get(this._private__hoveredId)?.setHovered(false);
19726
19953
  }
19727
19954
  this._private__hoveredId = id;
19955
+ this._private__hoveredPart = null;
19728
19956
  if (id !== null) {
19729
19957
  this._private__lines.get(id)?.setHovered(true);
19730
19958
  }
@@ -20248,6 +20476,702 @@ function createInteractiveLineManager(chart, series) {
20248
20476
  return new InteractiveLineManager(chart, series);
20249
20477
  }
20250
20478
 
20479
+ const positionLineDefaultColors = {
20480
+ entry: '#2962FF',
20481
+ takeProfit: '#26A17B',
20482
+ stopLoss: '#D9A23B',
20483
+ };
20484
+ const positionLineThemeDefaults = {
20485
+ badgeTextColor: '#FFFFFF',
20486
+ borderRadius: 4,
20487
+ borderWidth: 1,
20488
+ paddingX: 8,
20489
+ paddingY: 6,
20490
+ backgroundOpacity: 1,
20491
+ };
20492
+ const positionLineLevels = ['takeProfit', 'entry', 'stopLoss'];
20493
+
20494
+ class PositionLineRenderer {
20495
+ constructor() {
20496
+ this._private__data = null;
20497
+ this._private__layouts = [];
20498
+ this._private__connectorX = 0;
20499
+ this._private__font = '';
20500
+ this._private__colorParser = new ColorParser([]);
20501
+ this._private__textWidthCache = new TextWidthCache(50);
20502
+ }
20503
+ _internal_setData(data) {
20504
+ this._private__data = data;
20505
+ }
20506
+ _internal_hitTest(x, y) {
20507
+ // The close button sits on top of the label, which sits on top of the
20508
+ // line, so the narrowest target is tested first.
20509
+ for (const layout of this._private__layouts) {
20510
+ if (layout._internal_closable && x >= layout._internal_closeLeft && x <= layout._internal_closeRight &&
20511
+ Math.abs(y - layout._internal_y) <= layout._internal_height / 2) {
20512
+ return { _internal_level: layout._internal_level, _internal_part: 'close' };
20513
+ }
20514
+ }
20515
+ for (const layout of this._private__layouts) {
20516
+ if (x >= layout._internal_pillLeft && x <= layout._internal_pillRight && Math.abs(y - layout._internal_y) <= layout._internal_height / 2) {
20517
+ return { _internal_level: layout._internal_level, _internal_part: 'body' };
20518
+ }
20519
+ }
20520
+ for (const layout of this._private__layouts) {
20521
+ if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */) {
20522
+ return { _internal_level: layout._internal_level, _internal_part: 'line' };
20523
+ }
20524
+ }
20525
+ return null;
20526
+ }
20527
+ draw(target) {
20528
+ target.useBitmapCoordinateSpace((scope) => this._private__drawImpl(scope));
20529
+ }
20530
+ _private__drawImpl(scope) {
20531
+ const data = this._private__data;
20532
+ this._private__layouts = [];
20533
+ if (data === null || data._internal_levels.length === 0) {
20534
+ return;
20535
+ }
20536
+ const { context: ctx, mediaSize } = scope;
20537
+ ctx.save();
20538
+ if (this._private__font !== data._internal_font) {
20539
+ this._private__font = data._internal_font;
20540
+ this._private__textWidthCache._internal_reset();
20541
+ }
20542
+ ctx.font = data._internal_font;
20543
+ ctx.textBaseline = 'middle';
20544
+ this._private__connectorX = Math.max(0, mediaSize.width - data._internal_rightOffset);
20545
+ const lineEnd = data._internal_connectorVisible ? this._private__connectorX : mediaSize.width;
20546
+ for (const level of data._internal_levels) {
20547
+ this._private__layouts.push(this._private__drawLevel(scope, data, level, lineEnd));
20548
+ }
20549
+ if (data._internal_connectorVisible && data._internal_levels.length > 1) {
20550
+ this._private__drawConnector(scope, data);
20551
+ }
20552
+ ctx.restore();
20553
+ }
20554
+ // eslint-disable-next-line max-params
20555
+ _private__drawLevel(scope, data, level, lineEnd) {
20556
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20557
+ const height = data._internal_fontSize + data._internal_paddingY * 2;
20558
+ const badgeWidth = level._internal_badge.length === 0
20559
+ ? 0
20560
+ : Math.max(this._private__textWidthCache._internal_measureText(ctx, level._internal_badge) + data._internal_paddingX * 2, height * 0.85 /* Constants.BadgeMinWidthRatio */);
20561
+ const labelWidth = this._private__textWidthCache._internal_measureText(ctx, level._internal_text) + data._internal_paddingX * 2;
20562
+ const closeWidth = level._internal_closable ? height : 0;
20563
+ const pillWidth = badgeWidth + labelWidth + closeWidth;
20564
+ const pillRight = Math.max(pillWidth, lineEnd - 8 /* Constants.LabelGap */);
20565
+ const pillLeft = pillRight - pillWidth;
20566
+ const top = level._internal_y - height / 2;
20567
+ this._private__drawLineSegments(scope, level, pillLeft, pillRight, lineEnd);
20568
+ this._private__drawPill(scope, data, level, { _internal_left: pillLeft, _internal_top: top, _internal_width: pillWidth, _internal_height: height });
20569
+ let cellLeft = pillLeft;
20570
+ if (badgeWidth > 0) {
20571
+ this._private__drawBadge(scope, data, level, { _internal_left: cellLeft, _internal_top: top, _internal_width: badgeWidth, _internal_height: height });
20572
+ cellLeft += badgeWidth;
20573
+ this._private__drawSeparator(ctx, level._internal_color, cellLeft, top, height, hpr, vpr);
20574
+ }
20575
+ ctx.save();
20576
+ ctx.scale(hpr, vpr);
20577
+ ctx.textAlign = 'center';
20578
+ ctx.fillStyle = data._internal_textColor ?? level._internal_color;
20579
+ ctx.fillText(level._internal_text, cellLeft + labelWidth / 2, level._internal_y);
20580
+ ctx.restore();
20581
+ cellLeft += labelWidth;
20582
+ if (level._internal_closable) {
20583
+ this._private__drawSeparator(ctx, level._internal_color, cellLeft, top, height, hpr, vpr);
20584
+ this._private__drawCloseButton(scope, data, level, { _internal_left: cellLeft, _internal_top: top, _internal_width: closeWidth, _internal_height: height });
20585
+ }
20586
+ return {
20587
+ _internal_level: level._internal_level,
20588
+ _internal_y: level._internal_y,
20589
+ _internal_height: height,
20590
+ _internal_pillLeft: pillLeft,
20591
+ _internal_pillRight: pillRight,
20592
+ _internal_closeLeft: cellLeft,
20593
+ _internal_closeRight: cellLeft + closeWidth,
20594
+ _internal_closable: level._internal_closable,
20595
+ };
20596
+ }
20597
+ // eslint-disable-next-line max-params
20598
+ _private__drawLineSegments(scope, level, pillLeft, pillRight, lineEnd) {
20599
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20600
+ const lineWidth = Math.max(1, Math.round(level._internal_lineWidth * vpr));
20601
+ const y = Math.round(level._internal_y * vpr) - Math.floor(lineWidth / 2);
20602
+ ctx.save();
20603
+ ctx.strokeStyle = level._internal_color;
20604
+ ctx.lineWidth = lineWidth;
20605
+ setLineStyle(ctx, level._internal_lineStyle);
20606
+ ctx.beginPath();
20607
+ ctx.moveTo(0, y);
20608
+ ctx.lineTo(Math.round(Math.max(0, pillLeft - 8 /* Constants.LabelGap */) * hpr), y);
20609
+ if (lineEnd > pillRight + 8 /* Constants.LabelGap */) {
20610
+ ctx.moveTo(Math.round((pillRight + 8 /* Constants.LabelGap */) * hpr), y);
20611
+ ctx.lineTo(Math.round(lineEnd * hpr), y);
20612
+ }
20613
+ ctx.stroke();
20614
+ ctx.restore();
20615
+ }
20616
+ // eslint-disable-next-line max-params
20617
+ _private__drawPill(scope, data, level, box) {
20618
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20619
+ const hovered = data._internal_hoveredLevel === level._internal_level;
20620
+ const borderWidth = Math.max(1, Math.round((hovered ? data._internal_borderWidth + 1 : data._internal_borderWidth) * hpr));
20621
+ ctx.save();
20622
+ ctx.setLineDash([]);
20623
+ bitmapRoundRect(ctx, box, data._internal_borderRadius, hpr, vpr);
20624
+ ctx.fillStyle = this._private__colorParser._internal_applyAlpha(data._internal_background, data._internal_backgroundOpacity);
20625
+ ctx.fill();
20626
+ ctx.lineWidth = borderWidth;
20627
+ ctx.strokeStyle = level._internal_color;
20628
+ ctx.stroke();
20629
+ ctx.restore();
20630
+ }
20631
+ // eslint-disable-next-line max-params
20632
+ _private__drawBadge(scope, data, level, box) {
20633
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20634
+ if (level._internal_badgeFilled) {
20635
+ // The badge shares the label's left corners, so its fill has to stop
20636
+ // short of the border instead of squaring it off.
20637
+ const inset = data._internal_borderWidth;
20638
+ ctx.save();
20639
+ 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');
20640
+ ctx.fillStyle = level._internal_color;
20641
+ ctx.fill();
20642
+ ctx.restore();
20643
+ }
20644
+ ctx.save();
20645
+ ctx.scale(hpr, vpr);
20646
+ ctx.textAlign = 'center';
20647
+ ctx.fillStyle = level._internal_badgeFilled ? data._internal_badgeTextColor : level._internal_color;
20648
+ ctx.fillText(level._internal_badge, box._internal_left + box._internal_width / 2, box._internal_top + box._internal_height / 2);
20649
+ ctx.restore();
20650
+ }
20651
+ // eslint-disable-next-line max-params
20652
+ _private__drawSeparator(ctx, color, x, top, height, hpr, vpr) {
20653
+ const width = Math.max(1, Math.floor(hpr));
20654
+ ctx.save();
20655
+ ctx.setLineDash([]);
20656
+ ctx.fillStyle = this._private__colorParser._internal_applyAlpha(color, 0.4 /* Constants.SeparatorAlpha */);
20657
+ ctx.fillRect(Math.round(x * hpr), Math.round(top * vpr), width, Math.round(height * vpr));
20658
+ ctx.restore();
20659
+ }
20660
+ // eslint-disable-next-line max-params
20661
+ _private__drawCloseButton(scope, data, level, box) {
20662
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20663
+ const hovered = data._internal_hoveredLevel === level._internal_level && data._internal_hoveredPart === 'close';
20664
+ if (hovered) {
20665
+ ctx.save();
20666
+ const inset = data._internal_borderWidth;
20667
+ 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');
20668
+ ctx.fillStyle = this._private__colorParser._internal_applyAlpha(level._internal_color, 0.25);
20669
+ ctx.fill();
20670
+ ctx.restore();
20671
+ }
20672
+ const centerX = (box._internal_left + box._internal_width / 2) * hpr;
20673
+ const centerY = (box._internal_top + box._internal_height / 2) * vpr;
20674
+ const arm = (7 /* Constants.CloseGlyphSize */ / 2) * hpr;
20675
+ ctx.save();
20676
+ ctx.setLineDash([]);
20677
+ ctx.lineCap = 'round';
20678
+ ctx.lineWidth = Math.max(1, Math.round(1.4 * hpr));
20679
+ ctx.strokeStyle = level._internal_color;
20680
+ ctx.beginPath();
20681
+ ctx.moveTo(centerX - arm, centerY - arm);
20682
+ ctx.lineTo(centerX + arm, centerY + arm);
20683
+ ctx.moveTo(centerX + arm, centerY - arm);
20684
+ ctx.lineTo(centerX - arm, centerY + arm);
20685
+ ctx.stroke();
20686
+ ctx.restore();
20687
+ }
20688
+ _private__drawConnector(scope, data) {
20689
+ const { context: ctx, horizontalPixelRatio: hpr, verticalPixelRatio: vpr } = scope;
20690
+ const entry = data._internal_levels.find((level) => level._internal_level === 'entry') ?? data._internal_levels[0];
20691
+ const ys = data._internal_levels.map((level) => level._internal_y);
20692
+ const x = Math.round(this._private__connectorX * hpr);
20693
+ ctx.save();
20694
+ ctx.setLineDash([]);
20695
+ ctx.strokeStyle = entry._internal_color;
20696
+ ctx.lineWidth = Math.max(1, Math.floor(hpr));
20697
+ ctx.beginPath();
20698
+ ctx.moveTo(x, Math.round(Math.min(...ys) * vpr));
20699
+ ctx.lineTo(x, Math.round(Math.max(...ys) * vpr));
20700
+ ctx.stroke();
20701
+ for (const level of data._internal_levels) {
20702
+ ctx.beginPath();
20703
+ ctx.arc(x, Math.round(level._internal_y * vpr), 4.5 /* Constants.HandleRadius */ * hpr, 0, 2 * Math.PI);
20704
+ ctx.fillStyle = level._internal_level === 'entry'
20705
+ ? entry._internal_color
20706
+ : this._private__colorParser._internal_applyAlpha(data._internal_background, data._internal_backgroundOpacity);
20707
+ ctx.fill();
20708
+ ctx.lineWidth = Math.max(1, Math.round(1.5 * hpr));
20709
+ ctx.strokeStyle = level._internal_color;
20710
+ ctx.stroke();
20711
+ }
20712
+ ctx.restore();
20713
+ }
20714
+ }
20715
+ // eslint-disable-next-line max-params
20716
+ function bitmapRoundRect(ctx, box, radius, hpr, vpr, side = 'all') {
20717
+ const left = Math.round(box._internal_left * hpr);
20718
+ const top = Math.round(box._internal_top * vpr);
20719
+ const width = Math.round(box._internal_width * hpr);
20720
+ const height = Math.round(box._internal_height * vpr);
20721
+ const r = Math.min(radius * hpr, width / 2, height / 2);
20722
+ const radii = side === 'left'
20723
+ ? [r, 0, 0, r]
20724
+ : side === 'right'
20725
+ ? [0, r, r, 0]
20726
+ : [r, r, r, r];
20727
+ drawRoundRect(ctx, left, top, width, height, radii);
20728
+ }
20729
+
20730
+ class PositionLinePaneView {
20731
+ constructor() {
20732
+ this._private__renderer = new PositionLineRenderer();
20733
+ this._private__data = null;
20734
+ }
20735
+ _internal_update(data) {
20736
+ this._private__data = data;
20737
+ }
20738
+ renderer() {
20739
+ if (this._private__data === null) {
20740
+ return null;
20741
+ }
20742
+ this._private__renderer._internal_setData(this._private__data);
20743
+ return this._private__renderer;
20744
+ }
20745
+ zOrder() {
20746
+ return 'top';
20747
+ }
20748
+ _internal_hitTest(x, y) {
20749
+ return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y);
20750
+ }
20751
+ }
20752
+
20753
+ class PositionLineAxisView {
20754
+ constructor(source) {
20755
+ this._private__source = source;
20756
+ }
20757
+ coordinate() {
20758
+ // A hidden label is pushed far off the axis so it cannot reserve a gap
20759
+ // between the labels that are shown.
20760
+ return this._private__label()?._internal_coordinate ?? -1e3;
20761
+ }
20762
+ text() {
20763
+ return this._private__label()?._internal_text ?? '';
20764
+ }
20765
+ textColor() {
20766
+ return this._private__label()?._internal_textColor ?? '#FFFFFF';
20767
+ }
20768
+ backColor() {
20769
+ return this._private__label()?._internal_color ?? '#000000';
20770
+ }
20771
+ visible() {
20772
+ return this._private__label() !== null;
20773
+ }
20774
+ _private__label() {
20775
+ return this._private__source();
20776
+ }
20777
+ }
20778
+
20779
+ let nextPositionId = 0;
20780
+ const DEFAULT_RIGHT_OFFSET = 56;
20781
+ /**
20782
+ * A group of trading levels — entry, take profit and stop loss — drawn as one
20783
+ * unit: a line per level, a label carrying size and P&L, and a connector that
20784
+ * ties the three together.
20785
+ *
20786
+ * Input is not handled here. Every trading line on a chart shares a single
20787
+ * TradingLineController, which is what guarantees that one gesture moves one
20788
+ * level, and that a position line and a plain draggable price line on the same
20789
+ * chart do not fight over the pointer.
20790
+ */
20791
+ class PositionLine {
20792
+ constructor(chart, series, options) {
20793
+ this._private__paneView = new PositionLinePaneView();
20794
+ this._private__colorParser = new ColorParser([]);
20795
+ this._private__attached = false;
20796
+ this._private__hoveredLevel = null;
20797
+ this._private__hoveredPart = null;
20798
+ this._private__dragLevel = null;
20799
+ this._private__priceBeforeDrag = null;
20800
+ this._private__chart = chart;
20801
+ this._private__series = series;
20802
+ this._private__id = `pipsend-position-line-${nextPositionId++}`;
20803
+ this._private__options = options;
20804
+ this._private__theme = { ...positionLineThemeDefaults, ...options.theme };
20805
+ this._private__paneViews = [this._private__paneView];
20806
+ this._private__axisViews = positionLineLevels.map((level) => new PositionLineAxisView(() => this._private__axisLabel(level)));
20807
+ this._private__series.attachPrimitive(this);
20808
+ acquireController(this._private__chart)?._internal_register(this);
20809
+ }
20810
+ // ---- ISeriesPrimitive ----
20811
+ attached(param) {
20812
+ this._private__requestUpdate = param.requestUpdate;
20813
+ this._private__attached = true;
20814
+ this.requestUpdate();
20815
+ }
20816
+ detached() {
20817
+ this._private__attached = false;
20818
+ this._private__requestUpdate = undefined;
20819
+ }
20820
+ paneViews() {
20821
+ return this._private__paneViews;
20822
+ }
20823
+ priceAxisViews() {
20824
+ return this._private__axisViews;
20825
+ }
20826
+ updateAllViews() {
20827
+ this._private__paneView._internal_update(this._private__buildRendererData());
20828
+ }
20829
+ hitTest(x, y) {
20830
+ const hit = this._private__paneView._internal_hitTest(x, y);
20831
+ if (hit === null) {
20832
+ return null;
20833
+ }
20834
+ const level = this._private__levelOptions(hit._internal_level);
20835
+ if (level === null) {
20836
+ return null;
20837
+ }
20838
+ return {
20839
+ externalId: `${this._private__id}#${hit._internal_level}:${hit._internal_part}`,
20840
+ zOrder: 'top',
20841
+ cursorStyle: hit._internal_part === 'close'
20842
+ ? 'pointer'
20843
+ : (level.draggable ?? true) ? 'ns-resize' : undefined,
20844
+ };
20845
+ }
20846
+ // ---- ControllableLine ----
20847
+ id() {
20848
+ return this._private__id;
20849
+ }
20850
+ paneIndex() {
20851
+ try {
20852
+ return this._private__series.getPane().paneIndex();
20853
+ }
20854
+ catch (error) {
20855
+ // The engine asserts the series belongs to a pane, and that lookup can
20856
+ // come back empty while panes are being rebuilt. The main pane is the
20857
+ // right guess and keeps the gesture alive instead of throwing mid-drag.
20858
+ return 0;
20859
+ }
20860
+ }
20861
+ setHoveredPart(part) {
20862
+ const [level, name] = part === null ? [null, null] : part.split(':');
20863
+ const nextLevel = level ?? null;
20864
+ const nextPart = name ?? null;
20865
+ if (this._private__hoveredLevel === nextLevel && this._private__hoveredPart === nextPart) {
20866
+ return;
20867
+ }
20868
+ this._private__hoveredLevel = nextLevel;
20869
+ this._private__hoveredPart = nextPart;
20870
+ this.requestUpdate();
20871
+ }
20872
+ setHovered(hovered) {
20873
+ if (!hovered) {
20874
+ this.setHoveredPart(null);
20875
+ }
20876
+ }
20877
+ isDraggable() {
20878
+ if (this._private__hoveredLevel === null || this._private__hoveredPart === 'close') {
20879
+ return false;
20880
+ }
20881
+ return this._private__levelOptions(this._private__hoveredLevel)?.draggable ?? true;
20882
+ }
20883
+ isClickable() {
20884
+ if (this._private__hoveredPart === 'close') {
20885
+ return true;
20886
+ }
20887
+ return this._private__options.onClick !== undefined;
20888
+ }
20889
+ priceAt(paneY) {
20890
+ const price = this._private__series.coordinateToPrice(paneY);
20891
+ return price === null ? null : price;
20892
+ }
20893
+ beginDrag() {
20894
+ this._private__dragLevel = this._private__hoveredLevel;
20895
+ if (this._private__dragLevel === null) {
20896
+ return;
20897
+ }
20898
+ const price = this._private__levelOptions(this._private__dragLevel)?.price ?? null;
20899
+ this._private__priceBeforeDrag = price;
20900
+ if (price !== null && this._private__options.onDragStart) {
20901
+ this._private__options.onDragStart(this._private__dragLevel, price);
20902
+ }
20903
+ }
20904
+ dragTo(price) {
20905
+ if (this._private__dragLevel === null) {
20906
+ return;
20907
+ }
20908
+ this._private__applyPrice(this._private__dragLevel, price);
20909
+ if (this._private__options.onDragMove) {
20910
+ this._private__options.onDragMove(this._private__dragLevel, price);
20911
+ }
20912
+ }
20913
+ commitDrag() {
20914
+ const level = this._private__dragLevel;
20915
+ this._private__dragLevel = null;
20916
+ this._private__priceBeforeDrag = null;
20917
+ if (level === null) {
20918
+ return;
20919
+ }
20920
+ const price = this._private__levelOptions(level)?.price;
20921
+ if (price !== undefined && this._private__options.onDragEnd) {
20922
+ this._private__options.onDragEnd(level, price);
20923
+ }
20924
+ }
20925
+ cancelDrag() {
20926
+ const level = this._private__dragLevel;
20927
+ const original = this._private__priceBeforeDrag;
20928
+ this._private__dragLevel = null;
20929
+ this._private__priceBeforeDrag = null;
20930
+ if (level === null) {
20931
+ return;
20932
+ }
20933
+ // Reported even when the price did not move, so a caller that pauses work
20934
+ // on `onDragStart` always gets the matching end of the gesture.
20935
+ const restored = original !== null && original !== this._private__levelOptions(level)?.price;
20936
+ if (restored) {
20937
+ this._private__applyPrice(level, original);
20938
+ if (this._private__options.onDragMove) {
20939
+ this._private__options.onDragMove(level, original);
20940
+ }
20941
+ }
20942
+ if (this._private__options.onDragCancel) {
20943
+ this._private__options.onDragCancel(level, this._private__levelOptions(level)?.price ?? 0);
20944
+ }
20945
+ }
20946
+ click() {
20947
+ const level = this._private__hoveredLevel;
20948
+ if (level === null) {
20949
+ return;
20950
+ }
20951
+ if (this._private__hoveredPart === 'close') {
20952
+ if (this._private__options.onClose) {
20953
+ this._private__options.onClose(level);
20954
+ }
20955
+ return;
20956
+ }
20957
+ const price = this._private__levelOptions(level)?.price;
20958
+ if (price !== undefined && this._private__options.onClick) {
20959
+ this._private__options.onClick(level, price);
20960
+ }
20961
+ }
20962
+ // ---- public API ----
20963
+ /**
20964
+ * Updates the group. Any subset of options can be passed; the levels given
20965
+ * are merged into the current ones, and a level set to `undefined` is
20966
+ * removed.
20967
+ */
20968
+ applyOptions(options) {
20969
+ // A level under an active gesture owns its price. Callers feeding the
20970
+ // group from a socket re-send the old price several times a second, and
20971
+ // letting that through would pull the level out from under the cursor.
20972
+ const dragged = this._private__dragLevel;
20973
+ const draggedPrice = dragged === null ? undefined : this._private__levelOptions(dragged)?.price;
20974
+ const merged = { ...this._private__options, ...options };
20975
+ merged.entry = { ...this._private__options.entry, ...options.entry };
20976
+ merged.takeProfit = mergeLevel(this._private__options.takeProfit, options, 'takeProfit');
20977
+ merged.stopLoss = mergeLevel(this._private__options.stopLoss, options, 'stopLoss');
20978
+ this._private__options = merged;
20979
+ if (dragged !== null && draggedPrice !== undefined) {
20980
+ const level = this._private__levelOptions(dragged);
20981
+ if (level !== null) {
20982
+ level.price = draggedPrice;
20983
+ }
20984
+ }
20985
+ if (options.theme) {
20986
+ // Merged onto what is already applied, so two partial theme updates do
20987
+ // not undo each other.
20988
+ this._private__theme = { ...this._private__theme, ...options.theme };
20989
+ }
20990
+ this.requestUpdate();
20991
+ }
20992
+ /**
20993
+ * Moves one level to a new price, recomputing its text when the level has a
20994
+ * `formatText`.
20995
+ *
20996
+ * Ignored for a level the user is currently dragging — the gesture owns the
20997
+ * price until it reports back through
20998
+ * {@link PositionLineOptions.onDragEnd} or
20999
+ * {@link PositionLineOptions.onDragCancel}.
21000
+ */
21001
+ setPrice(level, price) {
21002
+ if (this._private__dragLevel === level) {
21003
+ return;
21004
+ }
21005
+ this._private__applyPrice(level, price);
21006
+ }
21007
+ /**
21008
+ * Replaces one level's label text. Use this for text that changes on its own
21009
+ * — a ticking P&L on a fixed entry — rather than with the price.
21010
+ */
21011
+ setText(level, text) {
21012
+ const options = this._private__levelOptions(level);
21013
+ if (options === null) {
21014
+ return;
21015
+ }
21016
+ options.text = text;
21017
+ this.requestUpdate();
21018
+ }
21019
+ /**
21020
+ * The current price of each level that is present.
21021
+ */
21022
+ prices() {
21023
+ const result = {};
21024
+ for (const level of positionLineLevels) {
21025
+ const options = this._private__levelOptions(level);
21026
+ if (options !== null) {
21027
+ result[level] = options.price;
21028
+ }
21029
+ }
21030
+ return result;
21031
+ }
21032
+ options() {
21033
+ return this._private__options;
21034
+ }
21035
+ /**
21036
+ * Removes the group from the chart and releases its share of the input
21037
+ * controller.
21038
+ */
21039
+ remove() {
21040
+ releaseController(this._private__chart, this);
21041
+ this._private__series.detachPrimitive(this);
21042
+ }
21043
+ requestUpdate() {
21044
+ if (this._private__requestUpdate) {
21045
+ this._private__requestUpdate();
21046
+ }
21047
+ }
21048
+ /** Reads back the label the price axis should draw for a level. */
21049
+ _private__axisLabel(level) {
21050
+ const options = this._private__levelOptions(level);
21051
+ if (options === null || !isFinite(options.price) ||
21052
+ this._private__options.visible === false || options.axisLabelVisible === false) {
21053
+ return null;
21054
+ }
21055
+ const y = this._private__series.priceToCoordinate(options.price);
21056
+ if (y === null) {
21057
+ return null;
21058
+ }
21059
+ const color = options.color ?? positionLineDefaultColors[level];
21060
+ return {
21061
+ _internal_coordinate: y,
21062
+ _internal_text: this._private__series.priceFormatter().format(options.price),
21063
+ _internal_color: color,
21064
+ _internal_textColor: this._private__colorParser._internal_generateContrastColors(color)._internal_foreground,
21065
+ };
21066
+ }
21067
+ _private__levelOptions(level) {
21068
+ const options = level === 'entry' ? this._private__options.entry : this._private__options[level];
21069
+ return options ?? null;
21070
+ }
21071
+ _private__applyPrice(level, price) {
21072
+ const options = this._private__levelOptions(level);
21073
+ if (options === null) {
21074
+ return;
21075
+ }
21076
+ options.price = price;
21077
+ if (options.formatText) {
21078
+ options.text = options.formatText(price);
21079
+ }
21080
+ this.requestUpdate();
21081
+ }
21082
+ _private__buildRendererData() {
21083
+ if (!this._private__attached || this._private__options.visible === false) {
21084
+ return null;
21085
+ }
21086
+ const levels = [];
21087
+ for (const level of positionLineLevels) {
21088
+ const options = this._private__levelOptions(level);
21089
+ // A level added through a patch can be missing its price until the
21090
+ // caller supplies one; drawing it would put it at NaN.
21091
+ if (options === null || !isFinite(options.price)) {
21092
+ continue;
21093
+ }
21094
+ const y = this._private__series.priceToCoordinate(options.price);
21095
+ if (y === null) {
21096
+ continue;
21097
+ }
21098
+ const isEntry = level === 'entry';
21099
+ levels.push({
21100
+ _internal_level: level,
21101
+ _internal_y: y,
21102
+ _internal_color: options.color ?? positionLineDefaultColors[level],
21103
+ _internal_text: options.formatText ? options.formatText(options.price) : options.text ?? '',
21104
+ _internal_badge: options.badge ?? '',
21105
+ _internal_badgeFilled: options.badgeFilled ?? isEntry,
21106
+ _internal_lineWidth: options.lineWidth ?? 1,
21107
+ _internal_lineStyle: options.lineStyle ?? (isEntry ? 0 /* LineStyle.Solid */ : 2 /* LineStyle.Dashed */),
21108
+ _internal_closable: options.closable ?? true,
21109
+ _internal_draggable: options.draggable ?? true,
21110
+ });
21111
+ }
21112
+ if (levels.length === 0) {
21113
+ return null;
21114
+ }
21115
+ const layout = this._private__chart.options()['layout'];
21116
+ const fontSize = this._private__theme.fontSize ?? layout.fontSize;
21117
+ return {
21118
+ _internal_levels: levels,
21119
+ _internal_background: this._private__theme.background ?? resolveBackgroundColor(layout.background),
21120
+ _internal_textColor: this._private__theme.textColor,
21121
+ _internal_badgeTextColor: this._private__theme.badgeTextColor,
21122
+ _internal_borderRadius: this._private__theme.borderRadius,
21123
+ _internal_borderWidth: this._private__theme.borderWidth,
21124
+ _internal_paddingX: this._private__theme.paddingX,
21125
+ _internal_paddingY: this._private__theme.paddingY,
21126
+ _internal_backgroundOpacity: this._private__theme.backgroundOpacity,
21127
+ _internal_font: makeFont(fontSize, this._private__theme.fontFamily ?? layout.fontFamily),
21128
+ _internal_fontSize: fontSize,
21129
+ _internal_connectorVisible: this._private__options.connectorVisible !== false && levels.length > 1,
21130
+ _internal_rightOffset: this._private__options.rightOffset ?? DEFAULT_RIGHT_OFFSET,
21131
+ _internal_hoveredLevel: this._private__hoveredLevel,
21132
+ _internal_hoveredPart: this._private__hoveredPart,
21133
+ };
21134
+ }
21135
+ }
21136
+ function mergeLevel(current, options, key) {
21137
+ if (!(key in options)) {
21138
+ return current;
21139
+ }
21140
+ const next = options[key];
21141
+ return next === undefined ? undefined : { ...current, ...next };
21142
+ }
21143
+ /**
21144
+ * Reads the chart's own background so the label sits on a solid surface. The
21145
+ * parameter is typed as the public {@link Background}: the production build
21146
+ * renames the members of structural types it does not see in the public API,
21147
+ * and an anonymous `{ color: string }` here resolved to nothing at runtime.
21148
+ */
21149
+ function resolveBackgroundColor(background) {
21150
+ return background.type === "solid" /* ColorType.Solid */ ? background.color : background.topColor;
21151
+ }
21152
+ /**
21153
+ * Creates a position line group: entry, take profit and stop loss drawn as one
21154
+ * interactive unit.
21155
+ *
21156
+ * @param series - The series the levels are priced against.
21157
+ * @param chart - The chart the series belongs to.
21158
+ * @param options - The levels and their style.
21159
+ *
21160
+ * @example
21161
+ * ```js
21162
+ * const position = createPositionLine(candleSeries, chart, {
21163
+ * entry: { price: 4306.79, badge: '1', formatText: () => '+ 2.32 USD' },
21164
+ * takeProfit: { price: 4349.58, badge: '1', text: '+ 42.79 USD' },
21165
+ * stopLoss: { price: 4266.06, badge: '1', text: '- 40.73 USD' },
21166
+ * onClose: (level) => console.log('close', level),
21167
+ * onDragEnd: (level, price) => console.log(level, 'moved to', price),
21168
+ * });
21169
+ * ```
21170
+ */
21171
+ function createPositionLine(series, chart, options) {
21172
+ return new PositionLine(chart, series, options);
21173
+ }
21174
+
20251
21175
  /** Hit parts that drag the whole object rather than a single handle. */
20252
21176
  const WHOLE_OBJECT_PARTS = new Set([
20253
21177
  'line',
@@ -21127,13 +22051,6 @@ class TrendLineTool extends DrawingToolBase {
21127
22051
  // Clean up references
21128
22052
  this._private__primitive = null;
21129
22053
  this._private__paneView = null;
21130
- // Force chart update by triggering a resize
21131
- const chartElement = this._chart.chartElement?.();
21132
- if (chartElement) {
21133
- const currentWidth = chartElement.clientWidth;
21134
- const currentHeight = chartElement.clientHeight;
21135
- this._chart.resize(currentWidth, currentHeight);
21136
- }
21137
22054
  }
21138
22055
  if (this._private__trendOptions.onRemove) {
21139
22056
  this._private__trendOptions.onRemove();
@@ -21406,12 +22323,6 @@ class HorizontalLineTool extends DrawingToolBase {
21406
22323
  this._series.detachPrimitive(this._private__primitive);
21407
22324
  this._private__primitive = null;
21408
22325
  this._private__paneView = null;
21409
- const chartElement = this._chart.chartElement?.();
21410
- if (chartElement) {
21411
- const currentWidth = chartElement.clientWidth;
21412
- const currentHeight = chartElement.clientHeight;
21413
- this._chart.resize(currentWidth, currentHeight);
21414
- }
21415
22326
  }
21416
22327
  if (this._private__hLineOptions.onRemove) {
21417
22328
  this._private__hLineOptions.onRemove();
@@ -23250,12 +24161,6 @@ class VerticalLineTool extends DrawingToolBase {
23250
24161
  this._series.detachPrimitive(this._private__primitive);
23251
24162
  this._private__primitive = null;
23252
24163
  this._private__paneView = null;
23253
- const chartElement = this._chart.chartElement?.();
23254
- if (chartElement) {
23255
- const currentWidth = chartElement.clientWidth;
23256
- const currentHeight = chartElement.clientHeight;
23257
- this._chart.resize(currentWidth, currentHeight);
23258
- }
23259
24164
  }
23260
24165
  if (this._private__vLineOptions.onRemove) {
23261
24166
  this._private__vLineOptions.onRemove();
@@ -23908,12 +24813,6 @@ class FibonacciTool extends DrawingToolBase {
23908
24813
  this._series.detachPrimitive(this._private__primitive);
23909
24814
  this._private__primitive = null;
23910
24815
  this._private__paneView = null;
23911
- const chartElement = this._chart.chartElement?.();
23912
- if (chartElement) {
23913
- const currentWidth = chartElement.clientWidth;
23914
- const currentHeight = chartElement.clientHeight;
23915
- this._chart.resize(currentWidth, currentHeight);
23916
- }
23917
24816
  }
23918
24817
  if (this._private__drawingManager) {
23919
24818
  this._private__drawingManager._internal_destroy();
@@ -23929,12 +24828,6 @@ class FibonacciTool extends DrawingToolBase {
23929
24828
  this._series.detachPrimitive(this._private__primitive);
23930
24829
  this._private__primitive = null;
23931
24830
  this._private__paneView = null;
23932
- const chartElement = this._chart.chartElement?.();
23933
- if (chartElement) {
23934
- const currentWidth = chartElement.clientWidth;
23935
- const currentHeight = chartElement.clientHeight;
23936
- this._chart.resize(currentWidth, currentHeight);
23937
- }
23938
24831
  }
23939
24832
  if (this._private__fibOptions.onRemove) {
23940
24833
  this._private__fibOptions.onRemove();
@@ -24362,12 +25255,6 @@ class FibonacciExtensionTool extends DrawingToolBase {
24362
25255
  this._series.detachPrimitive(this._private__primitive);
24363
25256
  this._private__primitive = null;
24364
25257
  this._private__paneView = null;
24365
- const chartElement = this._chart.chartElement?.();
24366
- if (chartElement) {
24367
- const currentWidth = chartElement.clientWidth;
24368
- const currentHeight = chartElement.clientHeight;
24369
- this._chart.resize(currentWidth, currentHeight);
24370
- }
24371
25258
  }
24372
25259
  }
24373
25260
  }
@@ -24809,12 +25696,6 @@ class FibonacciFanTool extends DrawingToolBase {
24809
25696
  this._series.detachPrimitive(this._private__primitive);
24810
25697
  this._private__primitive = null;
24811
25698
  this._private__paneView = null;
24812
- const chartElement = this._chart.chartElement?.();
24813
- if (chartElement) {
24814
- const currentWidth = chartElement.clientWidth;
24815
- const currentHeight = chartElement.clientHeight;
24816
- this._chart.resize(currentWidth, currentHeight);
24817
- }
24818
25699
  }
24819
25700
  if (this._private__fanOptions.onRemove) {
24820
25701
  this._private__fanOptions.onRemove();
@@ -25355,12 +26236,6 @@ class RectangleTool extends DrawingToolBase {
25355
26236
  this._series.detachPrimitive(this._private__primitive);
25356
26237
  this._private__primitive = null;
25357
26238
  this._private__paneView = null;
25358
- const chartElement = this._chart.chartElement?.();
25359
- if (chartElement) {
25360
- const currentWidth = chartElement.clientWidth;
25361
- const currentHeight = chartElement.clientHeight;
25362
- this._chart.resize(currentWidth, currentHeight);
25363
- }
25364
26239
  }
25365
26240
  if (this._private__rectOptions.onRemove) {
25366
26241
  this._private__rectOptions.onRemove();
@@ -25821,12 +26696,6 @@ class CircleTool extends DrawingToolBase {
25821
26696
  this._series.detachPrimitive(this._private__primitive);
25822
26697
  this._private__primitive = null;
25823
26698
  this._private__paneView = null;
25824
- const chartElement = this._chart.chartElement?.();
25825
- if (chartElement) {
25826
- const currentWidth = chartElement.clientWidth;
25827
- const currentHeight = chartElement.clientHeight;
25828
- this._chart.resize(currentWidth, currentHeight);
25829
- }
25830
26699
  }
25831
26700
  if (this._private__circleOptions.onRemove) {
25832
26701
  this._private__circleOptions.onRemove();
@@ -26376,12 +27245,6 @@ class ArrowTool extends DrawingToolBase {
26376
27245
  this._series.detachPrimitive(this._private__primitive);
26377
27246
  this._private__primitive = null;
26378
27247
  this._private__paneView = null;
26379
- const chartElement = this._chart.chartElement?.();
26380
- if (chartElement) {
26381
- const currentWidth = chartElement.clientWidth;
26382
- const currentHeight = chartElement.clientHeight;
26383
- this._chart.resize(currentWidth, currentHeight);
26384
- }
26385
27248
  }
26386
27249
  if (this._private__arrowOptions.onRemove) {
26387
27250
  this._private__arrowOptions.onRemove();
@@ -27242,12 +28105,6 @@ class TextTool extends DrawingToolBase {
27242
28105
  this._series.detachPrimitive(this._private__primitive);
27243
28106
  this._private__primitive = null;
27244
28107
  this._private__paneView = null;
27245
- const chartElement = this._chart.chartElement?.();
27246
- if (chartElement) {
27247
- const currentWidth = chartElement.clientWidth;
27248
- const currentHeight = chartElement.clientHeight;
27249
- this._chart.resize(currentWidth, currentHeight);
27250
- }
27251
28108
  }
27252
28109
  if (this._private__textOptions.onRemove) {
27253
28110
  this._private__textOptions.onRemove();
@@ -27830,12 +28687,6 @@ class RulerTool extends DrawingToolBase {
27830
28687
  this._series.detachPrimitive(this._private__primitive);
27831
28688
  this._private__primitive = null;
27832
28689
  this._private__paneView = null;
27833
- const chartElement = this._chart.chartElement?.();
27834
- if (chartElement) {
27835
- const currentWidth = chartElement.clientWidth;
27836
- const currentHeight = chartElement.clientHeight;
27837
- this._chart.resize(currentWidth, currentHeight);
27838
- }
27839
28690
  }
27840
28691
  if (this._private__drawingManager) {
27841
28692
  this._private__drawingManager._internal_destroy();
@@ -28691,12 +29542,6 @@ class PositionTool extends DrawingToolBase {
28691
29542
  this._series.detachPrimitive(this._private__primitive);
28692
29543
  this._private__primitive = null;
28693
29544
  this._private__paneView = null;
28694
- const chartElement = this._chart.chartElement?.();
28695
- if (chartElement) {
28696
- const currentWidth = chartElement.clientWidth;
28697
- const currentHeight = chartElement.clientHeight;
28698
- this._chart.resize(currentWidth, currentHeight);
28699
- }
28700
29545
  }
28701
29546
  if (this._private__positionOptions.onRemove) {
28702
29547
  this._private__positionOptions.onRemove();
@@ -29039,12 +29884,6 @@ class GanttTool extends DrawingToolBase {
29039
29884
  this._series.detachPrimitive(this._private__primitive);
29040
29885
  this._private__primitive = null;
29041
29886
  this._private__paneView = null;
29042
- const chartElement = this._chart.chartElement?.();
29043
- if (chartElement) {
29044
- const currentWidth = chartElement.clientWidth;
29045
- const currentHeight = chartElement.clientHeight;
29046
- this._chart.resize(currentWidth, currentHeight);
29047
- }
29048
29887
  }
29049
29888
  if (this._private__ganttOptions.onRemove) {
29050
29889
  this._private__ganttOptions.onRemove();
@@ -29055,6 +29894,8 @@ function createGanttTool(context, options) {
29055
29894
  return new GanttTool(context, options);
29056
29895
  }
29057
29896
 
29897
+ /** Undo steps kept, each a full snapshot of every drawing. */
29898
+ const UNDO_HISTORY_LIMIT = 100;
29058
29899
  /**
29059
29900
  * Central manager for all drawing tools - TradingView style
29060
29901
  * Handles multiple tools, selection, deletion, and keyboard shortcuts
@@ -29077,6 +29918,8 @@ class DrawingToolsManager {
29077
29918
  this._private__pointerDownHandler = null;
29078
29919
  this._private__pointerUpHandler = null;
29079
29920
  this._private__pointerCancelHandler = null;
29921
+ this._private__lostCaptureHandler = null;
29922
+ this._private__windowPointerUpHandler = null;
29080
29923
  this._private__pointerId = null;
29081
29924
  /** A press that grabbed a tool already selected it; its click must not undo that. */
29082
29925
  this._private__gestureHandled = false;
@@ -29242,6 +30085,9 @@ class DrawingToolsManager {
29242
30085
  return;
29243
30086
  }
29244
30087
  this._private__past.push(this._private__committed);
30088
+ if (this._private__past.length > UNDO_HISTORY_LIMIT) {
30089
+ this._private__past.shift();
30090
+ }
29245
30091
  this._private__future = [];
29246
30092
  this._private__committed = this.serializeAll();
29247
30093
  }
@@ -29621,8 +30467,12 @@ class DrawingToolsManager {
29621
30467
  this._private__completionCheck = null;
29622
30468
  }
29623
30469
  this._private__drawingCompleted._internal_destroy();
30470
+ this._private__selectionChanged._internal_destroy();
29624
30471
  this.clearAll();
29625
30472
  this._private__detachEventHandlers();
30473
+ this._private__past = [];
30474
+ this._private__future = [];
30475
+ this._private__committed = [];
29626
30476
  }
29627
30477
  _private__attachEventHandlers() {
29628
30478
  // Click handler for selection
@@ -29642,9 +30492,15 @@ class DrawingToolsManager {
29642
30492
  this._private__pointerDownHandler = (event) => this._private__handlePointerDown(event);
29643
30493
  this._private__pointerUpHandler = (event) => this._private__handlePointerUp(event);
29644
30494
  this._private__pointerCancelHandler = (event) => this._private__handlePointerUp(event);
30495
+ this._private__lostCaptureHandler = (event) => this._private__handleLostPointerCapture(event);
29645
30496
  chartElement.addEventListener('pointerdown', this._private__pointerDownHandler);
29646
30497
  chartElement.addEventListener('pointerup', this._private__pointerUpHandler);
29647
30498
  chartElement.addEventListener('pointercancel', this._private__pointerCancelHandler);
30499
+ chartElement.addEventListener('lostpointercapture', this._private__lostCaptureHandler);
30500
+ }
30501
+ if (isRunningOnClientSide) {
30502
+ this._private__windowPointerUpHandler = (event) => this._private__handlePointerUp(event);
30503
+ window.addEventListener('pointerup', this._private__windowPointerUpHandler);
29648
30504
  }
29649
30505
  // Keyboard handler for shortcuts
29650
30506
  if (this._private__options.enableKeyboardShortcuts) {
@@ -29677,6 +30533,14 @@ class DrawingToolsManager {
29677
30533
  chartElement.removeEventListener('pointercancel', this._private__pointerCancelHandler);
29678
30534
  this._private__pointerCancelHandler = null;
29679
30535
  }
30536
+ if (this._private__lostCaptureHandler) {
30537
+ chartElement.removeEventListener('lostpointercapture', this._private__lostCaptureHandler);
30538
+ this._private__lostCaptureHandler = null;
30539
+ }
30540
+ }
30541
+ if (this._private__windowPointerUpHandler) {
30542
+ window.removeEventListener('pointerup', this._private__windowPointerUpHandler);
30543
+ this._private__windowPointerUpHandler = null;
29680
30544
  }
29681
30545
  if (this._private__keyboardHandler) {
29682
30546
  document.removeEventListener('keydown', this._private__keyboardHandler);
@@ -29802,7 +30666,12 @@ class DrawingToolsManager {
29802
30666
  this._private__gestureHandled = true;
29803
30667
  this._private__draggedToolId = toolId;
29804
30668
  this._private__pointerId = event.pointerId;
29805
- chartElement.setPointerCapture(event.pointerId);
30669
+ try {
30670
+ chartElement.setPointerCapture(event.pointerId);
30671
+ }
30672
+ catch (error) {
30673
+ this._private__pointerId = null;
30674
+ }
29806
30675
  tool.startDrag(endpoint, anchor);
29807
30676
  // Panning is stopped by disabling it for the gesture, not by preventing
29808
30677
  // the event: preventDefault on pointerdown suppresses the compatibility
@@ -29816,17 +30685,32 @@ class DrawingToolsManager {
29816
30685
  if (event && this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
29817
30686
  return;
29818
30687
  }
29819
- const tool = this._private__tools.get(this._private__draggedToolId);
29820
- if (tool) {
29821
- tool.stopDrag();
29822
- }
29823
- this._private__releasePointer();
29824
- this._private__enableChartInteractions();
30688
+ const draggedToolId = this._private__draggedToolId;
30689
+ // Cleared first: anything below can throw, and a half-finished release
30690
+ // would leave the manager dragging forever.
29825
30691
  this._private__isDragging = false;
29826
30692
  this._private__draggedToolId = null;
30693
+ try {
30694
+ const tool = this._private__tools.get(draggedToolId);
30695
+ if (tool) {
30696
+ tool.stopDrag();
30697
+ }
30698
+ }
30699
+ finally {
30700
+ this._private__releasePointer();
30701
+ this._private__enableChartInteractions();
30702
+ }
29827
30703
  // A finished drag is one step, not one per frame
29828
30704
  this.recordChange();
29829
30705
  }
30706
+ /** Ends the drag when capture is lost without a pointerup ever arriving. */
30707
+ _private__handleLostPointerCapture(event) {
30708
+ if (this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
30709
+ return;
30710
+ }
30711
+ this._private__pointerId = null;
30712
+ this._private__handlePointerUp();
30713
+ }
29830
30714
  /**
29831
30715
  * Pane element of a tool's series. The engine asserts the series has a pane,
29832
30716
  * so the lookup is guarded.
@@ -29877,9 +30761,11 @@ class DrawingToolsManager {
29877
30761
  return;
29878
30762
  }
29879
30763
  const options = this._private__chart.options();
30764
+ // `options()` returns the live object and `applyOptions` merges into it
30765
+ // in place, so a snapshot by reference restores all-false.
29880
30766
  this._private__interactionsBeforeDrag = {
29881
- _internal_handleScroll: options.handleScroll,
29882
- _internal_handleScale: options.handleScale,
30767
+ _internal_handleScroll: clone(options.handleScroll),
30768
+ _internal_handleScale: clone(options.handleScale),
29883
30769
  };
29884
30770
  this._private__chart.applyOptions({
29885
30771
  handleScroll: false,
@@ -29965,7 +30851,7 @@ const customSeriesDefaultOptions = {
29965
30851
  * Returns the current version as a string. For example `'1.0.0'`.
29966
30852
  */
29967
30853
  function version() {
29968
- return "2.2.1";
30854
+ return "2.3.0-dev+202609220108";
29969
30855
  }
29970
30856
 
29971
- 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 };
30857
+ 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 };