@luxalgo/vela 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataProvider-DpOWZD8F.d.ts → DataProvider-oH78tYXL.d.ts} +1 -1
- package/dist/{DataProvider-COGDs9Xg.d.cts → DataProvider-wbtJ3-Sa.d.cts} +1 -1
- package/dist/{chunk-R2JMNIHY.js → chunk-2IPXYM4B.js} +258 -169
- package/dist/{chunk-NLDTVFOI.js → chunk-G7B7ZCBF.js} +129 -10
- package/dist/{chunk-T3DZIR5Y.js → chunk-HMHA733L.js} +306 -168
- package/dist/{chunk-DPAA3SRT.js → chunk-KWI3YDBW.js} +254 -9
- package/dist/{chunk-27UTYE7T.js → chunk-TO3GIK7Z.js} +49 -7
- package/dist/{chunk-HKNO24GD.js → chunk-VHGACEHO.js} +50 -1
- package/dist/{contributions-Cgm9RJYP.d.cts → contributions-BhOBRenr.d.cts} +44 -4
- package/dist/{contributions-bWgwyiVi.d.ts → contributions-HGqnNb_P.d.ts} +44 -4
- package/dist/index.cjs +497 -79
- package/dist/index.d.cts +34 -14
- package/dist/index.d.ts +34 -14
- package/dist/index.js +5 -5
- package/dist/{options-NAUHiQEC.d.ts → options-lMUwmRwh.d.cts} +66 -1
- package/dist/{options-NAUHiQEC.d.cts → options-lMUwmRwh.d.ts} +66 -1
- package/dist/{plugin-CqxWoDKS.d.ts → plugin-Cr2Pj8q8.d.ts} +4 -4
- package/dist/{plugin-CjjzZX2F.d.cts → plugin-Do5J5xuF.d.cts} +4 -4
- package/dist/plugin.cjs +18 -0
- package/dist/plugin.d.cts +5 -5
- package/dist/plugin.d.ts +5 -5
- package/dist/plugin.js +3 -3
- 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-wMNfgyZb.d.cts → side-panel-_2UK1gSm.d.cts} +45 -3
- package/dist/{side-panel-wMNfgyZb.d.ts → side-panel-_2UK1gSm.d.ts} +45 -3
- package/dist/{statusline-model-Dpfpq54A.d.cts → statusline-model-B-2xGlB_.d.cts} +3 -3
- package/dist/{statusline-model-Dih6FGWP.d.ts → statusline-model-CY1wzxHg.d.ts} +3 -3
- package/dist/ui.cjs +224 -14
- package/dist/ui.d.cts +119 -87
- package/dist/ui.d.ts +119 -87
- package/dist/ui.js +3 -3
- package/dist/vela.global.js +497 -79
- package/dist/vela.global.min.js +86 -52
- package/dist/widget.cjs +850 -167
- package/dist/widget.d.cts +24 -10
- package/dist/widget.d.ts +24 -10
- package/dist/widget.js +7 -7
- package/dist/workspace.cjs +849 -167
- package/dist/workspace.d.cts +47 -20
- package/dist/workspace.d.ts +47 -20
- package/dist/workspace.js +6 -6
- package/package.json +1 -1
- /package/dist/{chunk-JU4CWEBF.js → chunk-W5YPYZ2P.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { deserializeDrawing, chartTypes, rendererLayers, isLineLikeSeries, seriesShownOn, foldBaseModulation, registerChartType, rendererDefaults, getDrawingType, settingsRowVisible, normalizeSettingsRow, Magnifier, TextLabel, Callout, resetDrawingSettings, registerNativeIndicator, chartType, getNativeIndicator, nativeIndicatorDescriptors, nativeInstanceChannel, drawingTypes, settingsRowValueKeys, formatDuration, RegressionChannel, FixedRangeVolumeProfile, DEFAULT_DRAWING_COLOR, SegmentDrawing, ArrowMark, GlyphStamp, RadialFib, FibSpiral, DedekindTessellation, MachFigure, GannSquare, FibRatios, MeasureBox, PositionTool, AnchoredVwap, PatternDrawing, Comment, PriceNote, Signpost, Note, PriceLabel, GANN_SQUARE_ARCS, magnifierTimeframeLabel, lineSegmentIntersection, MAGNIFIER_TIMEFRAME_OPTIONS, GLYPH_OPTIONS, STAMP_SIZE_OPTIONS, LINE_STYLE_OPTIONS, DEDEKIND_CURVATURE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, TEXT_SIZE_OPTIONS, createDrawing, inputVisible, seriesInScale, tickerModifierIds, CalloutBase, DIRECTION_OPTIONS, FibRetracement, stableSeriesId } from './chunk-
|
|
2
|
-
import { themeTokens, Dialog, closeOpenPopovers, closeWidthPopover, fieldSection, buildFieldControl, fieldSeparator, fieldGrid, fieldRow, CALLOUT_STYLE_ID, CALLOUT_CSS, Popover, blendOver, splitColor, CalloutBubble, Menu, TextArea, NumberInput, buildColorPicker, isPopoverOpen, DatePicker, eventDismissedPopover, toggleSelectList, normalizeDateInput, openPopoverTrigger, fieldGridColumns, FIELD_GAP_PX, STATIC_TOKENS } from './chunk-
|
|
3
|
-
import { icon, iconAt, withAlpha, WARNING, ACCENT, NEUTRAL, INFO, BULLISH, BEARISH, announceSurface, isDarkColor, injectStyles, SERIES_LINE, CHIP_PLATE, CROSSHAIR, TRADE_EXIT, TRADE_SHORT, TRADE_LONG, iconMarkup, overlayScrollbarCss, SLATE_DEEP, VALID, INVALID, SLATE, FIELD_FOCUS_CSS, FIELD_FOCUS_RING, svg24, svg24Solid } from './chunk-
|
|
1
|
+
import { deserializeDrawing, chartTypes, rendererLayers, isLineLikeSeries, seriesShownOn, foldBaseModulation, registerChartType, rendererDefaults, getDrawingType, normalizeTimezone, settingsRowVisible, normalizeSettingsRow, Magnifier, TextLabel, Callout, resetDrawingSettings, registerNativeIndicator, chartType, getNativeIndicator, nativeIndicatorDescriptors, nativeInstanceChannel, drawingTypes, settingsRowValueKeys, TIMEZONES, tzMenuLabel, formatDuration, RegressionChannel, FixedRangeVolumeProfile, DEFAULT_DRAWING_COLOR, SegmentDrawing, ArrowMark, GlyphStamp, RadialFib, FibSpiral, DedekindTessellation, MachFigure, GannSquare, FibRatios, MeasureBox, PositionTool, AnchoredVwap, PatternDrawing, Comment, PriceNote, Signpost, Note, PriceLabel, GANN_SQUARE_ARCS, magnifierTimeframeLabel, lineSegmentIntersection, MAGNIFIER_TIMEFRAME_OPTIONS, GLYPH_OPTIONS, STAMP_SIZE_OPTIONS, LINE_STYLE_OPTIONS, DEDEKIND_CURVATURE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, TEXT_SIZE_OPTIONS, createDrawing, inputVisible, seriesInScale, tickerModifierIds, CalloutBase, DIRECTION_OPTIONS, FibRetracement, stableSeriesId } from './chunk-KWI3YDBW.js';
|
|
2
|
+
import { themeTokens, Dialog, closeOpenPopovers, closeWidthPopover, fieldSection, buildFieldControl, fieldSeparator, fieldGrid, fieldRow, CALLOUT_STYLE_ID, CALLOUT_CSS, Popover, blendOver, splitColor, CalloutBubble, Menu, TextArea, NumberInput, buildColorPicker, isPopoverOpen, DatePicker, eventDismissedPopover, toggleSelectList, normalizeDateInput, openPopoverTrigger, fieldGridColumns, FIELD_GAP_PX, STATIC_TOKENS } from './chunk-G7B7ZCBF.js';
|
|
3
|
+
import { icon, iconAt, withAlpha, WARNING, ACCENT, NEUTRAL, INFO, BULLISH, BEARISH, announceSurface, holdForExit, isDarkColor, injectStyles, SERIES_LINE, CHIP_PLATE, CROSSHAIR, TRADE_EXIT, TRADE_SHORT, TRADE_LONG, iconMarkup, overlayScrollbarCss, SLATE_DEEP, VALID, INVALID, SLATE, FIELD_FOCUS_CSS, FIELD_FOCUS_RING, svg24, svg24Solid } from './chunk-VHGACEHO.js';
|
|
4
4
|
|
|
5
5
|
// src/core/events/EventBus.ts
|
|
6
6
|
var TypedEventBus = class {
|
|
@@ -1885,100 +1885,6 @@ var SecondClock = class _SecondClock {
|
|
|
1885
1885
|
}
|
|
1886
1886
|
};
|
|
1887
1887
|
|
|
1888
|
-
// src/core/timezones.ts
|
|
1889
|
-
var TIMEZONES = [
|
|
1890
|
-
{ value: "Etc/UTC", label: "UTC" },
|
|
1891
|
-
{ value: "Etc/GMT+12", label: "International Date Line West" },
|
|
1892
|
-
{ value: "Pacific/Pago_Pago", label: "Pago Pago" },
|
|
1893
|
-
{ value: "Pacific/Honolulu", label: "Honolulu" },
|
|
1894
|
-
{ value: "Pacific/Marquesas", label: "Marquesas Islands" },
|
|
1895
|
-
{ value: "America/Anchorage", label: "Anchorage" },
|
|
1896
|
-
{ value: "America/Los_Angeles", label: "Los Angeles" },
|
|
1897
|
-
{ value: "America/Phoenix", label: "Phoenix" },
|
|
1898
|
-
{ value: "America/Denver", label: "Denver" },
|
|
1899
|
-
{ value: "America/Chicago", label: "Chicago" },
|
|
1900
|
-
{ value: "America/Mexico_City", label: "Mexico City" },
|
|
1901
|
-
{ value: "America/New_York", label: "New York" },
|
|
1902
|
-
{ value: "America/Bogota", label: "Bogot\xE1" },
|
|
1903
|
-
{ value: "America/Caracas", label: "Caracas" },
|
|
1904
|
-
{ value: "America/Santiago", label: "Santiago" },
|
|
1905
|
-
{ value: "America/St_Johns", label: "St. John's" },
|
|
1906
|
-
{ value: "America/Sao_Paulo", label: "S\xE3o Paulo" },
|
|
1907
|
-
{ value: "America/Argentina/Buenos_Aires", label: "Buenos Aires" },
|
|
1908
|
-
{ value: "America/Noronha", label: "Fernando de Noronha" },
|
|
1909
|
-
{ value: "Atlantic/Azores", label: "Azores" },
|
|
1910
|
-
{ value: "Atlantic/Reykjavik", label: "Reykjavik" },
|
|
1911
|
-
{ value: "Europe/London", label: "London" },
|
|
1912
|
-
{ value: "Europe/Paris", label: "Paris" },
|
|
1913
|
-
{ value: "Europe/Berlin", label: "Berlin" },
|
|
1914
|
-
{ value: "Europe/Athens", label: "Athens" },
|
|
1915
|
-
{ value: "Africa/Cairo", label: "Cairo" },
|
|
1916
|
-
{ value: "Africa/Johannesburg", label: "Johannesburg" },
|
|
1917
|
-
{ value: "Europe/Moscow", label: "Moscow" },
|
|
1918
|
-
{ value: "Europe/Istanbul", label: "Istanbul" },
|
|
1919
|
-
{ value: "Asia/Tehran", label: "Tehran" },
|
|
1920
|
-
{ value: "Asia/Dubai", label: "Dubai" },
|
|
1921
|
-
{ value: "Asia/Kabul", label: "Kabul" },
|
|
1922
|
-
{ value: "Asia/Karachi", label: "Karachi" },
|
|
1923
|
-
{ value: "Asia/Kolkata", label: "Mumbai" },
|
|
1924
|
-
{ value: "Asia/Kathmandu", label: "Kathmandu" },
|
|
1925
|
-
{ value: "Asia/Dhaka", label: "Dhaka" },
|
|
1926
|
-
{ value: "Asia/Yangon", label: "Yangon" },
|
|
1927
|
-
{ value: "Asia/Bangkok", label: "Bangkok" },
|
|
1928
|
-
{ value: "Asia/Shanghai", label: "Shanghai" },
|
|
1929
|
-
{ value: "Asia/Hong_Kong", label: "Hong Kong" },
|
|
1930
|
-
{ value: "Asia/Singapore", label: "Singapore" },
|
|
1931
|
-
{ value: "Australia/Eucla", label: "Eucla" },
|
|
1932
|
-
{ value: "Asia/Tokyo", label: "Tokyo" },
|
|
1933
|
-
{ value: "Asia/Seoul", label: "Seoul" },
|
|
1934
|
-
{ value: "Australia/Adelaide", label: "Adelaide" },
|
|
1935
|
-
{ value: "Australia/Sydney", label: "Sydney" },
|
|
1936
|
-
{ value: "Australia/Lord_Howe", label: "Lord Howe Island" },
|
|
1937
|
-
{ value: "Pacific/Noumea", label: "Noum\xE9a" },
|
|
1938
|
-
{ value: "Pacific/Auckland", label: "Auckland" },
|
|
1939
|
-
{ value: "Pacific/Chatham", label: "Chatham Islands" },
|
|
1940
|
-
{ value: "Pacific/Apia", label: "Apia" },
|
|
1941
|
-
{ value: "Pacific/Kiritimati", label: "Kiritimati" }
|
|
1942
|
-
];
|
|
1943
|
-
var EXCHANGE_TIMEZONE = "exchange";
|
|
1944
|
-
function isExchangeTimezone(zone) {
|
|
1945
|
-
return zone === EXCHANGE_TIMEZONE;
|
|
1946
|
-
}
|
|
1947
|
-
function resolveTimezone(zone, exchangeZone) {
|
|
1948
|
-
if (!isExchangeTimezone(zone)) return zone;
|
|
1949
|
-
return exchangeZone && exchangeZone !== "" ? exchangeZone : "Etc/UTC";
|
|
1950
|
-
}
|
|
1951
|
-
function normalizeTimezone(zone) {
|
|
1952
|
-
return zone === "UTC" || zone === "Etc/UTC" || zone === "Etc/GMT" ? "Etc/UTC" : zone;
|
|
1953
|
-
}
|
|
1954
|
-
function timezoneMenuRows(current) {
|
|
1955
|
-
const active = normalizeTimezone(current);
|
|
1956
|
-
const [utc, ...zones] = TIMEZONES.map((t) => ({ value: t.value, label: tzMenuLabel(t.value, t.label), checked: t.value === active }));
|
|
1957
|
-
return [utc, { value: EXCHANGE_TIMEZONE, label: "Exchange", checked: isExchangeTimezone(current) }, ...zones];
|
|
1958
|
-
}
|
|
1959
|
-
function tzOffset(zone, date = /* @__PURE__ */ new Date()) {
|
|
1960
|
-
try {
|
|
1961
|
-
const parts = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "shortOffset" }).formatToParts(date);
|
|
1962
|
-
const raw = parts.find((p) => p.type === "timeZoneName")?.value ?? "";
|
|
1963
|
-
const m = raw.match(/GMT(?:(\+|-)(\d{1,2})(?::(\d{2}))?)?/);
|
|
1964
|
-
if (!m || !m[1]) return "UTC";
|
|
1965
|
-
const sign = m[1] === "-" ? "-" : "+";
|
|
1966
|
-
const hrs = m[2] ?? "0";
|
|
1967
|
-
const mins = m[3] ?? "";
|
|
1968
|
-
return mins ? `UTC${sign}${hrs}:${mins}` : `UTC${sign}${hrs}`;
|
|
1969
|
-
} catch {
|
|
1970
|
-
return "UTC";
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
function tzMenuLabel(zone, location) {
|
|
1974
|
-
if (normalizeTimezone(zone) === "Etc/UTC") return location;
|
|
1975
|
-
return `(${tzOffset(zone)}) ${location}`;
|
|
1976
|
-
}
|
|
1977
|
-
function tzButtonLabel(zone) {
|
|
1978
|
-
if (normalizeTimezone(zone) === "Etc/UTC") return "UTC";
|
|
1979
|
-
return tzOffset(zone);
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
1888
|
// src/core/drawings/effectiveColor.ts
|
|
1983
1889
|
var VALID_FILL = VALID;
|
|
1984
1890
|
var INVALID_FILL = INVALID;
|
|
@@ -2602,6 +2508,7 @@ function chromeHint(text, opts) {
|
|
|
2602
2508
|
// src/renderers/native/drawings/DrawingToolbar.ts
|
|
2603
2509
|
var TOOLBAR_WIDTH = 44;
|
|
2604
2510
|
var TOOLBAR_COLLAPSED_WIDTH = 16;
|
|
2511
|
+
var FLYOUT_GAP = 3;
|
|
2605
2512
|
var DrawingToolbar = class {
|
|
2606
2513
|
constructor(host, theme, onArm, onMagnet = () => {
|
|
2607
2514
|
}, onMeasure = () => {
|
|
@@ -2631,6 +2538,9 @@ var DrawingToolbar = class {
|
|
|
2631
2538
|
// group id (or MAGNET_ID) whose flyout is open
|
|
2632
2539
|
this.flyoutCell = null;
|
|
2633
2540
|
// the cell the open flyout is anchored to
|
|
2541
|
+
/** Closed flyouts still playing their exit animation, by owner id — reopening the same
|
|
2542
|
+
* owner takes its element back instead of stacking a second one on it. */
|
|
2543
|
+
this.exitingFlyouts = /* @__PURE__ */ new Map();
|
|
2634
2544
|
this.groupCells = /* @__PURE__ */ new Map();
|
|
2635
2545
|
// the composite cell (hover/active bg + flyout anchor)
|
|
2636
2546
|
this.groupIcons = /* @__PURE__ */ new Map();
|
|
@@ -2739,6 +2649,7 @@ var DrawingToolbar = class {
|
|
|
2739
2649
|
}
|
|
2740
2650
|
destroy() {
|
|
2741
2651
|
this.closeFlyout();
|
|
2652
|
+
for (const { exit } of [...this.exitingFlyouts.values()]) exit.finish();
|
|
2742
2653
|
for (const dispose of this.tipDisposers.splice(0)) dispose();
|
|
2743
2654
|
this.root.remove();
|
|
2744
2655
|
}
|
|
@@ -2966,16 +2877,22 @@ var DrawingToolbar = class {
|
|
|
2966
2877
|
* outside-dismiss. Callers fill it with items. */
|
|
2967
2878
|
beginFlyout(ownerId, cell) {
|
|
2968
2879
|
const t = this.theme;
|
|
2969
|
-
const
|
|
2880
|
+
const back = this.exitingFlyouts.get(ownerId);
|
|
2881
|
+
if (back) {
|
|
2882
|
+
this.exitingFlyouts.delete(ownerId);
|
|
2883
|
+
back.exit.cancel();
|
|
2884
|
+
back.fly.replaceChildren();
|
|
2885
|
+
}
|
|
2886
|
+
const fly = back?.fly ?? document.createElement("div");
|
|
2970
2887
|
fly.className = "vela-dtb-flyout";
|
|
2971
|
-
fly.style.cssText = `position:absolute;z-index:23;display:flex;flex-direction:column;gap:2px;padding:4px;border-radius:
|
|
2888
|
+
fly.style.cssText = `position:absolute;z-index:23;display:flex;flex-direction:column;gap:2px;padding:4px;border-radius:var(--vela-radius-md);background:var(--vela-surface);border:1px solid ${this.borderOverride ?? "var(--vela-border-strong)"};box-shadow:var(--vela-shadow);pointer-events:auto;overflow-y:auto;overscroll-behavior:contain;`;
|
|
2972
2889
|
applyChromeTokens(fly, t);
|
|
2973
2890
|
this.host.appendChild(fly);
|
|
2974
2891
|
const r = cell.getBoundingClientRect();
|
|
2975
2892
|
const rootR = this.root.getBoundingClientRect();
|
|
2976
2893
|
const hostR = this.host.getBoundingClientRect();
|
|
2977
2894
|
const top = r.top - hostR.top;
|
|
2978
|
-
fly.style.left = `${rootR.right - hostR.left
|
|
2895
|
+
fly.style.left = `${rootR.right - hostR.left + FLYOUT_GAP}px`;
|
|
2979
2896
|
fly.style.top = `${top}px`;
|
|
2980
2897
|
fly.style.maxHeight = `${Math.max(120, hostR.height - top - 8)}px`;
|
|
2981
2898
|
this.flyout = fly;
|
|
@@ -2991,6 +2908,7 @@ var DrawingToolbar = class {
|
|
|
2991
2908
|
if (!cell) return;
|
|
2992
2909
|
const fly = this.beginFlyout(group.id, cell);
|
|
2993
2910
|
const sections = group.sections ?? [{ label: "", tools: group.tools }];
|
|
2911
|
+
const badge = sections.some((s) => s.tools.some((tool) => !!tool.icon));
|
|
2994
2912
|
for (let si = 0; si < sections.length; si++) {
|
|
2995
2913
|
const section = sections[si];
|
|
2996
2914
|
if (section.label) {
|
|
@@ -3001,6 +2919,7 @@ var DrawingToolbar = class {
|
|
|
3001
2919
|
fly.appendChild(
|
|
3002
2920
|
this.makeFlyoutItem({
|
|
3003
2921
|
icon: tool.icon,
|
|
2922
|
+
badge,
|
|
3004
2923
|
label: tool.label,
|
|
3005
2924
|
selected: tool.type === this.active,
|
|
3006
2925
|
shortcut: this.shortcuts.get(tool.type),
|
|
@@ -3051,21 +2970,24 @@ var DrawingToolbar = class {
|
|
|
3051
2970
|
div.style.cssText = `height:1px;margin:4px 8px;background:${this.borderColor};`;
|
|
3052
2971
|
return div;
|
|
3053
2972
|
}
|
|
3054
|
-
/** A flyout row, left to right: optional leading icon, label, a check when it's the
|
|
3055
|
-
* entry, an optional shortcut hint, and — at the far right — the favorite star (tool
|
|
3056
|
-
* Hover tint is CSS (`.vela-dtb-item:hover`), so navigating the menu stays smooth. */
|
|
2973
|
+
/** A flyout row, left to right: optional leading icon badge, label, a check when it's the
|
|
2974
|
+
* selected entry, an optional shortcut hint, and — at the far right — the favorite star (tool
|
|
2975
|
+
* rows). Hover tint is CSS (`.vela-dtb-item:hover`), so navigating the menu stays smooth. */
|
|
3057
2976
|
makeFlyoutItem(opts) {
|
|
3058
2977
|
const t = this.theme;
|
|
3059
2978
|
const item = document.createElement("button");
|
|
3060
2979
|
item.type = "button";
|
|
3061
2980
|
item.className = "vela-dtb-item";
|
|
3062
2981
|
item.setAttribute("aria-label", opts.label);
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
2982
|
+
const badged = opts.badge === true || !!opts.icon;
|
|
2983
|
+
const box = badged ? "gap:10px;padding:4px 10px 4px 6px;" : "gap:8px;padding:5px 10px 5px 8px;";
|
|
2984
|
+
item.style.cssText = `display:flex;align-items:center;${box}cursor:pointer;color:${t.textColor};border-radius:var(--vela-radius-sm);font:13px ${t.fontFamily};white-space:nowrap;min-width:148px;`;
|
|
2985
|
+
if (opts.selected) item.dataset.selected = "1";
|
|
2986
|
+
if (badged) {
|
|
2987
|
+
const badge = document.createElement("span");
|
|
2988
|
+
badge.className = "vela-dtb-badge";
|
|
2989
|
+
if (opts.icon) badge.innerHTML = opts.icon;
|
|
2990
|
+
item.appendChild(badge);
|
|
3069
2991
|
}
|
|
3070
2992
|
const label = document.createElement("span");
|
|
3071
2993
|
label.textContent = opts.label;
|
|
@@ -3110,7 +3032,12 @@ var DrawingToolbar = class {
|
|
|
3110
3032
|
if (fly) {
|
|
3111
3033
|
this.flyout = null;
|
|
3112
3034
|
announceSurface(fly, false, "menu", this.flyoutCell);
|
|
3113
|
-
|
|
3035
|
+
const owner = this.flyoutOwnerId ?? "";
|
|
3036
|
+
const exit = holdForExit(fly, () => {
|
|
3037
|
+
if (this.exitingFlyouts.get(owner)?.fly === fly) this.exitingFlyouts.delete(owner);
|
|
3038
|
+
fly.remove();
|
|
3039
|
+
});
|
|
3040
|
+
if (exit) this.exitingFlyouts.set(owner, { fly, exit });
|
|
3114
3041
|
this.flyoutCell?.classList.remove("vela-open");
|
|
3115
3042
|
this.flyoutCell = null;
|
|
3116
3043
|
this.flyoutOwnerId = null;
|
|
@@ -3194,6 +3121,11 @@ function ensureStyles() {
|
|
|
3194
3121
|
.vela-dtb[data-collapsed='1'] .vela-dtb-collapse .vela-dtb-hit{width:14px;}
|
|
3195
3122
|
.vela-dtb-item{background:transparent;border:none;transition:background var(--vela-dur-fast) ease;}
|
|
3196
3123
|
.vela-dtb-item:hover{background:var(--vela-hover-strong);}
|
|
3124
|
+
.vela-dtb-badge{width:24px;height:24px;padding:3px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;flex:none;border-radius:var(--vela-radius-md);background:var(--vela-hover);border:1px solid var(--vela-border);color:var(--vela-fg-muted);transition:background var(--vela-dur-fast) ease,border-color var(--vela-dur-fast) ease,color var(--vela-dur-fast) ease;}
|
|
3125
|
+
.vela-dtb-badge:empty{background:transparent;border-color:transparent;}
|
|
3126
|
+
.vela-dtb-badge svg{width:100%;height:100%;}
|
|
3127
|
+
.vela-dtb-item:hover .vela-dtb-badge:not(:empty){background:var(--vela-active);color:var(--vela-fg-bright);}
|
|
3128
|
+
.vela-dtb-item[data-selected='1'] .vela-dtb-badge:not(:empty){background:color-mix(in srgb,var(--vela-fg-bright) 83%,var(--vela-surface));border-color:color-mix(in srgb,var(--vela-fg-bright) 40%,transparent);color:var(--vela-surface);}
|
|
3197
3129
|
.vela-dtb-star{width:26px;height:22px;margin:-3px -5px -3px 0;padding:3px 5px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;flex:none;opacity:0;color:inherit;border-radius:var(--vela-radius-sm);transition:opacity .1s ease,color .1s ease,background .1s ease;}
|
|
3198
3130
|
.vela-dtb-star svg{width:16px;height:16px;}
|
|
3199
3131
|
.vela-dtb-item:hover .vela-dtb-star{opacity:.55;}
|
|
@@ -4079,7 +4011,10 @@ var LEGEND_ICON_PX2 = 16;
|
|
|
4079
4011
|
var LEGEND_CTL_PX = 18;
|
|
4080
4012
|
var LEGEND_ROW_PAD_Y = 2;
|
|
4081
4013
|
var LEGEND_ROW_PAD_X = 6;
|
|
4014
|
+
var LEGEND_LEFT_PX = 10;
|
|
4015
|
+
var LEGEND_SCALE_GAP_PX = 6;
|
|
4082
4016
|
var LEGEND_TITLE_VALUES_GAP_PX = 6;
|
|
4017
|
+
var LEGEND_VALUES_GAP_PX = 5;
|
|
4083
4018
|
var LEGEND_TITLE_STATUS_GAP_PX = 8;
|
|
4084
4019
|
var LEGEND_ACTION_GAP_PX = 6;
|
|
4085
4020
|
var LEGEND_CTL_CSS = `cursor:pointer;display:inline-flex;align-items:center;justify-content:center;border:none;line-height:0;padding:0;width:${LEGEND_CTL_PX}px;height:${LEGEND_CTL_PX}px;border-radius:3px;box-sizing:border-box;flex:none;`;
|
|
@@ -4365,14 +4300,15 @@ var InputsUI = class {
|
|
|
4365
4300
|
row.valuesEl.replaceChildren();
|
|
4366
4301
|
return;
|
|
4367
4302
|
}
|
|
4368
|
-
row.valuesEl.style.display = "
|
|
4303
|
+
row.valuesEl.style.display = "block";
|
|
4369
4304
|
row.valuesEl.replaceChildren();
|
|
4370
|
-
|
|
4305
|
+
row.plotValues.forEach((v, i) => {
|
|
4371
4306
|
const span = document.createElement("span");
|
|
4372
4307
|
span.textContent = v.value;
|
|
4373
4308
|
span.style.color = v.color;
|
|
4309
|
+
if (i > 0) span.style.marginLeft = `${LEGEND_VALUES_GAP_PX}px`;
|
|
4374
4310
|
row.valuesEl.appendChild(span);
|
|
4375
|
-
}
|
|
4311
|
+
});
|
|
4376
4312
|
}
|
|
4377
4313
|
// ── legend move/merge (menu + drag) ─────────────────────────────────────
|
|
4378
4314
|
/** Open the "Move to" menu for a row, anchored under its move button. */
|
|
@@ -4473,7 +4409,7 @@ var InputsUI = class {
|
|
|
4473
4409
|
if (!lg) {
|
|
4474
4410
|
lg = document.createElement("div");
|
|
4475
4411
|
lg.dataset.velaPane = paneId;
|
|
4476
|
-
lg.style.cssText =
|
|
4412
|
+
lg.style.cssText = `position:absolute;left:${LEGEND_LEFT_PX}px;z-index:5;display:flex;flex-direction:column;align-items:flex-start;gap:0;pointer-events:none;font:12px -apple-system,Segoe UI,sans-serif;`;
|
|
4477
4413
|
applyChromeTokens(lg, this.theme);
|
|
4478
4414
|
this.positionLegend(lg, paneId);
|
|
4479
4415
|
this.container.appendChild(lg);
|
|
@@ -4485,6 +4421,7 @@ var InputsUI = class {
|
|
|
4485
4421
|
const bounds = this.paneBoundsOf ? this.paneBoundsOf(paneId) : { top: 0, height: Infinity };
|
|
4486
4422
|
lg.toggleAttribute(LEGEND_AT_TOP_ATTR, bounds.top === 0);
|
|
4487
4423
|
lg.style.display = bounds.height < 4 || !this.titlesVisible ? "none" : "flex";
|
|
4424
|
+
lg.style.maxWidth = `calc(100% - ${(bounds.rightAxis ?? 0) + LEGEND_LEFT_PX + LEGEND_SCALE_GAP_PX}px)`;
|
|
4488
4425
|
const collapsed = this.paneCollapse.has(paneId);
|
|
4489
4426
|
const masterId = this.paneCollapse.get(paneId) ?? null;
|
|
4490
4427
|
for (const row of this.rows.values()) {
|
|
@@ -4576,7 +4513,7 @@ var InputsUI = class {
|
|
|
4576
4513
|
}
|
|
4577
4514
|
ensureDialogStyles();
|
|
4578
4515
|
const el = document.createElement("div");
|
|
4579
|
-
el.style.cssText = `pointer-events:auto;display:flex;align-items:center;background:${this.idleRowFill()};border-radius:4px;padding:${LEGEND_ROW_PAD_Y}px ${LEGEND_ROW_PAD_X}px;margin-left:-${LEGEND_ROW_PAD_X}px;min-height:${LEGEND_ROW_MIN_H}px;box-sizing:border-box;color:${this.theme.textColor};user-select:none;-webkit-user-select:none;`;
|
|
4516
|
+
el.style.cssText = `pointer-events:auto;display:flex;align-items:center;background:${this.idleRowFill()};border-radius:4px;padding:${LEGEND_ROW_PAD_Y}px ${LEGEND_ROW_PAD_X}px;margin-left:-${LEGEND_ROW_PAD_X}px;max-width:calc(100% + ${LEGEND_ROW_PAD_X}px);min-height:${LEGEND_ROW_MIN_H}px;box-sizing:border-box;color:${this.theme.textColor};user-select:none;-webkit-user-select:none;`;
|
|
4580
4517
|
el.addEventListener("mouseleave", () => {
|
|
4581
4518
|
if (this.selectedId !== id) this.setRowHighlighted(id, false);
|
|
4582
4519
|
});
|
|
@@ -4604,7 +4541,7 @@ var InputsUI = class {
|
|
|
4604
4541
|
const statusEl = document.createElement("span");
|
|
4605
4542
|
statusEl.style.cssText = "display:none;box-sizing:border-box;flex:none;";
|
|
4606
4543
|
const titleWrap = document.createElement("span");
|
|
4607
|
-
titleWrap.style.cssText = "white-space:nowrap;";
|
|
4544
|
+
titleWrap.style.cssText = "white-space:nowrap;min-width:0;overflow:hidden;text-overflow:ellipsis;";
|
|
4608
4545
|
titleWrap.addEventListener("mouseenter", () => this.setRowHighlighted(id, true));
|
|
4609
4546
|
const titleEl = document.createElement("span");
|
|
4610
4547
|
titleEl.textContent = title;
|
|
@@ -4622,7 +4559,7 @@ var InputsUI = class {
|
|
|
4622
4559
|
el.appendChild(calloutsEl);
|
|
4623
4560
|
el.appendChild(statusEl);
|
|
4624
4561
|
const valuesEl = document.createElement("span");
|
|
4625
|
-
valuesEl.style.cssText = `display:none;
|
|
4562
|
+
valuesEl.style.cssText = `display:none;flex:1 1 0%;min-width:0;overflow:hidden;text-overflow:ellipsis;margin-left:${LEGEND_TITLE_VALUES_GAP_PX}px;white-space:nowrap;font-variant-numeric:tabular-nums;`;
|
|
4626
4563
|
el.appendChild(valuesEl);
|
|
4627
4564
|
const controlsEl = document.createElement("span");
|
|
4628
4565
|
controlsEl.style.cssText = `display:none;align-items:center;gap:${LEGEND_ACTION_GAP_PX}px;flex:none;margin-left:${LEGEND_ACTION_GAP_PX}px;`;
|
|
@@ -7217,6 +7154,11 @@ var InputController = class {
|
|
|
7217
7154
|
/** When true (the default), the separators between stacked panes are draggable to
|
|
7218
7155
|
* resize the panes above/below. When false, a press there is a normal data-area pan. */
|
|
7219
7156
|
this.paneResize = true;
|
|
7157
|
+
/** When true (the default), the user drawings take part in pointer input: they claim a
|
|
7158
|
+
* press over a drawing or with a tool armed, and see hover moves. When false, every press
|
|
7159
|
+
* is a plain pan/click and hover leaves them alone; a drawing gesture already under way
|
|
7160
|
+
* still finishes. */
|
|
7161
|
+
this.drawings = true;
|
|
7220
7162
|
this.el = null;
|
|
7221
7163
|
this.dragging = false;
|
|
7222
7164
|
this.moved = false;
|
|
@@ -7280,18 +7222,18 @@ var InputController = class {
|
|
|
7280
7222
|
this.onModifier = (e) => {
|
|
7281
7223
|
if (e.repeat || e.key !== "Shift" && e.key !== "Control" && e.key !== "Meta") return;
|
|
7282
7224
|
if (Number.isNaN(this.cursorX)) return;
|
|
7283
|
-
if (this.dragging
|
|
7225
|
+
if (this.dragging ? this.region !== "drawing" : !this.drawings) return;
|
|
7284
7226
|
this.deps.drawingsPointerMove?.(this.cursorX, this.cursorY, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
|
|
7285
7227
|
};
|
|
7286
7228
|
this.onDown = (e) => {
|
|
7287
7229
|
if (e.button === 1) {
|
|
7288
7230
|
const { x: x2, y: y2 } = this.local(e);
|
|
7289
|
-
this.middleDeleted = this.deps.drawingsDeleteAt?.(x2, y2) ?? false;
|
|
7231
|
+
this.middleDeleted = this.drawings && (this.deps.drawingsDeleteAt?.(x2, y2) ?? false);
|
|
7290
7232
|
if (this.middleDeleted) e.preventDefault();
|
|
7291
7233
|
return;
|
|
7292
7234
|
}
|
|
7293
7235
|
if (e.button === 2) {
|
|
7294
|
-
this.rightCancelled = this.deps.drawingsCancelPlacement?.() ?? false;
|
|
7236
|
+
this.rightCancelled = this.drawings && (this.deps.drawingsCancelPlacement?.() ?? false);
|
|
7295
7237
|
if (this.rightCancelled) e.preventDefault();
|
|
7296
7238
|
return;
|
|
7297
7239
|
}
|
|
@@ -7313,20 +7255,20 @@ var InputController = class {
|
|
|
7313
7255
|
this.startY = y;
|
|
7314
7256
|
this.prevPressDrawing = this.lastPressDrawing;
|
|
7315
7257
|
this.lastPressDrawing = false;
|
|
7316
|
-
if (this.deps.drawingsClaim?.(x, y)) {
|
|
7258
|
+
if (this.drawings && this.deps.drawingsClaim?.(x, y)) {
|
|
7317
7259
|
this.region = "drawing";
|
|
7318
7260
|
this.lastPressDrawing = true;
|
|
7319
7261
|
this.deps.drawingsPointerDown?.(x, y, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
|
|
7320
7262
|
this.capture(e.pointerId);
|
|
7321
7263
|
return;
|
|
7322
7264
|
}
|
|
7323
|
-
if (e.shiftKey && this.regionAt(x, y) === "data" && this.deps.drawingsMeasureStart?.(x, y, this.snapMode(e))) {
|
|
7265
|
+
if (this.drawings && e.shiftKey && this.regionAt(x, y) === "data" && this.deps.drawingsMeasureStart?.(x, y, this.snapMode(e))) {
|
|
7324
7266
|
this.region = "drawing";
|
|
7325
7267
|
this.lastPressDrawing = true;
|
|
7326
7268
|
this.capture(e.pointerId);
|
|
7327
7269
|
return;
|
|
7328
7270
|
}
|
|
7329
|
-
if ((e.ctrlKey || e.metaKey) && this.regionAt(x, y) === "data" && this.deps.drawingsMarqueeStart?.(x, y)) {
|
|
7271
|
+
if (this.drawings && (e.ctrlKey || e.metaKey) && this.regionAt(x, y) === "data" && this.deps.drawingsMarqueeStart?.(x, y)) {
|
|
7330
7272
|
this.region = "drawing";
|
|
7331
7273
|
this.lastPressDrawing = true;
|
|
7332
7274
|
this.capture(e.pointerId);
|
|
@@ -7403,7 +7345,7 @@ var InputController = class {
|
|
|
7403
7345
|
const drawCursor = this.deps.drawingsCursor?.(x, y);
|
|
7404
7346
|
const r = this.regionAt(x, y);
|
|
7405
7347
|
this.el.style.cursor = drawCursor ?? (r === "price" ? "ns-resize" : r === "time" ? "ew-resize" : r === "separator" ? "row-resize" : "");
|
|
7406
|
-
this.deps.drawingsPointerMove?.(x, y, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
|
|
7348
|
+
if (this.drawings) this.deps.drawingsPointerMove?.(x, y, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
|
|
7407
7349
|
}
|
|
7408
7350
|
if (e.pointerType !== "touch") this.deps.onPointerMove(x, y);
|
|
7409
7351
|
};
|
|
@@ -7645,7 +7587,7 @@ var InputController = class {
|
|
|
7645
7587
|
}
|
|
7646
7588
|
/** Shared double-click / double-tap routing, by the region under the point. */
|
|
7647
7589
|
doubleActivate(x, y) {
|
|
7648
|
-
if (this.deps.drawingsDblClick?.(x, y)) return;
|
|
7590
|
+
if (this.drawings && this.deps.drawingsDblClick?.(x, y)) return;
|
|
7649
7591
|
const region = this.regionAt(x, y);
|
|
7650
7592
|
if (region === "price") this.deps.resetPriceScale(x, y);
|
|
7651
7593
|
else if (region === "separator") this.deps.resetPaneSize(y);
|
|
@@ -9695,10 +9637,13 @@ function priceTicks(min, max, target = 6) {
|
|
|
9695
9637
|
const norm = raw / mag;
|
|
9696
9638
|
const step = (norm < 1.5 ? 1 : norm < 3 ? 2 : norm < 7 ? 5 : 10) * mag;
|
|
9697
9639
|
const decimals = Math.max(0, -Math.floor(Math.log10(step)) + 1);
|
|
9698
|
-
const out = [];
|
|
9699
9640
|
const start = Math.ceil(min / step) * step;
|
|
9700
|
-
|
|
9701
|
-
|
|
9641
|
+
if (!(step > 0) || start + step === start) return [];
|
|
9642
|
+
const count = Math.floor((max - start) / step + 1e-6) + 1;
|
|
9643
|
+
if (!(count > 0) || count > 1e3) return [];
|
|
9644
|
+
const out = [];
|
|
9645
|
+
for (let i = 0; i < count; i += 1) {
|
|
9646
|
+
out.push(Number((start + i * step).toFixed(decimals)));
|
|
9702
9647
|
}
|
|
9703
9648
|
return out;
|
|
9704
9649
|
}
|
|
@@ -9896,6 +9841,100 @@ function calendarTicks(zFrom, zTo, months, offsetMs) {
|
|
|
9896
9841
|
return out;
|
|
9897
9842
|
}
|
|
9898
9843
|
|
|
9844
|
+
// src/renderers/native/chrome/priceAxisTicks.ts
|
|
9845
|
+
var PriceAxisTickSource = class {
|
|
9846
|
+
constructor() {
|
|
9847
|
+
this.fn = null;
|
|
9848
|
+
this.memo = /* @__PURE__ */ new WeakMap();
|
|
9849
|
+
this.warned = false;
|
|
9850
|
+
}
|
|
9851
|
+
/** The host function, or null for the built-in ticks. */
|
|
9852
|
+
get hook() {
|
|
9853
|
+
return this.fn;
|
|
9854
|
+
}
|
|
9855
|
+
/** Set (or clear) the host function. Drops every memoized result, so setting the same
|
|
9856
|
+
* function again recomputes — how a host refreshes ticks that depend on its own state. */
|
|
9857
|
+
setHook(fn) {
|
|
9858
|
+
this.fn = fn;
|
|
9859
|
+
this.memo = /* @__PURE__ */ new WeakMap();
|
|
9860
|
+
}
|
|
9861
|
+
/** The pane's master-scale ticks for this frame. An unscaled pane (`axisFormat: 'none'`)
|
|
9862
|
+
* gets none, and the host is never asked for it. */
|
|
9863
|
+
ticksFor(scene, pane, coords) {
|
|
9864
|
+
const format = pane.axisFormat;
|
|
9865
|
+
if (format === "none") return [];
|
|
9866
|
+
const pct = percentScaleFor(scene, pane);
|
|
9867
|
+
const height = pane.bounds.height;
|
|
9868
|
+
const fn = this.fn;
|
|
9869
|
+
if (!fn || !(height > 0)) return paneAxisTicks(pane.scale, height, pct, scene.priceMintick, format);
|
|
9870
|
+
const s = pane.scale;
|
|
9871
|
+
const m = this.memo.get(pane);
|
|
9872
|
+
const fontSize = scene.style.fontSize;
|
|
9873
|
+
if (m && m.kind === pane.kind && m.min === s.min && m.max === s.max && m.log === !!s.log && m.invert === !!s.invert && m.height === height && m.baseline === pct?.baseline && m.indexed === !!pct?.indexed && m.mintick === scene.priceMintick && m.format === format && m.fontSize === fontSize) {
|
|
9874
|
+
return m.ticks;
|
|
9875
|
+
}
|
|
9876
|
+
const defaults = paneAxisTicks(s, height, pct, scene.priceMintick, format);
|
|
9877
|
+
const ticks = this.callHook(fn, scene, pane, coords, defaults, pct?.baseline, pct ? pct.indexed ? "indexed" : "percent" : "price");
|
|
9878
|
+
this.memo.set(pane, {
|
|
9879
|
+
kind: pane.kind,
|
|
9880
|
+
min: s.min,
|
|
9881
|
+
max: s.max,
|
|
9882
|
+
log: !!s.log,
|
|
9883
|
+
invert: !!s.invert,
|
|
9884
|
+
height,
|
|
9885
|
+
baseline: pct?.baseline,
|
|
9886
|
+
indexed: !!pct?.indexed,
|
|
9887
|
+
mintick: scene.priceMintick,
|
|
9888
|
+
format,
|
|
9889
|
+
fontSize,
|
|
9890
|
+
ticks
|
|
9891
|
+
});
|
|
9892
|
+
return ticks;
|
|
9893
|
+
}
|
|
9894
|
+
callHook(fn, scene, pane, coords, defaults, baseline, mode) {
|
|
9895
|
+
const scale = { min: pane.scale.min, max: pane.scale.max, log: !!pane.scale.log, invert: !!pane.scale.invert };
|
|
9896
|
+
const bounds = { top: 0, height: pane.bounds.height };
|
|
9897
|
+
const ctx = {
|
|
9898
|
+
pane: { id: pane.id, kind: pane.kind },
|
|
9899
|
+
min: Math.min(scale.min, scale.max),
|
|
9900
|
+
max: Math.max(scale.min, scale.max),
|
|
9901
|
+
log: !!scale.log,
|
|
9902
|
+
height: bounds.height,
|
|
9903
|
+
mode,
|
|
9904
|
+
baseline,
|
|
9905
|
+
mintick: scene.priceMintick,
|
|
9906
|
+
fontSize: scene.style.fontSize,
|
|
9907
|
+
priceToY: (price) => coords.priceToY(price, scale, bounds),
|
|
9908
|
+
defaults
|
|
9909
|
+
};
|
|
9910
|
+
let out;
|
|
9911
|
+
try {
|
|
9912
|
+
out = fn(ctx);
|
|
9913
|
+
} catch (err) {
|
|
9914
|
+
this.warnOnce("threw", err);
|
|
9915
|
+
return defaults;
|
|
9916
|
+
}
|
|
9917
|
+
if (out == null) return defaults;
|
|
9918
|
+
if (!Array.isArray(out)) {
|
|
9919
|
+
this.warnOnce("returned a non-array", out);
|
|
9920
|
+
return defaults;
|
|
9921
|
+
}
|
|
9922
|
+
const ticks = [];
|
|
9923
|
+
for (const t of out) {
|
|
9924
|
+
if (!t || typeof t !== "object") continue;
|
|
9925
|
+
const { price, label, major } = t;
|
|
9926
|
+
if (typeof price !== "number" || !Number.isFinite(price) || typeof label !== "string") continue;
|
|
9927
|
+
ticks.push(typeof major === "boolean" ? { price, label, major } : { price, label });
|
|
9928
|
+
}
|
|
9929
|
+
return ticks;
|
|
9930
|
+
}
|
|
9931
|
+
warnOnce(what, detail) {
|
|
9932
|
+
if (this.warned) return;
|
|
9933
|
+
this.warned = true;
|
|
9934
|
+
console.warn(`[vela] the priceAxisTicks function ${what} \u2014 the default ticks are used instead.`, detail);
|
|
9935
|
+
}
|
|
9936
|
+
};
|
|
9937
|
+
|
|
9899
9938
|
// src/renderers/native/chrome/countdown.ts
|
|
9900
9939
|
function countdownText(barOpen, barMs, now2) {
|
|
9901
9940
|
if (!(barMs > 0)) return null;
|
|
@@ -10248,8 +10287,11 @@ function standaloneSvg(markup, ink, px) {
|
|
|
10248
10287
|
}
|
|
10249
10288
|
|
|
10250
10289
|
// src/renderers/native/chrome/ChromeRenderer.ts
|
|
10290
|
+
var MINOR_LABEL_ALPHA = 0.5;
|
|
10251
10291
|
var ChromeRenderer = class {
|
|
10252
|
-
|
|
10292
|
+
/** `axisTicks` is shared with the backdrop layer, so price labels and gridlines agree. */
|
|
10293
|
+
constructor(axisTicks = new PriceAxisTickSource()) {
|
|
10294
|
+
this.axisTicks = axisTicks;
|
|
10253
10295
|
this.canvas = null;
|
|
10254
10296
|
this.ctx = null;
|
|
10255
10297
|
// The color for axis tick labels — the host-passed surface text, set each frame in render().
|
|
@@ -10354,7 +10396,8 @@ var ChromeRenderer = class {
|
|
|
10354
10396
|
this.drawTimeAxis(ctx, scene, coords, theme, dataW, dataH, fullH);
|
|
10355
10397
|
this.drawMarkLane(ctx, scene, coords, theme, dataW, dataH);
|
|
10356
10398
|
}
|
|
10357
|
-
/** The timeline-mark lane — after the axis, so the tokens read over the plot's bottom edge
|
|
10399
|
+
/** The timeline-mark lane — after the axis, so the tokens read over the plot's bottom edge,
|
|
10400
|
+
* but clipped to the data area so a glyph on the edge bar never paints over the price scale. */
|
|
10358
10401
|
drawMarkLane(ctx, scene, coords, theme, dataW, dataH) {
|
|
10359
10402
|
if (!scene.marks.visible || scene.timelineMarks.length === 0) {
|
|
10360
10403
|
this.markLayout = { glyphs: [], stacks: /* @__PURE__ */ new Map() };
|
|
@@ -10372,6 +10415,10 @@ var ChromeRenderer = class {
|
|
|
10372
10415
|
expanded: scene.marksExpandedStack
|
|
10373
10416
|
});
|
|
10374
10417
|
const nowMs = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
10418
|
+
ctx.save();
|
|
10419
|
+
ctx.beginPath();
|
|
10420
|
+
ctx.rect(0, 0, dataW, dataH);
|
|
10421
|
+
ctx.clip();
|
|
10375
10422
|
paintMarkLane(ctx, this.markLayout, {
|
|
10376
10423
|
axisY: dataH,
|
|
10377
10424
|
background: theme.background,
|
|
@@ -10385,6 +10432,7 @@ var ChromeRenderer = class {
|
|
|
10385
10432
|
flashKey: scene.marksFlash && scene.marksFlash.until > nowMs ? scene.marksFlash.key : null,
|
|
10386
10433
|
nowMs
|
|
10387
10434
|
});
|
|
10435
|
+
ctx.restore();
|
|
10388
10436
|
}
|
|
10389
10437
|
barTimes(scene) {
|
|
10390
10438
|
if (this.barTimesSrc !== scene.bars || this.barTimesCache.length !== scene.bars.length) {
|
|
@@ -10441,13 +10489,19 @@ var ChromeRenderer = class {
|
|
|
10441
10489
|
if (!scene.showAxisLabels) return;
|
|
10442
10490
|
ctx.fillStyle = this.axisTextColor;
|
|
10443
10491
|
ctx.textAlign = "left";
|
|
10492
|
+
const font = `${scene.style.fontSize}px ${theme.fontFamily}`;
|
|
10493
|
+
const majorFont = `600 ${font}`;
|
|
10494
|
+
const alpha = ctx.globalAlpha;
|
|
10444
10495
|
for (const pane of panes) {
|
|
10445
10496
|
if (pane.collapsed) continue;
|
|
10446
|
-
const
|
|
10447
|
-
for (const t of paneAxisTicks(pane.scale, pane.bounds.height, pct, scene.priceMintick, pane.axisFormat)) {
|
|
10497
|
+
for (const t of this.axisTicks.ticksFor(scene, pane, coords)) {
|
|
10448
10498
|
const y = coords.priceToY(t.price, pane.scale, pane.bounds);
|
|
10449
10499
|
if (y < pane.bounds.top + 6 || y > pane.bounds.top + pane.bounds.height - 4) continue;
|
|
10500
|
+
if (t.major === true) ctx.font = majorFont;
|
|
10501
|
+
else if (t.major === false) ctx.globalAlpha = alpha * MINOR_LABEL_ALPHA;
|
|
10450
10502
|
ctx.fillText(t.label, dataW + 6, y);
|
|
10503
|
+
if (t.major === true) ctx.font = font;
|
|
10504
|
+
else if (t.major === false) ctx.globalAlpha = alpha;
|
|
10451
10505
|
}
|
|
10452
10506
|
if (pane.axisBands) {
|
|
10453
10507
|
for (const b of pane.axisBands) {
|
|
@@ -10689,15 +10743,23 @@ var CrosshairRenderer = class {
|
|
|
10689
10743
|
constructor() {
|
|
10690
10744
|
this.canvas = null;
|
|
10691
10745
|
this.ctx = null;
|
|
10746
|
+
this.shade = null;
|
|
10692
10747
|
}
|
|
10693
10748
|
mount(canvas) {
|
|
10694
10749
|
this.canvas = canvas;
|
|
10695
10750
|
this.ctx = canvas.getContext("2d");
|
|
10696
10751
|
}
|
|
10752
|
+
/** The plot area the last frame veiled for `crosshairOverride.shadeRight` — from the
|
|
10753
|
+
* picked bar's right edge to the price scale, full plot height (the union when both the
|
|
10754
|
+
* local and a synced crosshair veil) — or null when no veil was painted. */
|
|
10755
|
+
get shadeRightArea() {
|
|
10756
|
+
return this.shade;
|
|
10757
|
+
}
|
|
10697
10758
|
/** Clear the cursor canvas and (re)draw the crosshair lines + axis chips. The optional
|
|
10698
10759
|
* `separatorHoverY` highlights the draggable pane separator under the cursor;
|
|
10699
10760
|
* `external` is a SYNCED ghost crosshair (another chart's pointer, pixel-resolved). */
|
|
10700
10761
|
render(scene, coords, theme, separatorHoverY = null, external = null) {
|
|
10762
|
+
this.shade = null;
|
|
10701
10763
|
const ctx = this.ctx;
|
|
10702
10764
|
const canvas = this.canvas;
|
|
10703
10765
|
if (!ctx || !canvas) return;
|
|
@@ -10720,12 +10782,7 @@ var CrosshairRenderer = class {
|
|
|
10720
10782
|
const x = crisp(coords.logicalToX(logical), ov?.width ?? cs.width);
|
|
10721
10783
|
if (vertical && ov?.shadeRight) {
|
|
10722
10784
|
const from = Math.max(0, Math.round(coords.logicalToX(logical + 0.5)));
|
|
10723
|
-
if (from < dataW)
|
|
10724
|
-
ctx.fillStyle = ov.shadeRight.color;
|
|
10725
|
-
ctx.globalAlpha = ov.shadeRight.opacity ?? 1;
|
|
10726
|
-
ctx.fillRect(from, 0, dataW - from, dataH);
|
|
10727
|
-
ctx.globalAlpha = 1;
|
|
10728
|
-
}
|
|
10785
|
+
if (from < dataW) this.paintShade(ctx, ov.shadeRight, from, dataW, dataH);
|
|
10729
10786
|
}
|
|
10730
10787
|
ctx.strokeStyle = ov?.color ?? cs.color ?? theme.textColor;
|
|
10731
10788
|
ctx.lineWidth = ov?.width ?? cs.width;
|
|
@@ -10761,6 +10818,7 @@ var CrosshairRenderer = class {
|
|
|
10761
10818
|
destroy() {
|
|
10762
10819
|
this.canvas = null;
|
|
10763
10820
|
this.ctx = null;
|
|
10821
|
+
this.shade = null;
|
|
10764
10822
|
}
|
|
10765
10823
|
/** The synced ghost: a dimmed vertical line at the bar the renderer resolved as
|
|
10766
10824
|
* CONTAINING the foreign time (+ horizontal line when a comparable price came
|
|
@@ -10780,12 +10838,7 @@ var CrosshairRenderer = class {
|
|
|
10780
10838
|
if (ov?.vertical === false) return;
|
|
10781
10839
|
if (ov?.shadeRight) {
|
|
10782
10840
|
const from = Math.max(0, Math.round(coords.logicalToX(Math.round(coords.xToLogical(ext.x)) + 0.5)));
|
|
10783
|
-
if (from < dataW)
|
|
10784
|
-
ctx.fillStyle = ov.shadeRight.color;
|
|
10785
|
-
ctx.globalAlpha = ov.shadeRight.opacity ?? 1;
|
|
10786
|
-
ctx.fillRect(from, 0, dataW - from, dataH);
|
|
10787
|
-
ctx.globalAlpha = 1;
|
|
10788
|
-
}
|
|
10841
|
+
if (from < dataW) this.paintShade(ctx, ov.shadeRight, from, dataW, dataH);
|
|
10789
10842
|
}
|
|
10790
10843
|
if (ext.line === false || x < 0 || x > dataW) return;
|
|
10791
10844
|
ctx.font = `${scene.style.fontSize}px ${theme.fontFamily}`;
|
|
@@ -10821,6 +10874,15 @@ var CrosshairRenderer = class {
|
|
|
10821
10874
|
this.chip(ctx, x, dataH + 1, formatTimeStamp(ext.time, scene.timezone, coords.barInterval), chipBg, "center", true, theme.background);
|
|
10822
10875
|
ctx.globalAlpha = 1;
|
|
10823
10876
|
}
|
|
10877
|
+
/** Paint the `shadeRight` veil from `from` to the price scale and record the veiled area. */
|
|
10878
|
+
paintShade(ctx, shade, from, dataW, dataH) {
|
|
10879
|
+
ctx.fillStyle = shade.color;
|
|
10880
|
+
ctx.globalAlpha = shade.opacity ?? 1;
|
|
10881
|
+
ctx.fillRect(from, 0, dataW - from, dataH);
|
|
10882
|
+
ctx.globalAlpha = 1;
|
|
10883
|
+
const x = this.shade ? Math.min(this.shade.x, from) : from;
|
|
10884
|
+
this.shade = { x, width: dataW - x, height: dataH };
|
|
10885
|
+
}
|
|
10824
10886
|
/** A soft band + a brighter crisp center line over the hovered separator, so it reads as
|
|
10825
10887
|
* a draggable handle (the cursor is already `row-resize`). Spans the full width (data +
|
|
10826
10888
|
* scale gutter) to match the separator itself. Theme-derived (textColor). */
|
|
@@ -14238,15 +14300,16 @@ var DrawingSettingsDialog = class {
|
|
|
14238
14300
|
}
|
|
14239
14301
|
open(drawing, actions, kind) {
|
|
14240
14302
|
this.close();
|
|
14241
|
-
const
|
|
14303
|
+
const live = actions.resolve() ?? drawing;
|
|
14304
|
+
const snapshot = clonePlain(live.serialize());
|
|
14242
14305
|
const grid = fieldGrid({ variant: "inputs" });
|
|
14243
14306
|
grid.style.padding = "16px 20px";
|
|
14244
14307
|
grid.style.overflowY = "auto";
|
|
14245
14308
|
grid.style.overflowX = "hidden";
|
|
14246
14309
|
grid.style.flex = "1 1 auto";
|
|
14247
|
-
if (kind === "position" &&
|
|
14248
|
-
else if (kind === "frvp" &&
|
|
14249
|
-
else if (kind === "levels") this.buildLevels(grid,
|
|
14310
|
+
if (kind === "position" && live instanceof PositionTool) this.buildPosition(grid, live, actions);
|
|
14311
|
+
else if (kind === "frvp" && live instanceof FixedRangeVolumeProfile) this.buildFrvp(grid, live, actions);
|
|
14312
|
+
else if (kind === "levels") this.buildLevels(grid, live, actions);
|
|
14250
14313
|
else return;
|
|
14251
14314
|
const ui = new Dialog({
|
|
14252
14315
|
host: this.host,
|
|
@@ -14893,7 +14956,7 @@ var DrawingSettingsPopup = class {
|
|
|
14893
14956
|
this.reposition();
|
|
14894
14957
|
return;
|
|
14895
14958
|
}
|
|
14896
|
-
const text = drawing.text;
|
|
14959
|
+
const text = (actions.resolve() ?? drawing).text;
|
|
14897
14960
|
const panel = document.createElement("div");
|
|
14898
14961
|
panel.style.cssText = `padding:6px;border-top:1px solid var(--vela-border);display:flex;flex-direction:column;gap:4px;`;
|
|
14899
14962
|
const ta = new TextArea({
|
|
@@ -16064,6 +16127,12 @@ var UserDrawingController = class {
|
|
|
16064
16127
|
this.render();
|
|
16065
16128
|
}
|
|
16066
16129
|
}
|
|
16130
|
+
/** Drop the hover (its handles) — the pointer no longer reaches the drawings. */
|
|
16131
|
+
clearHover() {
|
|
16132
|
+
if (this.hoveredId == null) return;
|
|
16133
|
+
this.hoveredId = null;
|
|
16134
|
+
this.render();
|
|
16135
|
+
}
|
|
16067
16136
|
pointerUp(x, y, snap = "off") {
|
|
16068
16137
|
if (this.eraserMode) {
|
|
16069
16138
|
this.erasing = false;
|
|
@@ -17054,9 +17123,10 @@ function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log =
|
|
|
17054
17123
|
consider(drawings.max);
|
|
17055
17124
|
}
|
|
17056
17125
|
if (min === Infinity || max === -Infinity) return { min: 0, max: 1 };
|
|
17057
|
-
if (min
|
|
17058
|
-
const
|
|
17059
|
-
|
|
17126
|
+
if (max - min <= Math.max(Math.abs(min), Math.abs(max)) * 1e-12) {
|
|
17127
|
+
const mid = (min + max) / 2;
|
|
17128
|
+
const pad = Math.abs(mid) * 0.1 || 1;
|
|
17129
|
+
return { min: mid - pad, max: mid + pad, log: log && mid - pad > 0 };
|
|
17060
17130
|
}
|
|
17061
17131
|
const content = Math.max(0.1, 1 - (margins.top + margins.bottom) / 100);
|
|
17062
17132
|
const above = margins.top / 100 / content;
|
|
@@ -17560,7 +17630,9 @@ function bandEdgeSlot(logical) {
|
|
|
17560
17630
|
return Math.ceil(logical) - 0.5;
|
|
17561
17631
|
}
|
|
17562
17632
|
var BackdropRenderer = class {
|
|
17563
|
-
|
|
17633
|
+
/** `axisTicks` is shared with the chrome layer, so gridlines and price labels agree. */
|
|
17634
|
+
constructor(axisTicks = new PriceAxisTickSource()) {
|
|
17635
|
+
this.axisTicks = axisTicks;
|
|
17564
17636
|
this.canvas = null;
|
|
17565
17637
|
this.ctx = null;
|
|
17566
17638
|
}
|
|
@@ -17637,9 +17709,8 @@ var BackdropRenderer = class {
|
|
|
17637
17709
|
if (scene.showGrid && gridHorz.visible && !pane.collapsed) {
|
|
17638
17710
|
ctx.globalAlpha = gridAlpha;
|
|
17639
17711
|
ctx.strokeStyle = horzColor;
|
|
17640
|
-
const pct = percentScaleFor(scene, pane);
|
|
17641
17712
|
ctx.beginPath();
|
|
17642
|
-
for (const t of
|
|
17713
|
+
for (const t of this.axisTicks.ticksFor(scene, pane, coords)) {
|
|
17643
17714
|
const y = Math.round(coords.priceToY(t.price, pane.scale, pane.bounds)) + 0.5;
|
|
17644
17715
|
if (y < pane.bounds.top || y > pane.bounds.top + pane.bounds.height) continue;
|
|
17645
17716
|
ctx.moveTo(0, y);
|
|
@@ -18229,8 +18300,16 @@ var NativeRenderer = class {
|
|
|
18229
18300
|
this.toolbarGutter = 0;
|
|
18230
18301
|
// px reserved on the left for the docked drawings toolbar (0 when hidden)
|
|
18231
18302
|
this.mountContainer = null;
|
|
18303
|
+
/** The host-styleable twin of the `shadeRight` veil (`.vela-shade-right`), directly under
|
|
18304
|
+
* the cursor canvas; hidden whenever the crosshair layer paints no veil. */
|
|
18305
|
+
this.shadeRightEl = null;
|
|
18306
|
+
/** The veil geometry last written to {@link shadeRightEl} ('' = hidden) — the DOM is
|
|
18307
|
+
* touched only when it changes, never on a plain pointer move. */
|
|
18308
|
+
this.shadeRightSig = "";
|
|
18232
18309
|
this.userDrawings = null;
|
|
18233
|
-
|
|
18310
|
+
/** One price-axis tick source for the gridlines (backdrop) and the labels (chrome). */
|
|
18311
|
+
this.priceAxisTicks = new PriceAxisTickSource();
|
|
18312
|
+
this.backdropRenderer = new BackdropRenderer(this.priceAxisTicks);
|
|
18234
18313
|
this.volumeRenderer = new VolumeRenderer();
|
|
18235
18314
|
/** SDK renderer layers instantiated at mount ({@link registerRendererLayer}). */
|
|
18236
18315
|
/**
|
|
@@ -18263,7 +18342,7 @@ var NativeRenderer = class {
|
|
|
18263
18342
|
this.backendMode = "auto";
|
|
18264
18343
|
this.glowAmount = 0;
|
|
18265
18344
|
// WebGL2 neon-glow intensity (canvas2d ignores it)
|
|
18266
|
-
this.chrome = new ChromeRenderer();
|
|
18345
|
+
this.chrome = new ChromeRenderer(this.priceAxisTicks);
|
|
18267
18346
|
/** Prepaints each indicator's Pine drawings into interleave slices at the model's z. */
|
|
18268
18347
|
this.indicatorSlices = new IndicatorDrawingSlices();
|
|
18269
18348
|
/** Hover tooltips for Pine labels (canvas hit-rects collected by the chrome layer). */
|
|
@@ -18380,6 +18459,8 @@ var NativeRenderer = class {
|
|
|
18380
18459
|
// pane just below it
|
|
18381
18460
|
this.resizeSplitStart = null;
|
|
18382
18461
|
// the two panes' shared span when the drag began
|
|
18462
|
+
/** The user drawings take part in pointer input (the runtime `drawingsInteractive` feature). */
|
|
18463
|
+
this.drawingsInteractive = true;
|
|
18383
18464
|
this.hoverSeparatorY = null;
|
|
18384
18465
|
// pixel y of the separator under the cursor (drives its hover highlight)
|
|
18385
18466
|
// ── pane management (merge / reorder / collapse / maximize) ──
|
|
@@ -18435,8 +18516,9 @@ var NativeRenderer = class {
|
|
|
18435
18516
|
this.toggleVisibleCbs = /* @__PURE__ */ new Set();
|
|
18436
18517
|
this.moveIndicatorCbs = /* @__PURE__ */ new Set();
|
|
18437
18518
|
this.priceStyleCbs = /* @__PURE__ */ new Set();
|
|
18519
|
+
this.priceStyleWillChangeCbs = /* @__PURE__ */ new Set();
|
|
18438
18520
|
this.name = "native";
|
|
18439
|
-
this.features = ["logScale", "currentPriceLine", "priceLabel", "countdown", "upColor", "downColor", "glow", "animZoom", "animPan", "animScroll", "animAutoscale", "animLiveBar", "intro", "zoomAnchor", "axisDrag", "paneResize", "candleZOrder", "candleVisible", "seriesOrder", "highlights", "sessionZones", "gridlines", "axisLabels", "scaleMode", "invertScale", "paneScales", "autoScale", "timezone", "keyboard", "historyChords", "priceStyle", "priceBaseline", "baselinePrice", "settings", "attribution", "dialogHost", "tradeMarkers", "marks", "indicatorTitles", "indicatorValues", "crosshairOverride"];
|
|
18521
|
+
this.features = ["logScale", "currentPriceLine", "priceLabel", "countdown", "upColor", "downColor", "glow", "animZoom", "animPan", "animScroll", "animAutoscale", "animLiveBar", "intro", "zoomAnchor", "axisDrag", "paneResize", "candleZOrder", "candleVisible", "seriesOrder", "highlights", "sessionZones", "gridlines", "axisLabels", "scaleMode", "invertScale", "paneScales", "autoScale", "timezone", "keyboard", "historyChords", "priceStyle", "priceBaseline", "baselinePrice", "settings", "attribution", "dialogHost", "tradeMarkers", "marks", "indicatorTitles", "indicatorValues", "crosshairOverride", "drawingsInteractive", "priceAxisTicks"];
|
|
18440
18522
|
/** Track cursor proximity to the scroll button on the plot (bubbles from the button too,
|
|
18441
18523
|
* so moving onto the button doesn't count as leaving). */
|
|
18442
18524
|
this.onScrollProximityMove = (e) => {
|
|
@@ -18480,6 +18562,7 @@ var NativeRenderer = class {
|
|
|
18480
18562
|
this.scene.priceStyle = opts.priceStyle;
|
|
18481
18563
|
this.scene.basePainting = basePaintingOf(opts.priceStyle);
|
|
18482
18564
|
this.scene.candleOverride = candleOverrideFor(opts.priceStyle, this.scene.style.chartTypes);
|
|
18565
|
+
if (typeof opts.priceAxisTicks === "function") this.priceAxisTicks.setHook(opts.priceAxisTicks);
|
|
18483
18566
|
}
|
|
18484
18567
|
this.theme = this.deriveTheme(DARK_THEME);
|
|
18485
18568
|
}
|
|
@@ -18618,6 +18701,15 @@ var NativeRenderer = class {
|
|
|
18618
18701
|
case "crosshairOverride":
|
|
18619
18702
|
this.scene.crosshairOverride = sanitizeCrosshairOverride(value);
|
|
18620
18703
|
break;
|
|
18704
|
+
case "drawingsInteractive":
|
|
18705
|
+
this.drawingsInteractive = value !== false;
|
|
18706
|
+
if (this.input) this.input.drawings = this.drawingsInteractive;
|
|
18707
|
+
if (!this.drawingsInteractive) this.userDrawings?.clearHover();
|
|
18708
|
+
return;
|
|
18709
|
+
// affects the next gesture only — clearHover repaints what it drops
|
|
18710
|
+
case "priceAxisTicks":
|
|
18711
|
+
this.priceAxisTicks.setHook(typeof value === "function" ? value : null);
|
|
18712
|
+
break;
|
|
18621
18713
|
case "keyboard":
|
|
18622
18714
|
this.setKeyboardEnabled(Boolean(value));
|
|
18623
18715
|
return;
|
|
@@ -18733,6 +18825,10 @@ var NativeRenderer = class {
|
|
|
18733
18825
|
return { visible: this.scene.marks.visible, groups: { ...this.scene.marks.groups } };
|
|
18734
18826
|
case "crosshairOverride":
|
|
18735
18827
|
return this.scene.crosshairOverride ? { ...this.scene.crosshairOverride } : null;
|
|
18828
|
+
case "drawingsInteractive":
|
|
18829
|
+
return this.drawingsInteractive;
|
|
18830
|
+
case "priceAxisTicks":
|
|
18831
|
+
return this.priceAxisTicks.hook;
|
|
18736
18832
|
case "keyboard":
|
|
18737
18833
|
return this.keyboardEnabled;
|
|
18738
18834
|
case "historyChords":
|
|
@@ -19406,6 +19502,12 @@ var NativeRenderer = class {
|
|
|
19406
19502
|
Object.assign(this.drawingsCanvas.style, { position: "absolute", inset: "0", width: "100%", height: "100%", pointerEvents: "none" });
|
|
19407
19503
|
this.cursorCanvas = document.createElement("canvas");
|
|
19408
19504
|
Object.assign(this.cursorCanvas.style, { position: "absolute", inset: "0", width: "100%", height: "100%", pointerEvents: "none" });
|
|
19505
|
+
this.shadeRightEl = document.createElement("div");
|
|
19506
|
+
this.shadeRightEl.className = "vela-shade-right";
|
|
19507
|
+
this.shadeRightEl.setAttribute("aria-hidden", "true");
|
|
19508
|
+
this.shadeRightEl.hidden = true;
|
|
19509
|
+
Object.assign(this.shadeRightEl.style, { position: "absolute", top: "0", left: "0", width: "0", height: "0", pointerEvents: "none", display: "none" });
|
|
19510
|
+
this.shadeRightSig = "";
|
|
19409
19511
|
this.overlayRoot = document.createElement("div");
|
|
19410
19512
|
Object.assign(this.overlayRoot.style, { position: "absolute", inset: "0", pointerEvents: "none" });
|
|
19411
19513
|
this.plot = document.createElement("div");
|
|
@@ -19413,7 +19515,7 @@ var NativeRenderer = class {
|
|
|
19413
19515
|
this.extLayers = rendererLayers().map((def) => ({ def, instance: def.create(), canvas: this.createLayerCanvas(), channel: def.id, owner: null }));
|
|
19414
19516
|
const below = this.extLayers.filter((l) => l.def.placement === "below-data").map((l) => l.canvas);
|
|
19415
19517
|
const above = this.extLayers.filter((l) => l.def.placement !== "below-data").map((l) => l.canvas);
|
|
19416
|
-
this.plot.append(this.backdropCanvas, ...below, this.dataCanvas, this.volumeCanvas, this.vpvrCanvas, ...above, this.chromeCanvas, this.drawingsCanvas, this.cursorCanvas, this.overlayRoot);
|
|
19518
|
+
this.plot.append(this.backdropCanvas, ...below, this.dataCanvas, this.volumeCanvas, this.vpvrCanvas, ...above, this.chromeCanvas, this.drawingsCanvas, this.shadeRightEl, this.cursorCanvas, this.overlayRoot);
|
|
19417
19519
|
this.layerOrderSig = "";
|
|
19418
19520
|
this.wrapper.appendChild(this.plot);
|
|
19419
19521
|
this.factoryConfig = this.getConfig();
|
|
@@ -19471,13 +19573,14 @@ var NativeRenderer = class {
|
|
|
19471
19573
|
drawingsPointerDown: (x, y, snap, shift2, mod) => this.userDrawings?.pointerDown(x, y, snap, shift2, mod),
|
|
19472
19574
|
drawingsPointerMove: (x, y, snap, shift2, mod) => this.userDrawings?.pointerMove(x, y, snap, shift2, mod),
|
|
19473
19575
|
drawingsPointerUp: (x, y, snap) => this.userDrawings?.pointerUp(x, y, snap),
|
|
19474
|
-
drawingsCursor: (x, y) => this.userDrawings?.cursorAt(x, y) ?? (this.chrome.markGlyphAt(x, y) ? "pointer" : null),
|
|
19576
|
+
drawingsCursor: (x, y) => (this.drawingsInteractive ? this.userDrawings?.cursorAt(x, y) : null) ?? (this.chrome.markGlyphAt(x, y) ? "pointer" : null),
|
|
19475
19577
|
drawingsDblClick: (x, y) => this.userDrawings?.dblClick(x, y) ?? false,
|
|
19476
19578
|
drawingsClearTransient: () => this.userDrawings?.clearTransient()
|
|
19477
19579
|
});
|
|
19478
19580
|
this.input.rightEdgeZoom = this.zoomAnchorMode === "right";
|
|
19479
19581
|
this.input.axisDrag = this.axisDragEnabled;
|
|
19480
19582
|
this.input.paneResize = this.paneResizeEnabled;
|
|
19583
|
+
this.input.drawings = this.drawingsInteractive;
|
|
19481
19584
|
this.input.attach(this.dataCanvas);
|
|
19482
19585
|
if (this.settingsEnabled) this.setSettingsEnabled(true);
|
|
19483
19586
|
this.syncCountdownTimer();
|
|
@@ -19786,6 +19889,8 @@ var NativeRenderer = class {
|
|
|
19786
19889
|
this.backend.destroy();
|
|
19787
19890
|
this.chrome.destroy();
|
|
19788
19891
|
this.crosshairLayer.destroy();
|
|
19892
|
+
this.shadeRightEl?.remove();
|
|
19893
|
+
this.shadeRightEl = null;
|
|
19789
19894
|
this.attributionEl?.remove();
|
|
19790
19895
|
this.attributionEl = null;
|
|
19791
19896
|
this.mountContainer?.style.removeProperty("--vela-toolbar-gutter");
|
|
@@ -20132,14 +20237,21 @@ var NativeRenderer = class {
|
|
|
20132
20237
|
this.priceStyleCbs.add(cb);
|
|
20133
20238
|
return () => this.priceStyleCbs.delete(cb);
|
|
20134
20239
|
}
|
|
20240
|
+
onPriceStyleWillChange(cb) {
|
|
20241
|
+
this.priceStyleWillChangeCbs.add(cb);
|
|
20242
|
+
return () => this.priceStyleWillChangeCbs.delete(cb);
|
|
20243
|
+
}
|
|
20135
20244
|
/**
|
|
20136
20245
|
* THE single write path for the base price style at runtime (feature set / settings dialog /
|
|
20137
|
-
* config template — the constructor seeds the field directly, pre-listeners).
|
|
20138
|
-
*
|
|
20139
|
-
*
|
|
20246
|
+
* config template — the constructor seeds the field directly, pre-listeners). Announces the
|
|
20247
|
+
* switch while the scene still holds the old style (a listener may paint/capture that frame),
|
|
20248
|
+
* then updates the scene, eases any reveal layer toward the new style's target, and notifies
|
|
20249
|
+
* the core — which owns the DATA side of styles that need one (a chart type's SeriesDataEngine).
|
|
20140
20250
|
*/
|
|
20141
20251
|
setPriceStyle(style) {
|
|
20142
20252
|
if (style === this.scene.priceStyle) return;
|
|
20253
|
+
const from = this.scene.priceStyle;
|
|
20254
|
+
for (const cb of this.priceStyleWillChangeCbs) cb(from, style);
|
|
20143
20255
|
this.scene.priceStyle = style;
|
|
20144
20256
|
this.scene.basePainting = basePaintingOf(style);
|
|
20145
20257
|
this.scene.candleOverride = candleOverrideFor(style, this.scene.style.chartTypes);
|
|
@@ -20369,7 +20481,7 @@ var NativeRenderer = class {
|
|
|
20369
20481
|
if (this.easeLiveBar(dtMs)) active = true;
|
|
20370
20482
|
this.skeletonClockMs += dtMs;
|
|
20371
20483
|
this.paintData();
|
|
20372
|
-
this.
|
|
20484
|
+
this.renderCrosshairLayer();
|
|
20373
20485
|
this.updateLegendValues();
|
|
20374
20486
|
this.emitViewportChange();
|
|
20375
20487
|
return active;
|
|
@@ -20944,10 +21056,31 @@ var NativeRenderer = class {
|
|
|
20944
21056
|
this.chrome.render(this.scene, this.coords, this.theme, this.axisSurface());
|
|
20945
21057
|
this.trackMarkPopover();
|
|
20946
21058
|
}
|
|
20947
|
-
this.
|
|
21059
|
+
this.renderCrosshairLayer();
|
|
20948
21060
|
if (!repaintsData(level) && this.paintedData) this.repaintCursorLayers();
|
|
20949
21061
|
this.updateLegendValues();
|
|
20950
21062
|
}
|
|
21063
|
+
/** Repaint the L2 crosshair canvas and keep the `.vela-shade-right` element on the veil it painted. */
|
|
21064
|
+
renderCrosshairLayer() {
|
|
21065
|
+
this.crosshairLayer.render(this.scene, this.coords, this.theme, this.hoverSeparatorY, this.externalCrossPx());
|
|
21066
|
+
this.syncShadeRight();
|
|
21067
|
+
}
|
|
21068
|
+
/** Position (or hide) the `.vela-shade-right` element over the veil of the last crosshair frame. */
|
|
21069
|
+
syncShadeRight() {
|
|
21070
|
+
const el = this.shadeRightEl;
|
|
21071
|
+
if (!el) return;
|
|
21072
|
+
const area = this.crosshairLayer.shadeRightArea;
|
|
21073
|
+
const sig = area ? `${area.x},${area.width},${area.height}` : "";
|
|
21074
|
+
if (sig === this.shadeRightSig) return;
|
|
21075
|
+
this.shadeRightSig = sig;
|
|
21076
|
+
if (!area) {
|
|
21077
|
+
el.hidden = true;
|
|
21078
|
+
el.style.display = "none";
|
|
21079
|
+
return;
|
|
21080
|
+
}
|
|
21081
|
+
Object.assign(el.style, { left: `${area.x}px`, width: `${area.width}px`, height: `${area.height}px`, display: "" });
|
|
21082
|
+
el.hidden = false;
|
|
21083
|
+
}
|
|
20951
21084
|
/** Repaint the SDK layers that opted into cursor tracking (their own canvas only). */
|
|
20952
21085
|
repaintCursorLayers() {
|
|
20953
21086
|
const pane = this.scene.panes.get(PRICE_PANE_ID);
|
|
@@ -21741,7 +21874,7 @@ var NativeRenderer = class {
|
|
|
21741
21874
|
if (this.animator.active) {
|
|
21742
21875
|
this.computeScales();
|
|
21743
21876
|
this.paintData();
|
|
21744
|
-
this.
|
|
21877
|
+
this.renderCrosshairLayer();
|
|
21745
21878
|
} else {
|
|
21746
21879
|
this.scheduler.flushNow(4 /* Full */);
|
|
21747
21880
|
}
|
|
@@ -22381,6 +22514,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
22381
22514
|
this.activeEngineStyle = null;
|
|
22382
22515
|
/** The chart's current price style (tracked from the renderer's change events + initial read). */
|
|
22383
22516
|
this.priceStyle = "candles";
|
|
22517
|
+
this.priceStyleWillChangeUnsub = null;
|
|
22384
22518
|
this.unresolvedUnsub = null;
|
|
22385
22519
|
/** Latest chart visible range (left/right bar times), fed to viewport-dependent scripts. */
|
|
22386
22520
|
this.visibleRange = null;
|
|
@@ -22479,6 +22613,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
22479
22613
|
this.renderer.onThemeSelect?.((name) => this.setTheme(resolveTheme(name)));
|
|
22480
22614
|
this.viewportUnsub = this.renderer.onViewportChange((range) => this.onViewportChange(range));
|
|
22481
22615
|
this.renderer.onPriceStyleChange?.((style) => this.syncPriceStyle(style));
|
|
22616
|
+
this.priceStyleWillChangeUnsub = this.renderer.onPriceStyleWillChange?.((from, to) => this.events.emit("priceStyle:change", { from, to })) ?? null;
|
|
22482
22617
|
const initialStyle = this.renderer.readFeature("priceStyle");
|
|
22483
22618
|
if (typeof initialStyle === "string") this.priceStyle = initialStyle;
|
|
22484
22619
|
this.barTransform = barTransformFor(initialStyle);
|
|
@@ -24009,6 +24144,8 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
24009
24144
|
if (this.viewportTimer != null) clearTimeout(this.viewportTimer);
|
|
24010
24145
|
this.viewportUnsub?.();
|
|
24011
24146
|
this.paneActionUnsub?.();
|
|
24147
|
+
this.priceStyleWillChangeUnsub?.();
|
|
24148
|
+
this.priceStyleWillChangeUnsub = null;
|
|
24012
24149
|
for (const record of this.registry.all()) {
|
|
24013
24150
|
this.settleCode(record, { ok: false, error: new Error("[vela] updateCode \u2014 the chart was destroyed.") });
|
|
24014
24151
|
record.session?.stop();
|
|
@@ -28672,7 +28809,8 @@ var Vela = class {
|
|
|
28672
28809
|
glow: options.glow ?? 0,
|
|
28673
28810
|
upColor: options.upColor ?? BULLISH,
|
|
28674
28811
|
downColor: options.downColor ?? BEARISH,
|
|
28675
|
-
priceStyle: options.priceStyle ?? "candles"
|
|
28812
|
+
priceStyle: options.priceStyle ?? "candles",
|
|
28813
|
+
priceAxisTicks: options.priceAxis?.ticks ?? null
|
|
28676
28814
|
};
|
|
28677
28815
|
const RendererClass = options.renderer ?? NativeRenderer;
|
|
28678
28816
|
if (typeof RendererClass !== "function") {
|
|
@@ -29016,4 +29154,4 @@ function resolveElement(container) {
|
|
|
29016
29154
|
return element;
|
|
29017
29155
|
}
|
|
29018
29156
|
|
|
29019
|
-
export { BUILTIN_PRICE_STYLES, BarStore, CachingDataFeed, DARK_THEME, DataControl, DrawingStore, DrawingToolbar, DrawingsControl, LEGEND_AT_TOP_ATTR, LIGHT_THEME, MarksControl, MultiProviderFeed, NativeRenderer, RendererControl, ReplayControl, SecondClock,
|
|
29157
|
+
export { BUILTIN_PRICE_STYLES, BarStore, CANDLE_OVERRIDE_KEYS, CachingDataFeed, DARK_THEME, DataControl, DrawingStore, DrawingToolbar, DrawingsControl, LEGEND_AT_TOP_ATTR, LIGHT_THEME, MarksControl, MultiProviderFeed, NativeRenderer, RendererControl, ReplayControl, SecondClock, TypedEventBus, Vela, applyAttributionMarkTheme, buildToolbar, createAttributionMark, createCustomMark, defaultMemberOf, defaultToolbar, groupKeyOf, groupMembers, isGroupRow, normalizeSession, parseSymbol, priceStyleIds, registerBuiltinChartTypes, resolveTheme, sharedBarStore, timeframeToMs };
|