@luxalgo/vela 0.6.14 → 0.6.15
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/NOTICE +28 -28
- package/README.md +1 -1
- package/dist/{DataProvider-DhzstpQb.d.ts → DataProvider-XLdJB86x.d.ts} +1 -1
- package/dist/{DataProvider-DlMtrwqM.d.cts → DataProvider-xH2VBcFT.d.cts} +1 -1
- package/dist/{chunk-F4M24ANM.js → chunk-32A7KHFM.js} +73 -3
- package/dist/{chunk-KG4YT3TI.js → chunk-6DPAYEGO.js} +8 -1
- package/dist/{chunk-64TF7JAJ.js → chunk-7C7NWEXH.js} +345 -148
- package/dist/{chunk-N2Q5EEFH.js → chunk-J5QIR2Z3.js} +163 -130
- package/dist/{chunk-MHY7MVXH.js → chunk-MWDNPGU3.js} +7 -1
- package/dist/{chunk-G77Y7LK2.js → chunk-MWS4CUJL.js} +2 -2
- package/dist/{contributions-37nni40G.d.ts → contributions-h5BzEiV2.d.ts} +13 -2
- package/dist/{contributions-lPojhTxI.d.cts → contributions-x7iamlnd.d.cts} +13 -2
- package/dist/index.cjs +174 -127
- package/dist/index.d.cts +20 -12
- package/dist/index.d.ts +20 -12
- package/dist/index.js +4 -4
- package/dist/{options-CYS5Wmlx.d.ts → options-bdSAtp7y.d.cts} +5 -0
- package/dist/{options-CYS5Wmlx.d.cts → options-bdSAtp7y.d.ts} +5 -0
- package/dist/{plugin-Cwikpz1m.d.cts → plugin-2sJcf5mk.d.cts} +11 -8
- package/dist/{plugin-DHyaoMjW.d.ts → plugin-BLaNPh55.d.ts} +11 -8
- package/dist/plugin.cjs +8 -0
- package/dist/plugin.d.cts +5 -5
- package/dist/plugin.d.ts +5 -5
- package/dist/plugin.js +2 -2
- package/dist/providers/binance.d.cts +2 -2
- package/dist/providers/binance.d.ts +2 -2
- package/dist/providers/coinbase.d.cts +2 -2
- package/dist/providers/coinbase.d.ts +2 -2
- package/dist/providers/hyperliquid.d.cts +2 -2
- package/dist/providers/hyperliquid.d.ts +2 -2
- package/dist/{side-panel-CT9ZwIGz.d.cts → side-panel-HF0IAzwf.d.cts} +17 -0
- package/dist/{side-panel-CT9ZwIGz.d.ts → side-panel-HF0IAzwf.d.ts} +17 -0
- package/dist/{statusline-model-D-q_OOx9.d.ts → statusline-model--tH0VWCy.d.cts} +6 -4
- package/dist/{statusline-model-CiJm-riV.d.cts → statusline-model-CLpaO3Dl.d.ts} +6 -4
- package/dist/ui.cjs +12 -0
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +3 -3
- package/dist/vela.global.js +174 -127
- package/dist/vela.global.min.js +52 -46
- package/dist/widget.cjs +585 -272
- package/dist/widget.d.cts +15 -11
- package/dist/widget.d.ts +15 -11
- package/dist/widget.js +7 -7
- package/dist/workspace.cjs +585 -272
- package/dist/workspace.d.cts +29 -10
- package/dist/workspace.d.ts +29 -10
- package/dist/workspace.js +6 -6
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { Drawer, KeymapManager, Tooltip, drawerController, tooltipController } from './chunk-
|
|
2
|
-
export { CALLOUT_CSS, CALLOUT_STYLE_ID, CalloutBubble, ColorField, Dialog, FIELD_GAP_PX, GlyphSelect, Menu, NumberInput, Popover, Select, Switch, TextArea, TextField, WIDTH_FIELD_OPTIONS, applyPlotOverlayTokens, applyThemeTokens, blendOver, buildColorPicker, buildFieldControl, buildPalette, calloutPanelRows, clampNumber, closeColorPopover, closeOpenPopovers, closeWidthPopover, closesPanel, colorField, colorPickerController, combineColor, decorateSelectScroll, dialogController, ensureUIHost, eventDismissedPopover, fieldGrid, fieldGridColumns, fieldRow, fieldSection, fieldSeparator, fillSelectList, glyphSelectController, hslHex, insetRect, intersectRects, isPopoverOpen, lineWidthGlyph, menuController, nextUid, normalizeProps, numberInputController, openPopoverTrigger, openSelectList, placePopover, popoverController, runMachine, selectController, snapToStep, splitColor, spreadProps, switchController, textAreaController, textFieldController, toggleSelectList, transparencyChecker, viewportRect, widthField, widthFieldOptions } from './chunk-
|
|
3
|
-
export { FIELD_FOCUS_CSS, FIELD_FOCUS_RING, iconEl, iconMarkup, injectStyles, overlayScrollbarCss, registerIcon, svg16, svg24, withAlpha } from './chunk-
|
|
1
|
+
export { Drawer, KeymapManager, Tooltip, drawerController, tooltipController } from './chunk-MWS4CUJL.js';
|
|
2
|
+
export { CALLOUT_CSS, CALLOUT_STYLE_ID, CalloutBubble, ColorField, Dialog, FIELD_GAP_PX, GlyphSelect, Menu, NumberInput, Popover, Select, Switch, TextArea, TextField, WIDTH_FIELD_OPTIONS, applyPlotOverlayTokens, applyThemeTokens, blendOver, buildColorPicker, buildFieldControl, buildPalette, calloutPanelRows, clampNumber, closeColorPopover, closeOpenPopovers, closeWidthPopover, closesPanel, colorField, colorPickerController, combineColor, decorateSelectScroll, dialogController, ensureUIHost, eventDismissedPopover, fieldGrid, fieldGridColumns, fieldRow, fieldSection, fieldSeparator, fillSelectList, glyphSelectController, hslHex, insetRect, intersectRects, isPopoverOpen, lineWidthGlyph, menuController, nextUid, normalizeProps, numberInputController, openPopoverTrigger, openSelectList, placePopover, popoverController, runMachine, selectController, snapToStep, splitColor, spreadProps, switchController, textAreaController, textFieldController, toggleSelectList, transparencyChecker, viewportRect, widthField, widthFieldOptions } from './chunk-MWDNPGU3.js';
|
|
3
|
+
export { FIELD_FOCUS_CSS, FIELD_FOCUS_RING, iconEl, iconMarkup, injectStyles, overlayScrollbarCss, registerIcon, svg16, svg24, withAlpha } from './chunk-6DPAYEGO.js';
|
package/dist/vela.global.js
CHANGED
|
@@ -276,6 +276,7 @@ var Vela = (function (exports) {
|
|
|
276
276
|
var CROSSHAIR = "#9aa0ad";
|
|
277
277
|
var SLATE_DEEP = "#1e293b";
|
|
278
278
|
var SLATE = "#475569";
|
|
279
|
+
var CHIP_PLATE = "#595959";
|
|
279
280
|
var TRADE_LONG = ACCENT;
|
|
280
281
|
var TRADE_SHORT = BEARISH;
|
|
281
282
|
var TRADE_EXIT = "#d500f9";
|
|
@@ -503,6 +504,10 @@ var Vela = (function (exports) {
|
|
|
503
504
|
"market-post",
|
|
504
505
|
svg24('<path d="M12 10V2"/><path d="m4.93 10.93 1.41 1.41"/><path d="M2 18h2"/><path d="M20 18h2"/><path d="m19.07 10.93-1.41 1.41"/><path d="M22 22H2"/><path d="m16 14-4 4-4-4"/><path d="M16 6a4 4 0 0 0-8 0"/>')
|
|
505
506
|
);
|
|
507
|
+
registerIcon(
|
|
508
|
+
"market-extended",
|
|
509
|
+
svg24('<path d="M22 22H2"/><path d="M12 3a5 5 0 0 0 7.5 7.5A7.5 7.5 0 1 1 12 3Z"/>')
|
|
510
|
+
);
|
|
506
511
|
registerIcon("market-closed", svg24('<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>'));
|
|
507
512
|
registerIcon(
|
|
508
513
|
"market-holiday",
|
|
@@ -516,6 +521,8 @@ var Vela = (function (exports) {
|
|
|
516
521
|
registerIcon("chevrons-left", S('<path d="M12 3.5 7.5 8l4.5 4.5"/><path d="M7.5 3.5 3 8l4.5 4.5"/>'));
|
|
517
522
|
registerIcon("check", S('<path d="m2.8 8.4 3.4 3.4 7-7.6"/>'));
|
|
518
523
|
registerIcon("close", S('<path d="m3.8 3.8 8.4 8.4M12.2 3.8l-8.4 8.4"/>'));
|
|
524
|
+
registerIcon("pin", S('<path d="M5.6 2.5h4.8M6.4 2.5v3.6L4.4 8.4v.9h7.2v-.9L9.6 6.1V2.5M8 9.3v4.2"/>'));
|
|
525
|
+
registerIcon("pin-filled", S('<path d="M5.6 2.5h4.8M6.4 2.5v3.6L4.4 8.4v.9h7.2v-.9L9.6 6.1V2.5M8 9.3v4.2"/><path d="M6.4 2.5h3.2v3.6l2 2.3v.9H4.4v-.9l2-2.3z" fill="currentColor" stroke="none"/>'));
|
|
519
526
|
registerIcon("eye", S('<path d="M1.5 8s2.5-5.4 6.5-5.4S14.5 8 14.5 8 12 13.4 8 13.4 1.5 8 1.5 8z"/><circle cx="8" cy="8" r="1.8"/>'));
|
|
520
527
|
registerIcon("eye-off", S('<path d="M1.5 8s2.5-5.4 6.5-5.4S14.5 8 14.5 8 12 13.4 8 13.4 1.5 8 1.5 8z" opacity="0.45"/><path d="m3 13 10-10"/>'));
|
|
521
528
|
registerIcon("lock", S('<rect x="3.2" y="7" width="9.6" height="6.6" rx="1.2"/><path d="M5.6 7V5.2a2.4 2.4 0 0 1 4.8 0V7"/>'));
|
|
@@ -9272,6 +9279,15 @@ var Vela = (function (exports) {
|
|
|
9272
9279
|
console.warn(`[vela] renderer "${this.renderer.name}" does not support screenshot().`);
|
|
9273
9280
|
return null;
|
|
9274
9281
|
}
|
|
9282
|
+
/**
|
|
9283
|
+
* Raster of the current chart onto a canvas (same pixels as {@link screenshot}),
|
|
9284
|
+
* or null if the renderer has no canvas export. Silent — a host compositing
|
|
9285
|
+
* several charts skips a renderer that cannot contribute.
|
|
9286
|
+
*/
|
|
9287
|
+
screenshotCanvas() {
|
|
9288
|
+
if (typeof this.renderer.screenshotCanvas === "function") return this.renderer.screenshotCanvas();
|
|
9289
|
+
return null;
|
|
9290
|
+
}
|
|
9275
9291
|
/**
|
|
9276
9292
|
* The active renderer's full cosmetic config as a serializable, versioned JSON
|
|
9277
9293
|
* document — persist it (templates, saved settings) and feed it back to
|
|
@@ -17141,6 +17157,12 @@ ${STATIC_DECLS}
|
|
|
17141
17157
|
.vela-ui *, .vela-ui-layer * { box-sizing: border-box; }
|
|
17142
17158
|
/* Text ENTRY is the one exception: selection is part of editing. */
|
|
17143
17159
|
.vela-ui :is(input, textarea), .vela-ui-layer :is(input, textarea) { user-select: text; -webkit-user-select: text; }
|
|
17160
|
+
/* iOS Safari zooms the page when a focused field is under 16px, and often
|
|
17161
|
+
keeps that zoom after the field blurs or a dialog closes. The shell's
|
|
17162
|
+
mobile size class is the honest gate \u2014 not a media query \u2014 so an embedded
|
|
17163
|
+
chart on a wide desktop still gets the rule when it is in the phone layout.
|
|
17164
|
+
Scoped to the kit root so a host page's own [data-layout] is never touched. */
|
|
17165
|
+
.vela-ui[data-layout='mobile'] :is(input, textarea, select) { font-size: 16px; }
|
|
17144
17166
|
.vela-icon { display: inline-flex; align-items: center; flex: none; }
|
|
17145
17167
|
.vela-icon svg { display: block; }
|
|
17146
17168
|
`;
|
|
@@ -22761,6 +22783,66 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
22761
22783
|
center: (wickLeftDev + wickDev / 2) / dpr
|
|
22762
22784
|
};
|
|
22763
22785
|
}
|
|
22786
|
+
function aggregateCandleColumns(bars, i0, i1, xOf, yOf) {
|
|
22787
|
+
const out = [];
|
|
22788
|
+
let col = NaN;
|
|
22789
|
+
let intervals = [];
|
|
22790
|
+
const flush = () => {
|
|
22791
|
+
if (intervals.length === 0) return;
|
|
22792
|
+
const merged = [intervals[0]];
|
|
22793
|
+
for (let k = 1; k < intervals.length; k += 1) {
|
|
22794
|
+
const prev3 = merged[merged.length - 1];
|
|
22795
|
+
const next2 = intervals[k];
|
|
22796
|
+
if (Math.abs(yOf(prev3.hi) - yOf(next2.lo)) < 1) {
|
|
22797
|
+
prev3.hi = next2.hi;
|
|
22798
|
+
if (next2.headIdx < prev3.headIdx) {
|
|
22799
|
+
prev3.headIdx = next2.headIdx;
|
|
22800
|
+
prev3.headTime = next2.headTime;
|
|
22801
|
+
prev3.open = next2.open;
|
|
22802
|
+
}
|
|
22803
|
+
if (next2.lastIdx > prev3.lastIdx) {
|
|
22804
|
+
prev3.lastIdx = next2.lastIdx;
|
|
22805
|
+
prev3.close = next2.close;
|
|
22806
|
+
}
|
|
22807
|
+
} else {
|
|
22808
|
+
merged.push(next2);
|
|
22809
|
+
}
|
|
22810
|
+
}
|
|
22811
|
+
for (const iv of merged) out.push({ x: col, hi: iv.hi, lo: iv.lo, headTime: iv.headTime, open: iv.open, close: iv.close });
|
|
22812
|
+
intervals = [];
|
|
22813
|
+
};
|
|
22814
|
+
for (let i = i0; i <= i1; i += 1) {
|
|
22815
|
+
const b = bars[i];
|
|
22816
|
+
if (!b || b.high <= b.low) continue;
|
|
22817
|
+
const x = Math.round(xOf(i));
|
|
22818
|
+
if (x !== col) {
|
|
22819
|
+
flush();
|
|
22820
|
+
col = x;
|
|
22821
|
+
}
|
|
22822
|
+
let lo = b.low;
|
|
22823
|
+
let hi = b.high;
|
|
22824
|
+
let headIdx = i;
|
|
22825
|
+
let headTime = b.time;
|
|
22826
|
+
let open2 = b.open;
|
|
22827
|
+
for (let k = intervals.length - 1; k >= 0; k -= 1) {
|
|
22828
|
+
const iv = intervals[k];
|
|
22829
|
+
if (iv.lo > hi || iv.hi < lo) continue;
|
|
22830
|
+
if (iv.lo < lo) lo = iv.lo;
|
|
22831
|
+
if (iv.hi > hi) hi = iv.hi;
|
|
22832
|
+
if (iv.headIdx < headIdx) {
|
|
22833
|
+
headIdx = iv.headIdx;
|
|
22834
|
+
headTime = iv.headTime;
|
|
22835
|
+
open2 = iv.open;
|
|
22836
|
+
}
|
|
22837
|
+
intervals.splice(k, 1);
|
|
22838
|
+
}
|
|
22839
|
+
let insertAt = 0;
|
|
22840
|
+
while (insertAt < intervals.length && intervals[insertAt].lo < lo) insertAt += 1;
|
|
22841
|
+
intervals.splice(insertAt, 0, { lo, hi, headIdx, headTime, open: open2, lastIdx: i, close: b.close });
|
|
22842
|
+
}
|
|
22843
|
+
flush();
|
|
22844
|
+
return out;
|
|
22845
|
+
}
|
|
22764
22846
|
|
|
22765
22847
|
// src/renderers/native/core/chartConfig.ts
|
|
22766
22848
|
var CHART_CONFIG_VERSION = 1;
|
|
@@ -22771,6 +22853,7 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
22771
22853
|
var BASELINE_LEVEL_DEFAULT = 50;
|
|
22772
22854
|
var PREMARKET_SHADE = withAlpha(WARNING, 0.08);
|
|
22773
22855
|
var POSTMARKET_SHADE = withAlpha(ACCENT, 0.08);
|
|
22856
|
+
var EXTENDED_SHADE = POSTMARKET_SHADE;
|
|
22774
22857
|
function defaultChartStyle() {
|
|
22775
22858
|
return {
|
|
22776
22859
|
chartTypes: {},
|
|
@@ -22779,7 +22862,7 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
22779
22862
|
gridHorz: { visible: true, color: null },
|
|
22780
22863
|
borderColor: null,
|
|
22781
22864
|
separatorColor: null,
|
|
22782
|
-
crosshair: { color: CROSSHAIR, width: 1, style: "dashed", opacity: 0.4, labelBackground:
|
|
22865
|
+
crosshair: { color: CROSSHAIR, width: 1, style: "dashed", opacity: 0.4, labelBackground: CHIP_PLATE },
|
|
22783
22866
|
candle: {
|
|
22784
22867
|
bodyVisible: true,
|
|
22785
22868
|
borderVisible: false,
|
|
@@ -22802,7 +22885,7 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
22802
22885
|
width: 2,
|
|
22803
22886
|
baselineLevel: BASELINE_LEVEL_DEFAULT
|
|
22804
22887
|
},
|
|
22805
|
-
sessions: { premarketColor: PREMARKET_SHADE, postmarketColor: POSTMARKET_SHADE }
|
|
22888
|
+
sessions: { premarketColor: PREMARKET_SHADE, postmarketColor: POSTMARKET_SHADE, extendedColor: EXTENDED_SHADE }
|
|
22806
22889
|
};
|
|
22807
22890
|
}
|
|
22808
22891
|
var LINE_STYLES = ["solid", "dashed", "dotted"];
|
|
@@ -23031,7 +23114,8 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
23031
23114
|
},
|
|
23032
23115
|
sessions: {
|
|
23033
23116
|
premarketColor: isColor(sessions.premarketColor) ? sessions.premarketColor : base.sessions.premarketColor,
|
|
23034
|
-
postmarketColor: isColor(sessions.postmarketColor) ? sessions.postmarketColor : base.sessions.postmarketColor
|
|
23117
|
+
postmarketColor: isColor(sessions.postmarketColor) ? sessions.postmarketColor : base.sessions.postmarketColor,
|
|
23118
|
+
extendedColor: isColor(sessions.extendedColor) ? sessions.extendedColor : base.sessions.extendedColor
|
|
23035
23119
|
},
|
|
23036
23120
|
stacking: {
|
|
23037
23121
|
candles: isNum(stacking.candles) ? stacking.candles : base.stacking.candles,
|
|
@@ -24016,44 +24100,19 @@ void main() {
|
|
|
24016
24100
|
}
|
|
24017
24101
|
}
|
|
24018
24102
|
/**
|
|
24019
|
-
* Sub-pixel LOD (mirrors Canvas2dBackend.drawCandlesAggregated):
|
|
24020
|
-
*
|
|
24021
|
-
*
|
|
24103
|
+
* Sub-pixel LOD (mirrors Canvas2dBackend.drawCandlesAggregated): bars sharing a
|
|
24104
|
+
* rounded pixel column collapse into high-low sticks — one per contiguous
|
|
24105
|
+
* coverage run (see {@link aggregateCandleColumns}), so a price gap inside the
|
|
24106
|
+
* column stays a void. Draw cost stays bounded by screen width, not bar count;
|
|
24107
|
+
* stick color follows its own first-open→last-close.
|
|
24022
24108
|
*/
|
|
24023
24109
|
emitCandlesAggregated(b, bars, i0, i1, coords, pane, up, down, barColors) {
|
|
24024
|
-
|
|
24025
|
-
|
|
24026
|
-
|
|
24027
|
-
|
|
24028
|
-
|
|
24029
|
-
let headTime = 0;
|
|
24030
|
-
let active = false;
|
|
24031
|
-
const flush = () => {
|
|
24032
|
-
if (!active) return;
|
|
24033
|
-
const c = parseColor(barColors.get(headTime) ?? (closeV >= openV ? up : down));
|
|
24034
|
-
const hY = coords.priceToY(hi, pane.scale, pane.bounds);
|
|
24035
|
-
const lY = coords.priceToY(lo, pane.scale, pane.bounds);
|
|
24036
|
-
b.rect(px - 0.5, hY, 1, lY - hY, c);
|
|
24037
|
-
};
|
|
24038
|
-
for (let i = i0; i <= i1; i += 1) {
|
|
24039
|
-
const bar = bars[i];
|
|
24040
|
-
if (!bar || bar.high <= bar.low) continue;
|
|
24041
|
-
const x = Math.round(coords.logicalToX(i));
|
|
24042
|
-
if (!active || x !== px) {
|
|
24043
|
-
flush();
|
|
24044
|
-
px = x;
|
|
24045
|
-
lo = bar.low;
|
|
24046
|
-
hi = bar.high;
|
|
24047
|
-
openV = bar.open;
|
|
24048
|
-
headTime = bar.time;
|
|
24049
|
-
active = true;
|
|
24050
|
-
} else {
|
|
24051
|
-
if (bar.low < lo) lo = bar.low;
|
|
24052
|
-
if (bar.high > hi) hi = bar.high;
|
|
24053
|
-
}
|
|
24054
|
-
closeV = bar.close;
|
|
24110
|
+
const yOf = (price) => coords.priceToY(price, pane.scale, pane.bounds);
|
|
24111
|
+
for (const s of aggregateCandleColumns(bars, i0, i1, (i) => coords.logicalToX(i), yOf)) {
|
|
24112
|
+
const c = parseColor(barColors.get(s.headTime) ?? (s.close >= s.open ? up : down));
|
|
24113
|
+
const hY = yOf(s.hi);
|
|
24114
|
+
b.rect(s.x - 0.5, hY, 1, yOf(s.lo) - hY, c);
|
|
24055
24115
|
}
|
|
24056
|
-
flush();
|
|
24057
24116
|
}
|
|
24058
24117
|
emitSeries(b, spec, pane, coords, i0, i1, theme, off = 0) {
|
|
24059
24118
|
if (spec.kind === "candle" || spec.kind === "bar") {
|
|
@@ -25351,13 +25410,15 @@ void main() {
|
|
|
25351
25410
|
if (!this.orderedCache) this.orderedCache = [...this.panes.values()].sort((a, b) => a.order - b.order);
|
|
25352
25411
|
return this.orderedCache;
|
|
25353
25412
|
}
|
|
25354
|
-
/** The session zones resolved into colored bands (pre/post-market
|
|
25355
|
-
* config's session colors) — consumed by the same painting path as
|
|
25413
|
+
/** The session zones resolved into colored bands (pre/post-market or extended-hours
|
|
25414
|
+
* washes from the config's session colors) — consumed by the same painting path as
|
|
25415
|
+
* {@link highlights}. */
|
|
25356
25416
|
sessionHighlightBands() {
|
|
25357
25417
|
if (!this.sessionZones) return [];
|
|
25358
25418
|
const out = [];
|
|
25359
25419
|
for (const [from, to] of this.sessionZones.pre) out.push({ from, to, color: this.style.sessions.premarketColor });
|
|
25360
25420
|
for (const [from, to] of this.sessionZones.post) out.push({ from, to, color: this.style.sessions.postmarketColor });
|
|
25421
|
+
for (const [from, to] of this.sessionZones.extended) out.push({ from, to, color: this.style.sessions.extendedColor });
|
|
25361
25422
|
return out;
|
|
25362
25423
|
}
|
|
25363
25424
|
indicatorsForPane(paneId) {
|
|
@@ -25896,50 +25957,23 @@ void main() {
|
|
|
25896
25957
|
}
|
|
25897
25958
|
}
|
|
25898
25959
|
/**
|
|
25899
|
-
* Sub-pixel LOD:
|
|
25900
|
-
*
|
|
25901
|
-
*
|
|
25902
|
-
*
|
|
25960
|
+
* Sub-pixel LOD: bars sharing a rounded pixel column collapse into high-low
|
|
25961
|
+
* sticks (one per contiguous coverage run — see {@link aggregateCandleColumns}),
|
|
25962
|
+
* so draw cost is bounded by screen width (not bar count) when zoomed far out
|
|
25963
|
+
* and a price gap inside the column stays a void. Each stick's color follows
|
|
25964
|
+
* its first-open→last-close direction (a barcolor() on the head bar still wins).
|
|
25903
25965
|
*/
|
|
25904
25966
|
drawCandlesAggregated(ctx, bars, i0, i1, coords, pane, up, down, barColors) {
|
|
25905
|
-
|
|
25906
|
-
|
|
25907
|
-
|
|
25908
|
-
|
|
25909
|
-
|
|
25910
|
-
let headTime = 0;
|
|
25911
|
-
let active = false;
|
|
25912
|
-
const flush = () => {
|
|
25913
|
-
if (!active) return;
|
|
25914
|
-
const color = barColors.get(headTime) ?? (closeV >= openV ? up : down);
|
|
25915
|
-
const hY = coords.priceToY(hi, pane.scale, pane.bounds);
|
|
25916
|
-
const lY = coords.priceToY(lo, pane.scale, pane.bounds);
|
|
25917
|
-
ctx.strokeStyle = color;
|
|
25918
|
-
ctx.lineWidth = 1;
|
|
25967
|
+
const yOf = (price) => coords.priceToY(price, pane.scale, pane.bounds);
|
|
25968
|
+
ctx.lineWidth = 1;
|
|
25969
|
+
for (const s of aggregateCandleColumns(bars, i0, i1, (i) => coords.logicalToX(i), yOf)) {
|
|
25970
|
+
const x = s.x + 0.5;
|
|
25971
|
+
ctx.strokeStyle = barColors.get(s.headTime) ?? (s.close >= s.open ? up : down);
|
|
25919
25972
|
ctx.beginPath();
|
|
25920
|
-
ctx.moveTo(
|
|
25921
|
-
ctx.lineTo(
|
|
25973
|
+
ctx.moveTo(x, yOf(s.hi));
|
|
25974
|
+
ctx.lineTo(x, yOf(s.lo));
|
|
25922
25975
|
ctx.stroke();
|
|
25923
|
-
};
|
|
25924
|
-
for (let i = i0; i <= i1; i += 1) {
|
|
25925
|
-
const b = bars[i];
|
|
25926
|
-
if (!b || b.high <= b.low) continue;
|
|
25927
|
-
const x = Math.round(coords.logicalToX(i)) + 0.5;
|
|
25928
|
-
if (!active || x !== px) {
|
|
25929
|
-
flush();
|
|
25930
|
-
px = x;
|
|
25931
|
-
lo = b.low;
|
|
25932
|
-
hi = b.high;
|
|
25933
|
-
openV = b.open;
|
|
25934
|
-
headTime = b.time;
|
|
25935
|
-
active = true;
|
|
25936
|
-
} else {
|
|
25937
|
-
if (b.low < lo) lo = b.low;
|
|
25938
|
-
if (b.high > hi) hi = b.high;
|
|
25939
|
-
}
|
|
25940
|
-
closeV = b.close;
|
|
25941
25976
|
}
|
|
25942
|
-
flush();
|
|
25943
25977
|
}
|
|
25944
25978
|
drawSeries(ctx, spec, pane, coords, i0, i1, theme, off = 0) {
|
|
25945
25979
|
if (spec.kind === "candle" || spec.kind === "bar") {
|
|
@@ -26963,6 +26997,32 @@ void main() {
|
|
|
26963
26997
|
}
|
|
26964
26998
|
};
|
|
26965
26999
|
|
|
27000
|
+
// src/renderers/native/chrome/tz.ts
|
|
27001
|
+
function tzOffsetMs(ms, timeZone) {
|
|
27002
|
+
if (!timeZone || timeZone === "UTC") return 0;
|
|
27003
|
+
try {
|
|
27004
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
27005
|
+
timeZone,
|
|
27006
|
+
hourCycle: "h23",
|
|
27007
|
+
year: "numeric",
|
|
27008
|
+
month: "2-digit",
|
|
27009
|
+
day: "2-digit",
|
|
27010
|
+
hour: "2-digit",
|
|
27011
|
+
minute: "2-digit",
|
|
27012
|
+
second: "2-digit"
|
|
27013
|
+
});
|
|
27014
|
+
const parts3 = dtf.formatToParts(new Date(ms));
|
|
27015
|
+
const get = (t) => Number(parts3.find((p) => p.type === t)?.value);
|
|
27016
|
+
const asUTC = Date.UTC(get("year"), get("month") - 1, get("day"), get("hour") % 24, get("minute"), get("second"));
|
|
27017
|
+
return asUTC - ms;
|
|
27018
|
+
} catch {
|
|
27019
|
+
return 0;
|
|
27020
|
+
}
|
|
27021
|
+
}
|
|
27022
|
+
function zonedDate(ms, timeZone) {
|
|
27023
|
+
return new Date(ms + tzOffsetMs(ms, timeZone));
|
|
27024
|
+
}
|
|
27025
|
+
|
|
26966
27026
|
// src/renderers/native/chrome/ticks.ts
|
|
26967
27027
|
function priceTicks(min2, max2, target = 6) {
|
|
26968
27028
|
if (!(max2 > min2) || !Number.isFinite(min2) || !Number.isFinite(max2)) return [];
|
|
@@ -27110,7 +27170,14 @@ void main() {
|
|
|
27110
27170
|
YEAR
|
|
27111
27171
|
];
|
|
27112
27172
|
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
27173
|
+
var WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
27113
27174
|
var pad2 = (n) => n < 10 ? `0${n}` : String(n);
|
|
27175
|
+
function formatTimeStamp(ms, timeZone, barIntervalMs) {
|
|
27176
|
+
const d = zonedDate(ms, timeZone);
|
|
27177
|
+
const date = `${WEEKDAYS[d.getUTCDay()]} ${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]} '${pad2(d.getUTCFullYear() % 100)}`;
|
|
27178
|
+
if (barIntervalMs >= DAY) return date;
|
|
27179
|
+
return `${date} ${pad2(d.getUTCHours())}:${pad2(d.getUTCMinutes())}`;
|
|
27180
|
+
}
|
|
27114
27181
|
function pickStep(targetMs) {
|
|
27115
27182
|
for (const step of STEP_LADDER) if (step >= targetMs) return step;
|
|
27116
27183
|
return STEP_LADDER[STEP_LADDER.length - 1];
|
|
@@ -27152,32 +27219,6 @@ void main() {
|
|
|
27152
27219
|
return out;
|
|
27153
27220
|
}
|
|
27154
27221
|
|
|
27155
|
-
// src/renderers/native/chrome/tz.ts
|
|
27156
|
-
function tzOffsetMs(ms, timeZone) {
|
|
27157
|
-
if (!timeZone || timeZone === "UTC") return 0;
|
|
27158
|
-
try {
|
|
27159
|
-
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
27160
|
-
timeZone,
|
|
27161
|
-
hourCycle: "h23",
|
|
27162
|
-
year: "numeric",
|
|
27163
|
-
month: "2-digit",
|
|
27164
|
-
day: "2-digit",
|
|
27165
|
-
hour: "2-digit",
|
|
27166
|
-
minute: "2-digit",
|
|
27167
|
-
second: "2-digit"
|
|
27168
|
-
});
|
|
27169
|
-
const parts3 = dtf.formatToParts(new Date(ms));
|
|
27170
|
-
const get = (t) => Number(parts3.find((p) => p.type === t)?.value);
|
|
27171
|
-
const asUTC = Date.UTC(get("year"), get("month") - 1, get("day"), get("hour") % 24, get("minute"), get("second"));
|
|
27172
|
-
return asUTC - ms;
|
|
27173
|
-
} catch {
|
|
27174
|
-
return 0;
|
|
27175
|
-
}
|
|
27176
|
-
}
|
|
27177
|
-
function zonedDate(ms, timeZone) {
|
|
27178
|
-
return new Date(ms + tzOffsetMs(ms, timeZone));
|
|
27179
|
-
}
|
|
27180
|
-
|
|
27181
27222
|
// src/renderers/native/chrome/ChromeRenderer.ts
|
|
27182
27223
|
var ChromeRenderer = class {
|
|
27183
27224
|
constructor() {
|
|
@@ -27624,7 +27665,7 @@ void main() {
|
|
|
27624
27665
|
const price = coords.yToPrice(ch.y, pane.scale, pane.bounds);
|
|
27625
27666
|
this.chip(ctx, dataW + 1, ch.y, formatAxisValue(pane.scale, pane.bounds.height, price, percentScaleFor(scene, pane), scene.priceMintick, pane.axisFormat), chipBg, "left", false, theme.background);
|
|
27626
27667
|
}
|
|
27627
|
-
this.chip(ctx, x, dataH + 1,
|
|
27668
|
+
this.chip(ctx, x, dataH + 1, formatTimeStamp(coords.logicalToTime(logical), scene.timezone, coords.barInterval), chipBg, "center", true, theme.background);
|
|
27628
27669
|
}
|
|
27629
27670
|
destroy() {
|
|
27630
27671
|
this.canvas = null;
|
|
@@ -27672,7 +27713,7 @@ void main() {
|
|
|
27672
27713
|
this.chip(ctx, dataW + 1, ext.y, formatAxisValue(pane.scale, pane.bounds.height, ext.price, percentScaleFor(scene, pane), scene.priceMintick, pane.axisFormat), chipBg, "left", false, theme.background);
|
|
27673
27714
|
}
|
|
27674
27715
|
}
|
|
27675
|
-
this.chip(ctx, x, dataH + 1,
|
|
27716
|
+
this.chip(ctx, x, dataH + 1, formatTimeStamp(ext.time, scene.timezone, coords.barInterval), chipBg, "center", true, theme.background);
|
|
27676
27717
|
ctx.globalAlpha = 1;
|
|
27677
27718
|
}
|
|
27678
27719
|
/** A soft band + a brighter crisp center line over the hovered separator, so it reads as
|
|
@@ -27705,11 +27746,6 @@ void main() {
|
|
|
27705
27746
|
else if (style === "dotted") ctx.setLineDash([2, 3]);
|
|
27706
27747
|
else ctx.setLineDash([]);
|
|
27707
27748
|
}
|
|
27708
|
-
function formatStamp(ms, timeZone) {
|
|
27709
|
-
const d = zonedDate(ms, timeZone);
|
|
27710
|
-
const pad = (n) => n < 10 ? `0${n}` : String(n);
|
|
27711
|
-
return `${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}`;
|
|
27712
|
-
}
|
|
27713
27749
|
|
|
27714
27750
|
// src/core/timezones.ts
|
|
27715
27751
|
var TIMEZONES = [
|
|
@@ -34198,6 +34234,9 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
34198
34234
|
const end = Math.min(right, x2);
|
|
34199
34235
|
return end > x ? { x, width: end - x } : null;
|
|
34200
34236
|
}
|
|
34237
|
+
function bandEdgeSlot(logical) {
|
|
34238
|
+
return Math.ceil(logical) - 0.5;
|
|
34239
|
+
}
|
|
34201
34240
|
var BackdropRenderer = class {
|
|
34202
34241
|
constructor() {
|
|
34203
34242
|
this.canvas = null;
|
|
@@ -34228,21 +34267,22 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
34228
34267
|
this.drawGrid(ctx, scene, coords, theme, coords.width, gridAlpha);
|
|
34229
34268
|
}
|
|
34230
34269
|
/** Renderer-owned session highlight bands: full-height (all panes), behind the grid.
|
|
34231
|
-
* Session-zone washes
|
|
34270
|
+
* Session-zone washes paint first (edges snapped to bar-slot boundaries so a band
|
|
34271
|
+
* never cuts a candle in two), host highlights on top (continuous time mapping —
|
|
34272
|
+
* hosts may paint sub-bar spans). */
|
|
34232
34273
|
drawHighlights(ctx, scene, coords) {
|
|
34233
34274
|
const sessions = scene.sessionHighlightBands();
|
|
34234
34275
|
if (sessions.length > 0) {
|
|
34235
34276
|
const left = Math.max(0, coords.logicalToX(-0.5));
|
|
34236
34277
|
const right = Math.min(coords.width, coords.logicalToX(coords.barCount - 0.5));
|
|
34237
|
-
this.drawHighlightSet(ctx, sessions, coords, left, right);
|
|
34278
|
+
this.drawHighlightSet(ctx, sessions, coords, left, right, true);
|
|
34238
34279
|
}
|
|
34239
|
-
this.drawHighlightSet(ctx, scene.highlights, coords, 0, coords.width);
|
|
34280
|
+
this.drawHighlightSet(ctx, scene.highlights, coords, 0, coords.width, false);
|
|
34240
34281
|
}
|
|
34241
|
-
drawHighlightSet(ctx, bands, coords, left, right) {
|
|
34282
|
+
drawHighlightSet(ctx, bands, coords, left, right, snapToSlots) {
|
|
34283
|
+
const edgeX = (ms) => snapToSlots ? coords.logicalToX(bandEdgeSlot(coords.timeToLogical(ms))) : coords.timeToX(ms);
|
|
34242
34284
|
for (const band of bands) {
|
|
34243
|
-
const
|
|
34244
|
-
const x2 = coords.timeToX(band.to);
|
|
34245
|
-
const rect = clipHighlightRect(x1, x2, left, right);
|
|
34285
|
+
const rect = clipHighlightRect(edgeX(band.from), edgeX(band.to), left, right);
|
|
34246
34286
|
if (!rect) continue;
|
|
34247
34287
|
ctx.fillStyle = band.color;
|
|
34248
34288
|
ctx.fillRect(rect.x, 0, rect.width, coords.height);
|
|
@@ -34501,6 +34541,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
34501
34541
|
});
|
|
34502
34542
|
el.style.color = attributionMarkColor(background);
|
|
34503
34543
|
el.innerHTML = html;
|
|
34544
|
+
el.dataset.velaScreenshot = "1";
|
|
34504
34545
|
return el;
|
|
34505
34546
|
}
|
|
34506
34547
|
function createAttributionMark(doc, background) {
|
|
@@ -34519,6 +34560,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
34519
34560
|
cursor: "pointer"
|
|
34520
34561
|
});
|
|
34521
34562
|
applyAttributionMarkTheme(a, background);
|
|
34563
|
+
a.dataset.velaScreenshot = "1";
|
|
34522
34564
|
const symbol = doc.createElement("span");
|
|
34523
34565
|
symbol.className = "vela-attr-symbol";
|
|
34524
34566
|
symbol.setAttribute("aria-hidden", "true");
|
|
@@ -35523,7 +35565,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35523
35565
|
};
|
|
35524
35566
|
})(),
|
|
35525
35567
|
series: { style: this.scene.priceStyle, baseline: this.scene.baselineValue, spacing: this.coords.spacingScale },
|
|
35526
|
-
sessions: { premarketColor: s.sessions.premarketColor, postmarketColor: s.sessions.postmarketColor }
|
|
35568
|
+
sessions: { premarketColor: s.sessions.premarketColor, postmarketColor: s.sessions.postmarketColor, extendedColor: s.sessions.extendedColor }
|
|
35527
35569
|
};
|
|
35528
35570
|
}
|
|
35529
35571
|
/**
|
|
@@ -35605,7 +35647,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35605
35647
|
width: next2.baseline.width,
|
|
35606
35648
|
baselineLevel: next2.baseline.baselineLevel
|
|
35607
35649
|
};
|
|
35608
|
-
s.sessions = { premarketColor: next2.sessions.premarketColor, postmarketColor: next2.sessions.postmarketColor };
|
|
35650
|
+
s.sessions = { premarketColor: next2.sessions.premarketColor, postmarketColor: next2.sessions.postmarketColor, extendedColor: next2.sessions.extendedColor };
|
|
35609
35651
|
this.setPriceStyle(next2.series.style);
|
|
35610
35652
|
this.scene.candleOverride = candleOverrideFor(this.scene.priceStyle, s.chartTypes);
|
|
35611
35653
|
this.scene.baselineValue = next2.series.baseline;
|
|
@@ -35827,9 +35869,10 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35827
35869
|
* opts in with a `data-vela-screenshot` attribute on the mount container's
|
|
35828
35870
|
* subtree (the widget marks its status line, and its symbol watermark with
|
|
35829
35871
|
* `"under"` — drawn beneath the canvases, where it sits on screen). Only the
|
|
35830
|
-
* crosshair (L2) is intentionally excluded.
|
|
35872
|
+
* crosshair (L2) is intentionally excluded. {@link screenshot} is this canvas
|
|
35873
|
+
* as a PNG data URL.
|
|
35831
35874
|
*/
|
|
35832
|
-
|
|
35875
|
+
screenshotCanvas() {
|
|
35833
35876
|
if (!this.dataCanvas) return null;
|
|
35834
35877
|
this.computeScales();
|
|
35835
35878
|
this.paintData();
|
|
@@ -35857,7 +35900,10 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35857
35900
|
if (el.getAttribute("data-vela-screenshot") !== "under") rasterizeOverlay(ctx, el, frame);
|
|
35858
35901
|
}
|
|
35859
35902
|
}
|
|
35860
|
-
return out
|
|
35903
|
+
return out;
|
|
35904
|
+
}
|
|
35905
|
+
screenshot() {
|
|
35906
|
+
return this.screenshotCanvas()?.toDataURL("image/png") ?? null;
|
|
35861
35907
|
}
|
|
35862
35908
|
/**
|
|
35863
35909
|
* The candles-first-appear reveal — animates the **candles themselves** (no extra
|
|
@@ -37252,7 +37298,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
37252
37298
|
const pricePane = this.dataWindowPricePane();
|
|
37253
37299
|
const ohlc = this.dataWindowOHLC(bar, pricePane);
|
|
37254
37300
|
const parts3 = [];
|
|
37255
|
-
if (bar) parts3.push(
|
|
37301
|
+
if (bar) parts3.push(formatStamp(bar.time, this.scene.timezone));
|
|
37256
37302
|
if (ohlc) parts3.push(`Open ${ohlc.o}, High ${ohlc.h}, Low ${ohlc.l}, Close ${ohlc.c}`);
|
|
37257
37303
|
for (const group of this.dataWindowGroups(idx, pricePane)) {
|
|
37258
37304
|
for (const row of group.rows) parts3.push(`${row.label} ${row.value}`);
|
|
@@ -38139,7 +38185,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
38139
38185
|
time: `${p(d.getUTCHours())}:${p(d.getUTCMinutes())}`
|
|
38140
38186
|
};
|
|
38141
38187
|
}
|
|
38142
|
-
function
|
|
38188
|
+
function formatStamp(ms, timeZone) {
|
|
38143
38189
|
const { date, time } = formatStampParts(ms, timeZone);
|
|
38144
38190
|
return `${date} ${time}`;
|
|
38145
38191
|
}
|
|
@@ -38170,7 +38216,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
38170
38216
|
}
|
|
38171
38217
|
return out.sort((a, b) => a[0] - b[0]);
|
|
38172
38218
|
};
|
|
38173
|
-
return { pre: windows(v.pre), post: windows(v.post) };
|
|
38219
|
+
return { pre: windows(v.pre), post: windows(v.post), extended: windows(v.extended) };
|
|
38174
38220
|
}
|
|
38175
38221
|
function clamp012(v) {
|
|
38176
38222
|
return Math.max(0, Math.min(1, v));
|
|
@@ -40078,6 +40124,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
40078
40124
|
exports.BarStore = BarStore;
|
|
40079
40125
|
exports.BinanceProvider = BinanceProvider;
|
|
40080
40126
|
exports.CATEGORICAL = CATEGORICAL;
|
|
40127
|
+
exports.CHIP_PLATE = CHIP_PLATE;
|
|
40081
40128
|
exports.CROSSHAIR = CROSSHAIR;
|
|
40082
40129
|
exports.CachingDataFeed = CachingDataFeed;
|
|
40083
40130
|
exports.CoinbaseProvider = CoinbaseProvider;
|