@pipsend/charts 2.3.18 → 2.3.20
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 +185 -116
- package/dist/pipsend-charts.production.mjs +2 -2
- package/dist/pipsend-charts.standalone.development.js +185 -115
- package/dist/pipsend-charts.standalone.development.mjs +185 -116
- package/dist/pipsend-charts.standalone.production.js +2 -2
- package/dist/pipsend-charts.standalone.production.mjs +2 -2
- package/dist/typings.d.ts +34 -6
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @license
|
|
3
|
-
* Pipsend Charts v2.3.
|
|
3
|
+
* Pipsend Charts v2.3.20-dev+202610211649
|
|
4
4
|
* Copyright (c) 2026 Pipsend
|
|
5
5
|
* Licensed under MIT License
|
|
6
6
|
* Built on TradingView Lightweight Charts™ (Apache 2.0)
|
|
@@ -5555,7 +5555,7 @@
|
|
|
5555
5555
|
const visibleBars = ensureNotNull(this._internal_visibleStrictRange());
|
|
5556
5556
|
const firstBar = Math.max(visibleBars._internal_left(), visibleBars._internal_left() - indexPerLabel);
|
|
5557
5557
|
const lastBar = Math.max(visibleBars._internal_right(), visibleBars._internal_right() - indexPerLabel);
|
|
5558
|
-
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);
|
|
5558
|
+
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, this._private__points[mark.index - 1]) ?? true);
|
|
5559
5559
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second label on time scale"
|
|
5560
5560
|
const earliestIndexOfSecondLabel = this._private__firstIndex() + indexPerLabel;
|
|
5561
5561
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second last label on time scale"
|
|
@@ -6829,6 +6829,75 @@
|
|
|
6829
6829
|
return localDateFromUtc.toLocaleString(locale, formatOptions);
|
|
6830
6830
|
}
|
|
6831
6831
|
|
|
6832
|
+
const DAY = 86400;
|
|
6833
|
+
const QUARTER_HOUR = 900;
|
|
6834
|
+
const zones = new Map();
|
|
6835
|
+
function zoneCache(timeZone) {
|
|
6836
|
+
let cache = zones.get(timeZone);
|
|
6837
|
+
if (cache === undefined) {
|
|
6838
|
+
let format = null;
|
|
6839
|
+
try {
|
|
6840
|
+
format = new Intl.DateTimeFormat('en-US', {
|
|
6841
|
+
timeZone,
|
|
6842
|
+
hourCycle: 'h23',
|
|
6843
|
+
year: 'numeric',
|
|
6844
|
+
month: 'numeric',
|
|
6845
|
+
day: 'numeric',
|
|
6846
|
+
hour: 'numeric',
|
|
6847
|
+
minute: 'numeric',
|
|
6848
|
+
second: 'numeric',
|
|
6849
|
+
});
|
|
6850
|
+
}
|
|
6851
|
+
catch (error) {
|
|
6852
|
+
format = null;
|
|
6853
|
+
}
|
|
6854
|
+
cache = { _internal_format: format, _internal_days: new Map(), _internal_quarters: new Map() };
|
|
6855
|
+
zones.set(timeZone, cache);
|
|
6856
|
+
}
|
|
6857
|
+
return cache;
|
|
6858
|
+
}
|
|
6859
|
+
function exactOffset(format, time) {
|
|
6860
|
+
const parts = format.formatToParts(new Date(time * 1000));
|
|
6861
|
+
const part = (type) => Number(parts.find((p) => p.type === type)?.value ?? 0);
|
|
6862
|
+
const wallClock = Date.UTC(part('year'), part('month') - 1, part('day'), part('hour') % 24, part('minute'), part('second'));
|
|
6863
|
+
return Math.round(wallClock / 1000 - time);
|
|
6864
|
+
}
|
|
6865
|
+
/**
|
|
6866
|
+
* Offset of `timeZone` from UTC at `time`, in seconds. Undefined, `'UTC'` and
|
|
6867
|
+
* unknown zones are 0.
|
|
6868
|
+
*
|
|
6869
|
+
* Resolved once per UTC day, and to the quarter hour only on days with a
|
|
6870
|
+
* transition: asking `Intl` for every bar is too slow for a whole series.
|
|
6871
|
+
*/
|
|
6872
|
+
function timeZoneOffset(timeZone, time) {
|
|
6873
|
+
if (timeZone === undefined || timeZone === 'UTC') {
|
|
6874
|
+
return 0;
|
|
6875
|
+
}
|
|
6876
|
+
const cache = zoneCache(timeZone);
|
|
6877
|
+
const format = cache._internal_format;
|
|
6878
|
+
if (format === null) {
|
|
6879
|
+
return 0;
|
|
6880
|
+
}
|
|
6881
|
+
const day = Math.floor(time / DAY);
|
|
6882
|
+
let wholeDay = cache._internal_days.get(day);
|
|
6883
|
+
if (wholeDay === undefined) {
|
|
6884
|
+
const start = exactOffset(format, day * DAY);
|
|
6885
|
+
const end = exactOffset(format, (day + 1) * DAY - 1);
|
|
6886
|
+
wholeDay = start === end ? start : null;
|
|
6887
|
+
cache._internal_days.set(day, wholeDay);
|
|
6888
|
+
}
|
|
6889
|
+
if (wholeDay !== null) {
|
|
6890
|
+
return wholeDay;
|
|
6891
|
+
}
|
|
6892
|
+
const quarter = Math.floor(time / QUARTER_HOUR);
|
|
6893
|
+
let offset = cache._internal_quarters.get(quarter);
|
|
6894
|
+
if (offset === undefined) {
|
|
6895
|
+
offset = exactOffset(format, quarter * QUARTER_HOUR);
|
|
6896
|
+
cache._internal_quarters.set(quarter, offset);
|
|
6897
|
+
}
|
|
6898
|
+
return offset;
|
|
6899
|
+
}
|
|
6900
|
+
|
|
6832
6901
|
function hours(count) {
|
|
6833
6902
|
return count * 60 * 60 * 1000;
|
|
6834
6903
|
}
|
|
@@ -6868,29 +6937,36 @@
|
|
|
6868
6937
|
function cast(t) {
|
|
6869
6938
|
return t;
|
|
6870
6939
|
}
|
|
6871
|
-
|
|
6940
|
+
// Business days are dates, not instants: never shifted
|
|
6941
|
+
function zonedTimestamp(point, timeZone) {
|
|
6942
|
+
const time = cast(point.time);
|
|
6943
|
+
return time._internal_businessDay === undefined ? time._internal_timestamp + timeZoneOffset(timeZone, time._internal_timestamp) : time._internal_timestamp;
|
|
6944
|
+
}
|
|
6945
|
+
function fillWeightsForPoints(sortedTimePoints, startIndex = 0, timeZone) {
|
|
6872
6946
|
if (sortedTimePoints.length === 0) {
|
|
6873
6947
|
return;
|
|
6874
6948
|
}
|
|
6875
|
-
let prevTime = startIndex === 0 ? null :
|
|
6949
|
+
let prevTime = startIndex === 0 ? null : zonedTimestamp(sortedTimePoints[startIndex - 1], timeZone);
|
|
6876
6950
|
let prevDate = prevTime !== null ? new Date(prevTime * 1000) : null;
|
|
6877
6951
|
let totalTimeDiff = 0;
|
|
6878
6952
|
for (let index = startIndex; index < sortedTimePoints.length; ++index) {
|
|
6879
6953
|
const currentPoint = sortedTimePoints[index];
|
|
6880
|
-
const
|
|
6954
|
+
const currentTime = zonedTimestamp(currentPoint, timeZone);
|
|
6955
|
+
const currentDate = new Date(currentTime * 1000);
|
|
6881
6956
|
if (prevDate !== null) {
|
|
6882
6957
|
currentPoint.timeWeight = weightByTime(currentDate, prevDate);
|
|
6883
6958
|
}
|
|
6884
|
-
totalTimeDiff +=
|
|
6885
|
-
prevTime =
|
|
6959
|
+
totalTimeDiff += currentTime - (prevTime || currentTime);
|
|
6960
|
+
prevTime = currentTime;
|
|
6886
6961
|
prevDate = currentDate;
|
|
6887
6962
|
}
|
|
6888
6963
|
if (startIndex === 0 && sortedTimePoints.length > 1) {
|
|
6889
6964
|
// let's guess a weight for the first point
|
|
6890
6965
|
// let's say the previous point was average time back in the history
|
|
6891
6966
|
const averageTimeDiff = Math.ceil(totalTimeDiff / (sortedTimePoints.length - 1));
|
|
6892
|
-
const
|
|
6893
|
-
|
|
6967
|
+
const firstTime = zonedTimestamp(sortedTimePoints[0], timeZone);
|
|
6968
|
+
const approxPrevDate = new Date((firstTime - averageTimeDiff) * 1000);
|
|
6969
|
+
sortedTimePoints[0].timeWeight = weightByTime(new Date(firstTime * 1000), approxPrevDate);
|
|
6894
6970
|
}
|
|
6895
6971
|
}
|
|
6896
6972
|
|
|
@@ -7045,16 +7121,15 @@
|
|
|
7045
7121
|
}
|
|
7046
7122
|
}
|
|
7047
7123
|
formatHorzItem(item) {
|
|
7048
|
-
|
|
7049
|
-
return this._private__dateTimeFormatter._internal_format(new Date(tp._internal_timestamp * 1000));
|
|
7124
|
+
return this._private__dateTimeFormatter._internal_format(new Date(this._private__zonedTimePoint(item)._internal_timestamp * 1000));
|
|
7050
7125
|
}
|
|
7051
|
-
allowsTickMark(tickMark, barsPerMark) {
|
|
7126
|
+
allowsTickMark(tickMark, barsPerMark, previous) {
|
|
7052
7127
|
const filter = this._private__options.timeScale.tickMarkFilter;
|
|
7053
7128
|
if (filter === undefined) {
|
|
7054
7129
|
return true;
|
|
7055
7130
|
}
|
|
7056
7131
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7057
|
-
return filter(tickMark.originalTime, tickMarkType, barsPerMark);
|
|
7132
|
+
return filter(tickMark.originalTime, tickMarkType, barsPerMark, previous === undefined ? null : previous.originalTime);
|
|
7058
7133
|
}
|
|
7059
7134
|
formatTickmark(tickMark, localizationOptions) {
|
|
7060
7135
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
@@ -7065,7 +7140,7 @@
|
|
|
7065
7140
|
return tickMarkString;
|
|
7066
7141
|
}
|
|
7067
7142
|
}
|
|
7068
|
-
return defaultTickMarkFormatter(tickMark.time, tickMarkType, localizationOptions.locale);
|
|
7143
|
+
return defaultTickMarkFormatter(this._private__zonedTimePoint(tickMark.time), tickMarkType, localizationOptions.locale);
|
|
7069
7144
|
}
|
|
7070
7145
|
maxTickMarkWeight(tickMarks) {
|
|
7071
7146
|
let maxWeight = tickMarks.reduce(markWithGreaterWeight$2, tickMarks[0]).weight;
|
|
@@ -7077,7 +7152,17 @@
|
|
|
7077
7152
|
return maxWeight;
|
|
7078
7153
|
}
|
|
7079
7154
|
fillWeightsForPoints(sortedTimePoints, startIndex) {
|
|
7080
|
-
fillWeightsForPoints(sortedTimePoints, startIndex);
|
|
7155
|
+
fillWeightsForPoints(sortedTimePoints, startIndex, this._private__timeZone());
|
|
7156
|
+
}
|
|
7157
|
+
_private__timeZone() {
|
|
7158
|
+
return this._private__options?.localization.timeZone;
|
|
7159
|
+
}
|
|
7160
|
+
_private__zonedTimePoint(timePoint) {
|
|
7161
|
+
if (timePoint._internal_businessDay !== undefined) {
|
|
7162
|
+
return timePoint;
|
|
7163
|
+
}
|
|
7164
|
+
const offset = timeZoneOffset(this._private__timeZone(), timePoint._internal_timestamp);
|
|
7165
|
+
return offset === 0 ? timePoint : { _internal_timestamp: (timePoint._internal_timestamp + offset) };
|
|
7081
7166
|
}
|
|
7082
7167
|
static _internal_applyDefaults(options) {
|
|
7083
7168
|
return merge({ localization: { dateFormat: 'dd MMM \'yy' } }, options ?? {});
|
|
@@ -11079,6 +11164,10 @@
|
|
|
11079
11164
|
this._private__sortedTimePoints = [];
|
|
11080
11165
|
this._private__horzScaleBehavior = horzScaleBehavior;
|
|
11081
11166
|
}
|
|
11167
|
+
_internal_refillTimeWeights() {
|
|
11168
|
+
this._private__horzScaleBehavior.fillWeightsForPoints(this._private__sortedTimePoints, 0);
|
|
11169
|
+
return this._private__sortedTimePoints;
|
|
11170
|
+
}
|
|
11082
11171
|
_internal_destroy() {
|
|
11083
11172
|
this._private__pointDataByTimePoint.clear();
|
|
11084
11173
|
this._private__seriesRowsBySeries.clear();
|
|
@@ -12583,7 +12672,13 @@
|
|
|
12583
12672
|
throw new Error(`colorParsers option should not be changed once the chart has been created.`);
|
|
12584
12673
|
}
|
|
12585
12674
|
}
|
|
12675
|
+
const timeZone = this.options().localization.timeZone;
|
|
12586
12676
|
this._private__chartWidget._internal_applyOptions(toInternalOptions(options));
|
|
12677
|
+
if (this.options().localization.timeZone !== timeZone) {
|
|
12678
|
+
const model = this._private__chartWidget._internal_model();
|
|
12679
|
+
model._internal_timeScale()._internal_update(this._private__dataLayer._internal_refillTimeWeights(), 0);
|
|
12680
|
+
model._internal_fullUpdate();
|
|
12681
|
+
}
|
|
12587
12682
|
}
|
|
12588
12683
|
options() {
|
|
12589
12684
|
return this._private__chartWidget._internal_options();
|
|
@@ -19221,8 +19316,9 @@
|
|
|
19221
19316
|
const DEFAULT_SESSIONS = [
|
|
19222
19317
|
{
|
|
19223
19318
|
name: 'Tokyo',
|
|
19224
|
-
startHour:
|
|
19225
|
-
endHour:
|
|
19319
|
+
startHour: 9,
|
|
19320
|
+
endHour: 18,
|
|
19321
|
+
timeZone: 'Asia/Tokyo',
|
|
19226
19322
|
color: '#FF6B00',
|
|
19227
19323
|
opacity: 0.1,
|
|
19228
19324
|
},
|
|
@@ -19230,13 +19326,15 @@
|
|
|
19230
19326
|
name: 'London',
|
|
19231
19327
|
startHour: 8,
|
|
19232
19328
|
endHour: 17,
|
|
19329
|
+
timeZone: 'Europe/London',
|
|
19233
19330
|
color: '#2962FF',
|
|
19234
19331
|
opacity: 0.1,
|
|
19235
19332
|
},
|
|
19236
19333
|
{
|
|
19237
19334
|
name: 'New York',
|
|
19238
|
-
startHour:
|
|
19239
|
-
endHour:
|
|
19335
|
+
startHour: 8,
|
|
19336
|
+
endHour: 17,
|
|
19337
|
+
timeZone: 'America/New_York',
|
|
19240
19338
|
color: '#089981',
|
|
19241
19339
|
opacity: 0.1,
|
|
19242
19340
|
},
|
|
@@ -19322,79 +19420,49 @@
|
|
|
19322
19420
|
}
|
|
19323
19421
|
}
|
|
19324
19422
|
_private__highlightSession(session, data) {
|
|
19325
|
-
|
|
19326
|
-
let sessionData = [];
|
|
19327
|
-
for (const point of data) {
|
|
19328
|
-
const time = point.time;
|
|
19329
|
-
const hour = this._private__getUTCHour(time);
|
|
19330
|
-
const isInSession = this._private__isTimeInSession(hour, session.startHour, session.endHour);
|
|
19331
|
-
if (isInSession) {
|
|
19332
|
-
if (!sessionStart) {
|
|
19333
|
-
sessionStart = time;
|
|
19334
|
-
}
|
|
19335
|
-
sessionData.push(point);
|
|
19336
|
-
}
|
|
19337
|
-
else {
|
|
19338
|
-
if (sessionStart && sessionData.length > 0) {
|
|
19339
|
-
// End of session, create highlight box
|
|
19340
|
-
this._private__createSessionBox(sessionStart, sessionData[sessionData.length - 1].time, session);
|
|
19341
|
-
sessionStart = null;
|
|
19342
|
-
sessionData = [];
|
|
19343
|
-
}
|
|
19344
|
-
}
|
|
19345
|
-
}
|
|
19346
|
-
// Handle case where session extends to end of visible range
|
|
19347
|
-
if (sessionStart && sessionData.length > 0) {
|
|
19348
|
-
this._private__createSessionBox(sessionStart, sessionData[sessionData.length - 1].time, session);
|
|
19349
|
-
}
|
|
19423
|
+
this._private__eachRun(data, (time) => this._private__inSession(time, session), (startTime, endTime) => this._private__createSessionBox(startTime, endTime, session));
|
|
19350
19424
|
}
|
|
19425
|
+
// Per bar, since each session reads the clock of its own zone
|
|
19351
19426
|
_private__highlightOverlaps(data) {
|
|
19352
|
-
// Find overlapping sessions
|
|
19353
19427
|
const sessions = this._private__options.sessions;
|
|
19354
19428
|
for (let i = 0; i < sessions.length; i++) {
|
|
19355
19429
|
for (let j = i + 1; j < sessions.length; j++) {
|
|
19356
|
-
|
|
19357
|
-
const session2 = sessions[j];
|
|
19358
|
-
// Check if sessions overlap
|
|
19359
|
-
const overlap = this._private__getSessionOverlap(session1, session2);
|
|
19360
|
-
if (overlap) {
|
|
19361
|
-
this._private__highlightOverlapPeriod(overlap, data);
|
|
19362
|
-
}
|
|
19430
|
+
this._private__eachRun(data, (time) => this._private__inSession(time, sessions[i]) && this._private__inSession(time, sessions[j]), (startTime, endTime) => this._private__createOverlapBox(startTime, endTime));
|
|
19363
19431
|
}
|
|
19364
19432
|
}
|
|
19365
19433
|
}
|
|
19366
|
-
|
|
19367
|
-
|
|
19368
|
-
|
|
19369
|
-
if (start < end) {
|
|
19370
|
-
return { _internal_start: start, _internal_end: end };
|
|
19371
|
-
}
|
|
19372
|
-
return null;
|
|
19373
|
-
}
|
|
19374
|
-
_private__highlightOverlapPeriod(overlap, data) {
|
|
19375
|
-
let overlapStart = null;
|
|
19376
|
-
let overlapData = [];
|
|
19434
|
+
_private__eachRun(data, inside, emit) {
|
|
19435
|
+
let runStart = null;
|
|
19436
|
+
let runEnd = null;
|
|
19377
19437
|
for (const point of data) {
|
|
19378
|
-
|
|
19379
|
-
|
|
19380
|
-
|
|
19381
|
-
if (isInOverlap) {
|
|
19382
|
-
if (!overlapStart) {
|
|
19383
|
-
overlapStart = time;
|
|
19384
|
-
}
|
|
19385
|
-
overlapData.push(point);
|
|
19438
|
+
if (inside(point.time)) {
|
|
19439
|
+
runStart = runStart ?? point.time;
|
|
19440
|
+
runEnd = point.time;
|
|
19386
19441
|
}
|
|
19387
|
-
else {
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
overlapData = [];
|
|
19392
|
-
}
|
|
19442
|
+
else if (runStart !== null && runEnd !== null) {
|
|
19443
|
+
emit(runStart, runEnd);
|
|
19444
|
+
runStart = null;
|
|
19445
|
+
runEnd = null;
|
|
19393
19446
|
}
|
|
19394
19447
|
}
|
|
19395
|
-
if (
|
|
19396
|
-
|
|
19448
|
+
if (runStart !== null && runEnd !== null) {
|
|
19449
|
+
emit(runStart, runEnd);
|
|
19450
|
+
}
|
|
19451
|
+
}
|
|
19452
|
+
_private__inSession(time, session) {
|
|
19453
|
+
const hour = this._private__hourIn(time, session.timeZone);
|
|
19454
|
+
if (session.startHour < session.endHour) {
|
|
19455
|
+
return hour >= session.startHour && hour < session.endHour;
|
|
19397
19456
|
}
|
|
19457
|
+
// Crosses midnight
|
|
19458
|
+
return hour >= session.startHour || hour < session.endHour;
|
|
19459
|
+
}
|
|
19460
|
+
_private__hourIn(time, timeZone) {
|
|
19461
|
+
const seconds = typeof time === 'number' ? time : typeof time === 'string' ? Date.parse(time) / 1000 : NaN;
|
|
19462
|
+
if (!Number.isFinite(seconds)) {
|
|
19463
|
+
return 0;
|
|
19464
|
+
}
|
|
19465
|
+
return new Date((seconds + timeZoneOffset(timeZone, seconds)) * 1000).getUTCHours();
|
|
19398
19466
|
}
|
|
19399
19467
|
_private__createSessionBox(startTime, endTime, session) {
|
|
19400
19468
|
// Validate times
|
|
@@ -19424,29 +19492,6 @@
|
|
|
19424
19492
|
};
|
|
19425
19493
|
this._private__sessionBoxes.push(box);
|
|
19426
19494
|
}
|
|
19427
|
-
_private__isTimeInSession(hour, startHour, endHour) {
|
|
19428
|
-
if (startHour < endHour) {
|
|
19429
|
-
return hour >= startHour && hour < endHour;
|
|
19430
|
-
}
|
|
19431
|
-
else {
|
|
19432
|
-
// Session crosses midnight
|
|
19433
|
-
return hour >= startHour || hour < endHour;
|
|
19434
|
-
}
|
|
19435
|
-
}
|
|
19436
|
-
_private__getUTCHour(time) {
|
|
19437
|
-
// Convert time to UTC hour
|
|
19438
|
-
if (typeof time === 'number') {
|
|
19439
|
-
// Unix timestamp in seconds
|
|
19440
|
-
const date = new Date(time * 1000);
|
|
19441
|
-
return date.getUTCHours();
|
|
19442
|
-
}
|
|
19443
|
-
else if (typeof time === 'string') {
|
|
19444
|
-
// ISO string
|
|
19445
|
-
const date = new Date(time);
|
|
19446
|
-
return date.getUTCHours();
|
|
19447
|
-
}
|
|
19448
|
-
return 0;
|
|
19449
|
-
}
|
|
19450
19495
|
_private__clearSessionBoxes() {
|
|
19451
19496
|
// Clear all session boxes
|
|
19452
19497
|
this._private__sessionBoxes = [];
|
|
@@ -27953,6 +27998,13 @@
|
|
|
27953
27998
|
isDrawingModeActive() {
|
|
27954
27999
|
return this._private__drawingModeActive;
|
|
27955
28000
|
}
|
|
28001
|
+
/**
|
|
28002
|
+
* A brush armed for its next stroke is not a drawing yet: it stays out of the
|
|
28003
|
+
* undo history, where restoring it would re-arm a brush the app does not hold.
|
|
28004
|
+
*/
|
|
28005
|
+
isComplete() {
|
|
28006
|
+
return (this._private__brushOptions.points ?? []).length > 0;
|
|
28007
|
+
}
|
|
27956
28008
|
_private__onPointerDown(event) {
|
|
27957
28009
|
// A press over an existing drawing belongs to that drawing: it is how the
|
|
27958
28010
|
// user grabs or selects one without putting the brush away first.
|
|
@@ -30592,6 +30644,14 @@
|
|
|
30592
30644
|
|
|
30593
30645
|
/** Undo steps kept, each a full snapshot of every drawing. */
|
|
30594
30646
|
const UNDO_HISTORY_LIMIT = 100;
|
|
30647
|
+
/**
|
|
30648
|
+
* Points for a restored freehand tool. Built with bracket notation: a plain
|
|
30649
|
+
* `{ time, price }` literal gets its keys renamed by the build, and the tool,
|
|
30650
|
+
* which reads them by their public names, comes back drawing nothing.
|
|
30651
|
+
*/
|
|
30652
|
+
function restorePoints(points) {
|
|
30653
|
+
return points.map((point) => makeSerializedPoint(readSerializedNumber(point, 'price') ?? 0, readSerializedTime(point)));
|
|
30654
|
+
}
|
|
30595
30655
|
/**
|
|
30596
30656
|
* Central manager for all drawing tools - TradingView style
|
|
30597
30657
|
* Handles multiple tools, selection, deletion, and keyboard shortcuts
|
|
@@ -30826,7 +30886,22 @@
|
|
|
30826
30886
|
_private__applySnapshot(snapshot) {
|
|
30827
30887
|
this._private__restoring = true;
|
|
30828
30888
|
try {
|
|
30829
|
-
|
|
30889
|
+
// The history only holds placed drawings, so a tool still being drawn
|
|
30890
|
+
// stays: undoing with the brush armed must leave it armed.
|
|
30891
|
+
this._private__applySelection(null);
|
|
30892
|
+
for (const [id, tool] of Array.from(this._private__tools)) {
|
|
30893
|
+
if (!tool.isComplete()) {
|
|
30894
|
+
continue;
|
|
30895
|
+
}
|
|
30896
|
+
tool.remove();
|
|
30897
|
+
this._private__tools.delete(id);
|
|
30898
|
+
this._private__pendingToolIds.delete(id);
|
|
30899
|
+
}
|
|
30900
|
+
// Annotated, or the build renames the keys the tools read
|
|
30901
|
+
const context = { chart: this._private__chart, series: this._private__series };
|
|
30902
|
+
for (const data of snapshot) {
|
|
30903
|
+
this.restoreTool(context, data);
|
|
30904
|
+
}
|
|
30830
30905
|
this._private__committed = snapshot;
|
|
30831
30906
|
}
|
|
30832
30907
|
finally {
|
|
@@ -31056,16 +31131,8 @@
|
|
|
31056
31131
|
...style,
|
|
31057
31132
|
});
|
|
31058
31133
|
case 'polygon':
|
|
31059
|
-
// Bracket notation on the way out too, not just on the way in: a
|
|
31060
|
-
// plain `{ time, price }` literal here gets its keys renamed and
|
|
31061
|
-
// the restored corners come back empty.
|
|
31062
31134
|
return createPolygonTool(context, {
|
|
31063
|
-
points: points
|
|
31064
|
-
const vertex = {};
|
|
31065
|
-
vertex['time'] = pt(index)._internal_t;
|
|
31066
|
-
vertex['price'] = pt(index)._internal_p;
|
|
31067
|
-
return vertex;
|
|
31068
|
-
}),
|
|
31135
|
+
points: restorePoints(points),
|
|
31069
31136
|
...style,
|
|
31070
31137
|
});
|
|
31071
31138
|
case 'crossLine':
|
|
@@ -31131,12 +31198,12 @@
|
|
|
31131
31198
|
});
|
|
31132
31199
|
case 'arrow':
|
|
31133
31200
|
return createArrowTool(context, {
|
|
31134
|
-
points: points
|
|
31201
|
+
points: restorePoints(points),
|
|
31135
31202
|
...style,
|
|
31136
31203
|
});
|
|
31137
31204
|
case 'brush':
|
|
31138
31205
|
return createBrushTool(context, {
|
|
31139
|
-
points: points
|
|
31206
|
+
points: restorePoints(points),
|
|
31140
31207
|
...style,
|
|
31141
31208
|
});
|
|
31142
31209
|
case 'text':
|
|
@@ -31434,6 +31501,8 @@
|
|
|
31434
31501
|
event.preventDefault();
|
|
31435
31502
|
}
|
|
31436
31503
|
_private__handlePointerUp(event) {
|
|
31504
|
+
// A brush stroke ends here, and no click follows it to run the check
|
|
31505
|
+
this._private__scheduleCompletionCheck();
|
|
31437
31506
|
if (!this._private__isDragging || this._private__draggedToolId === null) {
|
|
31438
31507
|
return;
|
|
31439
31508
|
}
|
|
@@ -31606,7 +31675,7 @@
|
|
|
31606
31675
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
31607
31676
|
*/
|
|
31608
31677
|
function version() {
|
|
31609
|
-
return "2.3.
|
|
31678
|
+
return "2.3.20-dev+202610211649";
|
|
31610
31679
|
}
|
|
31611
31680
|
|
|
31612
31681
|
var PipsendChartsModule = /*#__PURE__*/Object.freeze({
|
|
@@ -31725,6 +31794,7 @@
|
|
|
31725
31794
|
setSeriesVolumes: setSeriesVolumes,
|
|
31726
31795
|
setVolumeProfileData: setVolumeProfileData,
|
|
31727
31796
|
timeFromCoordinate: timeFromCoordinate,
|
|
31797
|
+
timeZoneOffset: timeZoneOffset,
|
|
31728
31798
|
version: version
|
|
31729
31799
|
});
|
|
31730
31800
|
|