@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)
|
|
@@ -5552,7 +5552,7 @@ class TimeScale {
|
|
|
5552
5552
|
const visibleBars = ensureNotNull(this._internal_visibleStrictRange());
|
|
5553
5553
|
const firstBar = Math.max(visibleBars._internal_left(), visibleBars._internal_left() - indexPerLabel);
|
|
5554
5554
|
const lastBar = Math.max(visibleBars._internal_right(), visibleBars._internal_right() - indexPerLabel);
|
|
5555
|
-
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);
|
|
5555
|
+
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);
|
|
5556
5556
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second label on time scale"
|
|
5557
5557
|
const earliestIndexOfSecondLabel = this._private__firstIndex() + indexPerLabel;
|
|
5558
5558
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second last label on time scale"
|
|
@@ -6826,6 +6826,75 @@ function defaultTickMarkFormatter(timePoint, tickMarkType, locale) {
|
|
|
6826
6826
|
return localDateFromUtc.toLocaleString(locale, formatOptions);
|
|
6827
6827
|
}
|
|
6828
6828
|
|
|
6829
|
+
const DAY = 86400;
|
|
6830
|
+
const QUARTER_HOUR = 900;
|
|
6831
|
+
const zones = new Map();
|
|
6832
|
+
function zoneCache(timeZone) {
|
|
6833
|
+
let cache = zones.get(timeZone);
|
|
6834
|
+
if (cache === undefined) {
|
|
6835
|
+
let format = null;
|
|
6836
|
+
try {
|
|
6837
|
+
format = new Intl.DateTimeFormat('en-US', {
|
|
6838
|
+
timeZone,
|
|
6839
|
+
hourCycle: 'h23',
|
|
6840
|
+
year: 'numeric',
|
|
6841
|
+
month: 'numeric',
|
|
6842
|
+
day: 'numeric',
|
|
6843
|
+
hour: 'numeric',
|
|
6844
|
+
minute: 'numeric',
|
|
6845
|
+
second: 'numeric',
|
|
6846
|
+
});
|
|
6847
|
+
}
|
|
6848
|
+
catch (error) {
|
|
6849
|
+
format = null;
|
|
6850
|
+
}
|
|
6851
|
+
cache = { _internal_format: format, _internal_days: new Map(), _internal_quarters: new Map() };
|
|
6852
|
+
zones.set(timeZone, cache);
|
|
6853
|
+
}
|
|
6854
|
+
return cache;
|
|
6855
|
+
}
|
|
6856
|
+
function exactOffset(format, time) {
|
|
6857
|
+
const parts = format.formatToParts(new Date(time * 1000));
|
|
6858
|
+
const part = (type) => Number(parts.find((p) => p.type === type)?.value ?? 0);
|
|
6859
|
+
const wallClock = Date.UTC(part('year'), part('month') - 1, part('day'), part('hour') % 24, part('minute'), part('second'));
|
|
6860
|
+
return Math.round(wallClock / 1000 - time);
|
|
6861
|
+
}
|
|
6862
|
+
/**
|
|
6863
|
+
* Offset of `timeZone` from UTC at `time`, in seconds. Undefined, `'UTC'` and
|
|
6864
|
+
* unknown zones are 0.
|
|
6865
|
+
*
|
|
6866
|
+
* Resolved once per UTC day, and to the quarter hour only on days with a
|
|
6867
|
+
* transition: asking `Intl` for every bar is too slow for a whole series.
|
|
6868
|
+
*/
|
|
6869
|
+
function timeZoneOffset(timeZone, time) {
|
|
6870
|
+
if (timeZone === undefined || timeZone === 'UTC') {
|
|
6871
|
+
return 0;
|
|
6872
|
+
}
|
|
6873
|
+
const cache = zoneCache(timeZone);
|
|
6874
|
+
const format = cache._internal_format;
|
|
6875
|
+
if (format === null) {
|
|
6876
|
+
return 0;
|
|
6877
|
+
}
|
|
6878
|
+
const day = Math.floor(time / DAY);
|
|
6879
|
+
let wholeDay = cache._internal_days.get(day);
|
|
6880
|
+
if (wholeDay === undefined) {
|
|
6881
|
+
const start = exactOffset(format, day * DAY);
|
|
6882
|
+
const end = exactOffset(format, (day + 1) * DAY - 1);
|
|
6883
|
+
wholeDay = start === end ? start : null;
|
|
6884
|
+
cache._internal_days.set(day, wholeDay);
|
|
6885
|
+
}
|
|
6886
|
+
if (wholeDay !== null) {
|
|
6887
|
+
return wholeDay;
|
|
6888
|
+
}
|
|
6889
|
+
const quarter = Math.floor(time / QUARTER_HOUR);
|
|
6890
|
+
let offset = cache._internal_quarters.get(quarter);
|
|
6891
|
+
if (offset === undefined) {
|
|
6892
|
+
offset = exactOffset(format, quarter * QUARTER_HOUR);
|
|
6893
|
+
cache._internal_quarters.set(quarter, offset);
|
|
6894
|
+
}
|
|
6895
|
+
return offset;
|
|
6896
|
+
}
|
|
6897
|
+
|
|
6829
6898
|
function hours(count) {
|
|
6830
6899
|
return count * 60 * 60 * 1000;
|
|
6831
6900
|
}
|
|
@@ -6865,29 +6934,36 @@ function weightByTime(currentDate, prevDate) {
|
|
|
6865
6934
|
function cast(t) {
|
|
6866
6935
|
return t;
|
|
6867
6936
|
}
|
|
6868
|
-
|
|
6937
|
+
// Business days are dates, not instants: never shifted
|
|
6938
|
+
function zonedTimestamp(point, timeZone) {
|
|
6939
|
+
const time = cast(point.time);
|
|
6940
|
+
return time._internal_businessDay === undefined ? time._internal_timestamp + timeZoneOffset(timeZone, time._internal_timestamp) : time._internal_timestamp;
|
|
6941
|
+
}
|
|
6942
|
+
function fillWeightsForPoints(sortedTimePoints, startIndex = 0, timeZone) {
|
|
6869
6943
|
if (sortedTimePoints.length === 0) {
|
|
6870
6944
|
return;
|
|
6871
6945
|
}
|
|
6872
|
-
let prevTime = startIndex === 0 ? null :
|
|
6946
|
+
let prevTime = startIndex === 0 ? null : zonedTimestamp(sortedTimePoints[startIndex - 1], timeZone);
|
|
6873
6947
|
let prevDate = prevTime !== null ? new Date(prevTime * 1000) : null;
|
|
6874
6948
|
let totalTimeDiff = 0;
|
|
6875
6949
|
for (let index = startIndex; index < sortedTimePoints.length; ++index) {
|
|
6876
6950
|
const currentPoint = sortedTimePoints[index];
|
|
6877
|
-
const
|
|
6951
|
+
const currentTime = zonedTimestamp(currentPoint, timeZone);
|
|
6952
|
+
const currentDate = new Date(currentTime * 1000);
|
|
6878
6953
|
if (prevDate !== null) {
|
|
6879
6954
|
currentPoint.timeWeight = weightByTime(currentDate, prevDate);
|
|
6880
6955
|
}
|
|
6881
|
-
totalTimeDiff +=
|
|
6882
|
-
prevTime =
|
|
6956
|
+
totalTimeDiff += currentTime - (prevTime || currentTime);
|
|
6957
|
+
prevTime = currentTime;
|
|
6883
6958
|
prevDate = currentDate;
|
|
6884
6959
|
}
|
|
6885
6960
|
if (startIndex === 0 && sortedTimePoints.length > 1) {
|
|
6886
6961
|
// let's guess a weight for the first point
|
|
6887
6962
|
// let's say the previous point was average time back in the history
|
|
6888
6963
|
const averageTimeDiff = Math.ceil(totalTimeDiff / (sortedTimePoints.length - 1));
|
|
6889
|
-
const
|
|
6890
|
-
|
|
6964
|
+
const firstTime = zonedTimestamp(sortedTimePoints[0], timeZone);
|
|
6965
|
+
const approxPrevDate = new Date((firstTime - averageTimeDiff) * 1000);
|
|
6966
|
+
sortedTimePoints[0].timeWeight = weightByTime(new Date(firstTime * 1000), approxPrevDate);
|
|
6891
6967
|
}
|
|
6892
6968
|
}
|
|
6893
6969
|
|
|
@@ -7042,16 +7118,15 @@ class HorzScaleBehaviorTime {
|
|
|
7042
7118
|
}
|
|
7043
7119
|
}
|
|
7044
7120
|
formatHorzItem(item) {
|
|
7045
|
-
|
|
7046
|
-
return this._private__dateTimeFormatter._internal_format(new Date(tp._internal_timestamp * 1000));
|
|
7121
|
+
return this._private__dateTimeFormatter._internal_format(new Date(this._private__zonedTimePoint(item)._internal_timestamp * 1000));
|
|
7047
7122
|
}
|
|
7048
|
-
allowsTickMark(tickMark, barsPerMark) {
|
|
7123
|
+
allowsTickMark(tickMark, barsPerMark, previous) {
|
|
7049
7124
|
const filter = this._private__options.timeScale.tickMarkFilter;
|
|
7050
7125
|
if (filter === undefined) {
|
|
7051
7126
|
return true;
|
|
7052
7127
|
}
|
|
7053
7128
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7054
|
-
return filter(tickMark.originalTime, tickMarkType, barsPerMark);
|
|
7129
|
+
return filter(tickMark.originalTime, tickMarkType, barsPerMark, previous === undefined ? null : previous.originalTime);
|
|
7055
7130
|
}
|
|
7056
7131
|
formatTickmark(tickMark, localizationOptions) {
|
|
7057
7132
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
@@ -7062,7 +7137,7 @@ class HorzScaleBehaviorTime {
|
|
|
7062
7137
|
return tickMarkString;
|
|
7063
7138
|
}
|
|
7064
7139
|
}
|
|
7065
|
-
return defaultTickMarkFormatter(tickMark.time, tickMarkType, localizationOptions.locale);
|
|
7140
|
+
return defaultTickMarkFormatter(this._private__zonedTimePoint(tickMark.time), tickMarkType, localizationOptions.locale);
|
|
7066
7141
|
}
|
|
7067
7142
|
maxTickMarkWeight(tickMarks) {
|
|
7068
7143
|
let maxWeight = tickMarks.reduce(markWithGreaterWeight$2, tickMarks[0]).weight;
|
|
@@ -7074,7 +7149,17 @@ class HorzScaleBehaviorTime {
|
|
|
7074
7149
|
return maxWeight;
|
|
7075
7150
|
}
|
|
7076
7151
|
fillWeightsForPoints(sortedTimePoints, startIndex) {
|
|
7077
|
-
fillWeightsForPoints(sortedTimePoints, startIndex);
|
|
7152
|
+
fillWeightsForPoints(sortedTimePoints, startIndex, this._private__timeZone());
|
|
7153
|
+
}
|
|
7154
|
+
_private__timeZone() {
|
|
7155
|
+
return this._private__options?.localization.timeZone;
|
|
7156
|
+
}
|
|
7157
|
+
_private__zonedTimePoint(timePoint) {
|
|
7158
|
+
if (timePoint._internal_businessDay !== undefined) {
|
|
7159
|
+
return timePoint;
|
|
7160
|
+
}
|
|
7161
|
+
const offset = timeZoneOffset(this._private__timeZone(), timePoint._internal_timestamp);
|
|
7162
|
+
return offset === 0 ? timePoint : { _internal_timestamp: (timePoint._internal_timestamp + offset) };
|
|
7078
7163
|
}
|
|
7079
7164
|
static _internal_applyDefaults(options) {
|
|
7080
7165
|
return merge({ localization: { dateFormat: 'dd MMM \'yy' } }, options ?? {});
|
|
@@ -11076,6 +11161,10 @@ class DataLayer {
|
|
|
11076
11161
|
this._private__sortedTimePoints = [];
|
|
11077
11162
|
this._private__horzScaleBehavior = horzScaleBehavior;
|
|
11078
11163
|
}
|
|
11164
|
+
_internal_refillTimeWeights() {
|
|
11165
|
+
this._private__horzScaleBehavior.fillWeightsForPoints(this._private__sortedTimePoints, 0);
|
|
11166
|
+
return this._private__sortedTimePoints;
|
|
11167
|
+
}
|
|
11079
11168
|
_internal_destroy() {
|
|
11080
11169
|
this._private__pointDataByTimePoint.clear();
|
|
11081
11170
|
this._private__seriesRowsBySeries.clear();
|
|
@@ -12580,7 +12669,13 @@ class ChartApi {
|
|
|
12580
12669
|
throw new Error(`colorParsers option should not be changed once the chart has been created.`);
|
|
12581
12670
|
}
|
|
12582
12671
|
}
|
|
12672
|
+
const timeZone = this.options().localization.timeZone;
|
|
12583
12673
|
this._private__chartWidget._internal_applyOptions(toInternalOptions(options));
|
|
12674
|
+
if (this.options().localization.timeZone !== timeZone) {
|
|
12675
|
+
const model = this._private__chartWidget._internal_model();
|
|
12676
|
+
model._internal_timeScale()._internal_update(this._private__dataLayer._internal_refillTimeWeights(), 0);
|
|
12677
|
+
model._internal_fullUpdate();
|
|
12678
|
+
}
|
|
12584
12679
|
}
|
|
12585
12680
|
options() {
|
|
12586
12681
|
return this._private__chartWidget._internal_options();
|
|
@@ -19218,8 +19313,9 @@ class TradingSessionsPaneView {
|
|
|
19218
19313
|
const DEFAULT_SESSIONS = [
|
|
19219
19314
|
{
|
|
19220
19315
|
name: 'Tokyo',
|
|
19221
|
-
startHour:
|
|
19222
|
-
endHour:
|
|
19316
|
+
startHour: 9,
|
|
19317
|
+
endHour: 18,
|
|
19318
|
+
timeZone: 'Asia/Tokyo',
|
|
19223
19319
|
color: '#FF6B00',
|
|
19224
19320
|
opacity: 0.1,
|
|
19225
19321
|
},
|
|
@@ -19227,13 +19323,15 @@ const DEFAULT_SESSIONS = [
|
|
|
19227
19323
|
name: 'London',
|
|
19228
19324
|
startHour: 8,
|
|
19229
19325
|
endHour: 17,
|
|
19326
|
+
timeZone: 'Europe/London',
|
|
19230
19327
|
color: '#2962FF',
|
|
19231
19328
|
opacity: 0.1,
|
|
19232
19329
|
},
|
|
19233
19330
|
{
|
|
19234
19331
|
name: 'New York',
|
|
19235
|
-
startHour:
|
|
19236
|
-
endHour:
|
|
19332
|
+
startHour: 8,
|
|
19333
|
+
endHour: 17,
|
|
19334
|
+
timeZone: 'America/New_York',
|
|
19237
19335
|
color: '#089981',
|
|
19238
19336
|
opacity: 0.1,
|
|
19239
19337
|
},
|
|
@@ -19319,79 +19417,49 @@ class TradingSessionsIndicator {
|
|
|
19319
19417
|
}
|
|
19320
19418
|
}
|
|
19321
19419
|
_private__highlightSession(session, data) {
|
|
19322
|
-
|
|
19323
|
-
let sessionData = [];
|
|
19324
|
-
for (const point of data) {
|
|
19325
|
-
const time = point.time;
|
|
19326
|
-
const hour = this._private__getUTCHour(time);
|
|
19327
|
-
const isInSession = this._private__isTimeInSession(hour, session.startHour, session.endHour);
|
|
19328
|
-
if (isInSession) {
|
|
19329
|
-
if (!sessionStart) {
|
|
19330
|
-
sessionStart = time;
|
|
19331
|
-
}
|
|
19332
|
-
sessionData.push(point);
|
|
19333
|
-
}
|
|
19334
|
-
else {
|
|
19335
|
-
if (sessionStart && sessionData.length > 0) {
|
|
19336
|
-
// End of session, create highlight box
|
|
19337
|
-
this._private__createSessionBox(sessionStart, sessionData[sessionData.length - 1].time, session);
|
|
19338
|
-
sessionStart = null;
|
|
19339
|
-
sessionData = [];
|
|
19340
|
-
}
|
|
19341
|
-
}
|
|
19342
|
-
}
|
|
19343
|
-
// Handle case where session extends to end of visible range
|
|
19344
|
-
if (sessionStart && sessionData.length > 0) {
|
|
19345
|
-
this._private__createSessionBox(sessionStart, sessionData[sessionData.length - 1].time, session);
|
|
19346
|
-
}
|
|
19420
|
+
this._private__eachRun(data, (time) => this._private__inSession(time, session), (startTime, endTime) => this._private__createSessionBox(startTime, endTime, session));
|
|
19347
19421
|
}
|
|
19422
|
+
// Per bar, since each session reads the clock of its own zone
|
|
19348
19423
|
_private__highlightOverlaps(data) {
|
|
19349
|
-
// Find overlapping sessions
|
|
19350
19424
|
const sessions = this._private__options.sessions;
|
|
19351
19425
|
for (let i = 0; i < sessions.length; i++) {
|
|
19352
19426
|
for (let j = i + 1; j < sessions.length; j++) {
|
|
19353
|
-
|
|
19354
|
-
const session2 = sessions[j];
|
|
19355
|
-
// Check if sessions overlap
|
|
19356
|
-
const overlap = this._private__getSessionOverlap(session1, session2);
|
|
19357
|
-
if (overlap) {
|
|
19358
|
-
this._private__highlightOverlapPeriod(overlap, data);
|
|
19359
|
-
}
|
|
19427
|
+
this._private__eachRun(data, (time) => this._private__inSession(time, sessions[i]) && this._private__inSession(time, sessions[j]), (startTime, endTime) => this._private__createOverlapBox(startTime, endTime));
|
|
19360
19428
|
}
|
|
19361
19429
|
}
|
|
19362
19430
|
}
|
|
19363
|
-
|
|
19364
|
-
|
|
19365
|
-
|
|
19366
|
-
if (start < end) {
|
|
19367
|
-
return { _internal_start: start, _internal_end: end };
|
|
19368
|
-
}
|
|
19369
|
-
return null;
|
|
19370
|
-
}
|
|
19371
|
-
_private__highlightOverlapPeriod(overlap, data) {
|
|
19372
|
-
let overlapStart = null;
|
|
19373
|
-
let overlapData = [];
|
|
19431
|
+
_private__eachRun(data, inside, emit) {
|
|
19432
|
+
let runStart = null;
|
|
19433
|
+
let runEnd = null;
|
|
19374
19434
|
for (const point of data) {
|
|
19375
|
-
|
|
19376
|
-
|
|
19377
|
-
|
|
19378
|
-
if (isInOverlap) {
|
|
19379
|
-
if (!overlapStart) {
|
|
19380
|
-
overlapStart = time;
|
|
19381
|
-
}
|
|
19382
|
-
overlapData.push(point);
|
|
19435
|
+
if (inside(point.time)) {
|
|
19436
|
+
runStart = runStart ?? point.time;
|
|
19437
|
+
runEnd = point.time;
|
|
19383
19438
|
}
|
|
19384
|
-
else {
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
|
|
19388
|
-
overlapData = [];
|
|
19389
|
-
}
|
|
19439
|
+
else if (runStart !== null && runEnd !== null) {
|
|
19440
|
+
emit(runStart, runEnd);
|
|
19441
|
+
runStart = null;
|
|
19442
|
+
runEnd = null;
|
|
19390
19443
|
}
|
|
19391
19444
|
}
|
|
19392
|
-
if (
|
|
19393
|
-
|
|
19445
|
+
if (runStart !== null && runEnd !== null) {
|
|
19446
|
+
emit(runStart, runEnd);
|
|
19447
|
+
}
|
|
19448
|
+
}
|
|
19449
|
+
_private__inSession(time, session) {
|
|
19450
|
+
const hour = this._private__hourIn(time, session.timeZone);
|
|
19451
|
+
if (session.startHour < session.endHour) {
|
|
19452
|
+
return hour >= session.startHour && hour < session.endHour;
|
|
19394
19453
|
}
|
|
19454
|
+
// Crosses midnight
|
|
19455
|
+
return hour >= session.startHour || hour < session.endHour;
|
|
19456
|
+
}
|
|
19457
|
+
_private__hourIn(time, timeZone) {
|
|
19458
|
+
const seconds = typeof time === 'number' ? time : typeof time === 'string' ? Date.parse(time) / 1000 : NaN;
|
|
19459
|
+
if (!Number.isFinite(seconds)) {
|
|
19460
|
+
return 0;
|
|
19461
|
+
}
|
|
19462
|
+
return new Date((seconds + timeZoneOffset(timeZone, seconds)) * 1000).getUTCHours();
|
|
19395
19463
|
}
|
|
19396
19464
|
_private__createSessionBox(startTime, endTime, session) {
|
|
19397
19465
|
// Validate times
|
|
@@ -19421,29 +19489,6 @@ class TradingSessionsIndicator {
|
|
|
19421
19489
|
};
|
|
19422
19490
|
this._private__sessionBoxes.push(box);
|
|
19423
19491
|
}
|
|
19424
|
-
_private__isTimeInSession(hour, startHour, endHour) {
|
|
19425
|
-
if (startHour < endHour) {
|
|
19426
|
-
return hour >= startHour && hour < endHour;
|
|
19427
|
-
}
|
|
19428
|
-
else {
|
|
19429
|
-
// Session crosses midnight
|
|
19430
|
-
return hour >= startHour || hour < endHour;
|
|
19431
|
-
}
|
|
19432
|
-
}
|
|
19433
|
-
_private__getUTCHour(time) {
|
|
19434
|
-
// Convert time to UTC hour
|
|
19435
|
-
if (typeof time === 'number') {
|
|
19436
|
-
// Unix timestamp in seconds
|
|
19437
|
-
const date = new Date(time * 1000);
|
|
19438
|
-
return date.getUTCHours();
|
|
19439
|
-
}
|
|
19440
|
-
else if (typeof time === 'string') {
|
|
19441
|
-
// ISO string
|
|
19442
|
-
const date = new Date(time);
|
|
19443
|
-
return date.getUTCHours();
|
|
19444
|
-
}
|
|
19445
|
-
return 0;
|
|
19446
|
-
}
|
|
19447
19492
|
_private__clearSessionBoxes() {
|
|
19448
19493
|
// Clear all session boxes
|
|
19449
19494
|
this._private__sessionBoxes = [];
|
|
@@ -27950,6 +27995,13 @@ class BrushTool extends DrawingToolBase {
|
|
|
27950
27995
|
isDrawingModeActive() {
|
|
27951
27996
|
return this._private__drawingModeActive;
|
|
27952
27997
|
}
|
|
27998
|
+
/**
|
|
27999
|
+
* A brush armed for its next stroke is not a drawing yet: it stays out of the
|
|
28000
|
+
* undo history, where restoring it would re-arm a brush the app does not hold.
|
|
28001
|
+
*/
|
|
28002
|
+
isComplete() {
|
|
28003
|
+
return (this._private__brushOptions.points ?? []).length > 0;
|
|
28004
|
+
}
|
|
27953
28005
|
_private__onPointerDown(event) {
|
|
27954
28006
|
// A press over an existing drawing belongs to that drawing: it is how the
|
|
27955
28007
|
// user grabs or selects one without putting the brush away first.
|
|
@@ -30589,6 +30641,14 @@ function createGanttTool(context, options) {
|
|
|
30589
30641
|
|
|
30590
30642
|
/** Undo steps kept, each a full snapshot of every drawing. */
|
|
30591
30643
|
const UNDO_HISTORY_LIMIT = 100;
|
|
30644
|
+
/**
|
|
30645
|
+
* Points for a restored freehand tool. Built with bracket notation: a plain
|
|
30646
|
+
* `{ time, price }` literal gets its keys renamed by the build, and the tool,
|
|
30647
|
+
* which reads them by their public names, comes back drawing nothing.
|
|
30648
|
+
*/
|
|
30649
|
+
function restorePoints(points) {
|
|
30650
|
+
return points.map((point) => makeSerializedPoint(readSerializedNumber(point, 'price') ?? 0, readSerializedTime(point)));
|
|
30651
|
+
}
|
|
30592
30652
|
/**
|
|
30593
30653
|
* Central manager for all drawing tools - TradingView style
|
|
30594
30654
|
* Handles multiple tools, selection, deletion, and keyboard shortcuts
|
|
@@ -30823,7 +30883,22 @@ class DrawingToolsManager {
|
|
|
30823
30883
|
_private__applySnapshot(snapshot) {
|
|
30824
30884
|
this._private__restoring = true;
|
|
30825
30885
|
try {
|
|
30826
|
-
|
|
30886
|
+
// The history only holds placed drawings, so a tool still being drawn
|
|
30887
|
+
// stays: undoing with the brush armed must leave it armed.
|
|
30888
|
+
this._private__applySelection(null);
|
|
30889
|
+
for (const [id, tool] of Array.from(this._private__tools)) {
|
|
30890
|
+
if (!tool.isComplete()) {
|
|
30891
|
+
continue;
|
|
30892
|
+
}
|
|
30893
|
+
tool.remove();
|
|
30894
|
+
this._private__tools.delete(id);
|
|
30895
|
+
this._private__pendingToolIds.delete(id);
|
|
30896
|
+
}
|
|
30897
|
+
// Annotated, or the build renames the keys the tools read
|
|
30898
|
+
const context = { chart: this._private__chart, series: this._private__series };
|
|
30899
|
+
for (const data of snapshot) {
|
|
30900
|
+
this.restoreTool(context, data);
|
|
30901
|
+
}
|
|
30827
30902
|
this._private__committed = snapshot;
|
|
30828
30903
|
}
|
|
30829
30904
|
finally {
|
|
@@ -31053,16 +31128,8 @@ class DrawingToolsManager {
|
|
|
31053
31128
|
...style,
|
|
31054
31129
|
});
|
|
31055
31130
|
case 'polygon':
|
|
31056
|
-
// Bracket notation on the way out too, not just on the way in: a
|
|
31057
|
-
// plain `{ time, price }` literal here gets its keys renamed and
|
|
31058
|
-
// the restored corners come back empty.
|
|
31059
31131
|
return createPolygonTool(context, {
|
|
31060
|
-
points: points
|
|
31061
|
-
const vertex = {};
|
|
31062
|
-
vertex['time'] = pt(index)._internal_t;
|
|
31063
|
-
vertex['price'] = pt(index)._internal_p;
|
|
31064
|
-
return vertex;
|
|
31065
|
-
}),
|
|
31132
|
+
points: restorePoints(points),
|
|
31066
31133
|
...style,
|
|
31067
31134
|
});
|
|
31068
31135
|
case 'crossLine':
|
|
@@ -31128,12 +31195,12 @@ class DrawingToolsManager {
|
|
|
31128
31195
|
});
|
|
31129
31196
|
case 'arrow':
|
|
31130
31197
|
return createArrowTool(context, {
|
|
31131
|
-
points: points
|
|
31198
|
+
points: restorePoints(points),
|
|
31132
31199
|
...style,
|
|
31133
31200
|
});
|
|
31134
31201
|
case 'brush':
|
|
31135
31202
|
return createBrushTool(context, {
|
|
31136
|
-
points: points
|
|
31203
|
+
points: restorePoints(points),
|
|
31137
31204
|
...style,
|
|
31138
31205
|
});
|
|
31139
31206
|
case 'text':
|
|
@@ -31431,6 +31498,8 @@ class DrawingToolsManager {
|
|
|
31431
31498
|
event.preventDefault();
|
|
31432
31499
|
}
|
|
31433
31500
|
_private__handlePointerUp(event) {
|
|
31501
|
+
// A brush stroke ends here, and no click follows it to run the check
|
|
31502
|
+
this._private__scheduleCompletionCheck();
|
|
31434
31503
|
if (!this._private__isDragging || this._private__draggedToolId === null) {
|
|
31435
31504
|
return;
|
|
31436
31505
|
}
|
|
@@ -31603,7 +31672,7 @@ const customSeriesDefaultOptions = {
|
|
|
31603
31672
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
31604
31673
|
*/
|
|
31605
31674
|
function version() {
|
|
31606
|
-
return "2.3.
|
|
31675
|
+
return "2.3.20-dev+202610211649";
|
|
31607
31676
|
}
|
|
31608
31677
|
|
|
31609
|
-
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, createTimeLabels, createTradingLine, createTradingSessionsIndicator, createTrendLineTool, createUpDownMarkers, createVerticalLineTool, createVolumeProfileIndicator, createYieldCurveChart, customSeriesDefaultOptions, defaultHorzScaleBehavior, getPipConfig, hideSeriesPaint, isBusinessDay, isUTCTimestamp, setSeriesVolumes, setVolumeProfileData, timeFromCoordinate, version };
|
|
31678
|
+
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, createTimeLabels, createTradingLine, createTradingSessionsIndicator, createTrendLineTool, createUpDownMarkers, createVerticalLineTool, createVolumeProfileIndicator, createYieldCurveChart, customSeriesDefaultOptions, defaultHorzScaleBehavior, getPipConfig, hideSeriesPaint, isBusinessDay, isUTCTimestamp, setSeriesVolumes, setVolumeProfileData, timeFromCoordinate, timeZoneOffset, version };
|