@trdrs/quickcharts 1.3.0 → 2.0.0
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/CHANGELOG.md +84 -0
- package/README.md +209 -200
- package/dist/adapters/rest.d.ts +3 -3
- package/dist/adapters/rest.js +2 -2
- package/dist/adapters/rest.js.map +1 -1
- package/dist/{ar-G7MVXRE4.js → ar-KSXQ2USS.js} +20 -20
- package/dist/ar-KSXQ2USS.js.map +1 -0
- package/dist/{assets-ySndlUS3.d.ts → assets-DOuBBsOp.d.ts} +50 -50
- package/dist/{ca_ES-EUSRU4VG.js → ca_ES-JG4FM55E.js} +20 -20
- package/dist/ca_ES-JG4FM55E.js.map +1 -0
- package/dist/{chunk-AA7XKXH4.js → chunk-6S6TO2N6.js} +33 -33
- package/dist/chunk-6S6TO2N6.js.map +1 -0
- package/dist/{chunk-KFBQSPNA.js → chunk-D3S26ARP.js} +2 -2
- package/dist/chunk-D3S26ARP.js.map +1 -0
- package/dist/{chunk-AKXIFHQN.js → chunk-KLPTCWA2.js} +1 -1
- package/dist/{chunk-AKXIFHQN.js.map → chunk-KLPTCWA2.js.map} +1 -1
- package/dist/{de-2SVTG25S.js → de-VSW2LHNF.js} +20 -20
- package/dist/de-VSW2LHNF.js.map +1 -0
- package/dist/drawings.d.ts +16 -16
- package/dist/drawings.js +12 -12
- package/dist/{es-UDHZM4W7.js → es-5ZXIPVOB.js} +20 -20
- package/dist/es-5ZXIPVOB.js.map +1 -0
- package/dist/feature-manifest.json +3 -3
- package/dist/{fr-35VN4G4S.js → fr-4F6DAWGD.js} +20 -20
- package/dist/fr-4F6DAWGD.js.map +1 -0
- package/dist/{he_IL-JPZMCURP.js → he_IL-B7PBQUEV.js} +20 -20
- package/dist/he_IL-B7PBQUEV.js.map +1 -0
- package/dist/{id_ID-XSTFHHJQ.js → id_ID-CYJRMXPC.js} +20 -20
- package/dist/id_ID-CYJRMXPC.js.map +1 -0
- package/dist/index.d.ts +167 -163
- package/dist/index.js +248 -237
- package/dist/index.js.map +1 -1
- package/dist/{it-EIY6JESQ.js → it-KTX4SG5P.js} +20 -20
- package/dist/it-KTX4SG5P.js.map +1 -0
- package/dist/{ja-42N4XRCW.js → ja-V7OURU5D.js} +20 -20
- package/dist/ja-V7OURU5D.js.map +1 -0
- package/dist/{ko-3VRPTIP3.js → ko-2RNEBYVE.js} +20 -20
- package/dist/ko-2RNEBYVE.js.map +1 -0
- package/dist/{ms_MY-SKN7O6M5.js → ms_MY-EY235E7Q.js} +20 -20
- package/dist/ms_MY-EY235E7Q.js.map +1 -0
- package/dist/{pl-TYARHCLT.js → pl-ADNVRP55.js} +20 -20
- package/dist/pl-ADNVRP55.js.map +1 -0
- package/dist/{pt-72IIFLL4.js → pt-OL2DR3DO.js} +20 -20
- package/dist/pt-OL2DR3DO.js.map +1 -0
- package/dist/quickcharts.css +97 -96
- package/dist/{resources-Ch8eA1Mw.d.ts → resources-Le6flcEn.d.ts} +3 -3
- package/dist/rest-openapi.json +11 -11
- package/dist/{ru-TPH4F7IB.js → ru-V6YFEPAF.js} +20 -20
- package/dist/ru-V6YFEPAF.js.map +1 -0
- package/dist/{sv-DC5RS67Z.js → sv-TORXQVE7.js} +20 -20
- package/dist/sv-TORXQVE7.js.map +1 -0
- package/dist/{th-I6H6AOZ3.js → th-K6SJSYSY.js} +20 -20
- package/dist/th-K6SJSYSY.js.map +1 -0
- package/dist/theme-manifest.json +10 -10
- package/dist/{tr-7FSUVCNW.js → tr-4AEM66KW.js} +20 -20
- package/dist/tr-4AEM66KW.js.map +1 -0
- package/dist/{vi-DLRPHLLH.js → vi-YU5XCEUU.js} +20 -20
- package/dist/vi-YU5XCEUU.js.map +1 -0
- package/dist/{zh-ZXIQBBEP.js → zh-QXKRYHU5.js} +20 -20
- package/dist/zh-QXKRYHU5.js.map +1 -0
- package/dist/{zh_TW-TYNUJU7U.js → zh_TW-AYPDKG4Q.js} +20 -20
- package/dist/zh_TW-AYPDKG4Q.js.map +1 -0
- package/package.json +1 -1
- package/dist/ar-G7MVXRE4.js.map +0 -1
- package/dist/ca_ES-EUSRU4VG.js.map +0 -1
- package/dist/chunk-AA7XKXH4.js.map +0 -1
- package/dist/chunk-KFBQSPNA.js.map +0 -1
- package/dist/de-2SVTG25S.js.map +0 -1
- package/dist/es-UDHZM4W7.js.map +0 -1
- package/dist/fr-35VN4G4S.js.map +0 -1
- package/dist/he_IL-JPZMCURP.js.map +0 -1
- package/dist/id_ID-XSTFHHJQ.js.map +0 -1
- package/dist/it-EIY6JESQ.js.map +0 -1
- package/dist/ja-42N4XRCW.js.map +0 -1
- package/dist/ko-3VRPTIP3.js.map +0 -1
- package/dist/ms_MY-SKN7O6M5.js.map +0 -1
- package/dist/pl-TYARHCLT.js.map +0 -1
- package/dist/pt-72IIFLL4.js.map +0 -1
- package/dist/ru-TPH4F7IB.js.map +0 -1
- package/dist/sv-DC5RS67Z.js.map +0 -1
- package/dist/th-I6H6AOZ3.js.map +0 -1
- package/dist/tr-7FSUVCNW.js.map +0 -1
- package/dist/vi-DLRPHLLH.js.map +0 -1
- package/dist/zh-ZXIQBBEP.js.map +0 -1
- package/dist/zh_TW-TYNUJU7U.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
TRANSIENT_TOOLS,
|
|
32
32
|
alphaOf,
|
|
33
33
|
blanks,
|
|
34
|
-
|
|
34
|
+
buildDrawingToolbarGroups,
|
|
35
35
|
button,
|
|
36
36
|
cancelText,
|
|
37
37
|
chooseHideMode,
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
cursorButtonArmed,
|
|
45
45
|
dismissOnOutside,
|
|
46
46
|
dragUntilRelease,
|
|
47
|
+
drawingToolbarFaceOf,
|
|
47
48
|
drawingTools,
|
|
48
49
|
editRefused,
|
|
49
50
|
el,
|
|
@@ -65,12 +66,11 @@ import {
|
|
|
65
66
|
paintedPosition,
|
|
66
67
|
parseCssColor,
|
|
67
68
|
parseDrawingPreferences,
|
|
68
|
-
|
|
69
|
+
parseTimeframeContext,
|
|
69
70
|
placePanel,
|
|
70
71
|
pushEscapeOwner,
|
|
71
|
-
railFaceOf,
|
|
72
72
|
readColor,
|
|
73
|
-
|
|
73
|
+
rememberDrawingToolbarTool,
|
|
74
74
|
removableDrawings,
|
|
75
75
|
removeRows,
|
|
76
76
|
restoreDrawings,
|
|
@@ -82,11 +82,11 @@ import {
|
|
|
82
82
|
viewportOf,
|
|
83
83
|
visibilityPreset,
|
|
84
84
|
withAlpha
|
|
85
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-6S6TO2N6.js";
|
|
86
86
|
import {
|
|
87
87
|
ResourceAbortError,
|
|
88
88
|
memorySaveLoadAdapter
|
|
89
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-D3S26ARP.js";
|
|
90
90
|
import {
|
|
91
91
|
DRAWING_CONTEXT_VERSION,
|
|
92
92
|
DRAWING_DOCUMENT_VERSION,
|
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
parseDrawingDocument,
|
|
100
100
|
reviseDrawingDocument,
|
|
101
101
|
sameDrawingContext
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-KLPTCWA2.js";
|
|
103
103
|
|
|
104
104
|
// src/datafeed.ts
|
|
105
105
|
function olderPageVerdict(page, askedTo, alreadyHopped) {
|
|
@@ -484,8 +484,7 @@ function createUdfDatafeed(options) {
|
|
|
484
484
|
name: String(col(raw.description, i) ?? symbol),
|
|
485
485
|
exchange: String(col(raw["exchange-listed"], i) ?? group),
|
|
486
486
|
type: String(col(raw.type, i) ?? ""),
|
|
487
|
-
|
|
488
|
-
via: null
|
|
487
|
+
dataSource: null
|
|
489
488
|
});
|
|
490
489
|
}
|
|
491
490
|
}
|
|
@@ -528,8 +527,7 @@ function createUdfDatafeed(options) {
|
|
|
528
527
|
name: r.description ?? r.symbol ?? "",
|
|
529
528
|
exchange: r.exchange ?? "",
|
|
530
529
|
type: r.type ?? "",
|
|
531
|
-
|
|
532
|
-
via: null
|
|
530
|
+
dataSource: null
|
|
533
531
|
}));
|
|
534
532
|
return { hits, hasMore: false };
|
|
535
533
|
},
|
|
@@ -724,8 +722,8 @@ var legend = {
|
|
|
724
722
|
* its percentage. Both arrive already written, sign included. */
|
|
725
723
|
"legend.change": "{change} ({percent}%)",
|
|
726
724
|
"legend.indicatorSettings": "Indicator settings",
|
|
727
|
-
"legend.showRows": "Show
|
|
728
|
-
"legend.hideRows": "Hide
|
|
725
|
+
"legend.showRows": "Show indicator rows",
|
|
726
|
+
"legend.hideRows": "Hide indicator rows",
|
|
729
727
|
"legend.restorePane": "Restore pane",
|
|
730
728
|
"legend.collapsePane": "Collapse pane",
|
|
731
729
|
"legend.maximizePane": "Maximize pane",
|
|
@@ -740,7 +738,7 @@ var legend = {
|
|
|
740
738
|
// The compare surface's legend side: the header door and the compare chips' verbs. The dialog
|
|
741
739
|
// both open belongs to the search family (search.ts).
|
|
742
740
|
"legend.changeSymbol": "Change symbol",
|
|
743
|
-
"legend.removeCompare": "Remove
|
|
741
|
+
"legend.removeCompare": "Remove comparison",
|
|
744
742
|
"legend.removeIndicator": "Remove indicator"
|
|
745
743
|
};
|
|
746
744
|
|
|
@@ -891,14 +889,14 @@ var replay = {
|
|
|
891
889
|
"replay.speed": "Replay speed",
|
|
892
890
|
"replay.updatesPerSecond": { one: "{count} update per second", other: "{count} updates per second" },
|
|
893
891
|
"replay.oneUpdatePerSeconds": { one: "1 update per {count} second", other: "1 update per {count} seconds" },
|
|
894
|
-
// The update
|
|
895
|
-
"replay.
|
|
896
|
-
"replay.
|
|
892
|
+
// The update timeframe.
|
|
893
|
+
"replay.timeframe": "Update timeframe",
|
|
894
|
+
"replay.timeframeHelp": "How much time each replay update advances. Finer than the chart timeframe, each bar forms from real finer bars.",
|
|
897
895
|
/** Why the control is unavailable: this timeframe has nothing finer to form its bars from. */
|
|
898
|
-
"replay.
|
|
899
|
-
/** The
|
|
896
|
+
"replay.timeframeNone": "No finer timeframe for this chart timeframe",
|
|
897
|
+
/** The timeframe option that picks the grain itself, rather than a named token. */
|
|
900
898
|
"replay.auto": "Auto",
|
|
901
|
-
"replay.
|
|
899
|
+
"replay.autoSelectTimeframe": "Auto select timeframe"
|
|
902
900
|
};
|
|
903
901
|
|
|
904
902
|
// src/i18n/en/inputs.ts
|
|
@@ -980,17 +978,17 @@ var layouts = {
|
|
|
980
978
|
"layouts.arrangement": "Chart arrangement",
|
|
981
979
|
"layouts.syncInLayout": "Sync in layout",
|
|
982
980
|
"layouts.syncSymbol": "Symbol",
|
|
983
|
-
"layouts.
|
|
981
|
+
"layouts.syncTimeframe": "Timeframe",
|
|
984
982
|
"layouts.syncCrosshair": "Crosshair",
|
|
985
983
|
"layouts.syncTime": "Time",
|
|
986
984
|
"layouts.syncDateRange": "Date range",
|
|
987
985
|
"layouts.syncSymbolTip": "Symbol changes on all charts within the layout",
|
|
988
|
-
"layouts.
|
|
986
|
+
"layouts.syncTimeframeTip": "Timeframe changes on all charts within the layout",
|
|
989
987
|
"layouts.syncCrosshairTip": "Crosshair is synced across all charts within the layout",
|
|
990
988
|
"layouts.syncTimeTip": "When a chart is clicked, all charts within the layout display the same point of time",
|
|
991
989
|
"layouts.syncDateRangeTip": "Date range changes on all charts within the layout",
|
|
992
990
|
"layouts.syncSymbolToggle": "Sync symbol",
|
|
993
|
-
"layouts.
|
|
991
|
+
"layouts.syncTimeframeToggle": "Sync timeframe",
|
|
994
992
|
"layouts.syncCrosshairToggle": "Sync crosshair",
|
|
995
993
|
"layouts.syncTimeToggle": "Sync time",
|
|
996
994
|
"layouts.syncDateRangeToggle": "Sync date range",
|
|
@@ -1029,9 +1027,9 @@ var layouts = {
|
|
|
1029
1027
|
"layouts.loading": "Loading",
|
|
1030
1028
|
"layouts.emptyNone": "No saved layouts yet.",
|
|
1031
1029
|
"layouts.openLayoutRow": "Open layout\u2026",
|
|
1032
|
-
/** A saved layout's second line: the market and
|
|
1033
|
-
* written as the toolbar writes them (`BTCUSDC`, `1h`). */
|
|
1034
|
-
"layouts.listingFacts": "{symbol}, {
|
|
1030
|
+
/** A saved layout's second line: the market and timeframe its active chart showed at the last
|
|
1031
|
+
* save, written as the toolbar writes them (`BTCUSDC`, `1h`). */
|
|
1032
|
+
"layouts.listingFacts": "{symbol}, {timeframe}",
|
|
1035
1033
|
/** A saved layout's line in the Layouts dialog: what it shows, then when it was last saved. */
|
|
1036
1034
|
"layouts.listingDated": "{facts} ({date})",
|
|
1037
1035
|
// The Layouts dialog.
|
|
@@ -1144,7 +1142,7 @@ var timeframe = {
|
|
|
1144
1142
|
"timeframe.unitDays": "Days",
|
|
1145
1143
|
"timeframe.unitWeeks": "Weeks",
|
|
1146
1144
|
"timeframe.unitMonths": "Months",
|
|
1147
|
-
/** A counted
|
|
1145
|
+
/** A counted timeframe, one plural per unit: '5t' reads "5 Ticks", '1h' reads "1 Hour". */
|
|
1148
1146
|
"timeframe.countTicks": { one: "{count} Tick", other: "{count} Ticks" },
|
|
1149
1147
|
"timeframe.countSeconds": { one: "{count} Second", other: "{count} Seconds" },
|
|
1150
1148
|
"timeframe.countMinutes": { one: "{count} Minute", other: "{count} Minutes" },
|
|
@@ -1152,11 +1150,11 @@ var timeframe = {
|
|
|
1152
1150
|
"timeframe.countDays": { one: "{count} Day", other: "{count} Days" },
|
|
1153
1151
|
"timeframe.countWeeks": { one: "{count} Week", other: "{count} Weeks" },
|
|
1154
1152
|
"timeframe.countMonths": { one: "{count} Month", other: "{count} Months" },
|
|
1155
|
-
/** The per-row verbs; `{timeframe}` is the counted
|
|
1153
|
+
/** The per-row verbs; `{timeframe}` is the counted timeframe. */
|
|
1156
1154
|
"timeframe.delete": "Delete {timeframe}",
|
|
1157
1155
|
"timeframe.save": "Save {timeframe}",
|
|
1158
1156
|
"timeframe.exists": "{timeframe} already exists",
|
|
1159
|
-
// The custom-
|
|
1157
|
+
// The custom-timeframe footer: a count stepper, a unit picker, and Add.
|
|
1160
1158
|
"timeframe.custom": "Custom timeframe",
|
|
1161
1159
|
"timeframe.customCount": "Custom timeframe count",
|
|
1162
1160
|
"timeframe.customUnit": "Custom timeframe unit",
|
|
@@ -1184,7 +1182,7 @@ var range = {
|
|
|
1184
1182
|
"range.fiveYears": "5 Years",
|
|
1185
1183
|
"range.all": "All data",
|
|
1186
1184
|
/** A preset's tooltip: what it frames, and the bars it frames it in. */
|
|
1187
|
-
"range.tip": "{range} \xB7 {
|
|
1185
|
+
"range.tip": "{range} \xB7 {timeframe} bars",
|
|
1188
1186
|
"range.zoomIn": "Zoom in",
|
|
1189
1187
|
"range.zoomOut": "Zoom out",
|
|
1190
1188
|
"range.scrollLeft": "Scroll left",
|
|
@@ -1374,7 +1372,7 @@ var drawing = {
|
|
|
1374
1372
|
"drawing.more": "More",
|
|
1375
1373
|
"drawing.moreActions": "More drawing actions",
|
|
1376
1374
|
"drawing.visualOrder": "Visual order",
|
|
1377
|
-
"drawing.
|
|
1375
|
+
"drawing.visibilityOnTimeframes": "Visibility on timeframes",
|
|
1378
1376
|
"drawing.clone": "Clone",
|
|
1379
1377
|
"drawing.copy": "Copy",
|
|
1380
1378
|
"drawing.modifierControl": "Ctrl",
|
|
@@ -1396,10 +1394,10 @@ var drawing = {
|
|
|
1396
1394
|
"drawing.sendToBack": "Send to back",
|
|
1397
1395
|
"drawing.bringForward": "Bring forward",
|
|
1398
1396
|
"drawing.sendBackward": "Send backward",
|
|
1399
|
-
"drawing.visCurrentAndAbove": "Current
|
|
1400
|
-
"drawing.visCurrentAndBelow": "Current
|
|
1401
|
-
"drawing.visCurrentOnly": "Current
|
|
1402
|
-
"drawing.visAll": "All
|
|
1397
|
+
"drawing.visCurrentAndAbove": "Current timeframe and above",
|
|
1398
|
+
"drawing.visCurrentAndBelow": "Current timeframe and below",
|
|
1399
|
+
"drawing.visCurrentOnly": "Current timeframe only",
|
|
1400
|
+
"drawing.visAll": "All timeframes",
|
|
1403
1401
|
// The template dialogs: naming a new template, and confirming a delete.
|
|
1404
1402
|
"drawing.saveTemplate": "Save drawing template",
|
|
1405
1403
|
"drawing.templateName": "Template name",
|
|
@@ -1559,7 +1557,7 @@ var drawing = {
|
|
|
1559
1557
|
// The Coordinates page: one row per anchor, numbered.
|
|
1560
1558
|
"drawing.coordBar": "#{n} (bar)",
|
|
1561
1559
|
"drawing.coordPriceBar": "#{n} (price, bar)",
|
|
1562
|
-
// The Visibility page: which
|
|
1560
|
+
// The Visibility page: which timeframes paint the drawing.
|
|
1563
1561
|
"drawing.unitTicks": "Ticks",
|
|
1564
1562
|
"drawing.unitSeconds": "Seconds",
|
|
1565
1563
|
"drawing.unitMinutes": "Minutes",
|
|
@@ -1567,7 +1565,7 @@ var drawing = {
|
|
|
1567
1565
|
"drawing.unitDays": "Days",
|
|
1568
1566
|
"drawing.unitWeeks": "Weeks",
|
|
1569
1567
|
"drawing.unitMonths": "Months",
|
|
1570
|
-
"drawing.
|
|
1568
|
+
"drawing.timeframePinnedNote": "A drawing stays on at least one timeframe, so it can always be reached again.",
|
|
1571
1569
|
// The color palette: swatches, the custom color panel, the opacity row.
|
|
1572
1570
|
"drawing.colorSwatch": "Color {hex}",
|
|
1573
1571
|
"drawing.customColor": "Custom color",
|
|
@@ -1651,7 +1649,7 @@ var command = {
|
|
|
1651
1649
|
"command.indicatorShow": "Show indicator",
|
|
1652
1650
|
"command.drawingsRemoveAll": "Remove drawings",
|
|
1653
1651
|
"command.drawingDeleteSelected": "Delete selected drawing",
|
|
1654
|
-
/** Arm a drawing tool. The tool is the argument, so the
|
|
1652
|
+
/** Arm a drawing tool. The tool is the argument, so the 90 tools share one command. */
|
|
1655
1653
|
"command.drawingArm": "Drawing tool",
|
|
1656
1654
|
// The toolbar's switches and menus. Each takes its value as the argument.
|
|
1657
1655
|
"command.drawingCursor": "Cursor mode",
|
|
@@ -1675,7 +1673,7 @@ var command = {
|
|
|
1675
1673
|
"command.drawingBringForward": "Bring drawing forward",
|
|
1676
1674
|
"command.drawingSendBackward": "Send drawing backward",
|
|
1677
1675
|
"command.drawingHideSelected": "Hide drawing",
|
|
1678
|
-
"command.drawingVisibility": "Drawing visibility on
|
|
1676
|
+
"command.drawingVisibility": "Drawing visibility on timeframes",
|
|
1679
1677
|
"command.drawingSettings": "Drawing settings",
|
|
1680
1678
|
"command.drawingCommitEdit": "Apply drawing settings",
|
|
1681
1679
|
"command.drawingPlaceImage": "Place image",
|
|
@@ -1700,7 +1698,7 @@ var command = {
|
|
|
1700
1698
|
"command.replayStepBack": "Step back",
|
|
1701
1699
|
"command.replayGoLive": "Replay to the live edge",
|
|
1702
1700
|
"command.replaySpeed": "Replay speed",
|
|
1703
|
-
"command.
|
|
1701
|
+
"command.replayTimeframe": "Replay update timeframe",
|
|
1704
1702
|
"command.timeframeSet": "Timeframe",
|
|
1705
1703
|
/** Which subsession intraday bars are shown for. A symbol with no extended hours offers only
|
|
1706
1704
|
* the first. */
|
|
@@ -1893,26 +1891,26 @@ function readingDirection(i18n) {
|
|
|
1893
1891
|
return BUILT_IN_LOCALES.find((l) => l.code === i18n.locale())?.dir ?? "ltr";
|
|
1894
1892
|
}
|
|
1895
1893
|
var chartDictionaries = createDictionaryLoader(en, {
|
|
1896
|
-
de: () => import("./de-
|
|
1897
|
-
fr: () => import("./fr-
|
|
1898
|
-
es: () => import("./es-
|
|
1899
|
-
it: () => import("./it-
|
|
1900
|
-
ca_ES: () => import("./ca_ES-
|
|
1901
|
-
pl: () => import("./pl-
|
|
1902
|
-
sv: () => import("./sv-
|
|
1903
|
-
tr: () => import("./tr-
|
|
1904
|
-
ru: () => import("./ru-
|
|
1905
|
-
pt: () => import("./pt-
|
|
1906
|
-
id_ID: () => import("./id_ID-
|
|
1907
|
-
ms_MY: () => import("./ms_MY-
|
|
1908
|
-
th: () => import("./th-
|
|
1909
|
-
vi: () => import("./vi-
|
|
1910
|
-
ja: () => import("./ja-
|
|
1911
|
-
ko: () => import("./ko-
|
|
1912
|
-
zh: () => import("./zh-
|
|
1913
|
-
zh_TW: () => import("./zh_TW-
|
|
1914
|
-
ar: () => import("./ar-
|
|
1915
|
-
he_IL: () => import("./he_IL-
|
|
1894
|
+
de: () => import("./de-VSW2LHNF.js"),
|
|
1895
|
+
fr: () => import("./fr-4F6DAWGD.js"),
|
|
1896
|
+
es: () => import("./es-5ZXIPVOB.js"),
|
|
1897
|
+
it: () => import("./it-KTX4SG5P.js"),
|
|
1898
|
+
ca_ES: () => import("./ca_ES-JG4FM55E.js"),
|
|
1899
|
+
pl: () => import("./pl-ADNVRP55.js"),
|
|
1900
|
+
sv: () => import("./sv-TORXQVE7.js"),
|
|
1901
|
+
tr: () => import("./tr-4AEM66KW.js"),
|
|
1902
|
+
ru: () => import("./ru-V6YFEPAF.js"),
|
|
1903
|
+
pt: () => import("./pt-OL2DR3DO.js"),
|
|
1904
|
+
id_ID: () => import("./id_ID-CYJRMXPC.js"),
|
|
1905
|
+
ms_MY: () => import("./ms_MY-EY235E7Q.js"),
|
|
1906
|
+
th: () => import("./th-K6SJSYSY.js"),
|
|
1907
|
+
vi: () => import("./vi-YU5XCEUU.js"),
|
|
1908
|
+
ja: () => import("./ja-V7OURU5D.js"),
|
|
1909
|
+
ko: () => import("./ko-2RNEBYVE.js"),
|
|
1910
|
+
zh: () => import("./zh-QXKRYHU5.js"),
|
|
1911
|
+
zh_TW: () => import("./zh_TW-AYPDKG4Q.js"),
|
|
1912
|
+
ar: () => import("./ar-KSXQ2USS.js"),
|
|
1913
|
+
he_IL: () => import("./he_IL-B7PBQUEV.js")
|
|
1916
1914
|
});
|
|
1917
1915
|
var dynamic = (t) => t;
|
|
1918
1916
|
var source = null;
|
|
@@ -2180,9 +2178,9 @@ var THEME_ROLES = [
|
|
|
2180
2178
|
{ id: "canvas.background", family: "canvas", kind: "color", description: "The fill behind the plotted series." },
|
|
2181
2179
|
{ id: "canvas.paneBorder", family: "canvas", kind: "color", description: "The divider between stacked panes and around the plot area." },
|
|
2182
2180
|
// ── series: direction, before any chart appearance override ─────────────────────────────────
|
|
2183
|
-
{ id: "series.up", family: "series", kind: "color", description: "A rising value: up volume, a rising
|
|
2184
|
-
{ id: "series.down", family: "series", kind: "color", description: "A falling value: down volume, a falling
|
|
2185
|
-
{ id: "series.neutral", family: "series", kind: "color", description: "A series or level with no direction, such as
|
|
2181
|
+
{ id: "series.up", family: "series", kind: "color", description: "A rising value: up volume, a rising indicator tint, a positive series default." },
|
|
2182
|
+
{ id: "series.down", family: "series", kind: "color", description: "A falling value: down volume, a falling indicator tint, a negative series default." },
|
|
2183
|
+
{ id: "series.neutral", family: "series", kind: "color", description: "A series or level with no direction, such as an indicator level line." },
|
|
2186
2184
|
// ── scale: grid, axes, crosshair, and session shading ───────────────────────────────────────
|
|
2187
2185
|
{ id: "scale.grid", family: "scale", kind: "color", description: "The grid lines drawn across the plot area." },
|
|
2188
2186
|
{ id: "scale.background", family: "scale", kind: "color", description: "The ground behind the price and time scales." },
|
|
@@ -2257,7 +2255,7 @@ var THEME_ROLES = [
|
|
|
2257
2255
|
{ id: "text.fontSizeSmall", family: "text", kind: "length", description: "Size of dense control text, such as a legend row." },
|
|
2258
2256
|
{ id: "text.fontSizeMicro", family: "text", kind: "length", description: "Size of the smallest chip and hint text." },
|
|
2259
2257
|
// ── chrome: the surfaces and borders of the chart's own controls ────────────────────────────
|
|
2260
|
-
{ id: "chrome.surface", family: "chrome", kind: "color", description: "The fill of toolbars,
|
|
2258
|
+
{ id: "chrome.surface", family: "chrome", kind: "color", description: "The fill of toolbars, bars, and panels." },
|
|
2261
2259
|
{ id: "chrome.surfaceRaised", family: "chrome", kind: "color", description: "The fill of a control sitting on a chrome surface, such as a button or field." },
|
|
2262
2260
|
{ id: "chrome.border", family: "chrome", kind: "color", description: "The ordinary border of a control or panel." },
|
|
2263
2261
|
{ id: "chrome.borderStrong", family: "chrome", kind: "color", description: "A border or divider that must stay visible at a glance.", contrast: [{ over: "chrome.surface", min: 3 }] },
|
|
@@ -2359,7 +2357,7 @@ var THEME_ROLES = [
|
|
|
2359
2357
|
{ id: "illustration.ink", family: "illustration", kind: "color", description: "The line drawing of an empty-state illustration.", contrast: [{ over: "overlay.surface", min: 3 }] },
|
|
2360
2358
|
{ id: "illustration.accent", family: "illustration", kind: "color", description: "The badge an empty-state illustration wears on the action it invites.", contrast: [{ over: "overlay.surface", min: 3 }] },
|
|
2361
2359
|
{ id: "illustration.accentInk", family: "illustration", kind: "color", description: "The mark on an illustration's badge.", contrast: [{ over: "illustration.accent", min: 3 }] },
|
|
2362
|
-
// ── drawing: what a new drawing wears before a
|
|
2360
|
+
// ── drawing: what a new drawing wears before a viewer styles it ─────────────────────────────
|
|
2363
2361
|
{ id: "drawing.line", family: "drawing", kind: "color", description: "The stroke of a newly placed drawing." },
|
|
2364
2362
|
{ id: "drawing.fill", family: "drawing", kind: "color", description: "The fill of a newly placed drawing that has an area." },
|
|
2365
2363
|
{ id: "drawing.text", family: "drawing", kind: "color", description: "The ink of a drawing label." },
|
|
@@ -2372,7 +2370,7 @@ var THEME_ROLES = [
|
|
|
2372
2370
|
{ id: "motion.durationBase", family: "motion", kind: "duration", description: "An ordinary transition: a modal dialog and its backdrop opening and closing, and the replay row entering and leaving." },
|
|
2373
2371
|
{ id: "motion.durationModerate", family: "motion", kind: "duration", description: "A control moving to its new state, such as a switch knob sliding." },
|
|
2374
2372
|
{ id: "motion.durationSlow", family: "motion", kind: "duration", description: "A small mark settling, such as a disclosure caret turning or a checkbox filling." },
|
|
2375
|
-
{ id: "motion.durationSlower", family: "motion", kind: "duration", description: "A larger mark turning, such as the drawing
|
|
2373
|
+
{ id: "motion.durationSlower", family: "motion", kind: "duration", description: "A larger mark turning, such as the drawing toolbar's chevron." },
|
|
2376
2374
|
{ id: "motion.easingStandard", family: "motion", kind: "easing", description: "The timing of an ordinary transition: a modal dialog box, the replay row, a caret dip, a checkbox fill." },
|
|
2377
2375
|
{ id: "motion.easingOut", family: "motion", kind: "easing", description: "The timing of a motion that settles as it ends: a modal backdrop fading, a switch knob sliding." },
|
|
2378
2376
|
{ id: "motion.easingLinear", family: "motion", kind: "easing", description: "The timing of a color or opacity change under the pointer." },
|
|
@@ -2521,9 +2519,9 @@ function cssVarName(roleId) {
|
|
|
2521
2519
|
function themeDeclarations(theme) {
|
|
2522
2520
|
return Object.keys(theme).sort().map((roleId) => ({ property: cssVarName(roleId), value: String(theme[roleId]) }));
|
|
2523
2521
|
}
|
|
2524
|
-
var STYLE_LAYERS = { tokens: "
|
|
2522
|
+
var STYLE_LAYERS = { tokens: "quickcharts.tokens", chart: "quickcharts.chart" };
|
|
2525
2523
|
var LAYER_ORDER_STATEMENT = `@layer ${STYLE_LAYERS.tokens}, ${STYLE_LAYERS.chart};`;
|
|
2526
|
-
var HOST_LAYER_ORDER = `@layer reset, ${STYLE_LAYERS.tokens}, ${STYLE_LAYERS.chart},
|
|
2524
|
+
var HOST_LAYER_ORDER = `@layer reset, ${STYLE_LAYERS.tokens}, ${STYLE_LAYERS.chart}, host;`;
|
|
2527
2525
|
|
|
2528
2526
|
// src/theme/renderer.ts
|
|
2529
2527
|
function themeRootStyle(mode, theme) {
|
|
@@ -4491,7 +4489,7 @@ function rangeAvailable(preset, earliestBarSecs, nowSecs = Math.floor(Date.now()
|
|
|
4491
4489
|
return nowSecs - earliestBarSecs >= preset.span;
|
|
4492
4490
|
}
|
|
4493
4491
|
function rangePresetTip(t, preset) {
|
|
4494
|
-
return t("range.tip", { range: t(preset.label),
|
|
4492
|
+
return t("range.tip", { range: t(preset.label), timeframe: timeframeLabel(t, preset.tf) });
|
|
4495
4493
|
}
|
|
4496
4494
|
function frameRange(chart, series2, span, tf, nowSecs = Math.floor(Date.now() / 1e3)) {
|
|
4497
4495
|
const data = series2.data();
|
|
@@ -4892,7 +4890,7 @@ var LAYOUT_MENU_ROWS = [
|
|
|
4892
4890
|
];
|
|
4893
4891
|
|
|
4894
4892
|
// src/widget/arrangements.ts
|
|
4895
|
-
var LAYOUT_SYNC_KEYS = ["symbol", "
|
|
4893
|
+
var LAYOUT_SYNC_KEYS = ["symbol", "timeframe", "crosshair", "time", "dateRange"];
|
|
4896
4894
|
var ALL_LAYOUTS_OFFERED = { arrangements: ARRANGEMENTS.map((a) => a.code), named: false, sync: LAYOUT_SYNC_KEYS };
|
|
4897
4895
|
var SYNC_PHRASE = `it takes ${LAYOUT_SYNC_KEYS.join(", ")}`;
|
|
4898
4896
|
function resolveOfferedLayouts(layouts2, layoutSync, arrangement) {
|
|
@@ -4962,9 +4960,9 @@ var DEFAULT_OVERRIDES = {
|
|
|
4962
4960
|
background: "#ece7c0",
|
|
4963
4961
|
upColor: "#26a69a",
|
|
4964
4962
|
downColor: "#ffa726",
|
|
4965
|
-
// Candle anatomy: solid black ring and wick, the SAME ink both directions
|
|
4966
|
-
//
|
|
4967
|
-
//
|
|
4963
|
+
// Candle anatomy: solid black ring and wick, the SAME ink both directions. On a paper canvas
|
|
4964
|
+
// the black is what separates a candle from the background, and that job does not change with
|
|
4965
|
+
// direction.
|
|
4968
4966
|
borderUpColor: "#000000",
|
|
4969
4967
|
borderDownColor: "#000000",
|
|
4970
4968
|
wickUpColor: "#000000",
|
|
@@ -8596,7 +8594,7 @@ function attachDrawings(options) {
|
|
|
8596
8594
|
const manager = new DrawingManager();
|
|
8597
8595
|
manager.setGlyphSource(options.glyphSource ?? bundledGlyphSource);
|
|
8598
8596
|
manager.attach(chart, series2);
|
|
8599
|
-
manager.
|
|
8597
|
+
manager.setTimeframeContext(parseTimeframeContext(options.timeframe ?? ""));
|
|
8600
8598
|
if (options.bars) {
|
|
8601
8599
|
const read = options.bars;
|
|
8602
8600
|
let cacheKey = "";
|
|
@@ -8974,7 +8972,7 @@ function attachDrawings(options) {
|
|
|
8974
8972
|
setVisibilityPreset(preset) {
|
|
8975
8973
|
const sel = selection();
|
|
8976
8974
|
if (!sel) return;
|
|
8977
|
-
sel.updateOptions({ visibility: visibilityPreset(preset,
|
|
8975
|
+
sel.updateOptions({ visibility: visibilityPreset(preset, parseTimeframeContext(timeframe2)) });
|
|
8978
8976
|
persist();
|
|
8979
8977
|
changed();
|
|
8980
8978
|
},
|
|
@@ -9041,7 +9039,7 @@ function attachDrawings(options) {
|
|
|
9041
9039
|
},
|
|
9042
9040
|
setTimeframe(tf) {
|
|
9043
9041
|
timeframe2 = tf;
|
|
9044
|
-
manager.
|
|
9042
|
+
manager.setTimeframeContext(parseTimeframeContext(tf));
|
|
9045
9043
|
},
|
|
9046
9044
|
setTick: (tick) => manager.setTickSize(tick),
|
|
9047
9045
|
setPriceFormatter: (format2) => manager.setPriceFormatter(format2),
|
|
@@ -9776,17 +9774,17 @@ var HIDE_ICON = {
|
|
|
9776
9774
|
};
|
|
9777
9775
|
function mountDrawingToolbar(deps) {
|
|
9778
9776
|
const { t } = deps;
|
|
9779
|
-
const groups =
|
|
9777
|
+
const groups = buildDrawingToolbarGroups();
|
|
9780
9778
|
const shown2 = (command2) => deps.shown?.(command2) ?? true;
|
|
9781
9779
|
const toolShown = (type) => deps.toolShown?.(type) ?? true;
|
|
9782
9780
|
const drawnGroup = (group) => ({
|
|
9783
9781
|
...group,
|
|
9784
9782
|
sections: group.sections.map((section) => ({ ...section, tools: section.tools.filter((tool) => toolShown(tool.type)) })).filter((section) => section.tools.length > 0)
|
|
9785
9783
|
});
|
|
9786
|
-
const
|
|
9787
|
-
ownPointer(
|
|
9784
|
+
const toolbar = el("div", { class: "qc-surface qc-drawing-toolbar", role: "toolbar", "aria-orientation": "vertical", "aria-label": t("drawing.toolbar"), "data-role": "drawing-toolbar" });
|
|
9785
|
+
ownPointer(toolbar);
|
|
9788
9786
|
const column = el("div", { class: "qc-drawing-toolbar-column" });
|
|
9789
|
-
|
|
9787
|
+
toolbar.appendChild(column);
|
|
9790
9788
|
let closeFlyout = null;
|
|
9791
9789
|
let panelHost = deps.chrome;
|
|
9792
9790
|
const closeOpen = () => {
|
|
@@ -9832,16 +9830,16 @@ function mountDrawingToolbar(deps) {
|
|
|
9832
9830
|
};
|
|
9833
9831
|
const cell2 = (face, arrow) => {
|
|
9834
9832
|
const box = el("div", { class: "qc-drawing-cell" }, face);
|
|
9835
|
-
face.classList.add("qc-drawing-
|
|
9833
|
+
face.classList.add("qc-drawing-toolbar-button");
|
|
9836
9834
|
if (arrow) {
|
|
9837
|
-
arrow.classList.add("qc-drawing-
|
|
9835
|
+
arrow.classList.add("qc-drawing-toolbar-arrow");
|
|
9838
9836
|
arrow.setAttribute("aria-haspopup", "menu");
|
|
9839
9837
|
arrow.setAttribute("aria-expanded", "false");
|
|
9840
9838
|
box.appendChild(arrow);
|
|
9841
9839
|
}
|
|
9842
9840
|
return box;
|
|
9843
9841
|
};
|
|
9844
|
-
const divider = (where = "
|
|
9842
|
+
const divider = (where = "toolbar") => el("div", { class: `qc-separator qc-drawing-${where === "toolbar" ? "divider" : where === "flyout" ? "flyout-rule" : "menu-rule"}`, role: "separator" });
|
|
9845
9843
|
const cursorFace = button({ class: "qc-button", label: t("drawing.cursor"), onClick: () => deps.run("chart.drawings.arm", null) });
|
|
9846
9844
|
const cursorArrow = button({ class: "qc-button", label: t("drawing.cursorMenu"), icon: deps.icons.icon("chevronRight16") });
|
|
9847
9845
|
cursorArrow.addEventListener("click", () => {
|
|
@@ -9926,7 +9924,7 @@ function mountDrawingToolbar(deps) {
|
|
|
9926
9924
|
const face = button({ class: "qc-button", label: t(group.label) });
|
|
9927
9925
|
const arrow = button({ class: "qc-button", label: t("drawing.groupMenu", { group: t(group.label) }), icon: deps.icons.icon("chevronRight16") });
|
|
9928
9926
|
face.addEventListener("click", () => {
|
|
9929
|
-
const faceTool =
|
|
9927
|
+
const faceTool = drawingToolbarFaceOf(drawnGroup(group), deps.state().drawingToolbarTools);
|
|
9930
9928
|
if (group.id === "glyphs" || !faceTool) {
|
|
9931
9929
|
openGroup(group, arrow);
|
|
9932
9930
|
return;
|
|
@@ -9962,7 +9960,7 @@ function mountDrawingToolbar(deps) {
|
|
|
9962
9960
|
)
|
|
9963
9961
|
);
|
|
9964
9962
|
});
|
|
9965
|
-
const stay = button({ class: "qc-button qc-drawing-
|
|
9963
|
+
const stay = button({ class: "qc-button qc-drawing-toolbar-mode", label: t("drawing.stayInDrawingMode"), onClick: () => deps.run("chart.drawings.stayInMode", !deps.state().stayInDrawingMode) });
|
|
9966
9964
|
const lockAll = button({ class: "qc-button", label: t("drawing.lockAll"), onClick: () => deps.run("chart.drawings.lockAll", !deps.state().allLocked) });
|
|
9967
9965
|
column.append(cell2(magnetFace, magnetArrow), cell2(stay, null), cell2(lockAll, null));
|
|
9968
9966
|
const eyeFace = button({ class: "qc-button", label: t("drawing.hideDrawings"), onClick: () => deps.run("chart.drawings.hide", { mode: deps.state().hide.mode, on: !deps.state().hide.on }) });
|
|
@@ -10020,9 +10018,9 @@ function mountDrawingToolbar(deps) {
|
|
|
10020
10018
|
openFlyout(removeArrow, menu2(t("drawing.removeMenu"), ...items2, divider("menu"), policy));
|
|
10021
10019
|
});
|
|
10022
10020
|
column.append(cell2(removeFace, removeArrow));
|
|
10023
|
-
const favorites = button({ class: "qc-button qc-drawing-
|
|
10021
|
+
const favorites = button({ class: "qc-button qc-drawing-toolbar-mode", label: t("drawing.favToolsBar"), title: t("drawing.favTools"), onClick: () => deps.run("chart.drawings.favoritesBar", !deps.state().favorites.visible) });
|
|
10024
10022
|
column.append(el("div", { class: "qc-drawing-toolbar-end" }, cell2(favorites, null)));
|
|
10025
|
-
const unrove = rovingFocus(
|
|
10023
|
+
const unrove = rovingFocus(toolbar, () => [...column.querySelectorAll("button")].filter((b) => !b.closest("[hidden]")), "vertical");
|
|
10026
10024
|
const setActive = (b, active) => {
|
|
10027
10025
|
b.dataset.qcActive = String(active);
|
|
10028
10026
|
};
|
|
@@ -10045,7 +10043,7 @@ function mountDrawingToolbar(deps) {
|
|
|
10045
10043
|
for (const group of groups) {
|
|
10046
10044
|
const entry = groupFaces.get(group.id);
|
|
10047
10045
|
const drawn = drawnGroup(group);
|
|
10048
|
-
const faceTool = activeGroup === group.id && s.activeTool && toolShown(s.activeTool) ? s.activeTool :
|
|
10046
|
+
const faceTool = activeGroup === group.id && s.activeTool && toolShown(s.activeTool) ? s.activeTool : drawingToolbarFaceOf(drawn, s.drawingToolbarTools);
|
|
10049
10047
|
entry.face.replaceChildren(...[group.id === "glyphs" ? deps.icons.icon("groupGlyphs") : faceTool ? deps.icons.tool(faceTool) : null].filter((face) => face !== null));
|
|
10050
10048
|
const faceName = faceTool && group.id !== "glyphs" ? toolName(t, faceTool, faceTool) : t(group.label);
|
|
10051
10049
|
relabelButton(entry.face, faceName);
|
|
@@ -10085,7 +10083,7 @@ function mountDrawingToolbar(deps) {
|
|
|
10085
10083
|
gate(eyeArrow, "chart.drawings.hide");
|
|
10086
10084
|
if (s.layoutCharts > 1) {
|
|
10087
10085
|
if (!syncButton) {
|
|
10088
|
-
syncButton = button({ class: "qc-button qc-drawing-
|
|
10086
|
+
syncButton = button({ class: "qc-button qc-drawing-toolbar-button", label: t("drawing.syncLabel"), icon: deps.icons.icon("sync"), onClick: () => deps.run("chart.drawings.sync", !deps.state().sync) });
|
|
10089
10087
|
syncCell.appendChild(syncButton);
|
|
10090
10088
|
}
|
|
10091
10089
|
syncButton.title = t(s.sync ? "drawing.syncOnHelp" : "drawing.syncOffHelp");
|
|
@@ -10111,7 +10109,7 @@ function mountDrawingToolbar(deps) {
|
|
|
10111
10109
|
tidyRules(column, (child) => !child.hidden && [...child.querySelectorAll("button")].some((control) => !control.closest("[hidden]")));
|
|
10112
10110
|
};
|
|
10113
10111
|
const relabel = () => {
|
|
10114
|
-
|
|
10112
|
+
toolbar.setAttribute("aria-label", t("drawing.toolbar"));
|
|
10115
10113
|
relabelButton(cursorFace, t("drawing.cursor"));
|
|
10116
10114
|
relabelButton(cursorArrow, t("drawing.cursorMenu"));
|
|
10117
10115
|
for (const group of groups) relabelButton(groupFaces.get(group.id).arrow, t("drawing.groupMenu", { group: t(group.label) }));
|
|
@@ -10129,11 +10127,11 @@ function mountDrawingToolbar(deps) {
|
|
|
10129
10127
|
};
|
|
10130
10128
|
const mount = (container) => {
|
|
10131
10129
|
const nextPanelHost = panelHostFor(container, deps.chrome);
|
|
10132
|
-
if (
|
|
10130
|
+
if (toolbar.parentElement === container && panelHost === nextPanelHost) return;
|
|
10133
10131
|
closeOpen();
|
|
10134
10132
|
panelHost = nextPanelHost;
|
|
10135
|
-
|
|
10136
|
-
container?.appendChild(
|
|
10133
|
+
toolbar.remove();
|
|
10134
|
+
container?.appendChild(toolbar);
|
|
10137
10135
|
render();
|
|
10138
10136
|
};
|
|
10139
10137
|
mount(deps.container === void 0 ? deps.chrome : deps.container);
|
|
@@ -10147,7 +10145,7 @@ function mountDrawingToolbar(deps) {
|
|
|
10147
10145
|
unrove();
|
|
10148
10146
|
glyphPicker?.destroy();
|
|
10149
10147
|
glyphPicker = null;
|
|
10150
|
-
|
|
10148
|
+
toolbar.remove();
|
|
10151
10149
|
}
|
|
10152
10150
|
};
|
|
10153
10151
|
}
|
|
@@ -10283,9 +10281,9 @@ var ICONS = {
|
|
|
10283
10281
|
viewBox: "0 0 120 120",
|
|
10284
10282
|
body: '<path fill="currentColor" d="M113 2.5A7 7 0 0 1 120 9.5L120 71.5A6 6 0 0 1 114 77.5L83 77.5A3 3 0 0 1 80 74.5L80 42.5A4 4 0 0 1 84 38.5L110 38.5A4 4 0 0 0 114 34.5L114 12.5A4 4 0 0 0 110 8.5L10 8.5A4 4 0 0 0 6 12.5L6 34.5A4 4 0 0 0 10 38.5L36 38.5A4 4 0 0 1 40 42.5L40 74.5A3 3 0 0 1 37 77.5L6 77.5A6 6 0 0 1 0 71.5L0 9.5A7 7 0 0 1 7 2.5Z"/><path fill="currentColor" d="M40 77.5H80V110.5A7 7 0 0 1 73 117.5H47A7 7 0 0 1 40 110.5Z"/>'
|
|
10285
10283
|
},
|
|
10286
|
-
/**
|
|
10284
|
+
/** The market-status mark, on its native 18 grid. */
|
|
10287
10285
|
marketStatus: { viewBox: "0 0 18 18", body: '<circle cx="9" cy="9" r="7" fill="currentColor" opacity="0.2"/><path fill="currentColor" d="M9 5a4 4 0 1 1 0 8 4 4 0 0 1 0-8"/>' },
|
|
10288
|
-
/**
|
|
10286
|
+
/** The replay marks, on their native 18 grid. */
|
|
10289
10287
|
// The disc carries the phase in `currentColor`; the rewind stays ONE ink in both modes, because a
|
|
10290
10288
|
// mark that changed the colour of its own shape between modes would read as a different mark.
|
|
10291
10289
|
replayStatus: { viewBox: "0 0 18 18", body: '<circle cx="9" cy="9" r="9" fill="currentColor"/><path d="M8 5.5v7L4.5 9 8 5.5Zm5 0v7L9.5 9 13 5.5Z" fill="var(--qc-state-markInk)"/>' },
|
|
@@ -10314,18 +10312,18 @@ var ICONS = {
|
|
|
10314
10312
|
viewBox: "0 0 28 28",
|
|
10315
10313
|
body: fill("M18 14a4 4 0 1 1-8 0 4 4 0 0 1 8 0Zm-1 0a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z") + fill("M8.5 5h11l5 9-5 9h-11l-5-9 5-9Zm-3.86 9L9.1 6h9.82l4.45 8-4.45 8H9.1l-4.45-8Z")
|
|
10316
10314
|
},
|
|
10317
|
-
// Enter fullscreen:
|
|
10315
|
+
// Enter fullscreen: four corner brackets turning outward, drawn as a one-unit
|
|
10318
10316
|
// wall on the 28 grid.
|
|
10319
10317
|
fullscreen: { viewBox: "0 0 28 28", body: fill("M7 18.5A2.5 2.5 0 0 0 9.5 21H12v1H9.5A3.5 3.5 0 0 1 6 18.5V16h1zm15 0a3.5 3.5 0 0 1-3.5 3.5H16v-1h2.5a2.5 2.5 0 0 0 2.5-2.5V16h1zM12 7H9.5A2.5 2.5 0 0 0 7 9.5V12H6V9.5A3.5 3.5 0 0 1 9.5 6H12zm6.5-1A3.5 3.5 0 0 1 22 9.5V12h-1V9.5A2.5 2.5 0 0 0 18.5 7H16V6z") },
|
|
10320
|
-
// Exit fullscreen: the same brackets folded inward, stroked at
|
|
10318
|
+
// Exit fullscreen: the same brackets folded inward, stroked at a 1.5 weight.
|
|
10321
10319
|
exitFullscreen: { viewBox: "0 0 28 28", body: stroke("M11 6v1.5A3.5 3.5 0 0 1 7.5 11H6M22 11h-1.5A3.5 3.5 0 0 1 17 7.5V6M17 22v-1.5a3.5 3.5 0 0 1 3.5-3.5H22M6 17h1.5a3.5 3.5 0 0 1 3.5 3.5V22", 1.5) },
|
|
10322
|
-
// Chart image:
|
|
10320
|
+
// Chart image: a camera, a one-unit-walled body with the shutter hump left of centre
|
|
10323
10321
|
// and the lens ring offset toward it.
|
|
10324
10322
|
camera: {
|
|
10325
10323
|
viewBox: "0 0 28 28",
|
|
10326
10324
|
body: fill("M11.118 6a.5.5 0 0 0-.447.276L9.809 8H5.5A1.5 1.5 0 0 0 4 9.5v10A1.5 1.5 0 0 0 5.5 21h16a1.5 1.5 0 0 0 1.5-1.5v-10A1.5 1.5 0 0 0 21.5 8h-4.309l-.862-1.724A.5.5 0 0 0 15.882 6h-4.764zm-1.342-.17A1.5 1.5 0 0 1 11.118 5h4.764a1.5 1.5 0 0 1 1.342.83L17.809 7H21.5A2.5 2.5 0 0 1 24 9.5v10a2.5 2.5 0 0 1-2.5 2.5h-16A2.5 2.5 0 0 1 3 19.5v-10A2.5 2.5 0 0 1 5.5 7h3.691l.585-1.17z") + fill("M13.5 18a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7zm0 1a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9z")
|
|
10327
10325
|
},
|
|
10328
|
-
/** The layout tile's own maximize and restore marks, on
|
|
10326
|
+
/** The layout tile's own maximize and restore marks, on their native 18 grid: two
|
|
10329
10327
|
* opposite corner brackets turning outward to fill the layout, and inward to give the tile back. */
|
|
10330
10328
|
tileMaximize: { viewBox: "0 0 18 18", body: '<path fill="currentColor" d="M14.5 8V3.5H10V2h6v6h-1.5Zm-11 2v4.5H8V16H2v-6h1.5Z"/>' },
|
|
10331
10329
|
tileRestore: { viewBox: "0 0 18 18", body: '<path fill="currentColor" d="M10 8V2h1.5v4.5H16V8h-6Zm-2 2v6H6.5v-4.5H2V10h6Z"/>' },
|
|
@@ -10336,7 +10334,7 @@ var ICONS = {
|
|
|
10336
10334
|
navZoomIn: { viewBox: "0 0 18 18", body: '<path fill="currentColor" d="M8.25 13.75v-9.5h1.5v9.5h-1.5Z"/><path fill="currentColor" d="M13.75 9.75h-9.5v-1.5h9.5v1.5Z"/>' },
|
|
10337
10335
|
navScroll: { viewBox: "0 0 18 18", body: '<path fill="currentColor" d="M7.83 3.92 12.28 9l-4.45 5.08-1.13-1L10.29 9l-3.6-4.09 1.14-.99Z"/>' },
|
|
10338
10336
|
navReset: { viewBox: "0 0 18 18", body: '<path fill="currentColor" d="M10 6.38V8L6 5.5 10 3v1.85A5.25 5.25 0 1 1 3.75 10a.75.75 0 0 1 1.5 0A3.75 3.75 0 1 0 10 6.38Z"/>' },
|
|
10339
|
-
/** The pickers' wide caret, on its native 16 by 8 grid: the
|
|
10337
|
+
/** The pickers' wide caret, on its native 16 by 8 grid: the trigger arrow, which
|
|
10340
10338
|
* renders half size beside a picker's text. */
|
|
10341
10339
|
menuArrowWide: { viewBox: "0 0 16 8", body: '<path fill="currentColor" d="M0 1.475l7.396 6.04.596.485.593-.49L16 1.39 14.807 0 7.393 6.122 8.58 6.12 1.186.08z"/>' },
|
|
10342
10340
|
// Hairline weight: these two sit beside a label rather than alone in a 38px cell.
|
|
@@ -10447,7 +10445,7 @@ var ICONS = {
|
|
|
10447
10445
|
ruler: { viewBox: "0 0 28 28", body: '<path fill="currentColor" fill-rule="evenodd" transform="rotate(-45 14 14)" d="M2 9.75a1.5 1.5 0 0 0-1.5 1.5v5.5a1.5 1.5 0 0 0 1.5 1.5h24a1.5 1.5 0 0 0 1.5-1.5v-5.5a1.5 1.5 0 0 0-1.5-1.5zm0 1h3v2.5h1v-2.5h3.25v3.9h1v-3.9h3.25v2.5h1v-2.5h3.25v3.9h1v-3.9H22v2.5h1v-2.5h3a.5.5 0 0 1 .5.5v5.5a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-5.5a.5.5 0 0 1 .5-.5z"/>' },
|
|
10448
10446
|
zoomIn: { viewBox: "0 0 28 28", body: '<path fill="currentColor" d="M17.646 18.354l4 4 .708-.708-4-4z"/><path fill="currentColor" d="M12.5 21a8.5 8.5 0 1 1 0-17 8.5 8.5 0 0 1 0 17zm0-1a7.5 7.5 0 1 0 0-15 7.5 7.5 0 0 0 0 15z"/><path fill="currentColor" d="M9 13h7v-1H9z"/><path fill="currentColor" d="M13 16V9h-1v7z"/>' },
|
|
10449
10447
|
groupGlyphs: { viewBox: "0 0 28 28", body: '<path fill="currentColor" d="M4.05 14a9.95 9.95 0 1 1 19.9 0 9.95 9.95 0 0 1-19.9 0ZM14 3a11 11 0 1 0 0 22 11 11 0 0 0 0-22Zm-3 13.03a.5.5 0 0 1 .64.3 2.5 2.5 0 0 0 4.72 0 .5.5 0 0 1 .94.34 3.5 3.5 0 0 1-6.6 0 .5.5 0 0 1 .3-.64Zm.5-4.53a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm5 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/>' },
|
|
10450
|
-
// The
|
|
10448
|
+
// The drawing toolbar's arrow: a filled chevron on a 10 by 16 grid, drawn 4 by 7 in the strip.
|
|
10451
10449
|
chevronRight16: { viewBox: "0 0 10 16", aspect: 4 / 7, size: 7, body: '<path fill="currentColor" d="M.6 1.4l1.4-1.4 8 8-8 8-1.4-1.4 6.389-6.532-6.389-6.668z"/>' },
|
|
10452
10450
|
// Six dots on an 8 by 12 grid, each PAINTED in currentColor: the svg the glyph is wrapped in
|
|
10453
10451
|
// carries `fill="none"`, so a rect with no fill of its own is a grip nobody can see.
|
|
@@ -10467,8 +10465,8 @@ var ICONS = {
|
|
|
10467
10465
|
textTee: { size: 15, aspect: 13 / 15, viewBox: "0 0 13 15", body: '<path stroke="currentColor" d="M4 14.5h2.5m2.5 0H6.5m0 0V.5m0 0h-5a1 1 0 0 0-1 1V4m6-3.5h5a1 1 0 0 1 1 1V4"/>' },
|
|
10468
10466
|
// A tool's star in a flyout: an outline at rest and a filled star once saved, on an 18 grid.
|
|
10469
10467
|
star: { viewBox: "0 0 18 18", body: '<path stroke="currentColor" d="M9 2.13l1.903 3.855.116.236.26.038 4.255.618-3.079 3.001-.188.184.044.259.727 4.237-3.805-2L9 12.434l-.233.122-3.805 2.001.727-4.237.044-.26-.188-.183-3.079-3.001 4.255-.618.26-.038.116-.236L9 2.13z"/>' },
|
|
10470
|
-
// The favorites bar's toggle on the
|
|
10471
|
-
// the button's fill.
|
|
10468
|
+
// The favorites bar's toggle on the drawing toolbar: one outlined star in either state, the state
|
|
10469
|
+
// carried by the button's fill.
|
|
10472
10470
|
favoritesBar: { viewBox: "0 0 28 28", body: '<path fill="currentColor" fill-rule="evenodd" d="m17.13 9.74 7.37.9-5.44 5.06L20.4 23 14 19.38 7.6 23l1.34-7.3-5.44-5.06 7.37-.9L14 3l3.13 6.74Zm5.11 1.63-4.26 3.97 1.04 5.74L14 18.24l-5.02 2.84 1.04-5.74-4.26-3.97 5.79-.7L14 5.37l2.45 5.3 5.8.7Z"/>' },
|
|
10473
10471
|
starFilled: { viewBox: "0 0 18 18", body: '<path fill="currentColor" d="M9 1l2.35 4.76 5.26.77-3.8 3.7.9 5.24L9 13l-4.7 2.47.9-5.23-3.8-3.71 5.25-.77L9 1z"/>' },
|
|
10474
10472
|
trash28: { viewBox: "0 0 28 28", body: '<path fill="currentColor" d="M18 7h5v1h-2.01l-1.33 14.64a1.5 1.5 0 0 1-1.5 1.36H9.84a1.5 1.5 0 0 1-1.49-1.36L7.01 8H5V7h5V6c0-1.1.9-2 2-2h4a2 2 0 0 1 2 2v1Zm-6-2a1 1 0 0 0-1 1v1h6V6a1 1 0 0 0-1-1h-4ZM8.02 8l1.32 14.54a.5.5 0 0 0 .5.46h8.33a.5.5 0 0 0 .5-.46L19.99 8H8.02Z"/>' },
|
|
@@ -10493,7 +10491,7 @@ var ICONS = {
|
|
|
10493
10491
|
submenuArrow: { viewBox: "0 0 24 24", body: '<path d="M9 18l6-6-6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>' },
|
|
10494
10492
|
close18: { viewBox: "0 0 18 18", body: '<path d="M4.5 4.5l9 9M13.5 4.5l-9 9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>' },
|
|
10495
10493
|
chevronDown18: { viewBox: "0 0 18 18", body: '<path fill="currentColor" d="M3.92 7.83 9 12.29l5.08-4.46-1-1.13L9 10.29l-4.09-3.6-.99 1.14Z"/>' },
|
|
10496
|
-
// The indicator
|
|
10494
|
+
// The indicator picker's marks, on the grids its rows were drawn for.
|
|
10497
10495
|
pickerStar: { viewBox: "0 0 18 18", body: '<path fill="none" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round" d="M9 2.13L11.057 6.168L15.534 6.877L12.329 10.082L13.038 14.558L9 12.5L4.962 14.558L5.671 10.082L2.466 6.877L6.943 6.168z"/>' },
|
|
10498
10496
|
pickerStarFilled: { viewBox: "0 0 18 18", body: '<path fill="currentColor" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round" d="M9 2.13L11.057 6.168L15.534 6.877L12.329 10.082L13.038 14.558L9 12.5L4.962 14.558L5.671 10.082L2.466 6.877L6.943 6.168z"/>' },
|
|
10499
10497
|
plus24: { viewBox: "0 0 24 24", body: '<path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>' },
|
|
@@ -10537,7 +10535,7 @@ function openDialog(options) {
|
|
|
10537
10535
|
if (options.width) box.style.width = `${options.width}px`;
|
|
10538
10536
|
stopPointer(box);
|
|
10539
10537
|
scrim.appendChild(box);
|
|
10540
|
-
|
|
10538
|
+
scrim.dataset.state = "opening";
|
|
10541
10539
|
let isOpen = true;
|
|
10542
10540
|
const previouslyFocused = document.activeElement;
|
|
10543
10541
|
const escape = pushEscapeOwner();
|
|
@@ -10562,7 +10560,7 @@ function openDialog(options) {
|
|
|
10562
10560
|
untrack();
|
|
10563
10561
|
document.removeEventListener("keydown", onKey, true);
|
|
10564
10562
|
previouslyFocused?.focus?.();
|
|
10565
|
-
const exitMs =
|
|
10563
|
+
const exitMs = closeOptions?.animate !== false ? motionDurationMs(scrim, "motion.durationBase") : 0;
|
|
10566
10564
|
if (exitMs <= 0) {
|
|
10567
10565
|
remove();
|
|
10568
10566
|
return;
|
|
@@ -10608,12 +10606,10 @@ function openDialog(options) {
|
|
|
10608
10606
|
const handle = { element: box, close, open: () => isOpen };
|
|
10609
10607
|
options.build(box, handle);
|
|
10610
10608
|
(layerFor(options.host) ?? options.host).appendChild(scrim);
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
scrim.dataset.state = "open";
|
|
10614
|
-
}
|
|
10609
|
+
scrim.getBoundingClientRect();
|
|
10610
|
+
scrim.dataset.state = "open";
|
|
10615
10611
|
const refresh = options.refresh;
|
|
10616
|
-
untrack = trackOverlay(options.host, close, refresh ? () => {
|
|
10612
|
+
untrack = trackOverlay(options.host, () => close({ animate: false }), refresh ? () => {
|
|
10617
10613
|
if (isOpen) refresh();
|
|
10618
10614
|
} : void 0);
|
|
10619
10615
|
document.addEventListener("keydown", onKey, true);
|
|
@@ -11000,7 +10996,7 @@ function mountSettingsBar(deps) {
|
|
|
11000
10996
|
const at = deps.stackPosition();
|
|
11001
10997
|
return menuOf(t("drawing.visualOrder"), "narrow", ...ORDER_MOVES.map((move) => menuRow(t(move.label), () => deps.run(move.command), { disabled: move.dead(at), command: move.command })));
|
|
11002
10998
|
}
|
|
11003
|
-
return menuOf(t("drawing.
|
|
10999
|
+
return menuOf(t("drawing.visibilityOnTimeframes"), "wide", ...VISIBILITY_PRESETS.map((v) => menuRow(t(v.label), () => deps.run("chart.drawings.visibility", v.preset), { command: "chart.drawings.visibility" })));
|
|
11004
11000
|
};
|
|
11005
11001
|
const arm = (kind, row2) => {
|
|
11006
11002
|
cancelClose();
|
|
@@ -11034,7 +11030,7 @@ function mountSettingsBar(deps) {
|
|
|
11034
11030
|
t("drawing.moreActions"),
|
|
11035
11031
|
"wide",
|
|
11036
11032
|
submenuRow("order", t("drawing.visualOrder"), "layers"),
|
|
11037
|
-
submenuRow("visibility", t("drawing.
|
|
11033
|
+
submenuRow("visibility", t("drawing.visibilityOnTimeframes")),
|
|
11038
11034
|
separator2(),
|
|
11039
11035
|
plain(menuRow(t("drawing.clone"), () => deps.run("chart.drawings.clone"), { icon: deps.icons.icon("clone"), hint: t("drawing.hintClone", { modifier: modifier() }), command: "chart.drawings.clone" })),
|
|
11040
11036
|
plain(menuRow(t("drawing.copy"), () => deps.run("chart.drawings.copy"), { spacer: true, hint: t("drawing.hintCopy", { modifier: modifier() }), command: "chart.drawings.copy" })),
|
|
@@ -11377,11 +11373,15 @@ function openDialog2(options) {
|
|
|
11377
11373
|
stopDrag = dragBy(header, element);
|
|
11378
11374
|
element.append(header, body, footer);
|
|
11379
11375
|
},
|
|
11380
|
-
|
|
11376
|
+
// The drag and whatever the dialog opened over itself (a palette, a menu, a template prompt) go
|
|
11377
|
+
// as the dialog begins to close, so nothing answers the viewer from a box that no longer takes
|
|
11378
|
+
// input and no document listener outlives the box it belonged to.
|
|
11379
|
+
onClosing: () => {
|
|
11381
11380
|
stopDrag();
|
|
11382
11381
|
if (box) closeOverlays(box);
|
|
11383
|
-
options.
|
|
11384
|
-
}
|
|
11382
|
+
options.onClosing?.();
|
|
11383
|
+
},
|
|
11384
|
+
onClose: () => options.onClose?.()
|
|
11385
11385
|
});
|
|
11386
11386
|
return { body, footer, box: modal.element, close: modal.close };
|
|
11387
11387
|
}
|
|
@@ -11411,7 +11411,9 @@ function openImagePicker(deps) {
|
|
|
11411
11411
|
icons: deps.icons,
|
|
11412
11412
|
role: "drawing-image-picker",
|
|
11413
11413
|
width: 420,
|
|
11414
|
-
|
|
11414
|
+
// The picker stops taking a paste as it begins to close, and the Image tool can open it again
|
|
11415
|
+
// while the leaving one finishes its exit.
|
|
11416
|
+
onClosing: () => {
|
|
11415
11417
|
document.removeEventListener("paste", onPaste);
|
|
11416
11418
|
deps.onClose?.();
|
|
11417
11419
|
}
|
|
@@ -11901,7 +11903,7 @@ function visibilityRows(ctx) {
|
|
|
11901
11903
|
const range2 = visibility[key];
|
|
11902
11904
|
out.push(visibilityRangeRow(t, ctx.icons, { label: t(text2), range: range2, max, disabled: pinned(range2.on), onChange: (next) => ctx.patchVisibility({ [key]: next }) }));
|
|
11903
11905
|
}
|
|
11904
|
-
if (enabled === 1) out.push(el("span", { class: "qc-muted qc-drawing-note", text: t("drawing.
|
|
11906
|
+
if (enabled === 1) out.push(el("span", { class: "qc-muted qc-drawing-note", text: t("drawing.timeframePinnedNote") }));
|
|
11905
11907
|
return out;
|
|
11906
11908
|
}
|
|
11907
11909
|
|
|
@@ -11920,7 +11922,9 @@ function openSettingsDialog(deps) {
|
|
|
11920
11922
|
icons: deps.icons,
|
|
11921
11923
|
role: "drawing-settings",
|
|
11922
11924
|
width: 380,
|
|
11923
|
-
|
|
11925
|
+
// Escape, the corner close or a press outside ends the session as the dialog begins to close,
|
|
11926
|
+
// so the drawing is back as it was before the exit motion starts rather than after it.
|
|
11927
|
+
onClosing: () => {
|
|
11924
11928
|
if (settled) return;
|
|
11925
11929
|
cancel();
|
|
11926
11930
|
}
|
|
@@ -12128,7 +12132,7 @@ function attachDrawingsPlane(deps) {
|
|
|
12128
12132
|
indicators: { hidden: "drawing.statusIndicatorsHidden", shown: "drawing.statusIndicatorsShown" },
|
|
12129
12133
|
all: { hidden: "drawing.statusAllHidden", shown: "drawing.statusAllShown" }
|
|
12130
12134
|
};
|
|
12131
|
-
const groups =
|
|
12135
|
+
const groups = buildDrawingToolbarGroups();
|
|
12132
12136
|
const events = {};
|
|
12133
12137
|
const handle = attachDrawings({
|
|
12134
12138
|
chart: deps.chart,
|
|
@@ -12200,7 +12204,7 @@ function attachDrawingsPlane(deps) {
|
|
|
12200
12204
|
removeLocked: p.removeLocked,
|
|
12201
12205
|
counts: handle.counts(),
|
|
12202
12206
|
indicatorCount: deps.indicators.count(),
|
|
12203
|
-
|
|
12207
|
+
drawingToolbarTools: p.drawingToolbarTools,
|
|
12204
12208
|
favorites: p.favorites,
|
|
12205
12209
|
recentGlyphs: p.recentGlyphs,
|
|
12206
12210
|
layoutCharts: deps.chartCount()
|
|
@@ -12350,7 +12354,7 @@ function attachDrawingsPlane(deps) {
|
|
|
12350
12354
|
}
|
|
12351
12355
|
handle.armTool(tool, props);
|
|
12352
12356
|
if (tool) {
|
|
12353
|
-
const patch = {
|
|
12357
|
+
const patch = { drawingToolbarTools: rememberDrawingToolbarTool(groups, prefs().drawingToolbarTools, tool) };
|
|
12354
12358
|
const glyph2 = props && typeof props.glyph === "string" ? props.glyph : null;
|
|
12355
12359
|
if (glyph2) patch.recentGlyphs = pushRecentGlyph(prefs().recentGlyphs, glyph2);
|
|
12356
12360
|
write(patch);
|
|
@@ -12724,7 +12728,7 @@ var FillBetweenPrimitive = class {
|
|
|
12724
12728
|
lower = [];
|
|
12725
12729
|
colors;
|
|
12726
12730
|
/** Nothing until the first `setData`, which every render path makes before a draw. A tint chosen
|
|
12727
|
-
* here would be a second
|
|
12731
|
+
* here would be a second indicator default with no owner. */
|
|
12728
12732
|
color = "transparent";
|
|
12729
12733
|
attached(param) {
|
|
12730
12734
|
this.chart = param.chart;
|
|
@@ -12925,7 +12929,7 @@ function shapeKeyOf(built) {
|
|
|
12925
12929
|
return JSON.stringify([built.placement, built.plots.map((p) => [p.key, p.type, p.location === "absolute", p.scale ?? null])]);
|
|
12926
12930
|
}
|
|
12927
12931
|
function makeEntry(chart, built, neutral) {
|
|
12928
|
-
const paneIndex = built.placement === "pane" ?
|
|
12932
|
+
const paneIndex = built.placement === "pane" ? indicatorPaneIndex(chart) : 0;
|
|
12929
12933
|
const labels = built.display?.labelsOnPriceScale !== false;
|
|
12930
12934
|
const series2 = [];
|
|
12931
12935
|
const markers = [];
|
|
@@ -13124,7 +13128,7 @@ function safeRemove(chart, series2) {
|
|
|
13124
13128
|
} catch {
|
|
13125
13129
|
}
|
|
13126
13130
|
}
|
|
13127
|
-
function
|
|
13131
|
+
function indicatorPaneIndex(chart) {
|
|
13128
13132
|
sweepEmptyPanes(chart);
|
|
13129
13133
|
return chart.panes().length;
|
|
13130
13134
|
}
|
|
@@ -13693,7 +13697,7 @@ function attachIndicatorsPlane(deps) {
|
|
|
13693
13697
|
};
|
|
13694
13698
|
const renderer = attachIndicators(deps.chart, {
|
|
13695
13699
|
candles: deps.candleSeries,
|
|
13696
|
-
//
|
|
13700
|
+
// An indicator that declares no precision writes its scale through the symbol formatter, so a
|
|
13697
13701
|
// moving average on a Treasury reads in thirty-seconds like the bars beside it.
|
|
13698
13702
|
symbolPriceFormat: () => ({ key: deps.formatKey(), formatter: (price) => deps.formatter().format(price), minMove: deps.minMove() }),
|
|
13699
13703
|
neutral: () => deps.canvas().neutral
|
|
@@ -14562,7 +14566,7 @@ var GRAIN_GROUPS = [
|
|
|
14562
14566
|
{ unit: "d", rungs: [{ tf: "1d", sec: 86400 }] }
|
|
14563
14567
|
];
|
|
14564
14568
|
var DAY_RUNG = { tf: "1d", sec: 86400 };
|
|
14565
|
-
function
|
|
14569
|
+
function subTimeframesFor(chartTf) {
|
|
14566
14570
|
const parsed = parseTimeframe(chartTf);
|
|
14567
14571
|
const parent = tfSeconds(chartTf);
|
|
14568
14572
|
if (!parsed || !parent) return [];
|
|
@@ -14572,8 +14576,8 @@ function subIntervalsFor(chartTf) {
|
|
|
14572
14576
|
const intraday = parsed.unit === "s" || parsed.unit === "m" || parsed.unit === "h";
|
|
14573
14577
|
return GRAIN_GROUPS.filter((g, i) => i === own || i === own - 1 || intraday && g.unit === "s").flatMap((g) => g.rungs).filter((s) => s.sec <= parent && parent % s.sec === 0).sort((a, b) => a.sec - b.sec);
|
|
14574
14578
|
}
|
|
14575
|
-
function
|
|
14576
|
-
const offered =
|
|
14579
|
+
function autoTimeframeFor(chartTf) {
|
|
14580
|
+
const offered = subTimeframesFor(chartTf);
|
|
14577
14581
|
return offered.length ? offered[offered.length - 1] : null;
|
|
14578
14582
|
}
|
|
14579
14583
|
function composeFormingBar(parent, subs, k) {
|
|
@@ -14595,8 +14599,8 @@ function attachReplayPlane(deps) {
|
|
|
14595
14599
|
let arming = false;
|
|
14596
14600
|
let timer = null;
|
|
14597
14601
|
let speed = deps.initialSpeed;
|
|
14598
|
-
let
|
|
14599
|
-
let
|
|
14602
|
+
let autoGrain = deps.initialGrain === "auto";
|
|
14603
|
+
let manualGrain = autoGrain ? null : deps.initialGrain;
|
|
14600
14604
|
let subs = null;
|
|
14601
14605
|
let formK = 0;
|
|
14602
14606
|
let stepping = null;
|
|
@@ -14608,18 +14612,18 @@ function attachReplayPlane(deps) {
|
|
|
14608
14612
|
};
|
|
14609
14613
|
const grains = () => {
|
|
14610
14614
|
const served = deps.resolutions();
|
|
14611
|
-
const ladder =
|
|
14615
|
+
const ladder = subTimeframesFor(deps.timeframe());
|
|
14612
14616
|
return served && served.length > 0 ? ladder.filter((s) => served.includes(s.tf)) : ladder;
|
|
14613
14617
|
};
|
|
14614
|
-
const
|
|
14618
|
+
const effectiveGrain = () => {
|
|
14615
14619
|
const available = grains();
|
|
14616
|
-
if (
|
|
14617
|
-
return available.find((s) => s.tf ===
|
|
14620
|
+
if (autoGrain) return available.length ? available[available.length - 1] : null;
|
|
14621
|
+
return available.find((s) => s.tf === manualGrain) ?? null;
|
|
14618
14622
|
};
|
|
14619
14623
|
const sync = () => {
|
|
14620
14624
|
deps.onChange();
|
|
14621
14625
|
};
|
|
14622
|
-
const
|
|
14626
|
+
const currentGrain = () => autoGrain ? "auto" : manualGrain ?? "auto";
|
|
14623
14627
|
const paintCursor = () => {
|
|
14624
14628
|
if (!master) return;
|
|
14625
14629
|
deps.paint(master.slice(0, cursor));
|
|
@@ -14654,15 +14658,15 @@ function attachReplayPlane(deps) {
|
|
|
14654
14658
|
deps.setCrosshair(!next);
|
|
14655
14659
|
};
|
|
14656
14660
|
const fetchSubs = async (parentIdx) => {
|
|
14657
|
-
const
|
|
14658
|
-
if (!master || !
|
|
14659
|
-
if (
|
|
14661
|
+
const grain = effectiveGrain();
|
|
14662
|
+
if (!master || !grain) return null;
|
|
14663
|
+
if (grain.sec >= tfSeconds(deps.timeframe())) return null;
|
|
14660
14664
|
const parent = master[parentIdx];
|
|
14661
14665
|
if (!parent) return null;
|
|
14662
14666
|
const from = parent.t;
|
|
14663
14667
|
const to = parent.t + tfSeconds(deps.timeframe()) - 1;
|
|
14664
14668
|
try {
|
|
14665
|
-
const page = await deps.datafeed.history(deps.symbol(),
|
|
14669
|
+
const page = await deps.datafeed.history(deps.symbol(), grain.tf, { from, to });
|
|
14666
14670
|
const found = page.bars.filter((b) => b.t >= from && b.t <= to);
|
|
14667
14671
|
return found.length >= 2 ? found : null;
|
|
14668
14672
|
} catch {
|
|
@@ -14693,11 +14697,11 @@ function attachReplayPlane(deps) {
|
|
|
14693
14697
|
const epoch = generation;
|
|
14694
14698
|
const symbol = deps.symbol();
|
|
14695
14699
|
const timeframe2 = deps.timeframe();
|
|
14696
|
-
const grain =
|
|
14697
|
-
const chosen =
|
|
14700
|
+
const grain = currentGrain();
|
|
14701
|
+
const chosen = effectiveGrain();
|
|
14698
14702
|
const wholeBar = !chosen || chosen.sec >= tfSeconds(deps.timeframe());
|
|
14699
14703
|
const found = wholeBar ? null : await fetchSubs(targetCursor - 1);
|
|
14700
|
-
if (destroyed || deps.disposed() || stepping !== flight || generation !== epoch || deps.symbol() !== symbol || deps.timeframe() !== timeframe2 ||
|
|
14704
|
+
if (destroyed || deps.disposed() || stepping !== flight || generation !== epoch || deps.symbol() !== symbol || deps.timeframe() !== timeframe2 || currentGrain() !== grain || !master || cursor !== targetCursor - 1 || master[targetCursor - 1] !== parent) return;
|
|
14701
14705
|
cursor = targetCursor;
|
|
14702
14706
|
if (found) {
|
|
14703
14707
|
subs = found;
|
|
@@ -14796,26 +14800,26 @@ function attachReplayPlane(deps) {
|
|
|
14796
14800
|
paintCursor();
|
|
14797
14801
|
sync();
|
|
14798
14802
|
},
|
|
14799
|
-
|
|
14803
|
+
timeframe: currentGrain,
|
|
14800
14804
|
// What `auto` actually RESOLVED to, so a surface can say the grain rather than the mode. Empty
|
|
14801
14805
|
// when the chart's timeframe has nothing finer to form from and updates advance whole bars.
|
|
14802
|
-
|
|
14803
|
-
|
|
14804
|
-
if (token ===
|
|
14806
|
+
resolvedTimeframe: () => effectiveGrain()?.tf ?? "",
|
|
14807
|
+
setTimeframe(token) {
|
|
14808
|
+
if (token === currentGrain()) return;
|
|
14805
14809
|
if (token === "auto") {
|
|
14806
|
-
|
|
14810
|
+
autoGrain = true;
|
|
14807
14811
|
} else {
|
|
14808
14812
|
if (!grains().some((s) => s.tf === token)) return;
|
|
14809
|
-
|
|
14810
|
-
|
|
14813
|
+
autoGrain = false;
|
|
14814
|
+
manualGrain = token;
|
|
14811
14815
|
}
|
|
14812
14816
|
invalidateStep();
|
|
14813
|
-
deps.persist("
|
|
14817
|
+
deps.persist("timeframe", currentGrain());
|
|
14814
14818
|
subs = null;
|
|
14815
14819
|
formK = 0;
|
|
14816
14820
|
sync();
|
|
14817
14821
|
},
|
|
14818
|
-
|
|
14822
|
+
subTimeframes: () => grains().map((s) => s.tf),
|
|
14819
14823
|
state: () => ({ on: master !== null, playing, cursor, total: master?.length ?? deps.bars().length, speed }),
|
|
14820
14824
|
// An OPEN QUESTION outranks a running session. Re-arming mid-replay to choose a different start
|
|
14821
14825
|
// puts the plot back to taking a click, and every surface that answers to the picker — the
|
|
@@ -14852,7 +14856,7 @@ function attachReplayPlane(deps) {
|
|
|
14852
14856
|
abandon,
|
|
14853
14857
|
snapshot: () => ({ on: master !== null, playing, cursor: master === null ? deps.bars().length : cursor, total: master?.length ?? deps.bars().length }),
|
|
14854
14858
|
speed: () => speed,
|
|
14855
|
-
|
|
14859
|
+
timeframe: currentGrain,
|
|
14856
14860
|
destroy() {
|
|
14857
14861
|
destroyed = true;
|
|
14858
14862
|
abandon();
|
|
@@ -14931,7 +14935,7 @@ function createExtensionHost(deps, extensions = []) {
|
|
|
14931
14935
|
}
|
|
14932
14936
|
}
|
|
14933
14937
|
clearLanes(record3.lanes);
|
|
14934
|
-
record3.
|
|
14938
|
+
record3.menuBuilders.clear();
|
|
14935
14939
|
if (record3.hideLayers.size) {
|
|
14936
14940
|
record3.hideLayers.clear();
|
|
14937
14941
|
notifyHideLayers();
|
|
@@ -14955,7 +14959,7 @@ function createExtensionHost(deps, extensions = []) {
|
|
|
14955
14959
|
} },
|
|
14956
14960
|
live: true,
|
|
14957
14961
|
lanes: newLanes(),
|
|
14958
|
-
|
|
14962
|
+
menuBuilders: /* @__PURE__ */ new Set(),
|
|
14959
14963
|
hideLayers: /* @__PURE__ */ new Map(),
|
|
14960
14964
|
commands: /* @__PURE__ */ new Map(),
|
|
14961
14965
|
priceLines: /* @__PURE__ */ new Set(),
|
|
@@ -15044,12 +15048,12 @@ function createExtensionHost(deps, extensions = []) {
|
|
|
15044
15048
|
record3.lanes.dispose.delete(callback);
|
|
15045
15049
|
};
|
|
15046
15050
|
},
|
|
15047
|
-
contributeContextMenu(
|
|
15051
|
+
contributeContextMenu(build) {
|
|
15048
15052
|
if (!record3.live) return () => {
|
|
15049
15053
|
};
|
|
15050
|
-
record3.
|
|
15054
|
+
record3.menuBuilders.add(build);
|
|
15051
15055
|
return () => {
|
|
15052
|
-
record3.
|
|
15056
|
+
record3.menuBuilders.delete(build);
|
|
15053
15057
|
};
|
|
15054
15058
|
},
|
|
15055
15059
|
contributeCommands(commands) {
|
|
@@ -15143,9 +15147,9 @@ function createExtensionHost(deps, extensions = []) {
|
|
|
15143
15147
|
if (!hostLive) return [];
|
|
15144
15148
|
const rows2 = [];
|
|
15145
15149
|
for (const record3 of liveRecords()) {
|
|
15146
|
-
for (const
|
|
15150
|
+
for (const build of [...record3.menuBuilders]) {
|
|
15147
15151
|
try {
|
|
15148
|
-
rows2.push(...
|
|
15152
|
+
rows2.push(...build(context));
|
|
15149
15153
|
} catch {
|
|
15150
15154
|
}
|
|
15151
15155
|
}
|
|
@@ -15540,7 +15544,7 @@ function mountChartLegend(container, strings, controls) {
|
|
|
15540
15544
|
venueText.className = "qc-legend-venue qc-legend-row-venue";
|
|
15541
15545
|
const value = document.createElement("span");
|
|
15542
15546
|
value.className = "qc-legend-value";
|
|
15543
|
-
value.dataset.role = "legend-
|
|
15547
|
+
value.dataset.role = "legend-indicator-value";
|
|
15544
15548
|
const gear = chipButton(controls.icons.glyph(ICONS.legendSettings, { size: 18 }), "", () => {
|
|
15545
15549
|
const r = gear.getBoundingClientRect();
|
|
15546
15550
|
controls.onSettings?.(chip.id, { x: r.x, y: r.y, w: r.width, h: r.height });
|
|
@@ -16195,7 +16199,7 @@ function attachLegendPlane(deps) {
|
|
|
16195
16199
|
const paneRemembered = /* @__PURE__ */ new Map();
|
|
16196
16200
|
const paneKeys = () => {
|
|
16197
16201
|
const keys = { 0: "main" };
|
|
16198
|
-
for (const [id, pane] of Object.entries(deps.indicators.renderer.paneOf())) if (pane > 0) keys[pane] = `
|
|
16202
|
+
for (const [id, pane] of Object.entries(deps.indicators.renderer.paneOf())) if (pane > 0) keys[pane] = `indicator:${id}`;
|
|
16199
16203
|
for (const entry of deps.compare?.api.list() ?? []) {
|
|
16200
16204
|
const pane = deps.compare.handle.paneIndexOf(entry.symbol);
|
|
16201
16205
|
if (pane !== null && pane > 0) keys[pane] = `compare:${entry.symbol}`;
|
|
@@ -16320,7 +16324,7 @@ function attachLegendPlane(deps) {
|
|
|
16320
16324
|
legend2?.setChips([
|
|
16321
16325
|
...deps.indicators.chipsAt(hovered).map((row2) => {
|
|
16322
16326
|
const paneIndex = paneOf[row2.id] ?? 0;
|
|
16323
|
-
const remembered = paneRemembered.get(`
|
|
16327
|
+
const remembered = paneRemembered.get(`indicator:${row2.id}`);
|
|
16324
16328
|
return {
|
|
16325
16329
|
...row2,
|
|
16326
16330
|
paneIndex,
|
|
@@ -16699,7 +16703,7 @@ var CONTROL_ICONS = byMeaning({
|
|
|
16699
16703
|
chevronDown: [ICONS.chevronDown, ICONS.chevronDown18],
|
|
16700
16704
|
chevronLeft: [ICONS.chevronLeft],
|
|
16701
16705
|
chevronRight: [ICONS.chevronRight],
|
|
16702
|
-
// The
|
|
16706
|
+
// The drawing toolbar's arrow, pointing where the flyout it opens will stand.
|
|
16703
16707
|
flyout: [ICONS.chevronRight16],
|
|
16704
16708
|
submenu: [ICONS.submenuArrow],
|
|
16705
16709
|
more: [ICONS.kebab],
|
|
@@ -16725,7 +16729,7 @@ var CONTROL_ICONS = byMeaning({
|
|
|
16725
16729
|
selectDate: [ICONS.calendar],
|
|
16726
16730
|
firstAvailable: [ICONS.firstAvailable],
|
|
16727
16731
|
randomBar: [ICONS.randomBar],
|
|
16728
|
-
// The drawing
|
|
16732
|
+
// The drawing toolbar, its menus, the favorites bar and the drawing settings.
|
|
16729
16733
|
cursorCross: [ICONS.cursorCross],
|
|
16730
16734
|
cursorDot: [ICONS.cursorDot],
|
|
16731
16735
|
cursorArrow: [ICONS.cursorArrow],
|
|
@@ -17116,7 +17120,7 @@ function attachMenuPlane(deps) {
|
|
|
17116
17120
|
{
|
|
17117
17121
|
priceText,
|
|
17118
17122
|
symbol: deps.symbol(),
|
|
17119
|
-
// The
|
|
17123
|
+
// The context menu's paste row is live exactly when the paste command would run (a copied
|
|
17120
17124
|
// drawing on the clipboard, the verb permitted). It offers no settings row: the settings
|
|
17121
17125
|
// dialog belongs to the selected drawing's own surfaces, which the drawing plane mounts
|
|
17122
17126
|
// and the chart.drawings.* commands drive.
|
|
@@ -17886,12 +17890,12 @@ function registerChartCommands(deps) {
|
|
|
17886
17890
|
}
|
|
17887
17891
|
});
|
|
17888
17892
|
add({
|
|
17889
|
-
id: "chart.replay.
|
|
17893
|
+
id: "chart.replay.setTimeframe",
|
|
17890
17894
|
scope: "chart",
|
|
17891
|
-
label: "command.
|
|
17895
|
+
label: "command.replayTimeframe",
|
|
17892
17896
|
available: () => handle.replay.state().on,
|
|
17893
17897
|
execute: (arg) => {
|
|
17894
|
-
if (typeof arg === "string" && arg) handle.replay.
|
|
17898
|
+
if (typeof arg === "string" && arg) handle.replay.setTimeframe(arg);
|
|
17895
17899
|
}
|
|
17896
17900
|
});
|
|
17897
17901
|
const servable = (token) => {
|
|
@@ -18220,7 +18224,7 @@ var SCALE_KEY = "quickcharts.scale.v1";
|
|
|
18220
18224
|
var PRICE_AXIS_KEY = "quickcharts.priceAxis.v1";
|
|
18221
18225
|
var HIDDEN_KEY = "quickcharts.indHidden.v1";
|
|
18222
18226
|
var REPLAY_SPEED_KEY = "quickcharts.replaySpeed.v1";
|
|
18223
|
-
var
|
|
18227
|
+
var REPLAY_TIMEFRAME_KEY = "quickcharts.replayTf.v1";
|
|
18224
18228
|
var TIMEZONE_KEY = "quickcharts.timezone.v1";
|
|
18225
18229
|
var SUBSESSION_KEY = "quickcharts.subsession.v1";
|
|
18226
18230
|
function sameIds(left, right) {
|
|
@@ -18465,8 +18469,8 @@ function createChartInstance(deps) {
|
|
|
18465
18469
|
const indicators2 = attachIndicatorsPlane({
|
|
18466
18470
|
chart,
|
|
18467
18471
|
candleSeries,
|
|
18468
|
-
//
|
|
18469
|
-
// it, so it computes over the painted model rather than the loaded one.
|
|
18472
|
+
// An indicator drawn over bars the active subsession hides would not line up with the series
|
|
18473
|
+
// beside it, so it computes over the painted model rather than the loaded one.
|
|
18470
18474
|
bars: () => shownBars(),
|
|
18471
18475
|
i18n,
|
|
18472
18476
|
formatter: () => symbolFormatter,
|
|
@@ -18622,9 +18626,9 @@ function createChartInstance(deps) {
|
|
|
18622
18626
|
// A chart whose crosshair the host switched OFF keeps it off: replay may take the crosshair
|
|
18623
18627
|
// away for the length of a question, never hand one back that was never there.
|
|
18624
18628
|
setCrosshair: (visible) => chart.applyOptions({ crosshair: { mode: visible && deps.features.crosshair ? CrosshairMode.Normal : CrosshairMode.Hidden } }),
|
|
18625
|
-
// The feed's own grains: a chart never offers, or fetches,
|
|
18629
|
+
// The feed's own grains: a chart never offers, or fetches, a timeframe its feed cannot serve.
|
|
18626
18630
|
resolutions: () => deps.capabilities().resolutions,
|
|
18627
|
-
persist: (key, value) => storage.set(key === "speed" ? REPLAY_SPEED_KEY :
|
|
18631
|
+
persist: (key, value) => storage.set(key === "speed" ? REPLAY_SPEED_KEY : REPLAY_TIMEFRAME_KEY, value),
|
|
18628
18632
|
onChange: () => {
|
|
18629
18633
|
const state = replay2.snapshot();
|
|
18630
18634
|
countdown?.refresh();
|
|
@@ -18634,7 +18638,7 @@ function createChartInstance(deps) {
|
|
|
18634
18638
|
events.emit("replay", state);
|
|
18635
18639
|
},
|
|
18636
18640
|
initialSpeed: coerceReplaySpeed(storage.get(REPLAY_SPEED_KEY) ?? deps.preferences.replaySpeed),
|
|
18637
|
-
|
|
18641
|
+
initialGrain: storage.get(REPLAY_TIMEFRAME_KEY) ?? deps.preferences.replayTimeframe ?? "auto"
|
|
18638
18642
|
});
|
|
18639
18643
|
const countdownClock = createCountdownClock(() => Date.now() / 1e3, datafeed.serverTime?.bind(datafeed));
|
|
18640
18644
|
countdown = attachCountdown({
|
|
@@ -18681,7 +18685,8 @@ function createChartInstance(deps) {
|
|
|
18681
18685
|
setTouchAction: (value) => {
|
|
18682
18686
|
gestures.style.touchAction = value;
|
|
18683
18687
|
},
|
|
18684
|
-
// A contributed layer rides the same eye the
|
|
18688
|
+
// A contributed layer rides the same eye the drawing toolbar drives, through the drawing
|
|
18689
|
+
// plane's verbs.
|
|
18685
18690
|
hideState: () => drawings2.verbs?.hide() ?? { mode: "drawings", on: false },
|
|
18686
18691
|
setHide: (state) => drawings2.verbs?.setHide(state),
|
|
18687
18692
|
hideLayersChanged: () => drawings2.syncHideLayers()
|
|
@@ -19357,7 +19362,7 @@ function createChartInstance(deps) {
|
|
|
19357
19362
|
resetAppearance,
|
|
19358
19363
|
t: () => i18n.t,
|
|
19359
19364
|
// What is PAINTED, which is the replay slice while replay is on: the data export writes what
|
|
19360
|
-
// the
|
|
19365
|
+
// the viewer can see and never a bar the cursor has not revealed.
|
|
19361
19366
|
bars: () => shownBars(),
|
|
19362
19367
|
// The feed's own statement of how deep its history goes, never the oldest bar that happens to
|
|
19363
19368
|
// be loaded: the chart opens on a short window, and a preset judged against that would be
|
|
@@ -19623,7 +19628,14 @@ function validGeometry(value, catalog) {
|
|
|
19623
19628
|
}
|
|
19624
19629
|
|
|
19625
19630
|
// src/widget/layout.ts
|
|
19626
|
-
var SYNC_OFF = { symbol: false,
|
|
19631
|
+
var SYNC_OFF = { symbol: false, timeframe: false, crosshair: false, time: false, dateRange: false };
|
|
19632
|
+
var syncSwitches = (stated) => Object.fromEntries(LAYOUT_SYNC_KEYS.map((key) => [key, stated[key] ?? SYNC_OFF[key]]));
|
|
19633
|
+
function readSyncFlags(value, defaults) {
|
|
19634
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
19635
|
+
const stated = value;
|
|
19636
|
+
if (LAYOUT_SYNC_KEYS.some((key) => key in stated && typeof stated[key] !== "boolean")) return null;
|
|
19637
|
+
return Object.fromEntries(LAYOUT_SYNC_KEYS.map((key) => [key, key in stated ? stated[key] : defaults[key]]));
|
|
19638
|
+
}
|
|
19627
19639
|
var LAYOUT_CONTENT_VERSION = 2;
|
|
19628
19640
|
var validEntityNamespace = (value) => /^(?:layout:(?:[A-Za-z0-9_.!~*'()-]|%[0-9A-F]{2})+|session:[a-z0-9-]+)$/.test(value);
|
|
19629
19641
|
var cloneIndicators = (instances) => instances.map((instance) => ({
|
|
@@ -19638,7 +19650,7 @@ var cloneTemplate = (template) => ({
|
|
|
19638
19650
|
});
|
|
19639
19651
|
function createLayoutPlane(deps) {
|
|
19640
19652
|
const slots = [];
|
|
19641
|
-
let flags =
|
|
19653
|
+
let flags = syncSwitches(deps.sync ?? {});
|
|
19642
19654
|
const fixedSync = deps.syncOffered ? LAYOUT_SYNC_KEYS.filter((key) => !deps.syncOffered.includes(key)) : [];
|
|
19643
19655
|
const fixedFlags = { ...flags };
|
|
19644
19656
|
const holdFixed = (next) => {
|
|
@@ -19757,7 +19769,7 @@ function createLayoutPlane(deps) {
|
|
|
19757
19769
|
if (!applying) emitActive();
|
|
19758
19770
|
}));
|
|
19759
19771
|
slot.unsubscribes.push(handle.on("timeframe", () => {
|
|
19760
|
-
if (flags.
|
|
19772
|
+
if (flags.timeframe) fanOut2(index(), (other) => other.setTimeframe(handle.timeframe()));
|
|
19761
19773
|
if (!applying) deps.onChange();
|
|
19762
19774
|
}));
|
|
19763
19775
|
};
|
|
@@ -20021,15 +20033,14 @@ function createLayoutPlane(deps) {
|
|
|
20021
20033
|
if (!arrangement2) throw new Error(`unknown arrangement code ${String(c.arrangement)}`);
|
|
20022
20034
|
if (charts.length !== arrangement2.count) throw new Error("layout chart count does not match arrangement");
|
|
20023
20035
|
if (!validGeometry(c.geometry, arrangement2.rects)) throw new Error("invalid layout geometry");
|
|
20024
|
-
const sync = c.sync
|
|
20025
|
-
|
|
20026
|
-
if (!sync || keys.some((key) => typeof sync[key] !== "boolean")) throw new Error("invalid layout sync flags");
|
|
20036
|
+
const sync = readSyncFlags(c.sync, fixedFlags);
|
|
20037
|
+
if (!sync) throw new Error("invalid layout sync flags");
|
|
20027
20038
|
if (!Number.isInteger(c.active) || c.active < 0 || c.active >= charts.length) throw new Error("invalid active chart");
|
|
20028
20039
|
return {
|
|
20029
20040
|
arrangement: arrangement2,
|
|
20030
20041
|
identity: { namespace: identity.namespace, next: identity.next },
|
|
20031
20042
|
geometry: c.geometry.map((rect) => ({ ...rect })),
|
|
20032
|
-
sync
|
|
20043
|
+
sync,
|
|
20033
20044
|
active: c.active,
|
|
20034
20045
|
charts
|
|
20035
20046
|
};
|
|
@@ -20111,7 +20122,7 @@ function createLayoutPlane(deps) {
|
|
|
20111
20122
|
setSync(partial) {
|
|
20112
20123
|
if (removed) return;
|
|
20113
20124
|
if (fixedSync.length > 0 && Object.keys(partial).every((key) => fixedSync.includes(key))) return;
|
|
20114
|
-
flags = holdFixed({ ...flags, ...partial });
|
|
20125
|
+
flags = holdFixed(syncSwitches({ ...flags, ...partial }));
|
|
20115
20126
|
deps.onChange();
|
|
20116
20127
|
emitCommitted();
|
|
20117
20128
|
},
|
|
@@ -20759,9 +20770,9 @@ var FLYOUT_WIDTH = {
|
|
|
20759
20770
|
session: 176,
|
|
20760
20771
|
/** The replay row's starting-point choices, opening upward. */
|
|
20761
20772
|
replayStart: 177,
|
|
20762
|
-
/** The replay row's update-
|
|
20763
|
-
* its rates. */
|
|
20764
|
-
|
|
20773
|
+
/** The replay row's update-timeframe list. The speed list opens at the same width and grows to
|
|
20774
|
+
* fit its rates. */
|
|
20775
|
+
replayTimeframe: 196
|
|
20765
20776
|
};
|
|
20766
20777
|
|
|
20767
20778
|
// src/ui/chrome/bottomBar.ts
|
|
@@ -21235,7 +21246,8 @@ function openIndicatorPicker(deps) {
|
|
|
21235
21246
|
className: "qc-picker-dialog",
|
|
21236
21247
|
width: 840,
|
|
21237
21248
|
refresh: () => redraw(),
|
|
21238
|
-
|
|
21249
|
+
// The host's listing is abandoned as the dialog begins to close, not when its exit ends.
|
|
21250
|
+
onClosing: () => {
|
|
21239
21251
|
cancel();
|
|
21240
21252
|
offLocale();
|
|
21241
21253
|
},
|
|
@@ -21547,7 +21559,7 @@ var PLACEMENTS2 = [
|
|
|
21547
21559
|
];
|
|
21548
21560
|
function rowLabels(row2) {
|
|
21549
21561
|
const names = symbolNames(row2);
|
|
21550
|
-
return { ticker: names.mark, description: names.description, source: row2.exchange || row2.
|
|
21562
|
+
return { ticker: names.mark, description: names.description, source: row2.exchange || row2.dataSource || "" };
|
|
21551
21563
|
}
|
|
21552
21564
|
function offeredOperators(spreads) {
|
|
21553
21565
|
if (spreads === false) return [];
|
|
@@ -21776,10 +21788,10 @@ function buildSearchSurface(deps, box, frame) {
|
|
|
21776
21788
|
option.appendChild(mark2);
|
|
21777
21789
|
} else {
|
|
21778
21790
|
const source3 = h("span", { class: "qc-search-source" });
|
|
21779
|
-
source3.appendChild(h("span", { class: "qc-search-source-text" }, label2.source ? h("span", { class: "qc-search-
|
|
21791
|
+
source3.appendChild(h("span", { class: "qc-search-source-text" }, label2.source ? h("span", { class: "qc-search-source-name" }, label2.source) : null, h("span", { class: "qc-search-kind" }, r.type)));
|
|
21780
21792
|
if (label2.source) {
|
|
21781
21793
|
const sourceMark = h("span", { class: "qc-search-mark", "aria-hidden": "true" });
|
|
21782
|
-
const dropSource = r.exchange ? deps.painters.venue?.({ exchange: r.exchange, host: sourceMark, size: SOURCE_MARK_SIZE }) : r.
|
|
21794
|
+
const dropSource = r.exchange ? deps.painters.venue?.({ exchange: r.exchange, host: sourceMark, size: SOURCE_MARK_SIZE }) : r.dataSource ? deps.painters.dataSource?.({ dataSource: r.dataSource, host: sourceMark, size: SOURCE_MARK_SIZE }) : void 0;
|
|
21783
21795
|
if (typeof dropSource === "function") {
|
|
21784
21796
|
sourceMark.dataset.qcHost = "true";
|
|
21785
21797
|
markDisposers.push(dropSource);
|
|
@@ -21886,7 +21898,6 @@ function openSearchDialog(deps) {
|
|
|
21886
21898
|
host: deps.host,
|
|
21887
21899
|
label: title,
|
|
21888
21900
|
className: `qc-search-dialog qc-search-dialog--${mode}`,
|
|
21889
|
-
animated: true,
|
|
21890
21901
|
// The compare family (compare, and a compare row's change-symbol) shares one role for a host
|
|
21891
21902
|
// test to find; a symbol search, with or without a chart behind it, is the other.
|
|
21892
21903
|
role: mode === "compare" || mode === "change-symbol" ? "compare-dialog" : "symbol-search",
|
|
@@ -22021,7 +22032,7 @@ var SORT_LABEL = {
|
|
|
22021
22032
|
"modified-desc": "layouts.sortModifiedDesc"
|
|
22022
22033
|
};
|
|
22023
22034
|
function listingFacts(t, row2) {
|
|
22024
|
-
return row2.symbol ? row2.timeframe ? t("layouts.listingFacts", { symbol: row2.symbol,
|
|
22035
|
+
return row2.symbol ? row2.timeframe ? t("layouts.listingFacts", { symbol: row2.symbol, timeframe: timeframeChipLabel(row2.timeframe) }) : row2.symbol : null;
|
|
22025
22036
|
}
|
|
22026
22037
|
function mountLayoutDialogs(deps) {
|
|
22027
22038
|
const t = () => deps.i18n.t;
|
|
@@ -22037,7 +22048,7 @@ function mountLayoutDialogs(deps) {
|
|
|
22037
22048
|
};
|
|
22038
22049
|
const askName = (question) => {
|
|
22039
22050
|
raise();
|
|
22040
|
-
asking?.close();
|
|
22051
|
+
asking?.close({ animate: false });
|
|
22041
22052
|
asking = openNameDialog({
|
|
22042
22053
|
host: deps.overlays,
|
|
22043
22054
|
t: t(),
|
|
@@ -22189,15 +22200,15 @@ function mountLayoutDialogs(deps) {
|
|
|
22189
22200
|
render();
|
|
22190
22201
|
redraw = render;
|
|
22191
22202
|
closeBrowser = catalog.onChange(render);
|
|
22192
|
-
browser =
|
|
22193
|
-
close: () => handle.close()
|
|
22194
|
-
};
|
|
22203
|
+
browser = handle;
|
|
22195
22204
|
void catalog.refresh().catch(() => {
|
|
22196
22205
|
deps.notify("error", t()("layouts.errList"));
|
|
22197
22206
|
});
|
|
22198
22207
|
},
|
|
22199
22208
|
initialFocus: (box) => box.querySelector(".qc-layouts-search-input"),
|
|
22200
|
-
|
|
22209
|
+
// The dialog lets go of the catalog and its slot as it begins to close, so a Layouts dialog
|
|
22210
|
+
// asked for during the exit opens at once and the leaving one never unsubscribes it.
|
|
22211
|
+
onClosing: () => {
|
|
22201
22212
|
closeBrowser();
|
|
22202
22213
|
browser = null;
|
|
22203
22214
|
}
|
|
@@ -22228,8 +22239,8 @@ function mountLayoutDialogs(deps) {
|
|
|
22228
22239
|
destroy() {
|
|
22229
22240
|
raising.clear();
|
|
22230
22241
|
offLayout();
|
|
22231
|
-
browser?.close();
|
|
22232
|
-
asking?.close();
|
|
22242
|
+
browser?.close({ animate: false });
|
|
22243
|
+
asking?.close({ animate: false });
|
|
22233
22244
|
}
|
|
22234
22245
|
};
|
|
22235
22246
|
}
|
|
@@ -22294,7 +22305,7 @@ function arrangementGlyph(code, icons) {
|
|
|
22294
22305
|
}
|
|
22295
22306
|
var SYNC_ROWS = [
|
|
22296
22307
|
{ key: "symbol", label: "layouts.syncSymbol", tip: "layouts.syncSymbolTip", toggle: "layouts.syncSymbolToggle" },
|
|
22297
|
-
{ key: "
|
|
22308
|
+
{ key: "timeframe", label: "layouts.syncTimeframe", tip: "layouts.syncTimeframeTip", toggle: "layouts.syncTimeframeToggle" },
|
|
22298
22309
|
{ key: "crosshair", label: "layouts.syncCrosshair", tip: "layouts.syncCrosshairTip", toggle: "layouts.syncCrosshairToggle" },
|
|
22299
22310
|
{ key: "time", label: "layouts.syncTime", tip: "layouts.syncTimeTip", toggle: "layouts.syncTimeToggle" },
|
|
22300
22311
|
{ key: "dateRange", label: "layouts.syncDateRange", tip: "layouts.syncDateRangeTip", toggle: "layouts.syncDateRangeToggle" }
|
|
@@ -22594,8 +22605,8 @@ function mountLayoutsMenu(deps) {
|
|
|
22594
22605
|
text: t()("layouts.createNewRow"),
|
|
22595
22606
|
icon: deps.icons.glyph(ICONS.plusThin, { size: 28 }),
|
|
22596
22607
|
disabled: !can("widget.layout.create"),
|
|
22597
|
-
// A new layout by the name it is given: the market and
|
|
22598
|
-
// of the open layout, and the open one left as it was saved.
|
|
22608
|
+
// A new layout by the name it is given: the market and timeframe on screen, nothing
|
|
22609
|
+
// else of the open layout, and the open one left as it was saved.
|
|
22599
22610
|
onSelect: () => askName({
|
|
22600
22611
|
title: "layouts.createTitle",
|
|
22601
22612
|
label: "layouts.newLayoutName",
|
|
@@ -22892,7 +22903,6 @@ function mountSettingsMenu(deps) {
|
|
|
22892
22903
|
host: deps.overlays,
|
|
22893
22904
|
label: t()("settings.menu"),
|
|
22894
22905
|
className: "qc-settings-menu qc-chart-settings-dialog",
|
|
22895
|
-
animated: true,
|
|
22896
22906
|
width: 750,
|
|
22897
22907
|
build(box, handle) {
|
|
22898
22908
|
content = h("div", { class: "qc-dialog-body qc-chart-settings-body" });
|
|
@@ -23760,7 +23770,7 @@ function openDatePicker(deps) {
|
|
|
23760
23770
|
function speedWords(t, speed) {
|
|
23761
23771
|
return speed >= 1 ? t("replay.updatesPerSecond", { count: speed }) : t("replay.oneUpdatePerSeconds", { count: Math.round(1 / speed) });
|
|
23762
23772
|
}
|
|
23763
|
-
function
|
|
23773
|
+
function timeframeWords(t, token) {
|
|
23764
23774
|
const sec = tfSeconds(token);
|
|
23765
23775
|
if (sec === 0) return token;
|
|
23766
23776
|
return timeframeLabel(t, token);
|
|
@@ -23931,36 +23941,36 @@ function mountReplayTransport(deps) {
|
|
|
23931
23941
|
}
|
|
23932
23942
|
}));
|
|
23933
23943
|
};
|
|
23934
|
-
const
|
|
23935
|
-
|
|
23936
|
-
const
|
|
23944
|
+
const timeframeButton = button2({ label: t()("replay.timeframe"), text: "", className: "qc-toolbar-button qc-replay-timeframe", onClick: () => toggleMenu(timeframeButton, openTimeframeMenu) });
|
|
23945
|
+
timeframeButton.setAttribute("aria-haspopup", "menu");
|
|
23946
|
+
const openTimeframeMenu = () => {
|
|
23937
23947
|
const menu2 = hold(openMenu({
|
|
23938
23948
|
host: deps.chrome,
|
|
23939
|
-
anchor:
|
|
23940
|
-
label: t()("replay.
|
|
23949
|
+
anchor: timeframeButton,
|
|
23950
|
+
label: t()("replay.timeframe"),
|
|
23941
23951
|
role: "dialog",
|
|
23942
23952
|
className: "qc-replay-menu",
|
|
23943
|
-
width: FLYOUT_WIDTH.
|
|
23953
|
+
width: FLYOUT_WIDTH.replayTimeframe,
|
|
23944
23954
|
placement: "up",
|
|
23945
23955
|
onClose: () => open2.delete(menu2),
|
|
23946
23956
|
build(body, menu3) {
|
|
23947
|
-
const heading = menuHeading(t()("replay.
|
|
23948
|
-
heading.title = t()("replay.
|
|
23957
|
+
const heading = menuHeading(t()("replay.timeframe"));
|
|
23958
|
+
heading.title = t()("replay.timeframeHelp");
|
|
23949
23959
|
body.appendChild(heading);
|
|
23950
|
-
const current = handle.replay.
|
|
23960
|
+
const current = handle.replay.timeframe();
|
|
23951
23961
|
const rows2 = [];
|
|
23952
23962
|
let previousUnit = null;
|
|
23953
|
-
for (const token of handle.replay.
|
|
23963
|
+
for (const token of handle.replay.subTimeframes()) {
|
|
23954
23964
|
const unit = timeframeGroupUnit(parseTimeframe(token)?.unit ?? "d");
|
|
23955
23965
|
if (previousUnit !== null && unit !== previousUnit) body.appendChild(menuSeparator());
|
|
23956
23966
|
previousUnit = unit;
|
|
23957
23967
|
const row2 = menuItem({
|
|
23958
|
-
text:
|
|
23968
|
+
text: timeframeWords(t(), token),
|
|
23959
23969
|
role: "menuitemradio",
|
|
23960
23970
|
checked: current === token,
|
|
23961
23971
|
onSelect: () => {
|
|
23962
23972
|
menu3.close();
|
|
23963
|
-
commands.execute("chart.replay.
|
|
23973
|
+
commands.execute("chart.replay.setTimeframe", token);
|
|
23964
23974
|
}
|
|
23965
23975
|
});
|
|
23966
23976
|
rows2.push({ token, row: row2 });
|
|
@@ -23969,12 +23979,12 @@ function mountReplayTransport(deps) {
|
|
|
23969
23979
|
body.appendChild(menuSeparator());
|
|
23970
23980
|
body.appendChild(
|
|
23971
23981
|
switchRow({
|
|
23972
|
-
label: t()("replay.
|
|
23982
|
+
label: t()("replay.autoSelectTimeframe"),
|
|
23973
23983
|
checked: current === "auto",
|
|
23974
23984
|
onChange: (on) => {
|
|
23975
|
-
const first = handle.replay.
|
|
23976
|
-
commands.execute("chart.replay.
|
|
23977
|
-
const now = handle.replay.
|
|
23985
|
+
const first = handle.replay.subTimeframes()[0];
|
|
23986
|
+
commands.execute("chart.replay.setTimeframe", on ? "auto" : first ?? "auto");
|
|
23987
|
+
const now = handle.replay.timeframe();
|
|
23978
23988
|
for (const entry of rows2) entry.row.setAttribute("aria-checked", String(now === entry.token));
|
|
23979
23989
|
}
|
|
23980
23990
|
})
|
|
@@ -23994,7 +24004,7 @@ function mountReplayTransport(deps) {
|
|
|
23994
24004
|
playPause,
|
|
23995
24005
|
stepForward,
|
|
23996
24006
|
speedButton,
|
|
23997
|
-
|
|
24007
|
+
timeframeButton,
|
|
23998
24008
|
rule(),
|
|
23999
24009
|
goLive
|
|
24000
24010
|
);
|
|
@@ -24010,19 +24020,19 @@ function mountReplayTransport(deps) {
|
|
|
24010
24020
|
stepForward.hidden = !shown2("chart.replay.stepForward");
|
|
24011
24021
|
goLive.hidden = !shown2("chart.replay.goLive");
|
|
24012
24022
|
speedButton.hidden = !shown2("chart.replay.setSpeed");
|
|
24013
|
-
|
|
24023
|
+
timeframeButton.hidden = !shown2("chart.replay.setTimeframe");
|
|
24014
24024
|
exit.hidden = !shown2("chart.replay.exit");
|
|
24015
24025
|
setDisabled(stepBack, !commands.available("chart.replay.stepBack") || state.cursor <= 2);
|
|
24016
24026
|
setDisabled(playPause, !commands.available(playing ? "chart.replay.pause" : "chart.replay.play") || !playing && atLive);
|
|
24017
24027
|
setDisabled(stepForward, !commands.available("chart.replay.stepForward") || atLive);
|
|
24018
24028
|
setDisabled(goLive, !commands.available("chart.replay.goLive") || atLive);
|
|
24019
24029
|
setDisabled(speedButton, !commands.available("chart.replay.setSpeed"));
|
|
24020
|
-
const
|
|
24021
|
-
const noGrain =
|
|
24022
|
-
setDisabled(
|
|
24030
|
+
const grains = handle.replay.subTimeframes();
|
|
24031
|
+
const noGrain = grains.length === 0;
|
|
24032
|
+
setDisabled(timeframeButton, noGrain || !commands.available("chart.replay.setTimeframe"));
|
|
24023
24033
|
retext(speedButton, t()("replay.speed"), `${state.speed}x`);
|
|
24024
|
-
const resolved = handle.replay.
|
|
24025
|
-
retext(
|
|
24034
|
+
const resolved = handle.replay.resolvedTimeframe();
|
|
24035
|
+
retext(timeframeButton, noGrain ? t()("replay.timeframeNone") : t()("replay.timeframe"), noGrain ? t()("replay.auto") : timeframeChipLabel(resolved));
|
|
24026
24036
|
setDisabled(exit, !commands.available("chart.replay.exit"));
|
|
24027
24037
|
reconcilePicking();
|
|
24028
24038
|
bar.setAttribute("aria-label", t()("chrome.replay"));
|
|
@@ -24053,7 +24063,7 @@ function mountReplayTransport(deps) {
|
|
|
24053
24063
|
if (destroyed) return;
|
|
24054
24064
|
destroyed = true;
|
|
24055
24065
|
releasePicking();
|
|
24056
|
-
for (const handle2 of [...open2]) handle2.close();
|
|
24066
|
+
for (const handle2 of [...open2]) handle2.close({ animate });
|
|
24057
24067
|
offStrings();
|
|
24058
24068
|
const view = bar.ownerDocument.defaultView;
|
|
24059
24069
|
const exitMs = animate && bar.isConnected ? motionDurationMs(bar, "motion.durationBase") : 0;
|
|
@@ -24158,7 +24168,7 @@ function mountChrome(deps) {
|
|
|
24158
24168
|
indicatorDialog = openIndicatorPicker({ ...ctx, storage: deps.storage, indicatorPicker: deps.indicatorPicker, initialCollection });
|
|
24159
24169
|
};
|
|
24160
24170
|
disposers.push(() => {
|
|
24161
|
-
indicatorDialog?.close();
|
|
24171
|
+
indicatorDialog?.close({ animate: false });
|
|
24162
24172
|
deps.doors.showIndicatorPicker = () => void 0;
|
|
24163
24173
|
});
|
|
24164
24174
|
deps.doors.openSearch = (request) => {
|
|
@@ -24213,7 +24223,8 @@ function mountChrome(deps) {
|
|
|
24213
24223
|
widget.theme.onChange((theme, mode) => paintThemeRoot(surface, mode, theme)),
|
|
24214
24224
|
i18n.onChange(() => surface.setAttribute("dir", readingDirection(i18n))),
|
|
24215
24225
|
() => surface.remove(),
|
|
24216
|
-
// A flyout still open in the layer closes with the
|
|
24226
|
+
// A flyout still open in the layer closes with the drawing toolbar, taking its document
|
|
24227
|
+
// listeners.
|
|
24217
24228
|
() => closeOverlays(deps.layer),
|
|
24218
24229
|
releasePanelHost
|
|
24219
24230
|
);
|
|
@@ -24404,7 +24415,7 @@ function resolveMarkPainters(hooks) {
|
|
|
24404
24415
|
return {
|
|
24405
24416
|
symbol: hooks.symbolMark ?? null,
|
|
24406
24417
|
venue: hooks.venueMark ?? null,
|
|
24407
|
-
|
|
24418
|
+
dataSource: hooks.dataSourceMark ?? null
|
|
24408
24419
|
};
|
|
24409
24420
|
}
|
|
24410
24421
|
|
|
@@ -24857,7 +24868,7 @@ function createChart(options) {
|
|
|
24857
24868
|
i18n,
|
|
24858
24869
|
features,
|
|
24859
24870
|
ui,
|
|
24860
|
-
// What the chrome keeps is the viewer's own choices about it (favorite and custom
|
|
24871
|
+
// What the chrome keeps is the viewer's own choices about it (favorite and custom timeframes,
|
|
24861
24872
|
// starred layouts and indicators, how the layouts sort), which change no layout, so it reads and
|
|
24862
24873
|
// writes the host's store directly rather than through the save-needed funnel.
|
|
24863
24874
|
storage: backing,
|
|
@@ -25182,7 +25193,7 @@ export {
|
|
|
25182
25193
|
attachCompare,
|
|
25183
25194
|
attachDrawings,
|
|
25184
25195
|
attachIndicators,
|
|
25185
|
-
|
|
25196
|
+
autoTimeframeFor,
|
|
25186
25197
|
buildManifestPlots,
|
|
25187
25198
|
canvasTheme,
|
|
25188
25199
|
canvasToBlob,
|
|
@@ -25269,7 +25280,7 @@ export {
|
|
|
25269
25280
|
sessionTimeline,
|
|
25270
25281
|
spreadExpression,
|
|
25271
25282
|
spreadSearchQuery,
|
|
25272
|
-
|
|
25283
|
+
subTimeframesFor,
|
|
25273
25284
|
subsessionBarFilter,
|
|
25274
25285
|
symbolNames,
|
|
25275
25286
|
tfSeconds,
|