@pipsend/charts 2.1.0 → 2.2.1

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.1.0
3
+ * Pipsend Charts v2.2.1
4
4
  * Copyright (c) 2026 Pipsend
5
5
  * Licensed under MIT License
6
6
  * Built on TradingView Lightweight Charts™ (Apache 2.0)
@@ -15916,6 +15916,85 @@
15916
15916
  return volumes !== undefined && volumes.size > 0;
15917
15917
  }
15918
15918
 
15919
+ const TRANSPARENT = 'rgba(0, 0, 0, 0)';
15920
+ /**
15921
+ * Take a series off the screen without hiding it.
15922
+ *
15923
+ * `visible: false` takes down everything hung off the series as well: its
15924
+ * price lines, primitives and price-axis label stop rendering. A transform
15925
+ * that only wants the bars themselves out of the way — Heikin Ashi drawing
15926
+ * over its source — needs the series to stay visible to the engine, so its
15927
+ * paint is made transparent instead and the last-value label and price line
15928
+ * are switched off. Custom series have no known colours; those fall back to
15929
+ * `visible: false`.
15930
+ *
15931
+ * @param series - Series to blank out.
15932
+ * @returns Puts back the options the series had when it was blanked.
15933
+ */
15934
+ function hideSeriesPaint(series) {
15935
+ switch (series.seriesType()) {
15936
+ case 'Candlestick':
15937
+ return blank(series, {
15938
+ upColor: TRANSPARENT,
15939
+ downColor: TRANSPARENT,
15940
+ borderVisible: false,
15941
+ wickVisible: false,
15942
+ });
15943
+ case 'Bar':
15944
+ return blank(series, {
15945
+ upColor: TRANSPARENT,
15946
+ downColor: TRANSPARENT,
15947
+ });
15948
+ case 'Line':
15949
+ return blank(series, {
15950
+ color: TRANSPARENT,
15951
+ crosshairMarkerVisible: false,
15952
+ pointMarkersVisible: false,
15953
+ });
15954
+ case 'Area':
15955
+ return blank(series, {
15956
+ lineColor: TRANSPARENT,
15957
+ topColor: TRANSPARENT,
15958
+ bottomColor: TRANSPARENT,
15959
+ crosshairMarkerVisible: false,
15960
+ pointMarkersVisible: false,
15961
+ });
15962
+ case 'Baseline':
15963
+ return blank(series, {
15964
+ topLineColor: TRANSPARENT,
15965
+ topFillColor1: TRANSPARENT,
15966
+ topFillColor2: TRANSPARENT,
15967
+ bottomLineColor: TRANSPARENT,
15968
+ bottomFillColor1: TRANSPARENT,
15969
+ bottomFillColor2: TRANSPARENT,
15970
+ crosshairMarkerVisible: false,
15971
+ pointMarkersVisible: false,
15972
+ });
15973
+ case 'Histogram':
15974
+ return blank(series, {
15975
+ color: TRANSPARENT,
15976
+ });
15977
+ default:
15978
+ return blank(series, { visible: false });
15979
+ }
15980
+ }
15981
+ function blank(series, paint) {
15982
+ const patch = {
15983
+ ...paint,
15984
+ lastValueVisible: false,
15985
+ priceLineVisible: false,
15986
+ };
15987
+ const before = series.options();
15988
+ const snapshot = {};
15989
+ for (const key of Object.keys(patch)) {
15990
+ snapshot[key] = before[key];
15991
+ }
15992
+ series.applyOptions(patch);
15993
+ return () => {
15994
+ series.applyOptions(snapshot);
15995
+ };
15996
+ }
15997
+
15919
15998
  /**
15920
15999
  * Pins a bounded indicator (RSI, Stochastic…) to a fixed price range.
15921
16000
  *
@@ -17612,9 +17691,9 @@
17612
17691
  * Draw a source series as Heikin Ashi candles.
17613
17692
  *
17614
17693
  * The source series is left in place holding its real prices — it is only
17615
- * hidden — so indicators bound to it keep computing on the true OHLC, and
17616
- * `remove()` puts the chart back exactly as it was. That makes this usable as a
17617
- * chart-type toggle:
17694
+ * painted transparent — so indicators bound to it keep computing on the true
17695
+ * OHLC, its price lines and primitives stay on screen, and `remove()` puts the
17696
+ * chart back exactly as it was. That makes this usable as a chart-type toggle:
17618
17697
  *
17619
17698
  * ```js
17620
17699
  * const ha = applyHeikinAshi(candleSeries, chart);
@@ -17656,10 +17735,16 @@
17656
17735
  priceScaleId: sourceOptions.priceScaleId,
17657
17736
  priceFormat: sourceOptions.priceFormat,
17658
17737
  }, resolved.paneIndex);
17659
- const sourceWasVisible = sourceOptions.visible;
17660
- if (resolved.hideSource === true) {
17661
- series.applyOptions({ visible: false });
17662
- }
17738
+ let restoreSourcePaint = null;
17739
+ const blankSource = (blank) => {
17740
+ if (blank && restoreSourcePaint === null) {
17741
+ restoreSourcePaint = hideSeriesPaint(series);
17742
+ }
17743
+ else if (!blank && restoreSourcePaint !== null) {
17744
+ restoreSourcePaint();
17745
+ restoreSourcePaint = null;
17746
+ }
17747
+ };
17663
17748
  const runtime = bindIndicator({
17664
17749
  _internal_source: series,
17665
17750
  _internal_chart: chart,
@@ -17683,9 +17768,7 @@
17683
17768
  wickUpColor: current.wickUpColor,
17684
17769
  wickDownColor: current.wickDownColor,
17685
17770
  });
17686
- series.applyOptions({
17687
- visible: current.hideSource === true ? false : sourceWasVisible,
17688
- });
17771
+ blankSource(current.hideSource === true);
17689
17772
  },
17690
17773
  });
17691
17774
  const handle = {
@@ -17695,10 +17778,10 @@
17695
17778
  recalculate: runtime.recalculate,
17696
17779
  remove: () => {
17697
17780
  runtime.remove();
17698
- // The source outlives the indicator, so its visibility is ours to put
17781
+ // The source outlives the indicator, so its paint is ours to put
17699
17782
  // back — otherwise removing a Heikin Ashi overlay leaves a blank chart.
17700
17783
  try {
17701
- series.applyOptions({ visible: sourceWasVisible });
17784
+ blankSource(false);
17702
17785
  }
17703
17786
  catch (error) {
17704
17787
  // The series may already be gone if the chart was disposed
@@ -20325,6 +20408,9 @@
20325
20408
  get type() {
20326
20409
  return this._type;
20327
20410
  }
20411
+ isComplete() {
20412
+ return true;
20413
+ }
20328
20414
  /**
20329
20415
  * Lets a tool hand the base its own options object, once, in the constructor.
20330
20416
  *
@@ -20652,6 +20738,7 @@
20652
20738
  this._private__dragStartPoint2 = null;
20653
20739
  // Interactive mode
20654
20740
  this._private__isComplete = false;
20741
+ this._private__interactive = null;
20655
20742
  this._private__previewPoint = null;
20656
20743
  this._private__trendOptions = {
20657
20744
  lineColor: '#2962ff',
@@ -20699,7 +20786,7 @@
20699
20786
  this._private__isComplete = true;
20700
20787
  }
20701
20788
  });
20702
- // Start the interactive drawing mode
20789
+ this._private__interactive = manager;
20703
20790
  manager._internal_startDrawing();
20704
20791
  }
20705
20792
  _private__createPrimitive() {
@@ -21029,7 +21116,14 @@
21029
21116
  _update() {
21030
21117
  this._private__requestUpdate();
21031
21118
  }
21119
+ isComplete() {
21120
+ return this._private__isComplete;
21121
+ }
21032
21122
  remove() {
21123
+ if (this._private__interactive) {
21124
+ this._private__interactive._internal_destroy();
21125
+ this._private__interactive = null;
21126
+ }
21033
21127
  if (this._private__primitive) {
21034
21128
  // Detach from series
21035
21129
  this._series.detachPrimitive(this._private__primitive);
@@ -21936,6 +22030,9 @@
21936
22030
  points() {
21937
22031
  return this._private__points;
21938
22032
  }
22033
+ isComplete() {
22034
+ return this._private__isComplete;
22035
+ }
21939
22036
  remove() {
21940
22037
  this._private__stopDrawing();
21941
22038
  if (this._private__primitive) {
@@ -22406,6 +22503,9 @@
22406
22503
  isHovered() {
22407
22504
  return this._private__isHovered;
22408
22505
  }
22506
+ isComplete() {
22507
+ return this._private__isComplete;
22508
+ }
22409
22509
  remove() {
22410
22510
  this._private__stopDrawing();
22411
22511
  if (this._private__primitive) {
@@ -22870,6 +22970,9 @@
22870
22970
  isHovered() {
22871
22971
  return this._private__isHovered;
22872
22972
  }
22973
+ isComplete() {
22974
+ return this._private__isComplete;
22975
+ }
22873
22976
  remove() {
22874
22977
  this._private__stopDrawing();
22875
22978
  if (this._private__primitive) {
@@ -23800,6 +23903,9 @@
23800
23903
  }
23801
23904
  return false;
23802
23905
  }
23906
+ isComplete() {
23907
+ return this._private__isComplete;
23908
+ }
23803
23909
  remove() {
23804
23910
  if (this._private__primitive) {
23805
23911
  this._series.detachPrimitive(this._private__primitive);
@@ -24690,6 +24796,9 @@
24690
24796
  _update() {
24691
24797
  this._private__requestUpdate();
24692
24798
  }
24799
+ isComplete() {
24800
+ return !this._private__isDrawing;
24801
+ }
24693
24802
  remove() {
24694
24803
  if (this._private__clickHandler) {
24695
24804
  this._chart.unsubscribeClick(this._private__clickHandler);
@@ -25233,6 +25342,9 @@
25233
25342
  _update() {
25234
25343
  this._private__requestUpdate();
25235
25344
  }
25345
+ isComplete() {
25346
+ return !this._private__isDrawing;
25347
+ }
25236
25348
  remove() {
25237
25349
  if (this._private__clickHandler) {
25238
25350
  this._chart.unsubscribeClick(this._private__clickHandler);
@@ -25696,6 +25808,9 @@
25696
25808
  _update() {
25697
25809
  this._private__requestUpdate();
25698
25810
  }
25811
+ isComplete() {
25812
+ return !this._private__isDrawing;
25813
+ }
25699
25814
  remove() {
25700
25815
  if (this._private__clickHandler) {
25701
25816
  this._chart.unsubscribeClick(this._private__clickHandler);
@@ -26238,6 +26353,9 @@
26238
26353
  _update() {
26239
26354
  this._private__requestUpdate();
26240
26355
  }
26356
+ isComplete() {
26357
+ return !this._private__isDrawing;
26358
+ }
26241
26359
  remove() {
26242
26360
  // Clean up click handler
26243
26361
  if (this._private__clickHandler) {
@@ -26804,7 +26922,7 @@
26804
26922
  }
26805
26923
  _private__setupClickOutsideHandler() {
26806
26924
  // Set up click handler to finish editing when clicking outside
26807
- this._private__clickOutsideHandler = this._chart.subscribeClick((param) => {
26925
+ const handler = (param) => {
26808
26926
  if (!this._private__isEditing)
26809
26927
  return;
26810
26928
  // Get click coordinates
@@ -26820,7 +26938,9 @@
26820
26938
  this.remove();
26821
26939
  }
26822
26940
  }
26823
- });
26941
+ };
26942
+ this._private__clickOutsideHandler = handler;
26943
+ this._chart.subscribeClick(handler);
26824
26944
  }
26825
26945
  _private__createPrimitive() {
26826
26946
  this._private__paneView = this._private__createPaneView();
@@ -28969,6 +29089,9 @@
28969
29089
  this._private__selectionChanged = new Delegate();
28970
29090
  this._private__isDragging = false;
28971
29091
  this._private__draggedToolId = null;
29092
+ this._private__pendingToolIds = new Set();
29093
+ this._private__completionCheck = null;
29094
+ this._private__drawingCompleted = new Delegate();
28972
29095
  this._private__chart = chart;
28973
29096
  this._private__series = series;
28974
29097
  this._private__options = {
@@ -29007,9 +29130,63 @@
29007
29130
  addTool(tool, id) {
29008
29131
  const toolId = id ?? tool.id;
29009
29132
  this._private__tools.set(toolId, tool);
29133
+ if (!tool.isComplete()) {
29134
+ this._private__pendingToolIds.add(toolId);
29135
+ }
29010
29136
  this.recordChange();
29011
29137
  return toolId;
29012
29138
  }
29139
+ hasPendingDrawing() {
29140
+ return this._private__pendingToolIds.size > 0;
29141
+ }
29142
+ /** Removes every tool still waiting for points; returns how many were dropped. */
29143
+ cancelPendingDrawings() {
29144
+ if (this._private__pendingToolIds.size === 0) {
29145
+ return 0;
29146
+ }
29147
+ let cancelled = 0;
29148
+ for (const id of Array.from(this._private__pendingToolIds)) {
29149
+ const tool = this._private__tools.get(id);
29150
+ if (tool) {
29151
+ if (this._private__selectedToolId === id) {
29152
+ this._private__applySelection(null);
29153
+ }
29154
+ tool.remove();
29155
+ this._private__tools.delete(id);
29156
+ cancelled++;
29157
+ }
29158
+ }
29159
+ this._private__pendingToolIds.clear();
29160
+ if (cancelled > 0) {
29161
+ this.recordChange();
29162
+ }
29163
+ return cancelled;
29164
+ }
29165
+ subscribeDrawingCompleted(handler) {
29166
+ this._private__drawingCompleted._internal_subscribe(handler);
29167
+ }
29168
+ unsubscribeDrawingCompleted(handler) {
29169
+ this._private__drawingCompleted._internal_unsubscribe(handler);
29170
+ }
29171
+ _private__scheduleCompletionCheck() {
29172
+ if (this._private__pendingToolIds.size === 0 || this._private__completionCheck !== null) {
29173
+ return;
29174
+ }
29175
+ this._private__completionCheck = setTimeout(() => {
29176
+ this._private__completionCheck = null;
29177
+ for (const id of Array.from(this._private__pendingToolIds)) {
29178
+ const tool = this._private__tools.get(id);
29179
+ if (!tool) {
29180
+ this._private__pendingToolIds.delete(id);
29181
+ continue;
29182
+ }
29183
+ if (tool.isComplete()) {
29184
+ this._private__pendingToolIds.delete(id);
29185
+ this._private__drawingCompleted._internal_fire(id);
29186
+ }
29187
+ }
29188
+ }, 0);
29189
+ }
29013
29190
  /**
29014
29191
  * Remove a tool by ID
29015
29192
  */
