@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)
|
|
@@ -2485,14 +2485,8 @@ class SeriesBarColorer {
|
|
|
2485
2485
|
return this._private__styleGetter(this._private__findBar, this._private__series._internal_options(), barIndex, precomputedBars);
|
|
2486
2486
|
}
|
|
2487
2487
|
/**
|
|
2488
|
-
* Like `barStyle`, but
|
|
2489
|
-
*
|
|
2490
|
-
*
|
|
2491
|
-
* Recolouring walks items that were laid out against the data as it was. A
|
|
2492
|
-
* bar that has since disappeared is not an error there: the view is about
|
|
2493
|
-
* to be rebuilt from the new data anyway. Letting it throw took down
|
|
2494
|
-
* whatever asked for the repaint — including `setData`, which left the
|
|
2495
|
-
* series without its data and the pane empty until the page was reloaded.
|
|
2488
|
+
* Like `barStyle`, but null instead of throwing when the bar is gone, which
|
|
2489
|
+
* a recolour of items laid out against older data can hit.
|
|
2496
2490
|
*/
|
|
2497
2491
|
_internal_barStyleOrNull(barIndex, precomputedBars) {
|
|
2498
2492
|
if (precomputedBars === undefined && this._private__series._internal_bars()._internal_valueAt(barIndex) === null) {
|
|
@@ -2894,7 +2888,10 @@ class SeriesPrimitivePriceAxisViewWrapper extends PriceAxisView {
|
|
|
2894
2888
|
commonRendererData._internal_additionalPaddingTop = additionalPadding;
|
|
2895
2889
|
commonRendererData._internal_additionalPaddingBottom = additionalPadding;
|
|
2896
2890
|
commonRendererData._internal_coordinate = data._internal_coordinate;
|
|
2897
|
-
|
|
2891
|
+
// Re-runs at draw time, after the axis has moved the label clear of overlaps.
|
|
2892
|
+
if (data._internal_fixedCoordinate !== undefined) {
|
|
2893
|
+
commonRendererData._internal_fixedCoordinate = data._internal_fixedCoordinate;
|
|
2894
|
+
}
|
|
2898
2895
|
axisRendererData._internal_text = data._internal_text;
|
|
2899
2896
|
axisRendererData._internal_visible = data._internal_visible;
|
|
2900
2897
|
axisRendererData._internal_tickVisible = data._internal_tickVisible;
|
|
@@ -3771,7 +3768,6 @@ class PriceTickSpanCalculator {
|
|
|
3771
3768
|
}
|
|
3772
3769
|
}
|
|
3773
3770
|
|
|
3774
|
-
const TICK_DENSITY = 2.5;
|
|
3775
3771
|
class PriceTickMarkBuilder {
|
|
3776
3772
|
constructor(priceScale, base, coordinateToLogicalFunc, logicalToCoordinateFunc) {
|
|
3777
3773
|
this._private__marks = [];
|
|
@@ -3832,7 +3828,7 @@ class PriceTickMarkBuilder {
|
|
|
3832
3828
|
return this._private__priceScale._internal_fontSize();
|
|
3833
3829
|
}
|
|
3834
3830
|
_private__tickMarkHeight() {
|
|
3835
|
-
return Math.ceil(this._private__fontHeight() *
|
|
3831
|
+
return Math.max(1, Math.ceil(this._private__fontHeight() * this._private__priceScale._internal_options().tickMarkSpacing));
|
|
3836
3832
|
}
|
|
3837
3833
|
_private__updateMarks(firstValue, span, high, low, minCoord, maxCoord) {
|
|
3838
3834
|
const marks = this._private__marks;
|
|
@@ -3997,6 +3993,9 @@ class PriceScale {
|
|
|
3997
3993
|
this._private__invalidateInternalHeightCache();
|
|
3998
3994
|
this._private__marksCache = null;
|
|
3999
3995
|
}
|
|
3996
|
+
if (options.tickMarkSpacing !== undefined) {
|
|
3997
|
+
this._private__marksCache = null;
|
|
3998
|
+
}
|
|
4000
3999
|
}
|
|
4001
4000
|
_internal_isAutoScale() {
|
|
4002
4001
|
return this._private__options.autoScale;
|
|
@@ -5174,6 +5173,9 @@ class TickMarks {
|
|
|
5174
5173
|
this._private__uniformDistribution = val;
|
|
5175
5174
|
this._private__cache = null;
|
|
5176
5175
|
}
|
|
5176
|
+
_internal_invalidate() {
|
|
5177
|
+
this._private__cache = null;
|
|
5178
|
+
}
|
|
5177
5179
|
_internal_setTimeScalePoints(newPoints, firstChangedPointIndex) {
|
|
5178
5180
|
this._private__removeMarksSinceIndex(firstChangedPointIndex);
|
|
5179
5181
|
this._private__cache = null;
|
|
@@ -5192,7 +5194,7 @@ class TickMarks {
|
|
|
5192
5194
|
});
|
|
5193
5195
|
}
|
|
5194
5196
|
}
|
|
5195
|
-
_internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId) {
|
|
5197
|
+
_internal_build(spacing, maxWidth, checkIndicesForData, indicesWithDataMap, indicesWithDataId, allows = () => true) {
|
|
5196
5198
|
const maxIndexesPerMark = Math.ceil(maxWidth / spacing);
|
|
5197
5199
|
if (this._private__cache === null ||
|
|
5198
5200
|
this._private__cache._internal_maxIndexesPerMark !== maxIndexesPerMark ||
|
|
@@ -5201,7 +5203,7 @@ class TickMarks {
|
|
|
5201
5203
|
this._private__cache = {
|
|
5202
5204
|
_internal_indicesWithDataId: indicesWithDataId,
|
|
5203
5205
|
_internal_checkIndicesForData: checkIndicesForData,
|
|
5204
|
-
_internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap),
|
|
5206
|
+
_internal_marks: this._private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows),
|
|
5205
5207
|
_internal_maxIndexesPerMark: maxIndexesPerMark,
|
|
5206
5208
|
};
|
|
5207
5209
|
}
|
|
@@ -5225,7 +5227,7 @@ class TickMarks {
|
|
|
5225
5227
|
this._private__marksByWeight.delete(weight);
|
|
5226
5228
|
}
|
|
5227
5229
|
}
|
|
5228
|
-
_private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap) {
|
|
5230
|
+
_private__buildMarksImpl(maxIndexesPerMark, checkIndicesForData, indicesWithDataMap, allows) {
|
|
5229
5231
|
let marks = [];
|
|
5230
5232
|
const canBeIncluded = (mark) => !checkIndicesForData || indicesWithDataMap.has(mark.index);
|
|
5231
5233
|
for (const weight of Array.from(this._private__marksByWeight.keys()).sort((a, b) => b - a)) {
|
|
@@ -5243,6 +5245,11 @@ class TickMarks {
|
|
|
5243
5245
|
let leftIndex = -Infinity;
|
|
5244
5246
|
for (let i = 0; i < currentWeightLength; i++) {
|
|
5245
5247
|
const mark = currentWeight[i];
|
|
5248
|
+
// Skipped before the fit check: a rejected mark must not count as one
|
|
5249
|
+
// that did not fit, which with uniform distribution drops its whole weight.
|
|
5250
|
+
if (!allows(mark, maxIndexesPerMark)) {
|
|
5251
|
+
continue;
|
|
5252
|
+
}
|
|
5246
5253
|
const currentIndex = mark.index;
|
|
5247
5254
|
// Determine indexes with which current index will be compared
|
|
5248
5255
|
// All marks to the right is moved to new array
|
|
@@ -5549,7 +5556,7 @@ class TimeScale {
|
|
|
5549
5556
|
const visibleBars = ensureNotNull(this._internal_visibleStrictRange());
|
|
5550
5557
|
const firstBar = Math.max(visibleBars._internal_left(), visibleBars._internal_left() - indexPerLabel);
|
|
5551
5558
|
const lastBar = Math.max(visibleBars._internal_right(), visibleBars._internal_right() - indexPerLabel);
|
|
5552
|
-
const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId);
|
|
5559
|
+
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);
|
|
5553
5560
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second label on time scale"
|
|
5554
5561
|
const earliestIndexOfSecondLabel = this._private__firstIndex() + indexPerLabel;
|
|
5555
5562
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second last label on time scale"
|
|
@@ -5927,6 +5934,7 @@ class TimeScale {
|
|
|
5927
5934
|
_private__invalidateTickMarks() {
|
|
5928
5935
|
this._private__resetTimeMarksCache();
|
|
5929
5936
|
this._private__formattedByWeight.clear();
|
|
5937
|
+
this._private__tickMarks._internal_invalidate();
|
|
5930
5938
|
}
|
|
5931
5939
|
_private__updateDateTimeFormatter() {
|
|
5932
5940
|
this._private__horzScaleBehavior.updateFormatter(this._private__localizationOptions);
|
|
@@ -7041,6 +7049,14 @@ class HorzScaleBehaviorTime {
|
|
|
7041
7049
|
const tp = item;
|
|
7042
7050
|
return this._private__dateTimeFormatter._internal_format(new Date(tp._internal_timestamp * 1000));
|
|
7043
7051
|
}
|
|
7052
|
+
allowsTickMark(tickMark, barsPerMark) {
|
|
7053
|
+
const filter = this._private__options.timeScale.tickMarkFilter;
|
|
7054
|
+
if (filter === undefined) {
|
|
7055
|
+
return true;
|
|
7056
|
+
}
|
|
7057
|
+
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7058
|
+
return filter(tickMark.originalTime, tickMarkType, barsPerMark);
|
|
7059
|
+
}
|
|
7044
7060
|
formatTickmark(tickMark, localizationOptions) {
|
|
7045
7061
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7046
7062
|
const options = this._private__options.timeScale;
|
|
@@ -11050,9 +11066,6 @@ class SeriesPaneViewBase {
|
|
|
11050
11066
|
_internal__updateOptions() {
|
|
11051
11067
|
const colorer = this._internal__series._internal_barColorer();
|
|
11052
11068
|
this._internal__items = this._internal__items.map((item) => {
|
|
11053
|
-
// An item whose bar is gone keeps the colour it had. Throwing here
|
|
11054
|
-
// took down whatever asked for the repaint — `setData` among them,
|
|
11055
|
-
// which left the series without its data and the pane empty.
|
|
11056
11069
|
const style = colorer._internal_barStyleOrNull(item._internal_time);
|
|
11057
11070
|
return style === null ? item : { ...item, ...style };
|
|
11058
11071
|
});
|
|
@@ -11355,6 +11368,7 @@ const priceScaleOptionsDefaults = {
|
|
|
11355
11368
|
},
|
|
11356
11369
|
minimumWidth: 0,
|
|
11357
11370
|
ensureEdgeTickMarksVisible: false,
|
|
11371
|
+
tickMarkSpacing: 2.5,
|
|
11358
11372
|
};
|
|
11359
11373
|
|
|
11360
11374
|
const timeScaleOptionsDefaults = {
|
|
@@ -12450,8 +12464,6 @@ class LinePaneViewBase extends SeriesPaneViewBase {
|
|
|
12450
12464
|
const colorer = this._internal__series._internal_barColorer();
|
|
12451
12465
|
this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => {
|
|
12452
12466
|
const value = row._internal_value[3 /* PlotRowValueIndex.Close */];
|
|
12453
|
-
// The row travels with the point: without it the colorer looks it up
|
|
12454
|
-
// again by index, and that lookup could fail and take the repaint down.
|
|
12455
12467
|
return this._internal__createRawItem(row._internal_index, value, colorer, row);
|
|
12456
12468
|
});
|
|
12457
12469
|
}
|
|
@@ -12474,10 +12486,10 @@ styleGetter) {
|
|
|
12474
12486
|
if (point) {
|
|
12475
12487
|
const style = styleGetter(renderingScope, point);
|
|
12476
12488
|
if (style !== prevStyle) {
|
|
12477
|
-
context.beginPath();
|
|
12478
12489
|
if (prevStyle !== null) {
|
|
12479
12490
|
context.fill();
|
|
12480
12491
|
}
|
|
12492
|
+
context.beginPath();
|
|
12481
12493
|
context.fillStyle = style;
|
|
12482
12494
|
prevStyle = style;
|
|
12483
12495
|
}
|
|
@@ -13416,9 +13428,6 @@ class BarsPaneViewBase extends SeriesPaneViewBase {
|
|
|
13416
13428
|
}
|
|
13417
13429
|
_internal__fillRawPoints() {
|
|
13418
13430
|
const colorer = this._internal__series._internal_barColorer();
|
|
13419
|
-
// The row goes to the colorer as it is. Asking for the style by index
|
|
13420
|
-
// alone made it look the row up again, and that second lookup could come
|
|
13421
|
-
// back empty and throw, taking the whole repaint down with it.
|
|
13422
13431
|
this._internal__items = this._internal__series._internal_bars()._internal_rows().map((row) => this._internal__createRawItem(row._internal_index, row, colorer));
|
|
13423
13432
|
}
|
|
13424
13433
|
}
|
|
@@ -17489,7 +17498,7 @@ function applyHeikinAshi(series, chart, options = {}) {
|
|
|
17489
17498
|
hideSource: options.hideSource ?? true,
|
|
17490
17499
|
};
|
|
17491
17500
|
const sourceOptions = series.options();
|
|
17492
|
-
// Same price scale and
|
|
17501
|
+
// Same price scale, formatting and axis labels as the source: the candles are a
|
|
17493
17502
|
// restatement of that series, not a second instrument, so they must not
|
|
17494
17503
|
// autoscale on their own axis or round to a different precision.
|
|
17495
17504
|
const haSeries = chart.addSeries(candlestickSeries, {
|
|
@@ -17503,6 +17512,8 @@ function applyHeikinAshi(series, chart, options = {}) {
|
|
|
17503
17512
|
wickDownColor: resolved.wickDownColor,
|
|
17504
17513
|
priceScaleId: sourceOptions.priceScaleId,
|
|
17505
17514
|
priceFormat: sourceOptions.priceFormat,
|
|
17515
|
+
lastValueVisible: sourceOptions.lastValueVisible,
|
|
17516
|
+
priceLineVisible: sourceOptions.priceLineVisible,
|
|
17506
17517
|
}, resolved.paneIndex);
|
|
17507
17518
|
let restoreSourcePaint = null;
|
|
17508
17519
|
const blankSource = (blank) => {
|
|
@@ -17704,12 +17715,14 @@ function applyMACD(series, chart, options = {}) {
|
|
|
17704
17715
|
const macdSeries = chart.addSeries(lineSeries, {
|
|
17705
17716
|
color: resolved.colorMACD,
|
|
17706
17717
|
}, paneIndex);
|
|
17718
|
+
// An index past the last pane opens a new one, so the rest follow MACD to where it landed.
|
|
17719
|
+
const macdPane = paneIndexOf(chart, macdSeries, paneIndex);
|
|
17707
17720
|
const signalSeries = chart.addSeries(lineSeries, {
|
|
17708
17721
|
color: resolved.colorSignal,
|
|
17709
|
-
},
|
|
17722
|
+
}, macdPane);
|
|
17710
17723
|
const histogramSeries$1 = chart.addSeries(histogramSeries, {
|
|
17711
17724
|
color: resolved.colorHistogramUp,
|
|
17712
|
-
},
|
|
17725
|
+
}, macdPane);
|
|
17713
17726
|
// Calculate EMA
|
|
17714
17727
|
const calculateEMA = (prices, period) => {
|
|
17715
17728
|
const ema = [];
|
|
@@ -17841,13 +17854,13 @@ function applyStochastic(series, chart, options = {}) {
|
|
|
17841
17854
|
// Stochastic is bounded to 0-100; pinning it keeps the pane readable
|
|
17842
17855
|
autoscaleInfoProvider: boundedScale,
|
|
17843
17856
|
}, paneIndex);
|
|
17857
|
+
// An index past the last pane opens a new one, so %D follows %K to where it landed.
|
|
17858
|
+
const scalePane = paneIndexOf(chart, kSeries, paneIndex);
|
|
17844
17859
|
// Create %D line (slow - signal)
|
|
17845
17860
|
const dSeries = chart.addSeries(lineSeries, {
|
|
17846
17861
|
color: resolved.colorD,
|
|
17847
17862
|
autoscaleInfoProvider: boundedScale,
|
|
17848
|
-
},
|
|
17849
|
-
// The pane the series landed in, which is not always the one asked for.
|
|
17850
|
-
const scalePane = paneIndexOf(chart, kSeries, paneIndex);
|
|
17863
|
+
}, scalePane);
|
|
17851
17864
|
chart.priceScale(kSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
|
|
17852
17865
|
scaleMargins: {
|
|
17853
17866
|
top: 0.1,
|
|
@@ -18189,15 +18202,16 @@ function applyADX(series, chart, options = {}) {
|
|
|
18189
18202
|
color: resolved.colorADX,
|
|
18190
18203
|
autoscaleInfoProvider: boundedScale,
|
|
18191
18204
|
}, paneIndex);
|
|
18205
|
+
// An index past the last pane opens a new one, so the DI lines follow ADX to where it landed.
|
|
18206
|
+
const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
|
|
18192
18207
|
const plusSeries = chart.addSeries(lineSeries, {
|
|
18193
18208
|
color: resolved.colorPlusDI,
|
|
18194
18209
|
autoscaleInfoProvider: boundedScale,
|
|
18195
|
-
},
|
|
18210
|
+
}, scalePane);
|
|
18196
18211
|
const minusSeries = chart.addSeries(lineSeries, {
|
|
18197
18212
|
color: resolved.colorMinusDI,
|
|
18198
18213
|
autoscaleInfoProvider: boundedScale,
|
|
18199
|
-
},
|
|
18200
|
-
const scalePane = paneIndexOf(chart, adxSeries, paneIndex);
|
|
18214
|
+
}, scalePane);
|
|
18201
18215
|
chart.priceScale(adxSeries.options().priceScaleId ?? 'right', scalePane).applyOptions({
|
|
18202
18216
|
scaleMargins: {
|
|
18203
18217
|
top: 0.1,
|
|
@@ -19313,6 +19327,8 @@ class TradingLineController {
|
|
|
19313
19327
|
this._private__pointerId = null;
|
|
19314
19328
|
this._private__pressOrigin = null;
|
|
19315
19329
|
this._private__pressedLine = null;
|
|
19330
|
+
/** Whether the gesture in flight came from a finger rather than a mouse. */
|
|
19331
|
+
this._private__pressWasTouch = false;
|
|
19316
19332
|
/** Distance from the pointer to the dragged line when the press landed. */
|
|
19317
19333
|
this._private__grabOffset = 0;
|
|
19318
19334
|
/** Latest pointer position in pane coordinates, or null when off the panes. */
|
|
@@ -19377,8 +19393,18 @@ class TradingLineController {
|
|
|
19377
19393
|
this._private__applyCursor();
|
|
19378
19394
|
}
|
|
19379
19395
|
_private__onPointerDown(event) {
|
|
19380
|
-
|
|
19396
|
+
// Hover belongs to the mouse. Touch leaves whatever the last press marked
|
|
19397
|
+
// still marked, so trusting it here grabbed that line again wherever the
|
|
19398
|
+
// next tap landed: every press resolves itself instead.
|
|
19399
|
+
this._private__pressWasTouch = event.pointerType !== 'mouse';
|
|
19400
|
+
let line = this._private__pressWasTouch || this._private__hoveredId === null
|
|
19401
|
+
? null
|
|
19402
|
+
: this._private__lines.get(this._private__hoveredId) ?? null;
|
|
19403
|
+
if (line === null) {
|
|
19404
|
+
line = this._private__resolveHitAt(event);
|
|
19405
|
+
}
|
|
19381
19406
|
if (!line) {
|
|
19407
|
+
this._private__clearTouchHover();
|
|
19382
19408
|
return;
|
|
19383
19409
|
}
|
|
19384
19410
|
this._private__pressOrigin = { _internal_x: event.clientX, _internal_y: event.clientY };
|
|
@@ -19417,6 +19443,7 @@ class TradingLineController {
|
|
|
19417
19443
|
}
|
|
19418
19444
|
_private__onPointerUp(event) {
|
|
19419
19445
|
const dragged = this._private__dragging;
|
|
19446
|
+
const wasTouch = this._private__pressWasTouch;
|
|
19420
19447
|
const pressed = this._private__pressedLine;
|
|
19421
19448
|
const origin = this._private__pressOrigin;
|
|
19422
19449
|
this._private__releasePointer();
|
|
@@ -19438,12 +19465,24 @@ class TradingLineController {
|
|
|
19438
19465
|
dragged.click();
|
|
19439
19466
|
}
|
|
19440
19467
|
}
|
|
19468
|
+
this._private__clearTouchHover(wasTouch);
|
|
19441
19469
|
this._private__applyCursor();
|
|
19442
19470
|
return;
|
|
19443
19471
|
}
|
|
19444
19472
|
if (pressed !== null && !moved && pressed.isClickable()) {
|
|
19445
19473
|
pressed.click();
|
|
19446
19474
|
}
|
|
19475
|
+
this._private__clearTouchHover(wasTouch);
|
|
19476
|
+
}
|
|
19477
|
+
/** A finger leaves nothing hovered behind it, the way lifting a mouse does. */
|
|
19478
|
+
_private__clearTouchHover(wasTouch = this._private__pressWasTouch) {
|
|
19479
|
+
if (!wasTouch || this._private__hoveredId === null) {
|
|
19480
|
+
return;
|
|
19481
|
+
}
|
|
19482
|
+
const line = this._private__lines.get(this._private__hoveredId) ?? null;
|
|
19483
|
+
this._private__setHovered(null);
|
|
19484
|
+
this._private__setHoveredPart(line, null);
|
|
19485
|
+
this._private__applyCursor();
|
|
19447
19486
|
}
|
|
19448
19487
|
/**
|
|
19449
19488
|
* Abort an in-flight gesture: the line goes back to where it was and no
|
|
@@ -19489,9 +19528,38 @@ class TradingLineController {
|
|
|
19489
19528
|
return paneY === null ? null : line.priceAt(paneY - this._private__grabOffset);
|
|
19490
19529
|
}
|
|
19491
19530
|
/** The pointer's position inside the line's pane, in pane coordinates. */
|
|
19492
|
-
|
|
19531
|
+
/**
|
|
19532
|
+
* The hovered id comes from the crosshair, which touch never moves before it
|
|
19533
|
+
* presses, so the press resolves the target itself.
|
|
19534
|
+
*/
|
|
19535
|
+
_private__resolveHitAt(event) {
|
|
19536
|
+
for (const line of this._private__lines.values()) {
|
|
19537
|
+
if (!line.hitTestAt) {
|
|
19538
|
+
continue;
|
|
19539
|
+
}
|
|
19540
|
+
const paneElement = this._private__paneElementOf(line);
|
|
19541
|
+
if (paneElement === null) {
|
|
19542
|
+
continue;
|
|
19543
|
+
}
|
|
19544
|
+
const rect = paneElement.getBoundingClientRect();
|
|
19545
|
+
// A fingertip is far coarser than a pointer, so its targets are widened.
|
|
19546
|
+
const slop = event.pointerType === 'mouse' ? 0 : 12 /* Constants.TouchSlopPx */;
|
|
19547
|
+
const hit = this._private__splitHit(line.hitTestAt(event.clientX - rect.left, event.clientY - rect.top, slop));
|
|
19548
|
+
if (hit === null) {
|
|
19549
|
+
continue;
|
|
19550
|
+
}
|
|
19551
|
+
this._private__setHovered(line.id());
|
|
19552
|
+
this._private__setHoveredPart(line, hit._internal_part);
|
|
19553
|
+
return line;
|
|
19554
|
+
}
|
|
19555
|
+
return null;
|
|
19556
|
+
}
|
|
19557
|
+
_private__paneElementOf(line) {
|
|
19493
19558
|
const pane = this._private__chart.panes()[line.paneIndex()];
|
|
19494
|
-
|
|
19559
|
+
return pane ? pane.getHTMLElement() : null;
|
|
19560
|
+
}
|
|
19561
|
+
_private__paneY(line, event) {
|
|
19562
|
+
const paneElement = this._private__paneElementOf(line);
|
|
19495
19563
|
if (paneElement) {
|
|
19496
19564
|
return event.clientY - paneElement.getBoundingClientRect().top;
|
|
19497
19565
|
}
|
|
@@ -19608,6 +19676,7 @@ let nextLineId = 0;
|
|
|
19608
19676
|
* line. Hit testing comes from the engine — the line's id travels as the price
|
|
19609
19677
|
* line's `externalId` — so the hit area matches what is drawn.
|
|
19610
19678
|
*/
|
|
19679
|
+
const HIT_TOLERANCE_PX$1 = 8;
|
|
19611
19680
|
class DraggablePriceLine {
|
|
19612
19681
|
constructor(chart, series, options) {
|
|
19613
19682
|
this._private__priceLine = null;
|
|
@@ -19660,6 +19729,14 @@ class DraggablePriceLine {
|
|
|
19660
19729
|
color: hovered ? this._private__options.hoverColor : this._private__originalColor,
|
|
19661
19730
|
});
|
|
19662
19731
|
}
|
|
19732
|
+
/**
|
|
19733
|
+
* The engine draws this one, so there is no pane view to ask: a press within
|
|
19734
|
+
* the line's own grab strip counts as a hit.
|
|
19735
|
+
*/
|
|
19736
|
+
hitTestAt(x, y, slop = 0) {
|
|
19737
|
+
const coord = this._private__series.priceToCoordinate(this._private__options.price);
|
|
19738
|
+
return coord !== null && Math.abs(y - coord) <= HIT_TOLERANCE_PX$1 + slop ? this._private__id : null;
|
|
19739
|
+
}
|
|
19663
19740
|
priceAt(paneY) {
|
|
19664
19741
|
const price = this._private__series.coordinateToPrice(paneY);
|
|
19665
19742
|
return price === null ? null : price;
|
|
@@ -20202,22 +20279,27 @@ class PositionLineRenderer {
|
|
|
20202
20279
|
_internal_setData(data) {
|
|
20203
20280
|
this._private__data = data;
|
|
20204
20281
|
}
|
|
20205
|
-
|
|
20282
|
+
/**
|
|
20283
|
+
* `slop` widens every target by the same amount, for input coarser than a
|
|
20284
|
+
* mouse pointer.
|
|
20285
|
+
*/
|
|
20286
|
+
_internal_hitTest(x, y, slop = 0) {
|
|
20206
20287
|
// The close button sits on top of the label, which sits on top of the
|
|
20207
20288
|
// line, so the narrowest target is tested first.
|
|
20208
20289
|
for (const layout of this._private__layouts) {
|
|
20209
|
-
if (layout._internal_closable && x >= layout._internal_closeLeft && x <= layout._internal_closeRight &&
|
|
20210
|
-
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2) {
|
|
20290
|
+
if (layout._internal_closable && x >= layout._internal_closeLeft - slop && x <= layout._internal_closeRight + slop &&
|
|
20291
|
+
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2 + slop) {
|
|
20211
20292
|
return { _internal_level: layout._internal_level, _internal_part: 'close' };
|
|
20212
20293
|
}
|
|
20213
20294
|
}
|
|
20214
20295
|
for (const layout of this._private__layouts) {
|
|
20215
|
-
if (x >= layout._internal_pillLeft && x <= layout._internal_pillRight
|
|
20296
|
+
if (x >= layout._internal_pillLeft - slop && x <= layout._internal_pillRight + slop &&
|
|
20297
|
+
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2 + slop) {
|
|
20216
20298
|
return { _internal_level: layout._internal_level, _internal_part: 'body' };
|
|
20217
20299
|
}
|
|
20218
20300
|
}
|
|
20219
20301
|
for (const layout of this._private__layouts) {
|
|
20220
|
-
if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */) {
|
|
20302
|
+
if (Math.abs(y - layout._internal_y) <= 8 /* Constants.LineHitTolerance */ + slop) {
|
|
20221
20303
|
return { _internal_level: layout._internal_level, _internal_part: 'line' };
|
|
20222
20304
|
}
|
|
20223
20305
|
}
|
|
@@ -20454,8 +20536,8 @@ class PositionLinePaneView {
|
|
|
20454
20536
|
zOrder() {
|
|
20455
20537
|
return 'top';
|
|
20456
20538
|
}
|
|
20457
|
-
_internal_hitTest(x, y) {
|
|
20458
|
-
return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y);
|
|
20539
|
+
_internal_hitTest(x, y, slop = 0) {
|
|
20540
|
+
return this._private__data === null ? null : this._private__renderer._internal_hitTest(x, y, slop);
|
|
20459
20541
|
}
|
|
20460
20542
|
}
|
|
20461
20543
|
|
|
@@ -20606,6 +20688,13 @@ class PositionLine {
|
|
|
20606
20688
|
* of jumping to sit under it — which matters most when the label has been
|
|
20607
20689
|
* fanned away from its own line.
|
|
20608
20690
|
*/
|
|
20691
|
+
hitTestAt(x, y, slop = 0) {
|
|
20692
|
+
const hit = this._private__paneView._internal_hitTest(x, y, slop);
|
|
20693
|
+
if (hit === null) {
|
|
20694
|
+
return null;
|
|
20695
|
+
}
|
|
20696
|
+
return this._private__levelOptions(hit._internal_level) === null ? null : `${this._private__id}#${hit._internal_level}:${hit._internal_part}`;
|
|
20697
|
+
}
|
|
20609
20698
|
dragAnchorY() {
|
|
20610
20699
|
if (this._private__dragLevel === null) {
|
|
20611
20700
|
return null;
|
|
@@ -29676,6 +29765,7 @@ class DrawingToolsManager {
|
|
|
29676
29765
|
this._private__mouseMoveHandler = null;
|
|
29677
29766
|
this._private__pointerDownHandler = null;
|
|
29678
29767
|
this._private__pointerUpHandler = null;
|
|
29768
|
+
this._private__pointerMoveHandler = null;
|
|
29679
29769
|
this._private__pointerCancelHandler = null;
|
|
29680
29770
|
this._private__lostCaptureHandler = null;
|
|
29681
29771
|
this._private__windowPointerUpHandler = null;
|
|
@@ -30250,10 +30340,12 @@ class DrawingToolsManager {
|
|
|
30250
30340
|
if (chartElement) {
|
|
30251
30341
|
this._private__pointerDownHandler = (event) => this._private__handlePointerDown(event);
|
|
30252
30342
|
this._private__pointerUpHandler = (event) => this._private__handlePointerUp(event);
|
|
30343
|
+
this._private__pointerMoveHandler = (event) => this._private__handlePointerMove(event);
|
|
30253
30344
|
this._private__pointerCancelHandler = (event) => this._private__handlePointerUp(event);
|
|
30254
30345
|
this._private__lostCaptureHandler = (event) => this._private__handleLostPointerCapture(event);
|
|
30255
30346
|
chartElement.addEventListener('pointerdown', this._private__pointerDownHandler);
|
|
30256
30347
|
chartElement.addEventListener('pointerup', this._private__pointerUpHandler);
|
|
30348
|
+
chartElement.addEventListener('pointermove', this._private__pointerMoveHandler);
|
|
30257
30349
|
chartElement.addEventListener('pointercancel', this._private__pointerCancelHandler);
|
|
30258
30350
|
chartElement.addEventListener('lostpointercapture', this._private__lostCaptureHandler);
|
|
30259
30351
|
}
|
|
@@ -30288,6 +30380,10 @@ class DrawingToolsManager {
|
|
|
30288
30380
|
chartElement.removeEventListener('pointerup', this._private__pointerUpHandler);
|
|
30289
30381
|
this._private__pointerUpHandler = null;
|
|
30290
30382
|
}
|
|
30383
|
+
if (this._private__pointerMoveHandler) {
|
|
30384
|
+
chartElement.removeEventListener('pointermove', this._private__pointerMoveHandler);
|
|
30385
|
+
this._private__pointerMoveHandler = null;
|
|
30386
|
+
}
|
|
30291
30387
|
if (this._private__pointerCancelHandler) {
|
|
30292
30388
|
chartElement.removeEventListener('pointercancel', this._private__pointerCancelHandler);
|
|
30293
30389
|
this._private__pointerCancelHandler = null;
|
|
@@ -30437,6 +30533,36 @@ class DrawingToolsManager {
|
|
|
30437
30533
|
// mouse events, and those are what drive the crosshair the drag reads.
|
|
30438
30534
|
this._private__disableChartInteractions();
|
|
30439
30535
|
}
|
|
30536
|
+
/**
|
|
30537
|
+
* The drag reads the crosshair, which touch never moves: its move handler
|
|
30538
|
+
* only tries to pan, and the drag has just turned panning off. So touch is
|
|
30539
|
+
* driven straight from the pointer instead.
|
|
30540
|
+
*/
|
|
30541
|
+
_private__handlePointerMove(event) {
|
|
30542
|
+
if (!this._private__isDragging || this._private__draggedToolId === null || event.pointerType === 'mouse') {
|
|
30543
|
+
return;
|
|
30544
|
+
}
|
|
30545
|
+
if (this._private__pointerId !== null && event.pointerId !== this._private__pointerId) {
|
|
30546
|
+
return;
|
|
30547
|
+
}
|
|
30548
|
+
const tool = this._private__tools.get(this._private__draggedToolId);
|
|
30549
|
+
if (!tool) {
|
|
30550
|
+
return;
|
|
30551
|
+
}
|
|
30552
|
+
const paneElement = this._private__paneElementOf(tool);
|
|
30553
|
+
if (paneElement === null) {
|
|
30554
|
+
return;
|
|
30555
|
+
}
|
|
30556
|
+
const rect = paneElement.getBoundingClientRect();
|
|
30557
|
+
const series = tool.series();
|
|
30558
|
+
const price = series.coordinateToPrice((event.clientY - rect.top));
|
|
30559
|
+
const time = timeFromCoordinate(this._private__chart, series, event.clientX - rect.left);
|
|
30560
|
+
if (price === null || time === null) {
|
|
30561
|
+
return;
|
|
30562
|
+
}
|
|
30563
|
+
tool.updateDrag(time, price);
|
|
30564
|
+
event.preventDefault();
|
|
30565
|
+
}
|
|
30440
30566
|
_private__handlePointerUp(event) {
|
|
30441
30567
|
if (!this._private__isDragging || this._private__draggedToolId === null) {
|
|
30442
30568
|
return;
|
|
@@ -30610,7 +30736,7 @@ const customSeriesDefaultOptions = {
|
|
|
30610
30736
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
30611
30737
|
*/
|
|
30612
30738
|
function version() {
|
|
30613
|
-
return "2.3.
|
|
30739
|
+
return "2.3.11";
|
|
30614
30740
|
}
|
|
30615
30741
|
|
|
30616
30742
|
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 };
|