@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)
|
|
@@ -5554,7 +5554,7 @@ class TimeScale {
|
|
|
5554
5554
|
const visibleBars = ensureNotNull(this._internal_visibleStrictRange());
|
|
5555
5555
|
const firstBar = Math.max(visibleBars._internal_left(), visibleBars._internal_left() - indexPerLabel);
|
|
5556
5556
|
const lastBar = Math.max(visibleBars._internal_right(), visibleBars._internal_right() - indexPerLabel);
|
|
5557
|
-
const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId, (mark, barsPerMark) => this._private__horzScaleBehavior.allowsTickMark?.(mark, barsPerMark) ?? true);
|
|
5557
|
+
const items = this._private__tickMarks._internal_build(spacing, maxLabelWidth, this._private__options.ignoreWhitespaceIndices, this._private__indicesWithData, this._private__indicesWithDataUpdateId, (mark, barsPerMark) => this._private__horzScaleBehavior.allowsTickMark?.(mark, barsPerMark, this._private__points[mark.index - 1]) ?? true);
|
|
5558
5558
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second label on time scale"
|
|
5559
5559
|
const earliestIndexOfSecondLabel = this._private__firstIndex() + indexPerLabel;
|
|
5560
5560
|
// according to indexPerLabel value this value means "earliest index which _might be_ used as the second last label on time scale"
|
|
@@ -6828,6 +6828,75 @@ function defaultTickMarkFormatter(timePoint, tickMarkType, locale) {
|
|
|
6828
6828
|
return localDateFromUtc.toLocaleString(locale, formatOptions);
|
|
6829
6829
|
}
|
|
6830
6830
|
|
|
6831
|
+
const DAY = 86400;
|
|
6832
|
+
const QUARTER_HOUR = 900;
|
|
6833
|
+
const zones = new Map();
|
|
6834
|
+
function zoneCache(timeZone) {
|
|
6835
|
+
let cache = zones.get(timeZone);
|
|
6836
|
+
if (cache === undefined) {
|
|
6837
|
+
let format = null;
|
|
6838
|
+
try {
|
|
6839
|
+
format = new Intl.DateTimeFormat('en-US', {
|
|
6840
|
+
timeZone,
|
|
6841
|
+
hourCycle: 'h23',
|
|
6842
|
+
year: 'numeric',
|
|
6843
|
+
month: 'numeric',
|
|
6844
|
+
day: 'numeric',
|
|
6845
|
+
hour: 'numeric',
|
|
6846
|
+
minute: 'numeric',
|
|
6847
|
+
second: 'numeric',
|
|
6848
|
+
});
|
|
6849
|
+
}
|
|
6850
|
+
catch (error) {
|
|
6851
|
+
format = null;
|
|
6852
|
+
}
|
|
6853
|
+
cache = { _internal_format: format, _internal_days: new Map(), _internal_quarters: new Map() };
|
|
6854
|
+
zones.set(timeZone, cache);
|
|
6855
|
+
}
|
|
6856
|
+
return cache;
|
|
6857
|
+
}
|
|
6858
|
+
function exactOffset(format, time) {
|
|
6859
|
+
const parts = format.formatToParts(new Date(time * 1000));
|
|
6860
|
+
const part = (type) => Number(parts.find((p) => p.type === type)?.value ?? 0);
|
|
6861
|
+
const wallClock = Date.UTC(part('year'), part('month') - 1, part('day'), part('hour') % 24, part('minute'), part('second'));
|
|
6862
|
+
return Math.round(wallClock / 1000 - time);
|
|
6863
|
+
}
|
|
6864
|
+
/**
|
|
6865
|
+
* Offset of `timeZone` from UTC at `time`, in seconds. Undefined, `'UTC'` and
|
|
6866
|
+
* unknown zones are 0.
|
|
6867
|
+
*
|
|
6868
|
+
* Resolved once per UTC day, and to the quarter hour only on days with a
|
|
6869
|
+
* transition: asking `Intl` for every bar is too slow for a whole series.
|
|
6870
|
+
*/
|
|
6871
|
+
function timeZoneOffset(timeZone, time) {
|
|
6872
|
+
if (timeZone === undefined || timeZone === 'UTC') {
|
|
6873
|
+
return 0;
|
|
6874
|
+
}
|
|
6875
|
+
const cache = zoneCache(timeZone);
|
|
6876
|
+
const format = cache._internal_format;
|
|
6877
|
+
if (format === null) {
|
|
6878
|
+
return 0;
|
|
6879
|
+
}
|
|
6880
|
+
const day = Math.floor(time / DAY);
|
|
6881
|
+
let wholeDay = cache._internal_days.get(day);
|
|
6882
|
+
if (wholeDay === undefined) {
|
|
6883
|
+
const start = exactOffset(format, day * DAY);
|
|
6884
|
+
const end = exactOffset(format, (day + 1) * DAY - 1);
|
|
6885
|
+
wholeDay = start === end ? start : null;
|
|
6886
|
+
cache._internal_days.set(day, wholeDay);
|
|
6887
|
+
}
|
|
6888
|
+
if (wholeDay !== null) {
|
|
6889
|
+
return wholeDay;
|
|
6890
|
+
}
|
|
6891
|
+
const quarter = Math.floor(time / QUARTER_HOUR);
|
|
6892
|
+
let offset = cache._internal_quarters.get(quarter);
|
|
6893
|
+
if (offset === undefined) {
|
|
6894
|
+
offset = exactOffset(format, quarter * QUARTER_HOUR);
|
|
6895
|
+
cache._internal_quarters.set(quarter, offset);
|
|
6896
|
+
}
|
|
6897
|
+
return offset;
|
|
6898
|
+
}
|
|
6899
|
+
|
|
6831
6900
|
function hours(count) {
|
|
6832
6901
|
return count * 60 * 60 * 1000;
|
|
6833
6902
|
}
|
|
@@ -6867,29 +6936,36 @@ function weightByTime(currentDate, prevDate) {
|
|
|
6867
6936
|
function cast(t) {
|
|
6868
6937
|
return t;
|
|
6869
6938
|
}
|
|
6870
|
-
|
|
6939
|
+
// Business days are dates, not instants: never shifted
|
|
6940
|
+
function zonedTimestamp(point, timeZone) {
|
|
6941
|
+
const time = cast(point.time);
|
|
6942
|
+
return time._internal_businessDay === undefined ? time._internal_timestamp + timeZoneOffset(timeZone, time._internal_timestamp) : time._internal_timestamp;
|
|
6943
|
+
}
|
|
6944
|
+
function fillWeightsForPoints(sortedTimePoints, startIndex = 0, timeZone) {
|
|
6871
6945
|
if (sortedTimePoints.length === 0) {
|
|
6872
6946
|
return;
|
|
6873
6947
|
}
|
|
6874
|
-
let prevTime = startIndex === 0 ? null :
|
|
6948
|
+
let prevTime = startIndex === 0 ? null : zonedTimestamp(sortedTimePoints[startIndex - 1], timeZone);
|
|
6875
6949
|
let prevDate = prevTime !== null ? new Date(prevTime * 1000) : null;
|
|
6876
6950
|
let totalTimeDiff = 0;
|
|
6877
6951
|
for (let index = startIndex; index < sortedTimePoints.length; ++index) {
|
|
6878
6952
|
const currentPoint = sortedTimePoints[index];
|
|
6879
|
-
const
|
|
6953
|
+
const currentTime = zonedTimestamp(currentPoint, timeZone);
|
|
6954
|
+
const currentDate = new Date(currentTime * 1000);
|
|
6880
6955
|
if (prevDate !== null) {
|
|
6881
6956
|
currentPoint.timeWeight = weightByTime(currentDate, prevDate);
|
|
6882
6957
|
}
|
|
6883
|
-
totalTimeDiff +=
|
|
6884
|
-
prevTime =
|
|
6958
|
+
totalTimeDiff += currentTime - (prevTime || currentTime);
|
|
6959
|
+
prevTime = currentTime;
|
|
6885
6960
|
prevDate = currentDate;
|
|
6886
6961
|
}
|
|
6887
6962
|
if (startIndex === 0 && sortedTimePoints.length > 1) {
|
|
6888
6963
|
// let's guess a weight for the first point
|
|
6889
6964
|
// let's say the previous point was average time back in the history
|
|
6890
6965
|
const averageTimeDiff = Math.ceil(totalTimeDiff / (sortedTimePoints.length - 1));
|
|
6891
|
-
const
|
|
6892
|
-
|
|
6966
|
+
const firstTime = zonedTimestamp(sortedTimePoints[0], timeZone);
|
|
6967
|
+
const approxPrevDate = new Date((firstTime - averageTimeDiff) * 1000);
|
|
6968
|
+
sortedTimePoints[0].timeWeight = weightByTime(new Date(firstTime * 1000), approxPrevDate);
|
|
6893
6969
|
}
|
|
6894
6970
|
}
|
|
6895
6971
|
|
|
@@ -7044,16 +7120,15 @@ class HorzScaleBehaviorTime {
|
|
|
7044
7120
|
}
|
|
7045
7121
|
}
|
|
7046
7122
|
formatHorzItem(item) {
|
|
7047
|
-
|
|
7048
|
-
return this._private__dateTimeFormatter._internal_format(new Date(tp._internal_timestamp * 1000));
|
|
7123
|
+
return this._private__dateTimeFormatter._internal_format(new Date(this._private__zonedTimePoint(item)._internal_timestamp * 1000));
|
|
7049
7124
|
}
|
|
7050
|
-
allowsTickMark(tickMark, barsPerMark) {
|
|
7125
|
+
allowsTickMark(tickMark, barsPerMark, previous) {
|
|
7051
7126
|
const filter = this._private__options.timeScale.tickMarkFilter;
|
|
7052
7127
|
if (filter === undefined) {
|
|
7053
7128
|
return true;
|
|
7054
7129
|
}
|
|
7055
7130
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
7056
|
-
return filter(tickMark.originalTime, tickMarkType, barsPerMark);
|
|
7131
|
+
return filter(tickMark.originalTime, tickMarkType, barsPerMark, previous === undefined ? null : previous.originalTime);
|
|
7057
7132
|
}
|
|
7058
7133
|
formatTickmark(tickMark, localizationOptions) {
|
|
7059
7134
|
const tickMarkType = weightToTickMarkType(tickMark.weight, this._private__options.timeScale.timeVisible, this._private__options.timeScale.secondsVisible);
|
|
@@ -7064,7 +7139,7 @@ class HorzScaleBehaviorTime {
|
|
|
7064
7139
|
return tickMarkString;
|
|
7065
7140
|
}
|
|
7066
7141
|
}
|
|
7067
|
-
return defaultTickMarkFormatter(tickMark.time, tickMarkType, localizationOptions.locale);
|
|
7142
|
+
return defaultTickMarkFormatter(this._private__zonedTimePoint(tickMark.time), tickMarkType, localizationOptions.locale);
|
|
7068
7143
|
}
|
|
7069
7144
|
maxTickMarkWeight(tickMarks) {
|
|
7070
7145
|
let maxWeight = tickMarks.reduce(markWithGreaterWeight$2, tickMarks[0]).weight;
|
|
@@ -7076,7 +7151,17 @@ class HorzScaleBehaviorTime {
|
|
|
7076
7151
|
return maxWeight;
|
|
7077
7152
|
}
|
|
7078
7153
|
fillWeightsForPoints(sortedTimePoints, startIndex) {
|
|
7079
|
-
fillWeightsForPoints(sortedTimePoints, startIndex);
|
|
7154
|
+
fillWeightsForPoints(sortedTimePoints, startIndex, this._private__timeZone());
|
|
7155
|
+
}
|
|
7156
|
+
_private__timeZone() {
|
|
7157
|
+
return this._private__options?.localization.timeZone;
|
|
7158
|
+
}
|
|
7159
|
+
_private__zonedTimePoint(timePoint) {
|
|
7160
|
+
if (timePoint._internal_businessDay !== undefined) {
|
|
7161
|
+
return timePoint;
|
|
7162
|
+
}
|
|
7163
|
+
const offset = timeZoneOffset(this._private__timeZone(), timePoint._internal_timestamp);
|
|
7164
|
+
return offset === 0 ? timePoint : { _internal_timestamp: (timePoint._internal_timestamp + offset) };
|
|
7080
7165
|
}
|
|
7081
7166
|
static _internal_applyDefaults(options) {
|
|
7082
7167
|
return merge({ localization: { dateFormat: 'dd MMM \'yy' } }, options ?? {});
|
|
@@ -10683,6 +10768,10 @@ class DataLayer {
|
|
|
10683
10768
|
this._private__sortedTimePoints = [];
|
|
10684
10769
|
this._private__horzScaleBehavior = horzScaleBehavior;
|
|
10685
10770
|
}
|
|
10771
|
+
_internal_refillTimeWeights() {
|
|
10772
|
+
this._private__horzScaleBehavior.fillWeightsForPoints(this._private__sortedTimePoints, 0);
|
|
10773
|
+
return this._private__sortedTimePoints;
|
|
10774
|
+
}
|
|
10686
10775
|
_internal_destroy() {
|
|
10687
10776
|
this._private__pointDataByTimePoint.clear();
|
|
10688
10777
|
this._private__seriesRowsBySeries.clear();
|
|
@@ -12187,7 +12276,13 @@ class ChartApi {
|
|
|
12187
12276
|
throw new Error(`colorParsers option should not be changed once the chart has been created.`);
|
|
12188
12277
|
}
|
|
12189
12278
|
}
|
|
12279
|
+
const timeZone = this.options().localization.timeZone;
|
|
12190
12280
|
this._private__chartWidget._internal_applyOptions(toInternalOptions(options));
|
|
12281
|
+
if (this.options().localization.timeZone !== timeZone) {
|
|
12282
|
+
const model = this._private__chartWidget._internal_model();
|
|
12283
|
+
model._internal_timeScale()._internal_update(this._private__dataLayer._internal_refillTimeWeights(), 0);
|
|
12284
|
+
model._internal_fullUpdate();
|
|
12285
|
+
}
|
|
12191
12286
|
}
|
|
12192
12287
|
options() {
|
|
12193
12288
|
return this._private__chartWidget._internal_options();
|
|
@@ -18825,8 +18920,9 @@ class TradingSessionsPaneView {
|
|
|
18825
18920
|
const DEFAULT_SESSIONS = [
|
|
18826
18921
|
{
|
|
18827
18922
|
name: 'Tokyo',
|
|
18828
|
-
startHour:
|
|
18829
|
-
endHour:
|
|
18923
|
+
startHour: 9,
|
|
18924
|
+
endHour: 18,
|
|
18925
|
+
timeZone: 'Asia/Tokyo',
|
|
18830
18926
|
color: '#FF6B00',
|
|
18831
18927
|
opacity: 0.1,
|
|
18832
18928
|
},
|
|
@@ -18834,13 +18930,15 @@ const DEFAULT_SESSIONS = [
|
|
|
18834
18930
|
name: 'London',
|
|
18835
18931
|
startHour: 8,
|
|
18836
18932
|
endHour: 17,
|
|
18933
|
+
timeZone: 'Europe/London',
|
|
18837
18934
|
color: '#2962FF',
|
|
18838
18935
|
opacity: 0.1,
|
|
18839
18936
|
},
|
|
18840
18937
|
{
|
|
18841
18938
|
name: 'New York',
|
|
18842
|
-
startHour:
|
|
18843
|
-
endHour:
|
|
18939
|
+
startHour: 8,
|
|
18940
|
+
endHour: 17,
|
|
18941
|
+
timeZone: 'America/New_York',
|
|
18844
18942
|
color: '#089981',
|
|
18845
18943
|
opacity: 0.1,
|
|
18846
18944
|
},
|
|
@@ -18926,79 +19024,49 @@ class TradingSessionsIndicator {
|
|
|
18926
19024
|
}
|
|
18927
19025
|
}
|
|
18928
19026
|
_private__highlightSession(session, data) {
|
|
18929
|
-
|
|
18930
|
-
let sessionData = [];
|
|
18931
|
-
for (const point of data) {
|
|
18932
|
-
const time = point.time;
|
|
18933
|
-
const hour = this._private__getUTCHour(time);
|
|
18934
|
-
const isInSession = this._private__isTimeInSession(hour, session.startHour, session.endHour);
|
|
18935
|
-
if (isInSession) {
|
|
18936
|
-
if (!sessionStart) {
|
|
18937
|
-
sessionStart = time;
|
|
18938
|
-
}
|
|
18939
|
-
sessionData.push(point);
|
|
18940
|
-
}
|
|
18941
|
-
else {
|
|
18942
|
-
if (sessionStart && sessionData.length > 0) {
|
|
18943
|
-
// End of session, create highlight box
|
|
18944
|
-
this._private__createSessionBox(sessionStart, sessionData[sessionData.length - 1].time, session);
|
|
18945
|
-
sessionStart = null;
|
|
18946
|
-
sessionData = [];
|
|
18947
|
-
}
|
|
18948
|
-
}
|
|
18949
|
-
}
|
|
18950
|
-
// Handle case where session extends to end of visible range
|
|
18951
|
-
if (sessionStart && sessionData.length > 0) {
|
|
18952
|
-
this._private__createSessionBox(sessionStart, sessionData[sessionData.length - 1].time, session);
|
|
18953
|
-
}
|
|
19027
|
+
this._private__eachRun(data, (time) => this._private__inSession(time, session), (startTime, endTime) => this._private__createSessionBox(startTime, endTime, session));
|
|
18954
19028
|
}
|
|
19029
|
+
// Per bar, since each session reads the clock of its own zone
|
|
18955
19030
|
_private__highlightOverlaps(data) {
|
|
18956
|
-
// Find overlapping sessions
|
|
18957
19031
|
const sessions = this._private__options.sessions;
|
|
18958
19032
|
for (let i = 0; i < sessions.length; i++) {
|
|
18959
19033
|
for (let j = i + 1; j < sessions.length; j++) {
|
|
18960
|
-
|
|
18961
|
-
const session2 = sessions[j];
|
|
18962
|
-
// Check if sessions overlap
|
|
18963
|
-
const overlap = this._private__getSessionOverlap(session1, session2);
|
|
18964
|
-
if (overlap) {
|
|
18965
|
-
this._private__highlightOverlapPeriod(overlap, data);
|
|
18966
|
-
}
|
|
19034
|
+
this._private__eachRun(data, (time) => this._private__inSession(time, sessions[i]) && this._private__inSession(time, sessions[j]), (startTime, endTime) => this._private__createOverlapBox(startTime, endTime));
|
|
18967
19035
|
}
|
|
18968
19036
|
}
|
|
18969
19037
|
}
|
|
18970
|
-
|
|
18971
|
-
|
|
18972
|
-
|
|
18973
|
-
if (start < end) {
|
|
18974
|
-
return { _internal_start: start, _internal_end: end };
|
|
18975
|
-
}
|
|
18976
|
-
return null;
|
|
18977
|
-
}
|
|
18978
|
-
_private__highlightOverlapPeriod(overlap, data) {
|
|
18979
|
-
let overlapStart = null;
|
|
18980
|
-
let overlapData = [];
|
|
19038
|
+
_private__eachRun(data, inside, emit) {
|
|
19039
|
+
let runStart = null;
|
|
19040
|
+
let runEnd = null;
|
|
18981
19041
|
for (const point of data) {
|
|
18982
|
-
|
|
18983
|
-
|
|
18984
|
-
|
|
18985
|
-
if (isInOverlap) {
|
|
18986
|
-
if (!overlapStart) {
|
|
18987
|
-
overlapStart = time;
|
|
18988
|
-
}
|
|
18989
|
-
overlapData.push(point);
|
|
19042
|
+
if (inside(point.time)) {
|
|
19043
|
+
runStart = runStart ?? point.time;
|
|
19044
|
+
runEnd = point.time;
|
|
18990
19045
|
}
|
|
18991
|
-
else {
|
|
18992
|
-
|
|
18993
|
-
|
|
18994
|
-
|
|
18995
|
-
overlapData = [];
|
|
18996
|
-
}
|
|
19046
|
+
else if (runStart !== null && runEnd !== null) {
|
|
19047
|
+
emit(runStart, runEnd);
|
|
19048
|
+
runStart = null;
|
|
19049
|
+
runEnd = null;
|
|
18997
19050
|
}
|
|
18998
19051
|
}
|
|
18999
|
-
if (
|
|
19000
|
-
|
|
19052
|
+
if (runStart !== null && runEnd !== null) {
|
|
19053
|
+
emit(runStart, runEnd);
|
|
19054
|
+
}
|
|
19055
|
+
}
|
|
19056
|
+
_private__inSession(time, session) {
|
|
19057
|
+
const hour = this._private__hourIn(time, session.timeZone);
|
|
19058
|
+
if (session.startHour < session.endHour) {
|
|
19059
|
+
return hour >= session.startHour && hour < session.endHour;
|
|
19001
19060
|
}
|
|
19061
|
+
// Crosses midnight
|
|
19062
|
+
return hour >= session.startHour || hour < session.endHour;
|
|
19063
|
+
}
|
|
19064
|
+
_private__hourIn(time, timeZone) {
|
|
19065
|
+
const seconds = typeof time === 'number' ? time : typeof time === 'string' ? Date.parse(time) / 1000 : NaN;
|
|
19066
|
+
if (!Number.isFinite(seconds)) {
|
|
19067
|
+
return 0;
|
|
19068
|
+
}
|
|
19069
|
+
return new Date((seconds + timeZoneOffset(timeZone, seconds)) * 1000).getUTCHours();
|
|
19002
19070
|
}
|
|
19003
19071
|
_private__createSessionBox(startTime, endTime, session) {
|
|
19004
19072
|
// Validate times
|
|
@@ -19028,29 +19096,6 @@ class TradingSessionsIndicator {
|
|
|
19028
19096
|
};
|
|
19029
19097
|
this._private__sessionBoxes.push(box);
|
|
19030
19098
|
}
|
|
19031
|
-
_private__isTimeInSession(hour, startHour, endHour) {
|
|
19032
|
-
if (startHour < endHour) {
|
|
19033
|
-
return hour >= startHour && hour < endHour;
|
|
19034
|
-
}
|
|
19035
|
-
else {
|
|
19036
|
-
// Session crosses midnight
|
|
19037
|
-
return hour >= startHour || hour < endHour;
|
|
19038
|
-
}
|
|
19039
|
-
}
|
|
19040
|
-
_private__getUTCHour(time) {
|
|
19041
|
-
// Convert time to UTC hour
|
|
19042
|
-
if (typeof time === 'number') {
|
|
19043
|
-
// Unix timestamp in seconds
|
|
19044
|
-
const date = new Date(time * 1000);
|
|
19045
|
-
return date.getUTCHours();
|
|
19046
|
-
}
|
|
19047
|
-
else if (typeof time === 'string') {
|
|
19048
|
-
// ISO string
|
|
19049
|
-
const date = new Date(time);
|
|
19050
|
-
return date.getUTCHours();
|
|
19051
|
-
}
|
|
19052
|
-
return 0;
|
|
19053
|
-
}
|
|
19054
19099
|
_private__clearSessionBoxes() {
|
|
19055
19100
|
// Clear all session boxes
|
|
19056
19101
|
this._private__sessionBoxes = [];
|
|
@@ -27557,6 +27602,13 @@ class BrushTool extends DrawingToolBase {
|
|
|
27557
27602
|
isDrawingModeActive() {
|
|
27558
27603
|
return this._private__drawingModeActive;
|
|
27559
27604
|
}
|
|
27605
|
+
/**
|
|
27606
|
+
* A brush armed for its next stroke is not a drawing yet: it stays out of the
|
|
27607
|
+
* undo history, where restoring it would re-arm a brush the app does not hold.
|
|
27608
|
+
*/
|
|
27609
|
+
isComplete() {
|
|
27610
|
+
return (this._private__brushOptions.points ?? []).length > 0;
|
|
27611
|
+
}
|
|
27560
27612
|
_private__onPointerDown(event) {
|
|
27561
27613
|
// A press over an existing drawing belongs to that drawing: it is how the
|
|
27562
27614
|
// user grabs or selects one without putting the brush away first.
|
|
@@ -30196,6 +30248,14 @@ function createGanttTool(context, options) {
|
|
|
30196
30248
|
|
|
30197
30249
|
/** Undo steps kept, each a full snapshot of every drawing. */
|
|
30198
30250
|
const UNDO_HISTORY_LIMIT = 100;
|
|
30251
|
+
/**
|
|
30252
|
+
* Points for a restored freehand tool. Built with bracket notation: a plain
|
|
30253
|
+
* `{ time, price }` literal gets its keys renamed by the build, and the tool,
|
|
30254
|
+
* which reads them by their public names, comes back drawing nothing.
|
|
30255
|
+
*/
|
|
30256
|
+
function restorePoints(points) {
|
|
30257
|
+
return points.map((point) => makeSerializedPoint(readSerializedNumber(point, 'price') ?? 0, readSerializedTime(point)));
|
|
30258
|
+
}
|
|
30199
30259
|
/**
|
|
30200
30260
|
* Central manager for all drawing tools - TradingView style
|
|
30201
30261
|
* Handles multiple tools, selection, deletion, and keyboard shortcuts
|
|
@@ -30430,7 +30490,22 @@ class DrawingToolsManager {
|
|
|
30430
30490
|
_private__applySnapshot(snapshot) {
|
|
30431
30491
|
this._private__restoring = true;
|
|
30432
30492
|
try {
|
|
30433
|
-
|
|
30493
|
+
// The history only holds placed drawings, so a tool still being drawn
|
|
30494
|
+
// stays: undoing with the brush armed must leave it armed.
|
|
30495
|
+
this._private__applySelection(null);
|
|
30496
|
+
for (const [id, tool] of Array.from(this._private__tools)) {
|
|
30497
|
+
if (!tool.isComplete()) {
|
|
30498
|
+
continue;
|
|
30499
|
+
}
|
|
30500
|
+
tool.remove();
|
|
30501
|
+
this._private__tools.delete(id);
|
|
30502
|
+
this._private__pendingToolIds.delete(id);
|
|
30503
|
+
}
|
|
30504
|
+
// Annotated, or the build renames the keys the tools read
|
|
30505
|
+
const context = { chart: this._private__chart, series: this._private__series };
|
|
30506
|
+
for (const data of snapshot) {
|
|
30507
|
+
this.restoreTool(context, data);
|
|
30508
|
+
}
|
|
30434
30509
|
this._private__committed = snapshot;
|
|
30435
30510
|
}
|
|
30436
30511
|
finally {
|
|
@@ -30660,16 +30735,8 @@ class DrawingToolsManager {
|
|
|
30660
30735
|
...style,
|
|
30661
30736
|
});
|
|
30662
30737
|
case 'polygon':
|
|
30663
|
-
// Bracket notation on the way out too, not just on the way in: a
|
|
30664
|
-
// plain `{ time, price }` literal here gets its keys renamed and
|
|
30665
|
-
// the restored corners come back empty.
|
|
30666
30738
|
return createPolygonTool(context, {
|
|
30667
|
-
points: points
|
|
30668
|
-
const vertex = {};
|
|
30669
|
-
vertex['time'] = pt(index)._internal_t;
|
|
30670
|
-
vertex['price'] = pt(index)._internal_p;
|
|
30671
|
-
return vertex;
|
|
30672
|
-
}),
|
|
30739
|
+
points: restorePoints(points),
|
|
30673
30740
|
...style,
|
|
30674
30741
|
});
|
|
30675
30742
|
case 'crossLine':
|
|
@@ -30735,12 +30802,12 @@ class DrawingToolsManager {
|
|
|
30735
30802
|
});
|
|
30736
30803
|
case 'arrow':
|
|
30737
30804
|
return createArrowTool(context, {
|
|
30738
|
-
points: points
|
|
30805
|
+
points: restorePoints(points),
|
|
30739
30806
|
...style,
|
|
30740
30807
|
});
|
|
30741
30808
|
case 'brush':
|
|
30742
30809
|
return createBrushTool(context, {
|
|
30743
|
-
points: points
|
|
30810
|
+
points: restorePoints(points),
|
|
30744
30811
|
...style,
|
|
30745
30812
|
});
|
|
30746
30813
|
case 'text':
|
|
@@ -31038,6 +31105,8 @@ class DrawingToolsManager {
|
|
|
31038
31105
|
event.preventDefault();
|
|
31039
31106
|
}
|
|
31040
31107
|
_private__handlePointerUp(event) {
|
|
31108
|
+
// A brush stroke ends here, and no click follows it to run the check
|
|
31109
|
+
this._private__scheduleCompletionCheck();
|
|
31041
31110
|
if (!this._private__isDragging || this._private__draggedToolId === null) {
|
|
31042
31111
|
return;
|
|
31043
31112
|
}
|
|
@@ -31210,7 +31279,7 @@ const customSeriesDefaultOptions = {
|
|
|
31210
31279
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
31211
31280
|
*/
|
|
31212
31281
|
function version() {
|
|
31213
|
-
return "2.3.
|
|
31282
|
+
return "2.3.20-dev+202610211649";
|
|
31214
31283
|
}
|
|
31215
31284
|
|
|
31216
|
-
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 };
|
|
31285
|
+
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 };
|