@@ -29021,6 +29198,7 @@
29021
29198
  }
29022
29199
  tool.remove();
29023
29200
  this._private__tools.delete(id);
29201
+ this._private__pendingToolIds.delete(id);
29024
29202
  this.recordChange();
29025
29203
  return true;
29026
29204
  }
@@ -29220,6 +29398,7 @@
29220
29398
  this._private__applySelection(null);
29221
29399
  this._private__tools.forEach((tool) => tool.remove());
29222
29400
  this._private__tools.clear();
29401
+ this._private__pendingToolIds.clear();
29223
29402
  this.recordChange();
29224
29403
  }
29225
29404
  /**
@@ -29440,6 +29619,11 @@
29440
29619
  * Destroy the manager and cleanup
29441
29620
  */
29442
29621
  destroy() {
29622
+ if (this._private__completionCheck !== null) {
29623
+ clearTimeout(this._private__completionCheck);
29624
+ this._private__completionCheck = null;
29625
+ }
29626
+ this._private__drawingCompleted._internal_destroy();
29443
29627
  this.clearAll();
29444
29628
  this._private__detachEventHandlers();
29445
29629
  }
@@ -29459,8 +29643,8 @@
29459
29643
  const chartElement = this._private__chart.chartElement();
29460
29644
  if (chartElement) {
29461
29645
  this._private__pointerDownHandler = (event) => this._private__handlePointerDown(event);
29462
- this._private__pointerUpHandler = (event) => this._private__handlePointerUp();
29463
- this._private__pointerCancelHandler = (event) => this._private__handlePointerUp();
29646
+ this._private__pointerUpHandler = (event) => this._private__handlePointerUp(event);
29647
+ this._private__pointerCancelHandler = (event) => this._private__handlePointerUp(event);
29464
29648
  chartElement.addEventListener('pointerdown', this._private__pointerDownHandler);
29465
29649
  chartElement.addEventListener('pointerup', this._private__pointerUpHandler);
29466
29650
  chartElement.addEventListener('pointercancel', this._private__pointerCancelHandler);
@@ -29503,6 +29687,7 @@
29503
29687
  }
