@pipsend/charts 2.3.4 → 2.3.11
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 +171 -45
- package/dist/pipsend-charts.production.mjs +2 -2
- package/dist/pipsend-charts.standalone.development.js +171 -45
- package/dist/pipsend-charts.standalone.development.mjs +171 -45
- package/dist/pipsend-charts.standalone.production.js +2 -2
- package/dist/pipsend-charts.standalone.production.mjs +2 -2
- package/dist/typings.d.ts +46 -8
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @license
|
|
3
|
-
* Pipsend Charts v2.3.
|
|
3
|
+
* Pipsend Charts v2.3.11
|
|
4
4
|
* Copyright (c) 2026 Pipsend
|
|
5
5
|
* Licensed under MIT License
|
|
6
6
|
* Built on TradingView Lightweight Charts™ (Apache 2.0)
|
|
@@ -2483,14 +2483,8 @@ class SeriesBarColorer {
|
|
|
2483
2483
|
return this._private__styleGetter(this._private__findBar, this._private__series._internal_options(), barIndex, precomputedBars);
|
|
2484
2484
|
}
|
|
2485
2485
|
/**
|
|
2486
|
-
* Like `barStyle`, but
|
|
2487
|
-
*
|
|
2488
|
-
*
|
|
2489
|
-
* Recolouring walks items that were laid out against the data as it was. A
|
|
2490
|
-
* bar that has since disappeared is not an error there: the view is about
|
|
2491
|
-
* to be rebuilt from the new data anyway. Letting it throw took down
|
|
2492
|
-
* whatever asked for the repaint — including `setData`, which left the
|
|
2493
|
-
* series without its data and the pane empty until the page was reloaded.
|
|
2486
|
+
* Like `barStyle`, but null instead of throwing when the bar is gone, which
|
|
2487
|
+
* a recolour of items laid out against older data can hit.
|
|
2494
2488
|
*/
|
|
2495
2489
|
_internal_barStyleOrNull(barIndex, precomputedBars) {
|
|
2496
2490
|
if (precomputedBars === undefined && this._private__series._internal_bars()._internal_valueAt(barIndex) === null) {
|
|
@@ -2892,7 +2886,10 @@ class SeriesPrimitivePriceAxisViewWrapper extends PriceAxisView {
|
|
|
2892
2886
|
commonRendererData._internal_additionalPaddingTop = additionalPadding;
|
|
2893
2887
|
commonRendererData._internal_additionalPaddingBottom = additionalPadding;
|
|
2894
2888
|
commonRendererData._internal_coordinate = data._internal_coordinate;
|
|
2895
|
-
|
|
2889
|
+
// Re-runs at draw time, after the axis has moved the label clear of overlaps.
|
|
2890
|
+
if (data._internal_fixedCoordinate !== undefined) {
|
|
2891
|
+
commonRendererData._internal_fixedCoordinate = data._internal_fixedCoordinate;
|
|
2892
|
+
}
|
|
2896
2893
|
axisRendererData._internal_text = data._internal_text;
|
|
2897
2894
|
axisRendererData._internal_visible = data._internal_visible;
|
|
2898
2895
|
axisRendererData._internal_tickVisible = data._internal_tickVisible;
|
|
@@ -3769,7 +3766,6 @@ class PriceTickSpanCalculator {
|
|
|
3769
3766
|
}
|
|
3770
3767
|
}
|
|
3771
3768
|
|
|
3772
|
-
const TICK_DENSITY = 2.5;
|
|
3773
3769
|
class PriceTickMarkBuilder {
|
|
3774
3770
|
constructor(priceScale, base, coordinateToLogicalFunc, logicalToCoordinateFunc) {
|
|
3775
3771
|
this._private__marks = [];
|
|
@@ -3830,7 +3826,7 @@ class PriceTickMarkBuilder {
|
|
|
3830
3826
|
return this._private__priceScale._internal_fontSize();
|
|
3831
3827
|
}
|
|
3832
3828
|
_private__tickMarkHeight() {
|
|
3833
|
-
return Math.ceil(this._private__fontHeight() *
|
|
3829
|
+
return Math.max(1, Math.ceil(this._private__fontHeight() * this._private__priceScale._internal_options().tickMarkSpacing));
|
|
3834
3830
|
}
|
|
3835
3831
|
_private__updateMarks(firstValue, span, high, low, minCoord, maxCoord) {
|
|
3836
3832
|
const marks = this._private__marks;
|
|
@@ -3995,6 +3991,9 @@ class PriceScale {
|
|
|
3995
3991
|
this._private__invalidateInternalHeightCache();
|
|
3996
3992
|
this._private__marksCache = null;
|
|
3997
3993
|
}
|
|
3994
|
+
if (options.tickMarkSpacing !== undefined) {
|
|
3995
|
+
this._private__marksCache = null;
|
|
3996
|
+
}
|
|
3998
3997
|
}
|
|
3999
3998
|
_internal_isAutoScale() {
|
|
4000
3999
|
return this._private__options.autoScale;
|
|
@@ -5172,6 +5171,9 @@ class TickMarks {
|
|
|
5172
5171
|
this._private__uniformDistribution = val;
|
|
5173
5172
|
this._private__cache = null;
|
|
5174
5173
|
}
|
|
5174
|
+
_internal_invalidate() {
|
|
5175
|
+
this._private__cache = null;
|
|
5176
|
+
}
|
|
5175
5177
|
_internal_setTimeScalePoints(newPoints, firstChangedPointIndex) {
|
|
5176
5178
|
this._private__removeMarksSinceIndex(firstChangedPointIndex);
|
|
5177
5179
|
this._private__cache = null;
|
|
@@ -5190,7 +5192,7 @@ class TickMarks {
|
|
|
5190
5192
|
});
|
|
5191
5193
|
}
|
|
5192
5194
|
}
|
|
5193
|
-
_internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId) {
|
|
5195
|
+
_internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId, allows = () => true) {
|
|
5194
5196
|
const maxIndexesPerMark = Math.ceil(maxWidth / spacing);
|
|
5195
5197
|
if (this._private__cache === null ||
|
|
5196
5198
|
this._private__cache._internal_maxIndexesPerMark !== maxIndexesPerMark ||
|
|
@@ -5199,7 +5201,7 @@ class TickMarks {
|
|
|
5199
5201
|
this._private__cache = {
|
|
5200
5202
|
_internal_indicesWithDataId: indicesWithDataId,
|
|
5201
5203
|
_internal_checkIndicesForData: checkIndicesForData,
|
|
5202
|
-
_internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap),
|
|
5204
|
+
_internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows),
|
|
5203
5205
|
_internal_maxIndexesPerMark: maxIndexesPerMark,
|
|
5204
5206
|
};
|
|
5205
5207
|
}
|
|
@@ -5223,7 +5225,7 @@ class TickMarks {
|
|
|
5223
5225
|
this._private__marksByWeight.delete(weight);
|
|
5224
5226
|
}
|
|
5225
5227
|
}
|
|
5226
|
-
_private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap) {
|
|
5228
|
+
_private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows) {
|
|
5227
5229
|
let marks = [];
|
|
5228
5230
|
const canBeIncluded = (mark) => !checkIndicesForData || indicesWithDataMap.has(mark.index);
|
|
5229
5231
|
for (const weight of Array.from(this._private__marksByWeight.keys()).sort((a, b) => b - a)) {
|
|
@@ -5241,6 +5243,11 @@ class TickMarks {
|
|
|
5241
5243
|
let leftIndex = -Infinity;
|
|
5242
5244
|
for (let i = 0; i < currentWeightLength; i++) {
|
|
5243
5245
|
const mark = currentWeight[i];
|
|
5246
|
+
// Skipped before the fit check: a rejected mark must not count as one
|
|
5247
|
+
// that did not fit, which with uniform distribution drops its whole weight.
|
|
5248
|
+
if (!allows(mark, maxIndexesPerMark)) {
|
|
5249
|
+
continue;
|
|
5250
|
+
}
|
|
5244
5251
|
const currentIndex = mark.index;
|
|
5245
5252
|
// Determine indexes with which current index will be compared
|
|
5246
5253
|
// All marks to the right is moved to new array
|
|
@@ -5547,7 +5554,7 @@ class TimeScale {
|
|
|
5547
5554
|
const visibleBars = ensureNotNull(this._internal_visibleStrictRange());
|
|
5548
5555
|
const firstBar = Math.max(visibleBars._internal_left(), visibleBars._internal_left() - indexPerLabel);
|
|
5549
5556
|
const lastBar = Math.max(visibleBars._internal_right(), visibleBars._internal_right() - indexPerLabel);
|
|
5550
|
-
const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId);
|
|
5557
|
+
const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId, (mark, barsPerMark) => this._private__horzScaleBehavior.allowsTickMark?.(mark, barsPerMark) ?? true);
|
|
5551
5558
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second label on time scale"
|
|
5552
5559
|
const earliestIndexOfSecondLabel = this._private__firstIndex() + indexPerLabel;
|
|
5553
5560
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second last label on time scale"
|
|
@@ -5925,6 +5932,7 @@ class TimeScale {
|
|
|
5925
5932
|
_private__invalidateTickMarks() {
|
|
5926
5933
|
this._private__resetTimeMarksCache();
|
|
5927
5934
|
this._private__formattedByWeight.clear();
|
|
5935
|
+
this._private__tickMarks._internal_invalidate();
|
|
5928
5936
|
}
|
|
5929
5937
|
_private__updateDateTimeFormatter() {
|
|
5930
5938
|
this._private__horzScaleBehavior.updateFormatter(this._private__localizationOptions);
|
|
@@ -7039,6 +7047,14 @@ class HorzScaleBehaviorTime {
|
|
|
7039
7047
|
const tp = item;
|
|
7040
7048
|
return this._private__dateTimeFormatter._internal_format(new Date(tp._internal_timestamp * 1000));
|
|
7041
7049
|
}
|
|
7050
|
+
allowsTickMark(tickMark, barsPerMark) {
|
|
7051
|
+
const filter = this._private__options.timeScale.tickMarkFilter;
|
|
7052
|
+
if (filter === undefined) {
|
|
7053
|
+
return true;
|
|
7054
|
+
}
|
|
7055
|
+
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7056
|
+
return filter(tickMark.originalTime, tickMarkType, barsPerMark);
|
|
7057
|
+
}
|
|
7042
7058
|
formatTickmark(tickMark, localizationOptions) {
|
|
7043
7059
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7044
7060
|
const options = this._private__options.timeScale;
|
|
@@ -11443,9 +11459,6 @@ class SeriesPaneViewBase {
|
|
|
11443
11459
|
_internal__updateOptions() {
|
|
11444
11460
|
const colorer = this._internal__series._internal_barColorer();
|
|
11445
11461
|
this._internal__items = this._internal__items.map((item) => {
|
|
11446
|
-
// An item whose bar is gone keeps the colour it had. Throwing here
|
|
11447
|
-
// took down whatever asked for the repaint — `setData` among them,
|
|
11448
|
-
// which left the series without its data and the pane empty.
|
|
11449
11462
|
const style = colorer._internal_barStyleOrNull(item._internal_time);
|
|
11450
11463
|
return style === null ? item : { ...item, ...style };
|
|
11451
11464
|
});
|
|
@@ -11748,6 +11761,7 @@ const priceScaleOptionsDefaults = {
|
|
|
11748
11761
|
},
|
|
11749
11762
|
minimumWidth: 0,
|
|
11750
11763
|
ensureEdgeTickMarksVisible: false,
|
|
11764
|
+
tickMarkSpacing: 2.5,
|
|
11751
11765
|
};
|
|
11752
11766
|
|
|
11753
11767
|
const timeScaleOptionsDefaults = {
|
|
@@ -12843,8 +12857,6 @@ class LinePaneViewBase extends SeriesPaneViewBase {
|
|
|
12843
12857
|
const colorer = this._internal__series._internal_barColorer();
|
|
12844
12858
|
this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => {
|
|
12845
12859
|
const value = row._internal_value[3 /* PlotRowValueIndex.Close */];
|
|
12846
|
-
// The row travels with the point: without it the colorer looks it up
|
|
12847
|
-
// again by index, and that lookup could fail and take the repaint down.
|
|
12848
12860
|
return this._internal__createRawItem(row._internal_index, value, colorer, row);
|
|
12849
12861
|
});
|
|
12850
12862
|
}
|
|
@@ -12867,10 +12879,10 @@ styleGetter) {
|
|
|
12867
12879
|
if (point) {
|
|
12868
12880
|
const style = styleGetter(renderingScope, point);
|
|
12869
12881
|
if (style !== prevStyle) {
|
|
12870
|
-
context.beginPath();
|
|
12871
12882
|
if (prevStyle !== null) {
|
|
12872
12883
|
context.fill();
|
|
12873
12884
|
}
|
|
12885
|
+
context.beginPath();
|
|
12874
12886
|
context.fillStyle = style;
|
|
12875
12887
|
prevStyle = style;
|
|
12876
12888
|
}
|
|
@@ -13809,9 +13821,6 @@ class BarsPaneViewBase extends SeriesPaneViewBase {
|
|
|
13809
13821
|
}
|
|
13810
13822
|
_internal__fillRawPoints() {
|
|
13811
13823
|
const colorer = this._internal__series._internal_barColorer();
|
|
13812
|
-
// The row goes to the colorer as it is. Asking for the style by index
|
|
13813
|
-
// alone made it look the row up again, and that second lookup could come
|
|
13814
|
-
// back empty and throw, taking the whole repaint down with it.
|
|
13815
13824
|
this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => this._internal__createRawItem(row._internal_index, row, colorer));
|
|
13816
13825
|
}
|
|
13817
13826
|
}
|
|
@@ -17882,7 +17891,7 @@ function applyHeikinAshi(series, chart, options = {}) {
|
|
|
17882
17891
|
hideSource: options.hideSource ?? true,
|
|
17883
17892
|
};
|
|
17884
17893
|
const sourceOptions = series.options();
|
|
17885
|
-
// Same price scale and
|
|
17894
|
+
// Same price scale, formatting and axis labels as the source: the candles are a
|
|
17886
17895
|
// restatement of that series, not a second instrument, so they must not
|
|
17887
17896
|
// autoscale on their own axis or round to a different precision.
|
|
17888
17897
|
const haSeries = chart.addSeries(candlestickSeries, {
|
|
@@ -17896,6 +17905,8 @@ function applyHeikinAshi(series, chart, options = {}) {
|
|
|
17896
17905
|
wickDownColor: resolved.wickDownColor,
|
|
17897
17906
|
priceScaleId: sourceOptions.priceScaleId,
|
|
17898
17907
|
priceFormat: sourceOptions.priceFormat,
|
|
17908
|
+
lastValueVisible: sourceOptions.lastValueVisible,
|
|
17909
|
+
priceLineVisible: sourceOptions.priceLineVisible,
|
|
17899
17910
|
}, resolved.paneIndex);
|
|
17900
17911
|
let restoreSourcePaint = null;
|
|
17901
17912
|
const blankSource = (blank) => {
|
|
@@ -18097,12 +18108,14 @@ function applyMACD(series, chart, options = {}) {
|
|
|
18097
18108
|
const macdSeries = chart.addSeries(lineSeries, {
|
|
18098
18109
|
color: resolved.colorMACD,
|
|
18099
18110
|
}, paneIndex);
|
|
18111
|
+
// An index past the last pane opens a new one, so the rest follow MACD to where it landed.
|
|
18112
|
+
const macdPane = paneIndexOf(chart, macdSeries, paneIndex);
|
|
18100
18113
|
const signalSeries = chart.addSeries(lineSeries, {
|
|
18101
18114
|
color: resolved.colorSignal,
|
|
18102
|
-
},
|
|
18115
|
+
}, macdPane);
|
|
18103
18116
|
const histogramSeries$1 = chart.addSeries(histogramSeries, {
|
|
18104
18117
|
color: resolved.colorHistogramUp,
|
|
18105
|
-
},
|
|
18118
|
+
}, macdPane);
|
|
18106
18119
|
// Calculate EMA
|
|
18107
18120
|
const calculateEMA = (prices, period) => {
|
|
18108
18121
|
const ema = [];
|
|
@@ -18234,13 +18247,13 @@ function applyStochastic(series, chart, options = {}) {
|
|
|
18234
18247
|
// Stochastic is bounded to 0-100; pinning it keeps the pane readable
|
|
18235
18248
|
autoscaleInfoProvider: boundedScale,
|
|
18236
18249
|
}, paneIndex);
|
|
18250
|
+
// An index past the last pane opens a new one, so %D follows %K to where it landed.
|
|
18251
|
+
const scalePane = paneIndexOf(chart, kSeries, paneIndex);
|
|
18237
18252
|
// Create %D line (slow - signal)
|
|
18238
18253
|
const dSeries = chart.addSeries(lineSeries, {
|
|
18239
18254
|
color: resolved.colorD,
|
|
18240
18255
|
autoscaleInfoProvider: boundedScale,
|
|
18241
|
-
},
|
|
18242
|
-
// The pane the series landed in, which is not always the one asked for.
|
|
18243
|
-
const scalePane = paneIndexOf(chart, kSeries, paneIndex);
|
|
18256
|
+
}, scalePane);
|
|
18244
18257
|
chart.priceScale(kSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
|
|
18245
18258
|
scaleMargins: {
|
|
18246
18259
|
top: 0.1,
|
|
@@ -18582,15 +18595,16 @@ function applyADX(series, chart, options = {}) {
|
|
|
18582
18595
|
color: resolved.colorADX,
|
|
18583
18596
|
autoscaleInfoProvider: boundedScale,
|
|
18584
18597
|
}, paneIndex);
|
|
18598
|
+
// An index past the last pane opens a new one, so the DI lines follow ADX to where it landed.
|
|
18599
|
+
const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
|
|
18585
18600
|
const plusSeries = chart.addSeries(lineSeries, {
|
|
18586
18601
|
color: resolved.colorPlusDI,
|
|
18587
18602
|
autoscaleInfoProvider: boundedScale,
|
|
18588
|
-
},
|
|
18603
|
+
}, scalePane);
|
|
18589
18604
|
const minusSeries = chart.addSeries(lineSeries, {
|
|
18590
18605
|
color: resolved.colorMinusDI,
|
|
18591
18606
|
autoscaleInfoProvider: boundedScale,
|
|
18592
|
-
},
|
|
18593
|
-
const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
|
|
18607
|
+
}, scalePane);
|
|
18594
18608
|
chart.priceScale(adxSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
|
|
18595
18609
|
scaleMargins: {
|
|
18596
18610
|
top: 0.1,
|
|
@@ -19706,6 +19720,8 @@ class TradingLineController {
|
|
|
19706
19720
|
this._private__pointerId = null;
|
|
19707
19721
|
this._private__pressOrigin = null;
|
|
19708
19722
|
this._private__pressedLine = null;
|
|
19723
|
+
/** Whether the gesture in flight came from a finger rather than a mouse. */
|
|
19724
|
+
this._private__pressWasTouch = false;
|
|
19709
19725
|
/** Distance from the pointer to the dragged line when the press landed. */
|
|
19710
19726
|
this._private__grabOffset = 0;
|
|
19711
19727
|
/** Latest pointer position in pane coordinates, or null when off the panes. */
|
|
@@ -19770,8 +19786,18 @@ class TradingLineController {
|
|
|
19770
19786
|
this._private__applyCursor();
|
|
19771
19787
|
}
|
|
19772
19788
|
_private__onPointerDown(event) {
|
|
19773
|
-
|
|
19789
|
+
// Hover belongs to the mouse. Touch leaves whatever the last press marked
|
|
19790
|
+
// still marked, so trusting it here grabbed that line again wherever the
|
|
19791
|
+
// next tap landed: every press resolves itself instead.
|
|
19792
|
+
this._private__pressWasTouch = event.pointerType !== 'mouse';
|
|
19793
|
+
let line = this._private__pressWasTouch || this._private__hoveredId === null
|
|
19794
|
+
? null
|
|
19795
|
+
: this._private__lines.get(this._private__hoveredId) ?? null;
|
|
19796
|
+
if (line === null) {
|
|
19797
|
+
line = this._private__resolveHitAt(event);
|
|
19798
|
+
}
|
|
19774
19799
|
if (!line) {
|
|
19800
|
+
this._private__clearTouchHover();
|
|
19775
19801
|
return;
|
|
19776
19802
|
}
|
|
19777
19803
|
this._private__pressOrigin = { _internal_x: event.clientX, _internal_y: event.clientY };
|
|
@@ -19810,6 +19836,7 @@ class TradingLineController {
|
|
|
19810
19836
|
}
|
|
19811
19837
|
_private__onPointerUp(event) {
|
|
19812
19838
|
const dragged = this._private__dragging;
|
|
19839
|
+
const wasTouch = this._private__pressWasTouch;
|
|
19813
19840
|
const pressed = this._private__pressedLine;
|
|
19814
19841
|
const origin = this._private__pressOrigin;
|
|
19815
19842
|
this._private__releasePointer();
|
|
@@ -19831,12 +19858,24 @@ class TradingLineController {
|
|
|
19831
19858
|
dragged.click();
|
|
19832
19859
|
}
|
|
19833
19860
|
}
|
|
19861
|
+
this._private__clearTouchHover(wasTouch);
|
|
19834
19862
|
this._private__applyCursor();
|
|
19835
19863
|
return;
|
|
19836
19864
|
}
|
|
19837
19865
|
if (pressed !== null && !moved && pressed.isClickable()) {
|
|
19838
19866
|
pressed.click();
|
|
19839
19867
|
}
|
|
19868
|
+
this._private__clearTouchHover(wasTouch);
|
|
19869
|
+
}
|
|
19870
|
+
/** A finger leaves nothing hovered behind it, the way lifting a mouse does. */
|
|
19871
|
+
_private__clearTouchHover(wasTouch = this._private__pressWasTouch) {
|
|
19872
|
+
if (!wasTouch || this._private__hoveredId === null) {
|
|
19873
|
+
return;
|
|
19874
|
+
}
|
|
19875
|
+
const line = this._private__lines.get(this._private__hoveredId) ?? null;
|
|
19876
|
+
this._private__setHovered(null);
|
|
19877
|
+
this._private__setHoveredPart(line, null);
|
|
19878
|
+
this._private__applyCursor();
|
|
19840
19879
|
}
|
|
19841
19880
|
/**
|
|
19842
19881
|
* Abort an in-flight gesture: the line goes back to where it was and no
|
|
@@ -19882,9 +19921,38 @@ class TradingLineController {
|
|
|
19882
19921
|
return paneY === null ? null : line.priceAt(paneY - this._private__grabOffset);
|
|
19883
19922
|
}
|
|
19884
19923
|
/** The pointer's position inside the line's pane, in pane coordinates. */
|
|
19885
|
-
|
|
19924
|
+
/**
|
|
19925
|
+
* The hovered id comes from the crosshair, which touch never moves before it
|
|
19926
|
+
* presses, so the press resolves the target itself.
|
|
19927
|
+
*/
|
|
19928
|
+
_private__resolveHitAt(event) {
|
|
19929
|
+
for (const line of this._private__lines.values()) {
|
|
19930
|
+
if (!line.hitTestAt) {
|
|
19931
|
+
continue;
|
|
19932
|
+
}
|
|
19933
|
+
const paneElement = this._private__paneElementOf(line);
|
|
19934
|
+
if (paneElement === null) {
|
|
19935
|
+
continue;
|
|
19936
|
+
}
|
|
19937
|
+
const rect = paneElement.getBoundingClientRect();
|
|
19938
|
+
// A fingertip is far coarser than a pointer, so its targets are widened.
|
|
19939
|
+
const slop = event.pointerType === 'mouse' ? 0 : 12 /* Constants.TouchSlopPx */;
|
|
19940
|
+
const hit = this._private__splitHit(line.hitTestAt(event.clientX - rect.left, event.clientY - rect.top, slop));
|
|
19941
|
+
if (hit === null) {
|
|
19942
|
+
continue;
|
|
19943
|
+
}
|
|
19944
|
+
this._private__setHovered(line.id());
|
|
19945
|
+
this._private__setHoveredPart(line, hit._internal_part);
|
|
19946
|
+
return line;
|
|
19947
|
+
}
|
|
19948
|
+
return null;
|
|
19949
|
+
}
|
|
19950
|
+
_private__paneElementOf(line) {
|
|
19886
19951
|
const pane = this._private__chart.panes()[line.paneIndex()];
|
|
19887
|
-
|
|
19952
|
+
return pane ? pane.getHTMLElement() : null;
|
|
19953
|
+
}
|
|
19954
|
+
_private__paneY(line, event) {
|
|
19955
|
+
const paneElement = this._private__paneElementOf(line);
|
|
19888
19956
|
if (paneElement) {
|
|
19889
19957
|
return event.clientY - paneElement.getBoundingClientRect().top;
|
|
19890
19958
|
}
|
|
@@ -20001,6 +20069,7 @@ let nextLineId = 0;
|
|
|
20001
20069
|
* line. Hit testing comes from the engine — the line's id travels as the price
|
|
20002
20070
|
* line's `externalId` — so the hit area matches what is drawn.
|
|
20003
20071
|
*/
|
|
20072
|
+
const HIT_TOLERANCE_PX$1 = 8;
|
|
20004
20073
|
class DraggablePriceLine {
|
|
20005
20074
|
constructor(chart, series, options) {
|
|
20006
20075
|
this._private__priceLine = null;
|
|
@@ -20053,6 +20122,14 @@ class DraggablePriceLine {
|
|
|
20053
20122
|
color: hovered ? this._private__options.hoverColor : this._private__originalColor,
|
|
20054
20123
|
});
|
|
20055
20124
|
}
|
|
20125
|
+
/**
|
|
20126
|
+
* The engine draws this one, so there is no pane view to ask: a press within
|
|
20127
|
+
* the line's own grab strip counts as a hit.
|
|
20128
|
+
*/
|
|
20129
|
+
hitTestAt(x, y, slop = 0) {
|
|
20130
|
+
const coord = this._private__series.priceToCoordinate(this._private__options.price);
|
|
20131
|
+
return coord !== null && Math.abs(y - coord) <= HIT_TOLERANCE_PX$1 + slop ? this._private__id : null;
|
|
20132
|
+
}
|
|
20056
20133
|
priceAt(paneY) {
|
|
20057
20134
|
const price = this._private__series.coordinateToPrice(paneY);
|
|
20058
20135
|
return price === null ? null : price;
|
|
@@ -20595,22 +20672,27 @@ class PositionLineRenderer {
|
|
|
20595
20672
|
_internal_setData(data) {
|
|
20596
20673
|
this._private__data = data;
|
|
20597
20674
|
}
|
|
20598
|
-
|
|
20675
|
+
/**
|
|
20676
|
+
* `slop` widens every target by the same amount, for input coarser than a
|
|
20677
|
+
* mouse pointer.
|
|
20678
|
+
*/
|
|
20679
|
+
_internal_hitTest(x, y, slop = 0) {
|
|
20599
20680
|
// The close button sits on top of the label, which sits on top of the
|
|
20600
20681
|
// line, so the narrowest target is tested first.
|
|
20601
20682
|
for (const layout of this._private__layouts) {
|
|
20602
|
-
if (layout._internal_closable && x >= layout._internal_closeLeft && x <= layout._internal_closeRight &&
|
|
20603
|
-
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2) {
|
|
20683
|
+
if (layout._internal_closable && x >= layout._internal_closeLeft - slop && x <= layout._internal_closeRight + slop &&
|
|
20684
|
+
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2 + slop) {
|
|
20604
20685
|
return { _internal_level: layout._internal_level, _internal_part: 'close' };
|
|
20605
20686
|
}
|
|
20606
20687
|
}
|
|
20607
20688
|
for (const layout of this._private__layouts) {
|
|
20608
|
-
if (x >= layout._internal_pillLeft && x <= layout._internal_pillRight
|
|
20689
|
+
if (x >= layout._internal_pillLeft - slop && x <= layout._internal_pillRight + slop &&
|
|
20690
|
+
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2 + slop) {
|
|
20609
20691
|
return { _internal_level: layout._internal_level, _internal_part: 'body' };
|
|
20610
20692
|
}
|
|
20611
20693
|
}
|
|
20612
20694
|
for (const layout of this._private__layouts) {
|
|
20613
|
-
if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */) {
|
|
20695
|
+
if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */ + slop) {
|
|
20614
20696
|
return { _internal_level: layout._internal_level, _internal_part: 'line' };
|
|
20615
20697
|
}
|
|
20616
20698
|
}
|
|
@@ -20847,8 +20929,8 @@ class PositionLinePaneView {
|
|
|
20847
20929
|
zOrder() {
|
|
20848
20930
|
return 'top';
|
|
20849
20931
|
}
|
|
20850
|
-
_internal_hitTest(x, y) {
|
|
20851
|
-
return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y);
|
|
20932
|
+
_internal_hitTest(x, y, slop = 0) {
|
|
20933
|
+
return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y, slop);
|
|
20852
20934
|
}
|
|
20853
20935
|
}
|
|
20854
20936
|
|
|
@@ -20999,6 +21081,13 @@ class PositionLine {
|
|
|
20999
21081
|
* of jumping to sit under it — which matters most when the label has been
|
|
21000
21082
|
* fanned away from its own line.
|
|
21001
21083
|
*/
|
|
21084
|
+
hitTestAt(x, y, slop = 0) {
|
|
21085
|
+
const hit = this._private__paneView._internal_hitTest(x, y, slop);
|
|
21086
|
+
if (hit === null) {
|
|
21087
|
+
return null;
|
|
21088
|
+
}
|
|
21089
|
+
return this._private__levelOptions(hit._internal_level) === null ? null : `${this._private__id}#${hit._internal_level}:${hit._internal_part}`;
|
|
21090
|
+
}
|
|
21002
21091
|
dragAnchorY() {
|
|
21003
21092
|
if (this._private__dragLevel === null) {
|
|
21004
21093
|
return null;
|
|
@@ -30069,6 +30158,7 @@ class DrawingToolsManager {
|
|
|
30069
30158
|
this._private__mouseMoveHandler = null;
|
|
30070
30159
|
this._private__pointerDownHandler = null;
|
|
30071
30160
|
this._private__pointerUpHandler = null;
|
|
30161
|
+
this._private__pointerMoveHandler = null;
|
|
30072
30162
|
this._private__pointerCancelHandler = null;
|
|
30073
30163
|
this._private__lostCaptureHandler = null;
|
|
30074
30164
|
this._private__windowPointerUpHandler = null;
|
|
@@ -30643,10 +30733,12 @@ class DrawingToolsManager {
|
|
|
30643
30733
|
if (chartElement) {
|
|
30644
30734
|
this._private__pointerDownHandler = (event) => this._private__handlePointerDown(event);
|
|
30645
30735
|
this._private__pointerUpHandler = (event) => this._private__handlePointerUp(event);
|
|
30736
|
+
this._private__pointerMoveHandler = (event) => this._private__handlePointerMove(event);
|
|
30646
30737
|
this._private__pointerCancelHandler = (event) => this._private__handlePointerUp(event);
|
|
30647
30738
|
this._private__lostCaptureHandler = (event) => this._private__handleLostPointerCapture(event);
|
|
30648
30739
|
chartElement.addEventListener('pointerdown', this._private__pointerDownHandler);
|
|
30649
30740
|
chartElement.addEventListener('pointerup', this._private__pointerUpHandler);
|
|
30741
|
+
chartElement.addEventListener('pointermove', this._private__pointerMoveHandler);
|
|
30650
30742
|
chartElement.addEventListener('pointercancel', this._private__pointerCancelHandler);
|
|
30651
30743
|
chartElement.addEventListener('lostpointercapture', this._private__lostCaptureHandler);
|
|
30652
30744
|
}
|
|
@@ -30681,6 +30773,10 @@ class DrawingToolsManager {
|
|
|
30681
30773
|
chartElement.removeEventListener('pointerup', this._private__pointerUpHandler);
|
|
30682
30774
|
this._private__pointerUpHandler = null;
|
|
30683
30775
|
}
|
|
30776
|
+
if (this._private__pointerMoveHandler) {
|
|
30777
|
+
chartElement.removeEventListener('pointermove', this._private__pointerMoveHandler);
|
|
30778
|
+
this._private__pointerMoveHandler = null;
|
|
30779
|
+
}
|
|
30684
30780
|
if (this._private__pointerCancelHandler) {
|
|
30685
30781
|
chartElement.removeEventListener('pointercancel', this._private__pointerCancelHandler);
|
|
30686
30782
|
this._private__pointerCancelHandler = null;
|
|
@@ -30830,6 +30926,36 @@ class DrawingToolsManager {
|
|
|
30830
30926
|
// mouse events, and those are what drive the crosshair the drag reads.
|
|
30831
30927
|
this._private__disableChartInteractions();
|
|
30832
30928
|
}
|
|
30929
|
+
/**
|
|
30930
|
+
* The drag reads the crosshair, which touch never moves: its move handler
|
|
30931
|
+
* only tries to pan, and the drag has just turned panning off. So touch is
|
|
30932
|
+
* driven straight from the pointer instead.
|
|
30933
|
+
*/
|
|
30934
|
+
_private__handlePointerMove(event) {
|
|
30935
|
+
if (!this._private__isDragging || this._private__draggedToolId === null || event.pointerType === 'mouse') {
|
|
30936
|
+
return;
|
|
30937
|
+
}
|
|
30938
|
+
if (this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
|
|
30939
|
+
return;
|
|
30940
|
+
}
|
|
30941
|
+
const tool = this._private__tools.get(this._private__draggedToolId);
|
|
30942
|
+
if (!tool) {
|
|
30943
|
+
return;
|
|
30944
|
+
}
|
|
30945
|
+
const paneElement = this._private__paneElementOf(tool);
|
|
30946
|
+
if (paneElement === null) {
|
|
30947
|
+
return;
|
|
30948
|
+
}
|
|
30949
|
+
const rect = paneElement.getBoundingClientRect();
|
|
30950
|
+
const series = tool.series();
|
|
30951
|
+
const price = series.coordinateToPrice((event.clientY - rect.top));
|
|
30952
|
+
const time = timeFromCoordinate(this._private__chart, series, event.clientX - rect.left);
|
|
30953
|
+
if (price === null || time === null) {
|
|
30954
|
+
return;
|
|
30955
|
+
}
|
|
30956
|
+
tool.updateDrag(time, price);
|
|
30957
|
+
event.preventDefault();
|
|
30958
|
+
}
|
|
30833
30959
|
_private__handlePointerUp(event) {
|
|
30834
30960
|
if (!this._private__isDragging || this._private__draggedToolId === null) {
|
|
30835
30961
|
return;
|
|
@@ -31003,7 +31129,7 @@ const customSeriesDefaultOptions = {
|
|
|
31003
31129
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
31004
31130
|
*/
|
|
31005
31131
|
function version() {
|
|
31006
|
-
return "2.3.
|
|
31132
|
+
return "2.3.11";
|
|
31007
31133
|
}
|
|
31008
31134
|
|
|
31009
31135
|
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 };
|