@pipsend/charts 2.3.13 → 2.3.15
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.
- package/dist/pipsend-charts.development.mjs +297 -86
- package/dist/pipsend-charts.production.mjs +2 -2
- package/dist/pipsend-charts.standalone.development.js +297 -86
- package/dist/pipsend-charts.standalone.development.mjs +297 -86
- package/dist/pipsend-charts.standalone.production.js +2 -2
- package/dist/pipsend-charts.standalone.production.mjs +2 -2
- package/dist/typings.d.ts +41 -3
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @license
|
|
3
|
-
* Pipsend Charts v2.3.
|
|
3
|
+
* Pipsend Charts v2.3.15
|
|
4
4
|
* Copyright (c) 2026 Pipsend
|
|
5
5
|
* Licensed under MIT License
|
|
6
6
|
* Built on TradingView Lightweight Charts™ (Apache 2.0)
|
|
@@ -14291,6 +14291,9 @@ function calculateShapeHeight(barSpacing) {
|
|
|
14291
14291
|
function shapeMargin(barSpacing) {
|
|
14292
14292
|
return Math.max(size(barSpacing, 0.1), 3 /* Constants.MinShapeMargin */);
|
|
14293
14293
|
}
|
|
14294
|
+
function barGap(barSpacing) {
|
|
14295
|
+
return Math.max(shapeMargin(barSpacing), 10 /* Constants.MinBarGap */);
|
|
14296
|
+
}
|
|
14294
14297
|
function calculateAdjustedMargin(margin, hasSide, hasInBar) {
|
|
14295
14298
|
if (hasSide) {
|
|
14296
14299
|
return margin;
|
|
@@ -14917,17 +14920,18 @@ class SeriesMarkersPaneView {
|
|
|
14917
14920
|
}
|
|
14918
14921
|
let prevTimeIndex = NaN;
|
|
14919
14922
|
const shapeMargin$1 = shapeMargin(timeScale.options().barSpacing);
|
|
14923
|
+
const barGap$1 = barGap(timeScale.options().barSpacing);
|
|
14920
14924
|
const offsets = {
|
|
14921
|
-
_internal_aboveBar:
|
|
14922
|
-
_internal_belowBar:
|
|
14925
|
+
_internal_aboveBar: barGap$1,
|
|
14926
|
+
_internal_belowBar: barGap$1,
|
|
14923
14927
|
};
|
|
14924
14928
|
this._private__data._internal_visibleRange = visibleTimedValues(this._private__data._internal_items, visibleBarsRange, true);
|
|
14925
14929
|
for (let index = this._private__data._internal_visibleRange.from; index < this._private__data._internal_visibleRange.to; index++) {
|
|
14926
14930
|
const marker = seriesMarkers[index];
|
|
14927
14931
|
if (marker.time !== prevTimeIndex) {
|
|
14928
14932
|
// new bar, reset stack counter
|
|
14929
|
-
offsets._internal_aboveBar =
|
|
14930
|
-
offsets._internal_belowBar =
|
|
14933
|
+
offsets._internal_aboveBar = barGap$1;
|
|
14934
|
+
offsets._internal_belowBar = barGap$1;
|
|
14931
14935
|
prevTimeIndex = marker.time;
|
|
14932
14936
|
}
|
|
14933
14937
|
const rendererItem = this._private__data._internal_items[index];
|
|
@@ -15044,7 +15048,7 @@ class SeriesMarkersPrimitive {
|
|
|
15044
15048
|
this._private__cachedBarSpacing = barSpacing;
|
|
15045
15049
|
if (this._private__markers.length > 0) {
|
|
15046
15050
|
const shapeMargin$1 = shapeMargin(barSpacing);
|
|
15047
|
-
const marginValue = calculateShapeHeight(barSpacing) * 1.5 + shapeMargin$1
|
|
15051
|
+
const marginValue = calculateShapeHeight(barSpacing) * 1.5 + shapeMargin$1 + barGap(barSpacing);
|
|
15048
15052
|
const positions = this._private__getMarkerPositions();
|
|
15049
15053
|
this._private__autoScaleMargins = {
|
|
15050
15054
|
above: calculateAdjustedMargin(marginValue, positions.aboveBar, positions.inBar),
|
|
@@ -17547,10 +17551,13 @@ function applyHeikinAshi(series, chart, options = {}) {
|
|
|
17547
17551
|
const blankSource = (blank) => {
|
|
17548
17552
|
if (blank && restoreSourcePaint === null) {
|
|
17549
17553
|
restoreSourcePaint = hideSeriesPaint(series);
|
|
17554
|
+
// Under the blank source, so what hangs off it draws over the candles.
|
|
17555
|
+
haSeries.setSeriesOrder(series.seriesOrder());
|
|
17550
17556
|
}
|
|
17551
17557
|
else if (!blank && restoreSourcePaint !== null) {
|
|
17552
17558
|
restoreSourcePaint();
|
|
17553
17559
|
restoreSourcePaint = null;
|
|
17560
|
+
haSeries.setSeriesOrder(series.seriesOrder() + 1);
|
|
17554
17561
|
}
|
|
17555
17562
|
};
|
|
17556
17563
|
const runtime = bindIndicator({
|
|
@@ -17579,8 +17586,9 @@ function applyHeikinAshi(series, chart, options = {}) {
|
|
|
17579
17586
|
blankSource(current.hideSource === true);
|
|
17580
17587
|
},
|
|
17581
17588
|
});
|
|
17582
|
-
|
|
17583
|
-
|
|
17589
|
+
// Returned as a literal: a local annotation would let the property renamer mangle `series`.
|
|
17590
|
+
return {
|
|
17591
|
+
series: haSeries,
|
|
17584
17592
|
options: runtime.options,
|
|
17585
17593
|
applyOptions: runtime.applyOptions,
|
|
17586
17594
|
recalculate: runtime.recalculate,
|
|
@@ -17596,7 +17604,6 @@ function applyHeikinAshi(series, chart, options = {}) {
|
|
|
17596
17604
|
}
|
|
17597
17605
|
},
|
|
17598
17606
|
};
|
|
17599
|
-
return handle;
|
|
17600
17607
|
}
|
|
17601
17608
|
|
|
17602
17609
|
/**
|
|
@@ -21248,6 +21255,13 @@ class DrawingToolBase {
|
|
|
21248
21255
|
series() {
|
|
21249
21256
|
return this._series;
|
|
21250
21257
|
}
|
|
21258
|
+
/**
|
|
21259
|
+
* Box the selection toolbar anchors to, in pane pixels. Null falls back to
|
|
21260
|
+
* the serialized points, which cannot place a line across the whole pane.
|
|
21261
|
+
*/
|
|
21262
|
+
selectionBox() {
|
|
21263
|
+
return null;
|
|
21264
|
+
}
|
|
21251
21265
|
getState() {
|
|
21252
21266
|
return this._state;
|
|
21253
21267
|
}
|
|
@@ -21924,6 +21938,53 @@ function createTrendLineTool(context, options) {
|
|
|
21924
21938
|
return new TrendLineTool(context, options);
|
|
21925
21939
|
}
|
|
21926
21940
|
|
|
21941
|
+
const END_HANDLE_MARGIN = 10;
|
|
21942
|
+
/**
|
|
21943
|
+
* Hands the next `clicks` clicks on the chart to `onClick`, past the last bar
|
|
21944
|
+
* too. A press that grabbed another drawing does not count.
|
|
21945
|
+
*/
|
|
21946
|
+
function placeByClicks(chart, series, clicks, onClick) {
|
|
21947
|
+
let placed = 0;
|
|
21948
|
+
let handler = null;
|
|
21949
|
+
const stop = () => {
|
|
21950
|
+
if (handler !== null) {
|
|
21951
|
+
chart.unsubscribeClick(handler);
|
|
21952
|
+
handler = null;
|
|
21953
|
+
}
|
|
21954
|
+
};
|
|
21955
|
+
handler = (param) => {
|
|
21956
|
+
if (!param.point || consumeInputClaim(chart)) {
|
|
21957
|
+
return;
|
|
21958
|
+
}
|
|
21959
|
+
const price = series.coordinateToPrice(param.point.y);
|
|
21960
|
+
const time = timeFromCoordinate(chart, series, param.point.x);
|
|
21961
|
+
if (price === null || time === null) {
|
|
21962
|
+
return;
|
|
21963
|
+
}
|
|
21964
|
+
placed++;
|
|
21965
|
+
if (placed >= clicks) {
|
|
21966
|
+
stop();
|
|
21967
|
+
}
|
|
21968
|
+
onClick({ _internal_time: time, _internal_price: price, _internal_x: param.point.x, _internal_y: param.point.y }, placed - 1);
|
|
21969
|
+
};
|
|
21970
|
+
chart.subscribeClick(handler);
|
|
21971
|
+
return {
|
|
21972
|
+
_internal_pending: () => handler !== null,
|
|
21973
|
+
_internal_stop: stop,
|
|
21974
|
+
};
|
|
21975
|
+
}
|
|
21976
|
+
/** A fifth of the pane, and never less than a bar. */
|
|
21977
|
+
function defaultWidth(chart) {
|
|
21978
|
+
const timeScale = chart.timeScale();
|
|
21979
|
+
return Math.max(timeScale.width() / 5, timeScale.options().barSpacing);
|
|
21980
|
+
}
|
|
21981
|
+
/** Kept inside the pane: past it, the handles on the end hide under the price axis. */
|
|
21982
|
+
function placedEndX(chart, x) {
|
|
21983
|
+
const timeScale = chart.timeScale();
|
|
21984
|
+
const onScreen = Math.min(x + defaultWidth(chart), timeScale.width() - END_HANDLE_MARGIN);
|
|
21985
|
+
return Math.max(onScreen, x + timeScale.options().barSpacing);
|
|
21986
|
+
}
|
|
21987
|
+
|
|
21927
21988
|
class HorizontalLinePaneRenderer {
|
|
21928
21989
|
constructor(tool) {
|
|
21929
21990
|
this._private__tool = tool;
|
|
@@ -21964,6 +22025,7 @@ class HorizontalLineTool extends DrawingToolBase {
|
|
|
21964
22025
|
this._private__isDragging = false;
|
|
21965
22026
|
this._private__grab = null;
|
|
21966
22027
|
this._private__moveStartPrice = 0;
|
|
22028
|
+
this._private__placement = null;
|
|
21967
22029
|
this._private__hLineOptions = {
|
|
21968
22030
|
lineColor: '#2962ff',
|
|
21969
22031
|
lineWidth: 2,
|
|
@@ -21976,6 +22038,26 @@ class HorizontalLineTool extends DrawingToolBase {
|
|
|
21976
22038
|
};
|
|
21977
22039
|
this._registerOptions(this._private__hLineOptions);
|
|
21978
22040
|
this._private__createPrimitive();
|
|
22041
|
+
if (this._private__hLineOptions.interactive) {
|
|
22042
|
+
this._private__placement = placeByClicks(this._chart, this._series, 1, (point) => this._private__placeAt(point));
|
|
22043
|
+
}
|
|
22044
|
+
}
|
|
22045
|
+
_private__placeAt(point) {
|
|
22046
|
+
this._private__hLineOptions.price = point._internal_price;
|
|
22047
|
+
if (this._private__hLineOptions.startTime !== undefined) {
|
|
22048
|
+
this._private__hLineOptions.startTime = point._internal_time;
|
|
22049
|
+
}
|
|
22050
|
+
this._private__requestUpdate();
|
|
22051
|
+
}
|
|
22052
|
+
isComplete() {
|
|
22053
|
+
return !this._private__placement?._internal_pending();
|
|
22054
|
+
}
|
|
22055
|
+
selectionBox() {
|
|
22056
|
+
const y = this._private__hLineOptions.price === undefined ? null : this._series.priceToCoordinate(this._private__hLineOptions.price);
|
|
22057
|
+
if (y === null) {
|
|
22058
|
+
return null;
|
|
22059
|
+
}
|
|
22060
|
+
return { left: this._private__startX(), right: this._chart.timeScale().width(), top: y, bottom: y };
|
|
21979
22061
|
}
|
|
21980
22062
|
_private__createPrimitive() {
|
|
21981
22063
|
this._private__paneView = this._private__createPaneView();
|
|
@@ -22013,7 +22095,7 @@ class HorizontalLineTool extends DrawingToolBase {
|
|
|
22013
22095
|
return coordinateFromTime(this._chart, this._series, this._private__hLineOptions.startTime) ?? 0;
|
|
22014
22096
|
}
|
|
22015
22097
|
drawToCanvas(ctx, horizontalPixelRatio, verticalPixelRatio) {
|
|
22016
|
-
if (this._private__hLineOptions.price === undefined)
|
|
22098
|
+
if (!this.isComplete() || this._private__hLineOptions.price === undefined)
|
|
22017
22099
|
return;
|
|
22018
22100
|
const y = (this._series.priceToCoordinate(this._private__hLineOptions.price) ?? 0) * verticalPixelRatio;
|
|
22019
22101
|
const chartWidth = this._chart.chartElement().clientWidth * horizontalPixelRatio;
|
|
@@ -22107,7 +22189,7 @@ class HorizontalLineTool extends DrawingToolBase {
|
|
|
22107
22189
|
return this.hitTest(x, y) ? toolHoveredItem(this.id, 'body', false) : null;
|
|
22108
22190
|
}
|
|
22109
22191
|
hitTest(x, y) {
|
|
22110
|
-
if (this._private__hLineOptions.price === undefined) {
|
|
22192
|
+
if (!this.isComplete() || this._private__hLineOptions.price === undefined) {
|
|
22111
22193
|
return false;
|
|
22112
22194
|
}
|
|
22113
22195
|
const lineY = this._series.priceToCoordinate(this._private__hLineOptions.price) ?? 0;
|
|
@@ -22182,6 +22264,7 @@ class HorizontalLineTool extends DrawingToolBase {
|
|
|
22182
22264
|
this._private__requestUpdate();
|
|
22183
22265
|
}
|
|
22184
22266
|
remove() {
|
|
22267
|
+
this._private__placement?._internal_stop();
|
|
22185
22268
|
if (this._private__primitive) {
|
|
22186
22269
|
this._series.detachPrimitive(this._private__primitive);
|
|
22187
22270
|
this._private__primitive = null;
|
|
@@ -22241,6 +22324,7 @@ class CrossLineTool extends DrawingToolBase {
|
|
|
22241
22324
|
this._private__grab = null;
|
|
22242
22325
|
this._private__moveStartTime = 0;
|
|
22243
22326
|
this._private__moveStartPrice = 0;
|
|
22327
|
+
this._private__placement = null;
|
|
22244
22328
|
this._private__crossOptions = {
|
|
22245
22329
|
lineColor: '#787b86',
|
|
22246
22330
|
lineWidth: 1,
|
|
@@ -22250,6 +22334,16 @@ class CrossLineTool extends DrawingToolBase {
|
|
|
22250
22334
|
};
|
|
22251
22335
|
this._registerOptions(this._private__crossOptions);
|
|
22252
22336
|
this._private__createPrimitive();
|
|
22337
|
+
if (this._private__crossOptions.interactive) {
|
|
22338
|
+
this._private__placement = placeByClicks(this._chart, this._series, 1, (point) => {
|
|
22339
|
+
this._private__crossOptions.time = point._internal_time;
|
|
22340
|
+
this._private__crossOptions.price = point._internal_price;
|
|
22341
|
+
this._private__requestUpdate();
|
|
22342
|
+
});
|
|
22343
|
+
}
|
|
22344
|
+
}
|
|
22345
|
+
isComplete() {
|
|
22346
|
+
return !this._private__placement?._internal_pending();
|
|
22253
22347
|
}
|
|
22254
22348
|
_private__createPrimitive() {
|
|
22255
22349
|
this._private__paneView = new CrossLinePaneView(this);
|
|
@@ -22277,7 +22371,7 @@ class CrossLineTool extends DrawingToolBase {
|
|
|
22277
22371
|
this._private__requestUpdate();
|
|
22278
22372
|
}
|
|
22279
22373
|
_private__coordinates() {
|
|
22280
|
-
if (this._private__crossOptions.time === undefined || this._private__crossOptions.price === undefined) {
|
|
22374
|
+
if (!this.isComplete() || this._private__crossOptions.time === undefined || this._private__crossOptions.price === undefined) {
|
|
22281
22375
|
return null;
|
|
22282
22376
|
}
|
|
22283
22377
|
const x = coordinateFromTime(this._chart, this._series, this._private__crossOptions.time);
|
|
@@ -22400,6 +22494,7 @@ class CrossLineTool extends DrawingToolBase {
|
|
|
22400
22494
|
return this._private__isHovered;
|
|
22401
22495
|
}
|
|
22402
22496
|
remove() {
|
|
22497
|
+
this._private__placement?._internal_stop();
|
|
22403
22498
|
if (this._private__primitive) {
|
|
22404
22499
|
try {
|
|
22405
22500
|
this._series.detachPrimitive(this._private__primitive);
|
|
@@ -23822,6 +23917,7 @@ class VerticalLineTool extends DrawingToolBase {
|
|
|
23822
23917
|
this._private__isDragging = false;
|
|
23823
23918
|
this._private__grab = null;
|
|
23824
23919
|
this._private__moveStartTime = 0;
|
|
23920
|
+
this._private__placement = null;
|
|
23825
23921
|
this._private__vLineOptions = {
|
|
23826
23922
|
lineColor: '#787b86',
|
|
23827
23923
|
lineWidth: 1,
|
|
@@ -23833,6 +23929,29 @@ class VerticalLineTool extends DrawingToolBase {
|
|
|
23833
23929
|
};
|
|
23834
23930
|
this._registerOptions(this._private__vLineOptions);
|
|
23835
23931
|
this._private__createPrimitive();
|
|
23932
|
+
if (this._private__vLineOptions.interactive) {
|
|
23933
|
+
this._private__placement = placeByClicks(this._chart, this._series, 1, (point) => {
|
|
23934
|
+
this._private__vLineOptions.time = point._internal_time;
|
|
23935
|
+
this._private__requestUpdate();
|
|
23936
|
+
});
|
|
23937
|
+
}
|
|
23938
|
+
}
|
|
23939
|
+
isComplete() {
|
|
23940
|
+
return !this._private__placement?._internal_pending();
|
|
23941
|
+
}
|
|
23942
|
+
selectionBox() {
|
|
23943
|
+
const x = coordinateFromTime(this._chart, this._series, this._private__vLineOptions.time);
|
|
23944
|
+
if (x === null) {
|
|
23945
|
+
return null;
|
|
23946
|
+
}
|
|
23947
|
+
let middle;
|
|
23948
|
+
try {
|
|
23949
|
+
middle = this._series.getPane().getHeight() / 2;
|
|
23950
|
+
}
|
|
23951
|
+
catch (error) {
|
|
23952
|
+
return null;
|
|
23953
|
+
}
|
|
23954
|
+
return { left: x, right: x, top: middle, bottom: middle };
|
|
23836
23955
|
}
|
|
23837
23956
|
_private__createPrimitive() {
|
|
23838
23957
|
this._private__paneView = this._private__createPaneView();
|
|
@@ -23863,7 +23982,7 @@ class VerticalLineTool extends DrawingToolBase {
|
|
|
23863
23982
|
return new VerticalLinePaneView(this);
|
|
23864
23983
|
}
|
|
23865
23984
|
drawToCanvas(ctx, horizontalPixelRatio, verticalPixelRatio) {
|
|
23866
|
-
if (this._private__vLineOptions.time === undefined)
|
|
23985
|
+
if (!this.isComplete() || this._private__vLineOptions.time === undefined)
|
|
23867
23986
|
return;
|
|
23868
23987
|
const x = (coordinateFromTime(this._chart, this._series, this._private__vLineOptions.time) ?? 0) * horizontalPixelRatio;
|
|
23869
23988
|
const chartHeight = this._chart.chartElement().clientHeight * verticalPixelRatio;
|
|
@@ -23950,7 +24069,7 @@ class VerticalLineTool extends DrawingToolBase {
|
|
|
23950
24069
|
return this.hitTest(x, y) ? toolHoveredItem(this.id, 'body', false) : null;
|
|
23951
24070
|
}
|
|
23952
24071
|
hitTest(x, y) {
|
|
23953
|
-
if (this._private__vLineOptions.time === undefined) {
|
|
24072
|
+
if (!this.isComplete() || this._private__vLineOptions.time === undefined) {
|
|
23954
24073
|
return false;
|
|
23955
24074
|
}
|
|
23956
24075
|
const lineX = coordinateFromTime(this._chart, this._series, this._private__vLineOptions.time) ?? 0;
|
|
@@ -24020,6 +24139,7 @@ class VerticalLineTool extends DrawingToolBase {
|
|
|
24020
24139
|
this._private__requestUpdate();
|
|
24021
24140
|
}
|
|
24022
24141
|
remove() {
|
|
24142
|
+
this._private__placement?._internal_stop();
|
|
24023
24143
|
if (this._private__primitive) {
|
|
24024
24144
|
this._series.detachPrimitive(this._private__primitive);
|
|
24025
24145
|
this._private__primitive = null;
|
|
@@ -24741,6 +24861,7 @@ class FibonacciExtensionTool extends DrawingToolBase {
|
|
|
24741
24861
|
this._private__isHovered = false;
|
|
24742
24862
|
this._private__isDragging = false;
|
|
24743
24863
|
this._private__dragTarget = null;
|
|
24864
|
+
this._private__placement = null;
|
|
24744
24865
|
this._private__fibOptions = {
|
|
24745
24866
|
levels: [
|
|
24746
24867
|
{ level: 0, color: '#787B86', label: '0%' },
|
|
@@ -24756,6 +24877,20 @@ class FibonacciExtensionTool extends DrawingToolBase {
|
|
|
24756
24877
|
...options,
|
|
24757
24878
|
};
|
|
24758
24879
|
this._private__createPrimitive();
|
|
24880
|
+
if (this._private__fibOptions.interactive) {
|
|
24881
|
+
this._private__placement = placeByClicks(this._chart, this._series, 3, (point, index) => {
|
|
24882
|
+
const placed = { time: point._internal_time, price: point._internal_price };
|
|
24883
|
+
if (index === 0) {
|
|
24884
|
+
this.setPoint1(placed);
|
|
24885
|
+
}
|
|
24886
|
+
else if (index === 1) {
|
|
24887
|
+
this.setPoint2(placed);
|
|
24888
|
+
}
|
|
24889
|
+
else {
|
|
24890
|
+
this.setPoint3(placed);
|
|
24891
|
+
}
|
|
24892
|
+
});
|
|
24893
|
+
}
|
|
24759
24894
|
}
|
|
24760
24895
|
_private__createPrimitive() {
|
|
24761
24896
|
this._private__paneView = this._private__createPaneView();
|
|
@@ -24813,7 +24948,7 @@ class FibonacciExtensionTool extends DrawingToolBase {
|
|
|
24813
24948
|
this._private__requestUpdate();
|
|
24814
24949
|
}
|
|
24815
24950
|
isComplete() {
|
|
24816
|
-
return !!(this._private__fibOptions.point1 && this._private__fibOptions.point2 && this._private__fibOptions.point3);
|
|
24951
|
+
return !this._private__placement?._internal_pending() && !!(this._private__fibOptions.point1 && this._private__fibOptions.point2 && this._private__fibOptions.point3);
|
|
24817
24952
|
}
|
|
24818
24953
|
setColor(color) {
|
|
24819
24954
|
this._private__fibOptions.lineColor = color;
|
|
@@ -25108,6 +25243,7 @@ class FibonacciExtensionTool extends DrawingToolBase {
|
|
|
25108
25243
|
this._private__requestUpdate();
|
|
25109
25244
|
}
|
|
25110
25245
|
remove() {
|
|
25246
|
+
this._private__placement?._internal_stop();
|
|
25111
25247
|
if (this._private__primitive) {
|
|
25112
25248
|
this._series.detachPrimitive(this._private__primitive);
|
|
25113
25249
|
this._private__primitive = null;
|
|
@@ -27673,6 +27809,7 @@ class TextTool extends DrawingToolBase {
|
|
|
27673
27809
|
this._private__moveStart = null;
|
|
27674
27810
|
this._private__isEditing = false;
|
|
27675
27811
|
this._private__clickOutsideHandler = null;
|
|
27812
|
+
this._private__placement = null;
|
|
27676
27813
|
this._private__textOptions = {
|
|
27677
27814
|
text: 'Double-click to edit',
|
|
27678
27815
|
fontSize: 14,
|
|
@@ -27693,6 +27830,14 @@ class TextTool extends DrawingToolBase {
|
|
|
27693
27830
|
this._registerOptions(this._private__textOptions);
|
|
27694
27831
|
this._private__createPrimitive();
|
|
27695
27832
|
this._private__setupClickOutsideHandler();
|
|
27833
|
+
if (this._private__textOptions.interactive) {
|
|
27834
|
+
this._private__placement = placeByClicks(this._chart, this._series, 1, (point) => {
|
|
27835
|
+
this.setPosition(point._internal_time, point._internal_price);
|
|
27836
|
+
if (this._private__textOptions.onComplete) {
|
|
27837
|
+
this._private__textOptions.onComplete();
|
|
27838
|
+
}
|
|
27839
|
+
});
|
|
27840
|
+
}
|
|
27696
27841
|
}
|
|
27697
27842
|
_private__setupClickOutsideHandler() {
|
|
27698
27843
|
// Set up click handler to finish editing when clicking outside
|
|
@@ -27778,7 +27923,7 @@ class TextTool extends DrawingToolBase {
|
|
|
27778
27923
|
this._private__requestUpdate();
|
|
27779
27924
|
}
|
|
27780
27925
|
isComplete() {
|
|
27781
|
-
return !!(this._private__textOptions.time && this._private__textOptions.price !== undefined);
|
|
27926
|
+
return !this._private__placement?._internal_pending() && !!(this._private__textOptions.time && this._private__textOptions.price !== undefined);
|
|
27782
27927
|
}
|
|
27783
27928
|
setColor(color) {
|
|
27784
27929
|
this._private__textOptions.textColor = color;
|
|
@@ -28061,6 +28206,7 @@ class TextTool extends DrawingToolBase {
|
|
|
28061
28206
|
};
|
|
28062
28207
|
}
|
|
28063
28208
|
remove() {
|
|
28209
|
+
this._private__placement?._internal_stop();
|
|
28064
28210
|
// Clean up click handler
|
|
28065
28211
|
if (this._private__clickOutsideHandler) {
|
|
28066
28212
|
this._chart.unsubscribeClick(this._private__clickOutsideHandler);
|
|
@@ -28919,6 +29065,7 @@ class PositionTool extends DrawingToolBase {
|
|
|
28919
29065
|
this._private__paneView = null;
|
|
28920
29066
|
this._private__isSelected = false;
|
|
28921
29067
|
this._private__isHovered = false;
|
|
29068
|
+
this._private__placement = null;
|
|
28922
29069
|
this._private__isDragging = false;
|
|
28923
29070
|
this._private__dragTarget = null;
|
|
28924
29071
|
this._private__grab = null;
|
|
@@ -28941,6 +29088,32 @@ class PositionTool extends DrawingToolBase {
|
|
|
28941
29088
|
// Create primitive and setup
|
|
28942
29089
|
this._private__createPrimitive();
|
|
28943
29090
|
this._private__updateMetrics();
|
|
29091
|
+
if (this._private__positionOptions.interactive) {
|
|
29092
|
+
this._private__placement = placeByClicks(this._chart, this._series, 1, (point) => this._private__placeAt(point));
|
|
29093
|
+
}
|
|
29094
|
+
}
|
|
29095
|
+
_private__placeAt(point) {
|
|
29096
|
+
const options = this._private__positionOptions;
|
|
29097
|
+
const shift = point._internal_price - options.entryPrice;
|
|
29098
|
+
options.entryPrice = point._internal_price;
|
|
29099
|
+
options.entryTime = point._internal_time;
|
|
29100
|
+
if (options.stopLoss !== undefined) {
|
|
29101
|
+
options.stopLoss += shift;
|
|
29102
|
+
}
|
|
29103
|
+
if (options.takeProfit !== undefined) {
|
|
29104
|
+
options.takeProfit += shift;
|
|
29105
|
+
}
|
|
29106
|
+
options.endTime = timeFromCoordinate(this._chart, this._series, placedEndX(this._chart, point._internal_x)) ?? undefined;
|
|
29107
|
+
this._private__updateMetrics();
|
|
29108
|
+
this._private__requestUpdate();
|
|
29109
|
+
}
|
|
29110
|
+
isComplete() {
|
|
29111
|
+
return !this._private__placement?._internal_pending();
|
|
29112
|
+
}
|
|
29113
|
+
_private__span() {
|
|
29114
|
+
const entryX = coordinateFromTime(this._chart, this._series, this._private__positionOptions.entryTime) ?? 0;
|
|
29115
|
+
const endX = coordinateFromTime(this._chart, this._series, this._private__positionOptions.endTime) ?? entryX + defaultWidth(this._chart);
|
|
29116
|
+
return { _internal_entryX: entryX, _internal_endX: endX };
|
|
28944
29117
|
}
|
|
28945
29118
|
_private__createPrimitive() {
|
|
28946
29119
|
// Create and cache the paneView once
|
|
@@ -28972,6 +29145,9 @@ class PositionTool extends DrawingToolBase {
|
|
|
28972
29145
|
return new PositionPaneView(this);
|
|
28973
29146
|
}
|
|
28974
29147
|
drawToCanvas(ctx, horizontalPixelRatio, verticalPixelRatio) {
|
|
29148
|
+
if (!this.isComplete()) {
|
|
29149
|
+
return;
|
|
29150
|
+
}
|
|
28975
29151
|
// Draw profit rectangle (green)
|
|
28976
29152
|
if (this._private__profitRect && this._private__positionOptions.takeProfit) {
|
|
28977
29153
|
const timeScale = this._chart.timeScale();
|
|
@@ -29005,16 +29181,9 @@ class PositionTool extends DrawingToolBase {
|
|
|
29005
29181
|
}
|
|
29006
29182
|
}
|
|
29007
29183
|
_private__drawRectangle(ctx, rect, horizontalPixelRatio, verticalPixelRatio, timeScale) {
|
|
29008
|
-
const
|
|
29009
|
-
|
|
29010
|
-
|
|
29011
|
-
if (this._private__positionOptions.endTime) {
|
|
29012
|
-
endX = (coordinateFromTime(this._chart, this._series, this._private__positionOptions.endTime) ?? 0) * horizontalPixelRatio;
|
|
29013
|
-
}
|
|
29014
|
-
else {
|
|
29015
|
-
const chartWidth = this._chart.chartElement().clientWidth * horizontalPixelRatio;
|
|
29016
|
-
endX = chartWidth;
|
|
29017
|
-
}
|
|
29184
|
+
const span = this._private__span();
|
|
29185
|
+
const entryX = span._internal_entryX * horizontalPixelRatio;
|
|
29186
|
+
const endX = span._internal_endX * horizontalPixelRatio;
|
|
29018
29187
|
const y1 = (this._series.priceToCoordinate(rect._internal_price1) ?? 0) * verticalPixelRatio;
|
|
29019
29188
|
const y2 = (this._series.priceToCoordinate(rect._internal_price2) ?? 0) * verticalPixelRatio;
|
|
29020
29189
|
// Draw filled rectangle with semi-transparent fill
|
|
@@ -29029,16 +29198,10 @@ class PositionTool extends DrawingToolBase {
|
|
|
29029
29198
|
ctx.stroke();
|
|
29030
29199
|
}
|
|
29031
29200
|
_private__drawEntryLine(ctx, horizontalPixelRatio, verticalPixelRatio, timeScale) {
|
|
29032
|
-
const
|
|
29201
|
+
const span = this._private__span();
|
|
29202
|
+
const entryX = span._internal_entryX * horizontalPixelRatio;
|
|
29203
|
+
const endX = span._internal_endX * horizontalPixelRatio;
|
|
29033
29204
|
const entryY = (this._series.priceToCoordinate(this._private__positionOptions.entryPrice) ?? 0) * verticalPixelRatio;
|
|
29034
|
-
let endX;
|
|
29035
|
-
if (this._private__positionOptions.endTime) {
|
|
29036
|
-
endX = (coordinateFromTime(this._chart, this._series, this._private__positionOptions.endTime) ?? 0) * horizontalPixelRatio;
|
|
29037
|
-
}
|
|
29038
|
-
else {
|
|
29039
|
-
const chartWidth = this._chart.chartElement().clientWidth * horizontalPixelRatio;
|
|
29040
|
-
endX = chartWidth;
|
|
29041
|
-
}
|
|
29042
29205
|
// Draw horizontal entry line (divider)
|
|
29043
29206
|
const lineColor = this._private__positionOptions.entryLineColor;
|
|
29044
29207
|
ctx.strokeStyle = lineColor;
|
|
@@ -29152,9 +29315,11 @@ class PositionTool extends DrawingToolBase {
|
|
|
29152
29315
|
const padding = 6 * horizontalPixelRatio;
|
|
29153
29316
|
const labelWidth = textMetrics.width + padding * 2;
|
|
29154
29317
|
const labelHeight = 20 * horizontalPixelRatio;
|
|
29155
|
-
//
|
|
29318
|
+
// Outside the box, so a label wider than it does not cover the handles on its edge
|
|
29319
|
+
const entryY = (this._series.priceToCoordinate(this._private__positionOptions.entryPrice) ?? 0) * verticalPixelRatio;
|
|
29320
|
+
const gap = 3 * verticalPixelRatio;
|
|
29156
29321
|
const labelX = entryX + 8 * horizontalPixelRatio;
|
|
29157
|
-
const labelY = y - labelHeight
|
|
29322
|
+
const labelY = y <= entryY ? y - labelHeight - gap : y + gap;
|
|
29158
29323
|
// Draw label background
|
|
29159
29324
|
ctx.fillStyle = rect._internal_color;
|
|
29160
29325
|
ctx.fillRect(labelX, labelY, labelWidth, labelHeight);
|
|
@@ -29162,10 +29327,12 @@ class PositionTool extends DrawingToolBase {
|
|
|
29162
29327
|
ctx.fillStyle = '#ffffff';
|
|
29163
29328
|
ctx.textAlign = 'left';
|
|
29164
29329
|
ctx.textBaseline = 'middle';
|
|
29165
|
-
ctx.fillText(labelText, labelX + padding,
|
|
29330
|
+
ctx.fillText(labelText, labelX + padding, labelY + labelHeight / 2);
|
|
29166
29331
|
}
|
|
29167
29332
|
_private__drawEndpoint(ctx, price, color, horizontalPixelRatio, verticalPixelRatio, timeScale) {
|
|
29168
|
-
const
|
|
29333
|
+
const span = this._private__span();
|
|
29334
|
+
const entryX = span._internal_entryX * horizontalPixelRatio;
|
|
29335
|
+
const endX = span._internal_endX * horizontalPixelRatio;
|
|
29169
29336
|
const y = (this._series.priceToCoordinate(price) ?? 0) * verticalPixelRatio;
|
|
29170
29337
|
// Draw circle endpoint at entry
|
|
29171
29338
|
const circleColor = color;
|
|
@@ -29177,14 +29344,6 @@ class PositionTool extends DrawingToolBase {
|
|
|
29177
29344
|
ctx.fill();
|
|
29178
29345
|
ctx.stroke();
|
|
29179
29346
|
// Draw square endpoint at the right edge
|
|
29180
|
-
let endX;
|
|
29181
|
-
if (this._private__positionOptions.endTime) {
|
|
29182
|
-
endX = (coordinateFromTime(this._chart, this._series, this._private__positionOptions.endTime) ?? 0) * horizontalPixelRatio;
|
|
29183
|
-
}
|
|
29184
|
-
else {
|
|
29185
|
-
const chartWidth = this._chart.chartElement().clientWidth * horizontalPixelRatio;
|
|
29186
|
-
endX = chartWidth - 10 * horizontalPixelRatio;
|
|
29187
|
-
}
|
|
29188
29347
|
const size = 8 * horizontalPixelRatio;
|
|
29189
29348
|
const squareColor = color;
|
|
29190
29349
|
ctx.fillStyle = squareColor;
|
|
@@ -29305,18 +29464,12 @@ class PositionTool extends DrawingToolBase {
|
|
|
29305
29464
|
return this.hitTest(x, y) ? toolHoveredItem(this.id, 'body', false) : null;
|
|
29306
29465
|
}
|
|
29307
29466
|
hitTest(x, y) {
|
|
29308
|
-
if (!this._private__positionOptions.stopLoss && !this._private__positionOptions.takeProfit) {
|
|
29467
|
+
if (!this.isComplete() || (!this._private__positionOptions.stopLoss && !this._private__positionOptions.takeProfit)) {
|
|
29309
29468
|
return false;
|
|
29310
29469
|
}
|
|
29311
|
-
const
|
|
29312
|
-
|
|
29313
|
-
|
|
29314
|
-
endX = coordinateFromTime(this._chart, this._series, this._private__positionOptions.endTime) ?? 0;
|
|
29315
|
-
}
|
|
29316
|
-
else {
|
|
29317
|
-
const chartWidth = this._chart.chartElement().clientWidth;
|
|
29318
|
-
endX = chartWidth;
|
|
29319
|
-
}
|
|
29470
|
+
const { _internal_entryX: entryX, _internal_endX: endX } = this._private__span();
|
|
29471
|
+
const left = Math.min(entryX, endX);
|
|
29472
|
+
const right = Math.max(entryX, endX);
|
|
29320
29473
|
// Check if inside the entire Position Tool area (rectangles)
|
|
29321
29474
|
if (this._private__positionOptions.takeProfit && this._private__positionOptions.stopLoss) {
|
|
29322
29475
|
const tpY = this._series.priceToCoordinate(this._private__positionOptions.takeProfit) ?? 0;
|
|
@@ -29324,7 +29477,7 @@ class PositionTool extends DrawingToolBase {
|
|
|
29324
29477
|
const minY = Math.min(tpY, slY);
|
|
29325
29478
|
const maxY = Math.max(tpY, slY);
|
|
29326
29479
|
// Check if inside the rectangle bounds (entire tool area)
|
|
29327
|
-
if (x >=
|
|
29480
|
+
if (x >= left && x <= right && y >= minY && y <= maxY) {
|
|
29328
29481
|
return true;
|
|
29329
29482
|
}
|
|
29330
29483
|
// Also check entry line area
|
|
@@ -29336,15 +29489,12 @@ class PositionTool extends DrawingToolBase {
|
|
|
29336
29489
|
return false;
|
|
29337
29490
|
}
|
|
29338
29491
|
hitTestEndpoint(x, y) {
|
|
29339
|
-
|
|
29340
|
-
|
|
29341
|
-
if (this._private__positionOptions.endTime) {
|
|
29342
|
-
endX = coordinateFromTime(this._chart, this._series, this._private__positionOptions.endTime) ?? 0;
|
|
29343
|
-
}
|
|
29344
|
-
else {
|
|
29345
|
-
const chartWidth = this._chart.chartElement().clientWidth;
|
|
29346
|
-
endX = chartWidth;
|
|
29492
|
+
if (!this.isComplete()) {
|
|
29493
|
+
return null;
|
|
29347
29494
|
}
|
|
29495
|
+
const { _internal_entryX: entryX, _internal_endX: endX } = this._private__span();
|
|
29496
|
+
const left = Math.min(entryX, endX);
|
|
29497
|
+
const right = Math.max(entryX, endX);
|
|
29348
29498
|
const tolerance = 10;
|
|
29349
29499
|
// Check TP left endpoint (circle)
|
|
29350
29500
|
if (this._private__positionOptions.takeProfit) {
|
|
@@ -29381,7 +29531,7 @@ class PositionTool extends DrawingToolBase {
|
|
|
29381
29531
|
// Check entry line (middle divider line) - higher priority than 'move'
|
|
29382
29532
|
const entryY = this._series.priceToCoordinate(this._private__positionOptions.entryPrice) ?? 0;
|
|
29383
29533
|
const lineTolerance = 8;
|
|
29384
|
-
if (x >=
|
|
29534
|
+
if (x >= left && x <= right && Math.abs(y - entryY) <= lineTolerance) {
|
|
29385
29535
|
return 'entry';
|
|
29386
29536
|
}
|
|
29387
29537
|
// Check if clicking on the body (rectangles) for moving entire tool
|
|
@@ -29391,7 +29541,7 @@ class PositionTool extends DrawingToolBase {
|
|
|
29391
29541
|
const minY = Math.min(tpY, slY);
|
|
29392
29542
|
const maxY = Math.max(tpY, slY);
|
|
29393
29543
|
// Check if inside the rectangle bounds
|
|
29394
|
-
if (x >=
|
|
29544
|
+
if (x >= left && x <= right && y >= minY && y <= maxY) {
|
|
29395
29545
|
return 'move';
|
|
29396
29546
|
}
|
|
29397
29547
|
}
|
|
@@ -29491,6 +29641,7 @@ class PositionTool extends DrawingToolBase {
|
|
|
29491
29641
|
this._private__requestUpdate();
|
|
29492
29642
|
}
|
|
29493
29643
|
remove() {
|
|
29644
|
+
this._private__placement?._internal_stop();
|
|
29494
29645
|
if (this._private__primitive) {
|
|
29495
29646
|
this._series.detachPrimitive(this._private__primitive);
|
|
29496
29647
|
this._private__primitive = null;
|
|
@@ -29537,6 +29688,7 @@ class GanttPaneView {
|
|
|
29537
29688
|
}
|
|
29538
29689
|
}
|
|
29539
29690
|
|
|
29691
|
+
const TOP_PADDING = 50;
|
|
29540
29692
|
class GanttTool extends DrawingToolBase {
|
|
29541
29693
|
constructor(context, options) {
|
|
29542
29694
|
super(context, 'gantt', options);
|
|
@@ -29550,6 +29702,7 @@ class GanttTool extends DrawingToolBase {
|
|
|
29550
29702
|
this._private__grab = null;
|
|
29551
29703
|
this._private__moveStart = null;
|
|
29552
29704
|
this._private__hoveredSegmentIndex = -1;
|
|
29705
|
+
this._private__placement = null;
|
|
29553
29706
|
this._private__ganttOptions = {
|
|
29554
29707
|
segments: [],
|
|
29555
29708
|
rowHeight: 40,
|
|
@@ -29562,6 +29715,43 @@ class GanttTool extends DrawingToolBase {
|
|
|
29562
29715
|
};
|
|
29563
29716
|
this._registerOptions(this._private__ganttOptions);
|
|
29564
29717
|
this._private__createPrimitive();
|
|
29718
|
+
if (this._private__ganttOptions.interactive) {
|
|
29719
|
+
this._private__placement = placeByClicks(this._chart, this._series, 1, (point) => this._private__placeAt(point));
|
|
29720
|
+
}
|
|
29721
|
+
}
|
|
29722
|
+
_private__placeAt(point) {
|
|
29723
|
+
const segments = this._private__ganttOptions.segments ?? [];
|
|
29724
|
+
const endTime = timeFromCoordinate(this._chart, this._series, placedEndX(this._chart, point._internal_x)) ?? point._internal_time;
|
|
29725
|
+
const rowPitch = this._private__ganttOptions.rowHeight + this._private__ganttOptions.rowSpacing;
|
|
29726
|
+
const row = Math.max(0, Math.floor((point._internal_y - TOP_PADDING) / rowPitch));
|
|
29727
|
+
const shift = segments.length > 0 ? row - segments[0].level : 0;
|
|
29728
|
+
for (const segment of segments) {
|
|
29729
|
+
segment.startTime = point._internal_time;
|
|
29730
|
+
segment.endTime = endTime;
|
|
29731
|
+
segment.level = Math.max(0, segment.level + shift);
|
|
29732
|
+
}
|
|
29733
|
+
this._private__requestUpdate();
|
|
29734
|
+
}
|
|
29735
|
+
isComplete() {
|
|
29736
|
+
return !this._private__placement?._internal_pending();
|
|
29737
|
+
}
|
|
29738
|
+
selectionBox() {
|
|
29739
|
+
const segments = this._private__ganttOptions.segments ?? [];
|
|
29740
|
+
if (segments.length === 0) {
|
|
29741
|
+
return null;
|
|
29742
|
+
}
|
|
29743
|
+
const rowHeight = this._private__ganttOptions.rowHeight;
|
|
29744
|
+
const pitch = rowHeight + this._private__ganttOptions.rowSpacing;
|
|
29745
|
+
// Typed as the public shape: an inferred one gets its keys renamed by the build
|
|
29746
|
+
const box = { left: Infinity, top: Infinity, right: -Infinity, bottom: -Infinity };
|
|
29747
|
+
for (const segment of segments) {
|
|
29748
|
+
const top = TOP_PADDING + segment.level * pitch;
|
|
29749
|
+
box.left = Math.min(box.left, coordinateFromTime(this._chart, this._series, segment.startTime) ?? 0);
|
|
29750
|
+
box.right = Math.max(box.right, coordinateFromTime(this._chart, this._series, segment.endTime) ?? 0);
|
|
29751
|
+
box.top = Math.min(box.top, top);
|
|
29752
|
+
box.bottom = Math.max(box.bottom, top + rowHeight);
|
|
29753
|
+
}
|
|
29754
|
+
return box;
|
|
29565
29755
|
}
|
|
29566
29756
|
_private__createPrimitive() {
|
|
29567
29757
|
this._private__paneView = this._private__createPaneView();
|
|
@@ -29592,11 +29782,10 @@ class GanttTool extends DrawingToolBase {
|
|
|
29592
29782
|
return new GanttPaneView(this);
|
|
29593
29783
|
}
|
|
29594
29784
|
drawToCanvas(ctx, horizontalPixelRatio, verticalPixelRatio) {
|
|
29595
|
-
if (!this._private__ganttOptions.segments || this._private__ganttOptions.segments.length === 0)
|
|
29785
|
+
if (!this.isComplete() || !this._private__ganttOptions.segments || this._private__ganttOptions.segments.length === 0)
|
|
29596
29786
|
return;
|
|
29597
29787
|
// Position gantt at top of chart with padding
|
|
29598
|
-
const
|
|
29599
|
-
const baseY = topPadding * verticalPixelRatio;
|
|
29788
|
+
const baseY = TOP_PADDING * verticalPixelRatio;
|
|
29600
29789
|
const rowHeight = this._private__ganttOptions.rowHeight * verticalPixelRatio;
|
|
29601
29790
|
const rowSpacing = this._private__ganttOptions.rowSpacing * verticalPixelRatio;
|
|
29602
29791
|
// Draw grid lines if enabled
|
|
@@ -29775,11 +29964,10 @@ class GanttTool extends DrawingToolBase {
|
|
|
29775
29964
|
this._private__moveStart = null;
|
|
29776
29965
|
}
|
|
29777
29966
|
hitTest(x, y) {
|
|
29778
|
-
if (!this._private__ganttOptions.segments || this._private__ganttOptions.segments.length === 0) {
|
|
29967
|
+
if (!this.isComplete() || !this._private__ganttOptions.segments || this._private__ganttOptions.segments.length === 0) {
|
|
29779
29968
|
return false;
|
|
29780
29969
|
}
|
|
29781
|
-
const
|
|
29782
|
-
const baseY = topPadding;
|
|
29970
|
+
const baseY = TOP_PADDING;
|
|
29783
29971
|
const rowHeight = this._private__ganttOptions.rowHeight;
|
|
29784
29972
|
const rowSpacing = this._private__ganttOptions.rowSpacing;
|
|
29785
29973
|
// Check each segment
|
|
@@ -29833,6 +30021,7 @@ class GanttTool extends DrawingToolBase {
|
|
|
29833
30021
|
this._private__requestUpdate();
|
|
29834
30022
|
}
|
|
29835
30023
|
remove() {
|
|
30024
|
+
this._private__placement?._internal_stop();
|
|
29836
30025
|
if (this._private__primitive) {
|
|
29837
30026
|
this._series.detachPrimitive(this._private__primitive);
|
|
29838
30027
|
this._private__primitive = null;
|
|
@@ -29968,6 +30157,7 @@ class DrawingToolsManager {
|
|
|
29968
30157
|
}
|
|
29969
30158
|
this._private__completionCheck = setTimeout(() => {
|
|
29970
30159
|
this._private__completionCheck = null;
|
|
30160
|
+
const completed = [];
|
|
29971
30161
|
for (const id of Array.from(this._private__pendingToolIds)) {
|
|
29972
30162
|
const tool = this._private__tools.get(id);
|
|
29973
30163
|
if (!tool) {
|
|
@@ -29976,9 +30166,15 @@ class DrawingToolsManager {
|
|
|
29976
30166
|
}
|
|
29977
30167
|
if (tool.isComplete()) {
|
|
29978
30168
|
this._private__pendingToolIds.delete(id);
|
|
29979
|
-
|
|
30169
|
+
completed.push(id);
|
|
29980
30170
|
}
|
|
29981
30171
|
}
|
|
30172
|
+
if (completed.length > 0) {
|
|
30173
|
+
this.recordChange();
|
|
30174
|
+
}
|
|
30175
|
+
for (const id of completed) {
|
|
30176
|
+
this._private__drawingCompleted._internal_fire(id);
|
|
30177
|
+
}
|
|
29982
30178
|
}, 0);
|
|
29983
30179
|
}
|
|
29984
30180
|
/**
|
|
@@ -30038,12 +30234,16 @@ class DrawingToolsManager {
|
|
|
30038
30234
|
if (this._private__restoring) {
|
|
30039
30235
|
return;
|
|
30040
30236
|
}
|
|
30237
|
+
const next = this.serializeAll();
|
|
30238
|
+
if (JSON.stringify(next) === JSON.stringify(this._private__committed)) {
|
|
30239
|
+
return;
|
|
30240
|
+
}
|
|
30041
30241
|
this._private__past.push(this._private__committed);
|
|
30042
30242
|
if (this._private__past.length > UNDO_HISTORY_LIMIT) {
|
|
30043
30243
|
this._private__past.shift();
|
|
30044
30244
|
}
|
|
30045
30245
|
this._private__future = [];
|
|
30046
|
-
this._private__committed =
|
|
30246
|
+
this._private__committed = next;
|
|
30047
30247
|
}
|
|
30048
30248
|
canUndo() {
|
|
30049
30249
|
return this._private__past.length > 0;
|
|
@@ -30099,11 +30299,25 @@ class DrawingToolsManager {
|
|
|
30099
30299
|
const tool = this._private__tools.get(this._private__selectedToolId);
|
|
30100
30300
|
return tool ? this._private__boundsOf(tool) : null;
|
|
30101
30301
|
}
|
|
30302
|
+
/** Relative to the chart element; the tool's box is relative to its pane. */
|
|
30303
|
+
_private__boundsOf(tool) {
|
|
30304
|
+
const box = tool.selectionBox() ?? this._private__boxFromPoints(tool);
|
|
30305
|
+
if (box === null) {
|
|
30306
|
+
return null;
|
|
30307
|
+
}
|
|
30308
|
+
const offset = this._private__paneOffsetOf(tool);
|
|
30309
|
+
return {
|
|
30310
|
+
left: box.left + offset._internal_x,
|
|
30311
|
+
right: box.right + offset._internal_x,
|
|
30312
|
+
top: box.top + offset._internal_y,
|
|
30313
|
+
bottom: box.bottom + offset._internal_y,
|
|
30314
|
+
};
|
|
30315
|
+
}
|
|
30102
30316
|
/**
|
|
30103
30317
|
* Bounds come from the tool's own serialized points, so this works for every
|
|
30104
30318
|
* tool without each one having to report a box.
|
|
30105
30319
|
*/
|
|
30106
|
-
|
|
30320
|
+
_private__boxFromPoints(tool) {
|
|
30107
30321
|
const series = tool.series();
|
|
30108
30322
|
const points = tool.serialize().points;
|
|
30109
30323
|
let left = Number.POSITIVE_INFINITY;
|
|
@@ -30126,13 +30340,7 @@ class DrawingToolsManager {
|
|
|
30126
30340
|
if (!found) {
|
|
30127
30341
|
return null;
|
|
30128
30342
|
}
|
|
30129
|
-
|
|
30130
|
-
return {
|
|
30131
|
-
left: left + offset._internal_x,
|
|
30132
|
-
right: right + offset._internal_x,
|
|
30133
|
-
top: top + offset._internal_y,
|
|
30134
|
-
bottom: bottom + offset._internal_y,
|
|
30135
|
-
};
|
|
30343
|
+
return { left, top, right, bottom };
|
|
30136
30344
|
}
|
|
30137
30345
|
/** Panes below the first one are offset inside the chart element. */
|
|
30138
30346
|
_private__paneOffsetOf(tool) {
|
|
@@ -30216,7 +30424,10 @@ class DrawingToolsManager {
|
|
|
30216
30424
|
serializeAll() {
|
|
30217
30425
|
const result = [];
|
|
30218
30426
|
for (const tool of this._private__tools.values()) {
|
|
30219
|
-
|
|
30427
|
+
// Not drawn yet: undo would bring it back as a finished drawing
|
|
30428
|
+
if (tool.isComplete()) {
|
|
30429
|
+
result.push(tool.serialize());
|
|
30430
|
+
}
|
|
30220
30431
|
}
|
|
30221
30432
|
return result;
|
|
30222
30433
|
}
|
|
@@ -30841,7 +31052,7 @@ const customSeriesDefaultOptions = {
|
|
|
30841
31052
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
30842
31053
|
*/
|
|
30843
31054
|
function version() {
|
|
30844
|
-
return "2.3.
|
|
31055
|
+
return "2.3.15";
|
|
30845
31056
|
}
|
|
30846
31057
|
|
|
30847
31058
|
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 };
|