29504
29688
  }
29505
29689
  _private__handleClick(param) {
29690
+ this._private__scheduleCompletionCheck();
29506
29691
  if (!param.point) {
29507
29692
  return;
29508
29693
  }
@@ -29582,6 +29767,9 @@
29582
29767
  return null;
29583
29768
  }
29584
29769
  _private__handlePointerDown(event) {
29770
+ if (this._private__isDragging) {
29771
+ return;
29772
+ }
29585
29773
  // Cleared for every press, then raised only if this one grabs a drawing
29586
29774
  setInputClaim(this._private__chart, false);
29587
29775
  const chartElement = this._private__chart.chartElement();
@@ -29624,10 +29812,13 @@
29624
29812
  // mouse events, and those are what drive the crosshair the drag reads.
29625
29813
  this._private__disableChartInteractions();
29626
29814
  }
29627
- _private__handlePointerUp() {
29815
+ _private__handlePointerUp(event) {
29628
29816
  if (!this._private__isDragging || this._private__draggedToolId === null) {
29629
29817
  return;
29630
29818
  }
29819
+ if (event && this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
29820
+ return;
29821
+ }
29631
29822
  const tool = this._private__tools.get(this._private__draggedToolId);
29632
29823
  if (tool) {
29633
29824
  tool.stopDrag();
@@ -29685,6 +29876,9 @@
29685
29876
  this._private__pointerId = null;
29686
29877
  }
29687
29878
  _private__disableChartInteractions() {
29879
+ if (this._private__interactionsBeforeDrag !== null) {
29880
+ return;
29881
+ }
29688
29882
  const options = this._private__chart.options();
29689
29883
  this._private__interactionsBeforeDrag = {
29690
29884
  _internal_handleScroll: options.handleScroll,
@@ -29709,6 +29903,14 @@
29709
29903
  });
29710
29904
  }
29711
29905
  _private__handleKeyboard(event) {
29906
+ const target = event.target;
29907
+ const typing = !!target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable);
29908
+ if (typing) {
29909
+ return;
29910
+ }
29911
+ if (event.key === 'Enter') {
29912
+ this._private__scheduleCompletionCheck();
29913
+ }
29712
29914
  // Delete or Backspace to remove selected tool
29713
29915
  if (event.key === 'Delete' || event.key === 'Backspace') {
29714
29916
  if (this.deleteSelected()) {
@@ -29729,8 +29931,8 @@
29729
29931
  }
29730
29932
  return;
29731
29933
  }
29732
- // Escape to deselect
29733
29934
  if (event.key === 'Escape') {
29935
+ this.cancelPendingDrawings();
29734
29936
  this._private__handlePointerUp();
29735
29937
  this._private__deselectAll();
29736
29938
  this.stopDrawing();
@@ -29766,7 +29968,7 @@
29766
29968
  * Returns the current version as a string. For example `'1.0.0'`.
29767
29969
  */
29768
29970
  function version() {
29769
- return "2.1.0";
29971
+ return "2.2.1";
29770
29972
  }
29771
29973
 
29772
29974
  var PipsendChartsModule = /*#__PURE__*/Object.freeze({
@@ -29876,6 +30078,7 @@
29876
30078
  customSeriesDefaultOptions: customSeriesDefaultOptions,
29877
30079
  defaultHorzScaleBehavior: defaultHorzScaleBehavior,
29878
30080
  getPipConfig: getPipConfig,
30081
+ hideSeriesPaint: hideSeriesPaint,
29879
30082
  isBusinessDay: isBusinessDay,
29880
30083
  isUTCTimestamp: isUTCTimestamp,
29881
30084
  setSeriesVolumes: setSeriesVolumes,