@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)
|
|
@@ -2486,14 +2486,8 @@
|
|
|
2486
2486
|
return this._private__styleGetter(this._private__findBar, this._private__series._internal_options(), barIndex, precomputedBars);
|
|
2487
2487
|
}
|
|
2488
2488
|
/**
|
|
2489
|
-
* Like `barStyle`, but
|
|
2490
|
-
*
|
|
2491
|
-
*
|
|
2492
|
-
* Recolouring walks items that were laid out against the data as it was. A
|
|
2493
|
-
* bar that has since disappeared is not an error there: the view is about
|
|
2494
|
-
* to be rebuilt from the new data anyway. Letting it throw took down
|
|
2495
|
-
* whatever asked for the repaint — including `setData`, which left the
|
|
2496
|
-
* series without its data and the pane empty until the page was reloaded.
|
|
2489
|
+
* Like `barStyle`, but null instead of throwing when the bar is gone, which
|
|
2490
|
+
* a recolour of items laid out against older data can hit.
|
|
2497
2491
|
*/
|
|
2498
2492
|
_internal_barStyleOrNull(barIndex, precomputedBars) {
|
|
2499
2493
|
if (precomputedBars === undefined && this._private__series._internal_bars()._internal_valueAt(barIndex) === null) {
|
|
@@ -2895,7 +2889,10 @@
|
|
|
2895
2889
|
commonRendererData._internal_additionalPaddingTop = additionalPadding;
|
|
2896
2890
|
commonRendererData._internal_additionalPaddingBottom = additionalPadding;
|
|
2897
2891
|
commonRendererData._internal_coordinate = data._internal_coordinate;
|
|
2898
|
-
|
|
2892
|
+
// Re-runs at draw time, after the axis has moved the label clear of overlaps.
|
|
2893
|
+
if (data._internal_fixedCoordinate !== undefined) {
|
|
2894
|
+
commonRendererData._internal_fixedCoordinate = data._internal_fixedCoordinate;
|
|
2895
|
+
}
|
|
2899
2896
|
axisRendererData._internal_text = data._internal_text;
|
|
2900
2897
|
axisRendererData._internal_visible = data._internal_visible;
|
|
2901
2898
|
axisRendererData._internal_tickVisible = data._internal_tickVisible;
|
|
@@ -3772,7 +3769,6 @@
|
|
|
3772
3769
|
}
|
|
3773
3770
|
}
|
|
3774
3771
|
|
|
3775
|
-
const TICK_DENSITY = 2.5;
|
|
3776
3772
|
class PriceTickMarkBuilder {
|
|
3777
3773
|
constructor(priceScale, base, coordinateToLogicalFunc, logicalToCoordinateFunc) {
|
|
3778
3774
|
this._private__marks = [];
|
|
@@ -3833,7 +3829,7 @@
|
|
|
3833
3829
|
return this._private__priceScale._internal_fontSize();
|
|
3834
3830
|
}
|
|
3835
3831
|
_private__tickMarkHeight() {
|
|
3836
|
-
return Math.ceil(this._private__fontHeight() *
|
|
3832
|
+
return Math.max(1, Math.ceil(this._private__fontHeight() * this._private__priceScale._internal_options().tickMarkSpacing));
|
|
3837
3833
|
}
|
|
3838
3834
|
_private__updateMarks(firstValue, span, high, low, minCoord, maxCoord) {
|
|
3839
3835
|
const marks = this._private__marks;
|
|
@@ -3998,6 +3994,9 @@
|
|
|
3998
3994
|
this._private__invalidateInternalHeightCache();
|
|
3999
3995
|
this._private__marksCache = null;
|
|
4000
3996
|
}
|
|
3997
|
+
if (options.tickMarkSpacing !== undefined) {
|
|
3998
|
+
this._private__marksCache = null;
|
|
3999
|
+
}
|
|
4001
4000
|
}
|
|
4002
4001
|
_internal_isAutoScale() {
|
|
4003
4002
|
return this._private__options.autoScale;
|
|
@@ -5175,6 +5174,9 @@
|
|
|
5175
5174
|
this._private__uniformDistribution = val;
|
|
5176
5175
|
this._private__cache = null;
|
|
5177
5176
|
}
|
|
5177
|
+
_internal_invalidate() {
|
|
5178
|
+
this._private__cache = null;
|
|
5179
|
+
}
|
|
5178
5180
|
_internal_setTimeScalePoints(newPoints, firstChangedPointIndex) {
|
|
5179
5181
|
this._private__removeMarksSinceIndex(firstChangedPointIndex);
|
|
5180
5182
|
this._private__cache = null;
|
|
@@ -5193,7 +5195,7 @@
|
|
|
5193
5195
|
});
|
|
5194
5196
|
}
|
|
5195
5197
|
}
|
|
5196
|
-
_internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId) {
|
|
5198
|
+
_internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId, allows = () => true) {
|
|
5197
5199
|
const maxIndexesPerMark = Math.ceil(maxWidth / spacing);
|
|
5198
5200
|
if (this._private__cache === null ||
|
|
5199
5201
|
this._private__cache._internal_maxIndexesPerMark !== maxIndexesPerMark ||
|
|
@@ -5202,7 +5204,7 @@
|
|
|
5202
5204
|
this._private__cache = {
|
|
5203
5205
|
_internal_indicesWithDataId: indicesWithDataId,
|
|
5204
5206
|
_internal_checkIndicesForData: checkIndicesForData,
|
|
5205
|
-
_internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap),
|
|
5207
|
+
_internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows),
|
|
5206
5208
|
_internal_maxIndexesPerMark: maxIndexesPerMark,
|
|
5207
5209
|
};
|
|
5208
5210
|
}
|
|
@@ -5226,7 +5228,7 @@
|
|
|
5226
5228
|
this._private__marksByWeight.delete(weight);
|
|
5227
5229
|
}
|
|
5228
5230
|
}
|
|
5229
|
-
_private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap) {
|
|
5231
|
+
_private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows) {
|
|
5230
5232
|
let marks = [];
|
|
5231
5233
|
const canBeIncluded = (mark) => !checkIndicesForData || indicesWithDataMap.has(mark.index);
|
|
5232
5234
|
for (const weight of Array.from(this._private__marksByWeight.keys()).sort((a, b) => b - a)) {
|
|
@@ -5244,6 +5246,11 @@
|
|
|
5244
5246
|
let leftIndex = -Infinity;
|
|
5245
5247
|
for (let i = 0; i < currentWeightLength; i++) {
|
|
5246
5248
|
const mark = currentWeight[i];
|
|
5249
|
+
// Skipped before the fit check: a rejected mark must not count as one
|
|
5250
|
+
// that did not fit, which with uniform distribution drops its whole weight.
|
|
5251
|
+
if (!allows(mark, maxIndexesPerMark)) {
|
|
5252
|
+
continue;
|
|
5253
|
+
}
|
|
5247
5254
|
const currentIndex = mark.index;
|
|
5248
5255
|
// Determine indexes with which current index will be compared
|
|
5249
5256
|
// All marks to the right is moved to new array
|
|
@@ -5550,7 +5557,7 @@
|
|
|
5550
5557
|
const visibleBars = ensureNotNull(this._internal_visibleStrictRange());
|
|
5551
5558
|
const firstBar = Math.max(visibleBars._internal_left(), visibleBars._internal_left() - indexPerLabel);
|
|
5552
5559
|
const lastBar = Math.max(visibleBars._internal_right(), visibleBars._internal_right() - indexPerLabel);
|
|
5553
|
-
const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId);
|
|
5560
|
+
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);
|
|
5554
5561
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second label on time scale"
|
|
5555
5562
|
const earliestIndexOfSecondLabel = this._private__firstIndex() + indexPerLabel;
|
|
5556
5563
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second last label on time scale"
|
|
@@ -5928,6 +5935,7 @@
|
|
|
5928
5935
|
_private__invalidateTickMarks() {
|
|
5929
5936
|
this._private__resetTimeMarksCache();
|
|
5930
5937
|
this._private__formattedByWeight.clear();
|
|
5938
|
+
this._private__tickMarks._internal_invalidate();
|
|
5931
5939
|
}
|
|
5932
5940
|
_private__updateDateTimeFormatter() {
|
|
5933
5941
|
this._private__horzScaleBehavior.updateFormatter(this._private__localizationOptions);
|
|
@@ -7042,6 +7050,14 @@
|
|
|
7042
7050
|
const tp = item;
|
|
7043
7051
|
return this._private__dateTimeFormatter._internal_format(new Date(tp._internal_timestamp * 1000));
|
|
7044
7052
|
}
|
|
7053
|
+
allowsTickMark(tickMark, barsPerMark) {
|
|
7054
|
+
const filter = this._private__options.timeScale.tickMarkFilter;
|
|
7055
|
+
if (filter === undefined) {
|
|
7056
|
+
return true;
|
|
7057
|
+
}
|
|
7058
|
+
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7059
|
+
return filter(tickMark.originalTime, tickMarkType, barsPerMark);
|
|
7060
|
+
}
|
|
7045
7061
|
formatTickmark(tickMark, localizationOptions) {
|
|
7046
7062
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7047
7063
|
const options = this._private__options.timeScale;
|
|
@@ -11446,9 +11462,6 @@
|
|
|
11446
11462
|
_internal__updateOptions() {
|
|
11447
11463
|
const colorer = this._internal__series._internal_barColorer();
|
|
11448
11464
|
this._internal__items = this._internal__items.map((item) => {
|
|
11449
|
-
// An item whose bar is gone keeps the colour it had. Throwing here
|
|
11450
|
-
// took down whatever asked for the repaint — `setData` among them,
|
|
11451
|
-
// which left the series without its data and the pane empty.
|
|
11452
11465
|
const style = colorer._internal_barStyleOrNull(item._internal_time);
|
|
11453
11466
|
return style === null ? item : { ...item, ...style };
|
|
11454
11467
|
});
|
|
@@ -11751,6 +11764,7 @@
|
|
|
11751
11764
|
},
|
|
11752
11765
|
minimumWidth: 0,
|
|
11753
11766
|
ensureEdgeTickMarksVisible: false,
|
|
11767
|
+
tickMarkSpacing: 2.5,
|
|
11754
11768
|
};
|
|
11755
11769
|
|
|
11756
11770
|
const timeScaleOptionsDefaults = {
|
|
@@ -12846,8 +12860,6 @@
|
|
|
12846
12860
|
const colorer = this._internal__series._internal_barColorer();
|
|
12847
12861
|
this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => {
|
|
12848
12862
|
const value = row._internal_value[3 /* PlotRowValueIndex.Close */];
|
|
12849
|
-
// The row travels with the point: without it the colorer looks it up
|
|
12850
|
-
// again by index, and that lookup could fail and take the repaint down.
|
|
12851
12863
|
return this._internal__createRawItem(row._internal_index, value, colorer, row);
|
|
12852
12864
|
});
|
|
12853
12865
|
}
|
|
@@ -12870,10 +12882,10 @@
|
|
|
12870
12882
|
if (point) {
|
|
12871
12883
|
const style = styleGetter(renderingScope, point);
|
|
12872
12884
|
if (style !== prevStyle) {
|
|
12873
|
-
context.beginPath();
|
|
12874
12885
|
if (prevStyle !== null) {
|
|
12875
12886
|
context.fill();
|
|
12876
12887
|
}
|
|
12888
|
+
context.beginPath();
|
|
12877
12889
|
context.fillStyle = style;
|
|
12878
12890
|
prevStyle = style;
|
|
12879
12891
|
}
|
|
@@ -13812,9 +13824,6 @@
|
|
|
13812
13824
|
}
|
|
13813
13825
|
_internal__fillRawPoints() {
|
|
13814
13826
|
const colorer = this._internal__series._internal_barColorer();
|
|
13815
|
-
// The row goes to the colorer as it is. Asking for the style by index
|
|
13816
|
-
// alone made it look the row up again, and that second lookup could come
|
|
13817
|
-
// back empty and throw, taking the whole repaint down with it.
|
|
13818
13827
|
this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => this._internal__createRawItem(row._internal_index, row, colorer));
|
|
13819
13828
|
}
|
|
13820
13829
|
}
|
|
@@ -17885,7 +17894,7 @@
|
|
|
17885
17894
|
hideSource: options.hideSource ?? true,
|
|
17886
17895
|
};
|
|
17887
17896
|
const sourceOptions = series.options();
|
|
17888
|
-
// Same price scale and
|
|
17897
|
+
// Same price scale, formatting and axis labels as the source: the candles are a
|
|
17889
17898
|
// restatement of that series, not a second instrument, so they must not
|
|
17890
17899
|
// autoscale on their own axis or round to a different precision.
|
|
17891
17900
|
const haSeries = chart.addSeries(candlestickSeries, {
|
|
@@ -17899,6 +17908,8 @@
|
|
|
17899
17908
|
wickDownColor: resolved.wickDownColor,
|
|
17900
17909
|
priceScaleId: sourceOptions.priceScaleId,
|
|
17901
17910
|
priceFormat: sourceOptions.priceFormat,
|
|
17911
|
+
lastValueVisible: sourceOptions.lastValueVisible,
|
|
17912
|
+
priceLineVisible: sourceOptions.priceLineVisible,
|
|
17902
17913
|
}, resolved.paneIndex);
|
|
17903
17914
|
let restoreSourcePaint = null;
|
|
17904
17915
|
const blankSource = (blank) => {
|
|
@@ -18100,12 +18111,14 @@
|
|
|
18100
18111
|
const macdSeries = chart.addSeries(lineSeries, {
|
|
18101
18112
|
color: resolved.colorMACD,
|
|
18102
18113
|
}, paneIndex);
|
|
18114
|
+
// An index past the last pane opens a new one, so the rest follow MACD to where it landed.
|
|
18115
|
+
const macdPane = paneIndexOf(chart, macdSeries, paneIndex);
|
|
18103
18116
|
const signalSeries = chart.addSeries(lineSeries, {
|
|
18104
18117
|
color: resolved.colorSignal,
|
|
18105
|
-
},
|
|
18118
|
+
}, macdPane);
|
|
18106
18119
|
const histogramSeries$1 = chart.addSeries(histogramSeries, {
|
|
18107
18120
|
color: resolved.colorHistogramUp,
|
|
18108
|
-
},
|
|
18121
|
+
}, macdPane);
|
|
18109
18122
|
// Calculate EMA
|
|
18110
18123
|
const calculateEMA = (prices, period) => {
|
|
18111
18124
|
const ema = [];
|
|
@@ -18237,13 +18250,13 @@
|
|
|
18237
18250
|
// Stochastic is bounded to 0-100; pinning it keeps the pane readable
|
|
18238
18251
|
autoscaleInfoProvider: boundedScale,
|
|
18239
18252
|
}, paneIndex);
|
|
18253
|
+
// An index past the last pane opens a new one, so %D follows %K to where it landed.
|
|
18254
|
+
const scalePane = paneIndexOf(chart, kSeries, paneIndex);
|
|
18240
18255
|
// Create %D line (slow - signal)
|
|
18241
18256
|
const dSeries = chart.addSeries(lineSeries, {
|
|
18242
18257
|
color: resolved.colorD,
|
|
18243
18258
|
autoscaleInfoProvider: boundedScale,
|
|
18244
|
-
},
|
|
18245
|
-
// The pane the series landed in, which is not always the one asked for.
|
|
18246
|
-
const scalePane = paneIndexOf(chart, kSeries, paneIndex);
|
|
18259
|
+
}, scalePane);
|
|
18247
18260
|
chart.priceScale(kSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
|
|
18248
18261
|
scaleMargins: {
|
|
18249
18262
|
top: 0.1,
|
|
@@ -18585,15 +18598,16 @@
|
|
|
18585
18598
|
color: resolved.colorADX,
|
|
18586
18599
|
autoscaleInfoProvider: boundedScale,
|
|
18587
18600
|
}, paneIndex);
|
|
18601
|
+
// An index past the last pane opens a new one, so the DI lines follow ADX to where it landed.
|
|
18602
|
+
const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
|
|
18588
18603
|
const plusSeries = chart.addSeries(lineSeries, {
|
|
18589
18604
|
color: resolved.colorPlusDI,
|
|
18590
18605
|
autoscaleInfoProvider: boundedScale,
|
|
18591
|
-
},
|
|
18606
|
+
}, scalePane);
|
|
18592
18607
|
const minusSeries = chart.addSeries(lineSeries, {
|
|
18593
18608
|
color: resolved.colorMinusDI,
|
|
18594
18609
|
autoscaleInfoProvider: boundedScale,
|
|
18595
|
-
},
|
|
18596
|
-
const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
|
|
18610
|
+
}, scalePane);
|
|
18597
18611
|
chart.priceScale(adxSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
|
|
18598
18612
|
scaleMargins: {
|
|
18599
18613
|
top: 0.1,
|
|
@@ -19709,6 +19723,8 @@
|
|
|
19709
19723
|
this._private__pointerId = null;
|
|
19710
19724
|
this._private__pressOrigin = null;
|
|
19711
19725
|
this._private__pressedLine = null;
|
|
19726
|
+
/** Whether the gesture in flight came from a finger rather than a mouse. */
|
|
19727
|
+
this._private__pressWasTouch = false;
|
|
19712
19728
|
/** Distance from the pointer to the dragged line when the press landed. */
|
|
19713
19729
|
this._private__grabOffset = 0;
|
|
19714
19730
|
/** Latest pointer position in pane coordinates, or null when off the panes. */
|
|
@@ -19773,8 +19789,18 @@
|
|
|
19773
19789
|
this._private__applyCursor();
|
|
19774
19790
|
}
|
|
19775
19791
|
_private__onPointerDown(event) {
|
|
19776
|
-
|
|
19792
|
+
// Hover belongs to the mouse. Touch leaves whatever the last press marked
|
|
19793
|
+
// still marked, so trusting it here grabbed that line again wherever the
|
|
19794
|
+
// next tap landed: every press resolves itself instead.
|
|
19795
|
+
this._private__pressWasTouch = event.pointerType !== 'mouse';
|
|
19796
|
+
let line = this._private__pressWasTouch || this._private__hoveredId === null
|
|
19797
|
+
? null
|
|
19798
|
+
: this._private__lines.get(this._private__hoveredId) ?? null;
|
|
19799
|
+
if (line === null) {
|
|
19800
|
+
line = this._private__resolveHitAt(event);
|
|
19801
|
+
}
|
|
19777
19802
|
if (!line) {
|
|
19803
|
+
this._private__clearTouchHover();
|
|
19778
19804
|
return;
|
|
19779
19805
|
}
|
|
19780
19806
|
this._private__pressOrigin = { _internal_x: event.clientX, _internal_y: event.clientY };
|
|
@@ -19813,6 +19839,7 @@
|
|
|
19813
19839
|
}
|
|
19814
19840
|
_private__onPointerUp(event) {
|
|
19815
19841
|
const dragged = this._private__dragging;
|
|
19842
|
+
const wasTouch = this._private__pressWasTouch;
|
|
19816
19843
|
const pressed = this._private__pressedLine;
|
|
19817
19844
|
const origin = this._private__pressOrigin;
|
|
19818
19845
|
this._private__releasePointer();
|
|
@@ -19834,12 +19861,24 @@
|
|
|
19834
19861
|
dragged.click();
|
|
19835
19862
|
}
|
|
19836
19863
|
}
|
|
19864
|
+
this._private__clearTouchHover(wasTouch);
|
|
19837
19865
|
this._private__applyCursor();
|
|
19838
19866
|
return;
|
|
19839
19867
|
}
|
|
19840
19868
|
if (pressed !== null && !moved && pressed.isClickable()) {
|
|
19841
19869
|
pressed.click();
|
|
19842
19870
|
}
|
|
19871
|
+
this._private__clearTouchHover(wasTouch);
|
|
19872
|
+
}
|
|
19873
|
+
/** A finger leaves nothing hovered behind it, the way lifting a mouse does. */
|
|
19874
|
+
_private__clearTouchHover(wasTouch = this._private__pressWasTouch) {
|
|
19875
|
+
if (!wasTouch || this._private__hoveredId === null) {
|
|
19876
|
+
return;
|
|
19877
|
+
}
|
|
19878
|
+
const line = this._private__lines.get(this._private__hoveredId) ?? null;
|
|
19879
|
+
this._private__setHovered(null);
|
|
19880
|
+
this._private__setHoveredPart(line, null);
|
|
19881
|
+
this._private__applyCursor();
|
|
19843
19882
|
}
|
|
19844
19883
|
/**
|
|
19845
19884
|
* Abort an in-flight gesture: the line goes back to where it was and no
|
|
@@ -19885,9 +19924,38 @@
|
|
|
19885
19924
|
return paneY === null ? null : line.priceAt(paneY - this._private__grabOffset);
|
|
19886
19925
|
}
|
|
19887
19926
|
/** The pointer's position inside the line's pane, in pane coordinates. */
|
|
19888
|
-
|
|
19927
|
+
/**
|
|
19928
|
+
* The hovered id comes from the crosshair, which touch never moves before it
|
|
19929
|
+
* presses, so the press resolves the target itself.
|
|
19930
|
+
*/
|
|
19931
|
+
_private__resolveHitAt(event) {
|
|
19932
|
+
for (const line of this._private__lines.values()) {
|
|
19933
|
+
if (!line.hitTestAt) {
|
|
19934
|
+
continue;
|
|
19935
|
+
}
|
|
19936
|
+
const paneElement = this._private__paneElementOf(line);
|
|
19937
|
+
if (paneElement === null) {
|
|
19938
|
+
continue;
|
|
19939
|
+
}
|
|
19940
|
+
const rect = paneElement.getBoundingClientRect();
|
|
19941
|
+
// A fingertip is far coarser than a pointer, so its targets are widened.
|
|
19942
|
+
const slop = event.pointerType === 'mouse' ? 0 : 12 /* Constants.TouchSlopPx */;
|
|
19943
|
+
const hit = this._private__splitHit(line.hitTestAt(event.clientX - rect.left, event.clientY - rect.top, slop));
|
|
19944
|
+
if (hit === null) {
|
|
19945
|
+
continue;
|
|
19946
|
+
}
|
|
19947
|
+
this._private__setHovered(line.id());
|
|
19948
|
+
this._private__setHoveredPart(line, hit._internal_part);
|
|
19949
|
+
return line;
|
|
19950
|
+
}
|
|
19951
|
+
return null;
|
|
19952
|
+
}
|
|
19953
|
+
_private__paneElementOf(line) {
|
|
19889
19954
|
const pane = this._private__chart.panes()[line.paneIndex()];
|
|
19890
|
-
|
|
19955
|
+
return pane ? pane.getHTMLElement() : null;
|
|
19956
|
+
}
|
|
19957
|
+
_private__paneY(line, event) {
|
|
19958
|
+
const paneElement = this._private__paneElementOf(line);
|
|
19891
19959
|
if (paneElement) {
|
|
19892
19960
|
return event.clientY - paneElement.getBoundingClientRect().top;
|
|
19893
19961
|
}
|
|
@@ -20004,6 +20072,7 @@
|
|
|
20004
20072
|
* line. Hit testing comes from the engine — the line's id travels as the price
|
|
20005
20073
|
* line's `externalId` — so the hit area matches what is drawn.
|
|
20006
20074
|
*/
|
|
20075
|
+
const HIT_TOLERANCE_PX$1 = 8;
|
|
20007
20076
|
class DraggablePriceLine {
|
|
20008
20077
|
constructor(chart, series, options) {
|
|
20009
20078
|
this._private__priceLine = null;
|
|
@@ -20056,6 +20125,14 @@
|
|
|
20056
20125
|
color: hovered ? this._private__options.hoverColor : this._private__originalColor,
|
|
20057
20126
|
});
|
|
20058
20127
|
}
|
|
20128
|
+
/**
|
|
20129
|
+
* The engine draws this one, so there is no pane view to ask: a press within
|
|
20130
|
+
* the line's own grab strip counts as a hit.
|
|
20131
|
+
*/
|
|
20132
|
+
hitTestAt(x, y, slop = 0) {
|
|
20133
|
+
const coord = this._private__series.priceToCoordinate(this._private__options.price);
|
|
20134
|
+
return coord !== null && Math.abs(y - coord) <= HIT_TOLERANCE_PX$1 + slop ? this._private__id : null;
|
|
20135
|
+
}
|
|
20059
20136
|
priceAt(paneY) {
|
|
20060
20137
|
const price = this._private__series.coordinateToPrice(paneY);
|
|
20061
20138
|
return price === null ? null : price;
|
|
@@ -20598,22 +20675,27 @@
|
|
|
20598
20675
|
_internal_setData(data) {
|
|
20599
20676
|
this._private__data = data;
|
|
20600
20677
|
}
|
|
20601
|
-
|
|
20678
|
+
/**
|
|
20679
|
+
* `slop` widens every target by the same amount, for input coarser than a
|
|
20680
|
+
* mouse pointer.
|
|
20681
|
+
*/
|
|
20682
|
+
_internal_hitTest(x, y, slop = 0) {
|
|
20602
20683
|
// The close button sits on top of the label, which sits on top of the
|
|
20603
20684
|
// line, so the narrowest target is tested first.
|
|
20604
20685
|
for (const layout of this._private__layouts) {
|
|
20605
|
-
if (layout._internal_closable && x >= layout._internal_closeLeft && x <= layout._internal_closeRight &&
|
|
20606
|
-
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2) {
|
|
20686
|
+
if (layout._internal_closable && x >= layout._internal_closeLeft - slop && x <= layout._internal_closeRight + slop &&
|
|
20687
|
+
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2 + slop) {
|
|
20607
20688
|
return { _internal_level: layout._internal_level, _internal_part: 'close' };
|
|
20608
20689
|
}
|
|
20609
20690
|
}
|
|
20610
20691
|
for (const layout of this._private__layouts) {
|
|
20611
|
-
if (x >= layout._internal_pillLeft && x <= layout._internal_pillRight
|
|
20692
|
+
if (x >= layout._internal_pillLeft - slop && x <= layout._internal_pillRight + slop &&
|
|
20693
|
+
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2 + slop) {
|
|
20612
20694
|
return { _internal_level: layout._internal_level, _internal_part: 'body' };
|
|
20613
20695
|
}
|
|
20614
20696
|
}
|
|
20615
20697
|
for (const layout of this._private__layouts) {
|
|
20616
|
-
if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */) {
|
|
20698
|
+
if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */ + slop) {
|
|
20617
20699
|
return { _internal_level: layout._internal_level, _internal_part: 'line' };
|
|
20618
20700
|
}
|
|
20619
20701
|
}
|
|
@@ -20850,8 +20932,8 @@
|
|
|
20850
20932
|
zOrder() {
|
|
20851
20933
|
return 'top';
|
|
20852
20934
|
}
|
|
20853
|
-
_internal_hitTest(x, y) {
|
|
20854
|
-
return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y);
|
|
20935
|
+
_internal_hitTest(x, y, slop = 0) {
|
|
20936
|
+
return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y, slop);
|
|
20855
20937
|
}
|
|
20856
20938
|
}
|
|
20857
20939
|
|
|
@@ -21002,6 +21084,13 @@
|
|
|
21002
21084
|
* of jumping to sit under it — which matters most when the label has been
|
|
21003
21085
|
* fanned away from its own line.
|
|
21004
21086
|
*/
|
|
21087
|
+
hitTestAt(x, y, slop = 0) {
|
|
21088
|
+
const hit = this._private__paneView._internal_hitTest(x, y, slop);
|
|
21089
|
+
if (hit === null) {
|
|
21090
|
+
return null;
|
|
21091
|
+
}
|
|
21092
|
+
return this._private__levelOptions(hit._internal_level) === null ? null : `${this._private__id}#${hit._internal_level}:${hit._internal_part}`;
|
|
21093
|
+
}
|
|
21005
21094
|
dragAnchorY() {
|
|
21006
21095
|
if (this._private__dragLevel === null) {
|
|
21007
21096
|
return null;
|
|
@@ -30072,6 +30161,7 @@
|
|
|
30072
30161
|
this._private__mouseMoveHandler = null;
|
|
30073
30162
|
this._private__pointerDownHandler = null;
|
|
30074
30163
|
this._private__pointerUpHandler = null;
|
|
30164
|
+
this._private__pointerMoveHandler = null;
|
|
30075
30165
|
this._private__pointerCancelHandler = null;
|
|
30076
30166
|
this._private__lostCaptureHandler = null;
|
|
30077
30167
|
this._private__windowPointerUpHandler = null;
|
|
@@ -30646,10 +30736,12 @@
|
|
|
30646
30736
|
if (chartElement) {
|
|
30647
30737
|
this._private__pointerDownHandler = (event) => this._private__handlePointerDown(event);
|
|
30648
30738
|
this._private__pointerUpHandler = (event) => this._private__handlePointerUp(event);
|
|
30739
|
+
this._private__pointerMoveHandler = (event) => this._private__handlePointerMove(event);
|
|
30649
30740
|
this._private__pointerCancelHandler = (event) => this._private__handlePointerUp(event);
|
|
30650
30741
|
this._private__lostCaptureHandler = (event) => this._private__handleLostPointerCapture(event);
|
|
30651
30742
|
chartElement.addEventListener('pointerdown', this._private__pointerDownHandler);
|
|
30652
30743
|
chartElement.addEventListener('pointerup', this._private__pointerUpHandler);
|
|
30744
|
+
chartElement.addEventListener('pointermove', this._private__pointerMoveHandler);
|
|
30653
30745
|
chartElement.addEventListener('pointercancel', this._private__pointerCancelHandler);
|
|
30654
30746
|
chartElement.addEventListener('lostpointercapture', this._private__lostCaptureHandler);
|
|
30655
30747
|
}
|
|
@@ -30684,6 +30776,10 @@
|
|
|
30684
30776
|
chartElement.removeEventListener('pointerup', this._private__pointerUpHandler);
|
|
30685
30777
|
this._private__pointerUpHandler = null;
|
|
30686
30778
|
}
|
|
30779
|
+
if (this._private__pointerMoveHandler) {
|
|
30780
|
+
chartElement.removeEventListener('pointermove', this._private__pointerMoveHandler);
|
|
30781
|
+
this._private__pointerMoveHandler = null;
|
|
30782
|
+
}
|
|
30687
30783
|
if (this._private__pointerCancelHandler) {
|
|
30688
30784
|
chartElement.removeEventListener('pointercancel', this._private__pointerCancelHandler);
|
|
30689
30785
|
this._private__pointerCancelHandler = null;
|
|
@@ -30833,6 +30929,36 @@
|
|
|
30833
30929
|
// mouse events, and those are what drive the crosshair the drag reads.
|
|
30834
30930
|
this._private__disableChartInteractions();
|
|
30835
30931
|
}
|
|
30932
|
+
/**
|
|
30933
|
+
* The drag reads the crosshair, which touch never moves: its move handler
|
|
30934
|
+
* only tries to pan, and the drag has just turned panning off. So touch is
|
|
30935
|
+
* driven straight from the pointer instead.
|
|
30936
|
+
*/
|
|
30937
|
+
_private__handlePointerMove(event) {
|
|
30938
|
+
if (!this._private__isDragging || this._private__draggedToolId === null || event.pointerType === 'mouse') {
|
|
30939
|
+
return;
|
|
30940
|
+
}
|
|
30941
|
+
if (this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
|
|
30942
|
+
return;
|
|
30943
|
+
}
|
|
30944
|
+
const tool = this._private__tools.get(this._private__draggedToolId);
|
|
30945
|
+
if (!tool) {
|
|
30946
|
+
return;
|
|
30947
|
+
}
|
|
30948
|
+
const paneElement = this._private__paneElementOf(tool);
|
|
30949
|
+
if (paneElement === null) {
|
|
30950
|
+
return;
|
|
30951
|
+
}
|
|
30952
|
+
const rect = paneElement.getBoundingClientRect();
|
|
30953
|
+
const series = tool.series();
|
|
30954
|
+
const price = series.coordinateToPrice((event.clientY - rect.top));
|
|
30955
|
+
const time = timeFromCoordinate(this._private__chart, series, event.clientX - rect.left);
|
|
30956
|
+
if (price === null || time === null) {
|
|
30957
|
+
return;
|
|
30958
|
+
}
|
|
30959
|
+
tool.updateDrag(time, price);
|
|
30960
|
+
event.preventDefault();
|
|
30961
|
+
}
|
|
30836
30962
|
_private__handlePointerUp(event) {
|
|
30837
30963
|
if (!this._private__isDragging || this._private__draggedToolId === null) {
|
|
30838
30964
|
return;
|
|
@@ -31006,7 +31132,7 @@
|
|
|
31006
31132
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
31007
31133
|
*/
|
|
31008
31134
|
function version() {
|
|
31009
|
-
return "2.3.
|
|
31135
|
+
return "2.3.11";
|
|
31010
31136
|
}
|
|
31011
31137
|
|
|
31012
31138
|
var PipsendChartsModule = /*#__PURE__*/Object.freeze({
|