@tradecanvas/chart 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +858 -824
- package/dist/Chart.d.ts +142 -2
- package/dist/Chart.d.ts.map +1 -1
- package/dist/DragDropImporter-C5kgfbET.cjs +2 -0
- package/dist/DragDropImporter-C5kgfbET.cjs.map +1 -0
- package/dist/{DragDropImporter-BcTzFeRP.js → DragDropImporter-Dd9Mud5J.js} +423 -159
- package/dist/DragDropImporter-Dd9Mud5J.js.map +1 -0
- package/dist/PaneManager.d.ts.map +1 -1
- package/dist/charts/ChartTypeStrategy.d.ts +6 -0
- package/dist/charts/ChartTypeStrategy.d.ts.map +1 -1
- package/dist/grid/ChartGrid.d.ts +1 -0
- package/dist/grid/ChartGrid.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +74 -89
- package/dist/index.js.map +1 -1
- package/dist/interaction/verticalPanGate.d.ts +22 -0
- package/dist/interaction/verticalPanGate.d.ts.map +1 -0
- package/dist/widget/ChartWidget.d.ts +71 -7
- package/dist/widget/ChartWidget.d.ts.map +1 -1
- package/dist/widget/WidgetCommandPalette.d.ts +3 -1
- package/dist/widget/WidgetCommandPalette.d.ts.map +1 -1
- package/dist/widget/WidgetDrawingSidebar.d.ts +12 -0
- package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
- package/dist/widget/WidgetGoToDate.d.ts +45 -0
- package/dist/widget/WidgetGoToDate.d.ts.map +1 -0
- package/dist/widget/WidgetHotkeySheet.d.ts +4 -2
- package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
- package/dist/widget/WidgetIndicatorLegend.d.ts +68 -0
- package/dist/widget/WidgetIndicatorLegend.d.ts.map +1 -0
- package/dist/widget/WidgetLoadingOverlay.d.ts +3 -1
- package/dist/widget/WidgetLoadingOverlay.d.ts.map +1 -1
- package/dist/widget/WidgetObjectTree.d.ts +1 -1
- package/dist/widget/WidgetReplayBar.d.ts +37 -7
- package/dist/widget/WidgetReplayBar.d.ts.map +1 -1
- package/dist/widget/WidgetSettings.d.ts +13 -1
- package/dist/widget/WidgetSettings.d.ts.map +1 -1
- package/dist/widget/WidgetStatusBar.d.ts +16 -1
- package/dist/widget/WidgetStatusBar.d.ts.map +1 -1
- package/dist/widget/WidgetSymbolSearch.d.ts +3 -1
- package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -1
- package/dist/widget/WidgetToolbar.d.ts +12 -3
- package/dist/widget/WidgetToolbar.d.ts.map +1 -1
- package/dist/widget/WidgetTooltip.d.ts +43 -0
- package/dist/widget/WidgetTooltip.d.ts.map +1 -0
- package/dist/widget/escapeHtml.d.ts +3 -0
- package/dist/widget/escapeHtml.d.ts.map +1 -0
- package/dist/widget/i18n.d.ts +26 -0
- package/dist/widget/i18n.d.ts.map +1 -1
- package/dist/widget/iconSet.d.ts +26 -0
- package/dist/widget/iconSet.d.ts.map +1 -0
- package/dist/widget/icons.d.ts +5 -0
- package/dist/widget/icons.d.ts.map +1 -1
- package/dist/widget/index.cjs +3035 -2465
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.d.ts +3 -0
- package/dist/widget/index.d.ts.map +1 -1
- package/dist/widget/index.js +1636 -606
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/legendValues.d.ts +14 -0
- package/dist/widget/legendValues.d.ts.map +1 -0
- package/dist/widget/types.d.ts +34 -8
- package/dist/widget/types.d.ts.map +1 -1
- package/dist/widget/widgetConfig.d.ts +1 -5
- package/dist/widget/widgetConfig.d.ts.map +1 -1
- package/dist/widget/widgetTimeframes.d.ts +20 -0
- package/dist/widget/widgetTimeframes.d.ts.map +1 -0
- package/package.json +3 -3
- package/dist/DragDropImporter-BcTzFeRP.js.map +0 -1
- package/dist/DragDropImporter-DZBrretS.cjs +0 -2
- package/dist/DragDropImporter-DZBrretS.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DragDropImporter-Dd9Mud5J.js","names":[],"sources":["../src/charts/ChartTypeStrategy.ts","../src/charts/IndicatorPriceRange.ts","../src/state/AutoSaveScheduler.ts","../src/DataManager.ts","../src/ThemeManager.ts","../src/layout/LayoutManager.ts","../src/layout/priceAxisWidth.ts","../src/interaction/verticalPanGate.ts","../src/plugins/contracts.ts","../src/plugins/registry.ts","../src/plugins/PluginManager.ts","../src/trading/wireExecution.ts","../src/Chart.ts","../src/io/parseOHLCV.ts","../src/io/DragDropImporter.ts"],"sourcesContent":["import type { ChartType, DataSeries } from '@tradecanvas/commons';\nimport {\n AreaRenderer,\n BarRenderer,\n BaselineRenderer,\n CandlestickRenderer,\n EquivolumeRenderer,\n HLCAreaRenderer,\n HollowCandleRenderer,\n KagiRenderer,\n LineRenderer,\n LineWithMarkersRenderer,\n PointAndFigureRenderer,\n RenkoRenderer,\n StepLineRenderer,\n VolumeCandleRenderer,\n toHeikinAshi,\n toKagi,\n toLineBreak,\n toPointAndFigure,\n toRangeBars,\n toRenko,\n} from '@tradecanvas/core';\nimport type { ChartRendererInterface } from '@tradecanvas/core';\nimport type { ChartTypePlugin } from '../plugins/contracts.js';\n\n/**\n * Pure mapping from `ChartType` to the renderer class that draws it. Several\n * chart types reuse `CandlestickRenderer` against transformed data\n * (heikinAshi, lineBreak, rangeBars).\n */\nexport function createRendererFor(type: ChartType): ChartRendererInterface {\n switch (type) {\n case 'candlestick':\n case 'heikinAshi':\n case 'lineBreak':\n case 'rangeBars':\n return new CandlestickRenderer();\n case 'line':\n return new LineRenderer();\n case 'area':\n return new AreaRenderer();\n case 'bar':\n return new BarRenderer();\n case 'hollowCandle':\n return new HollowCandleRenderer();\n case 'baseline':\n return new BaselineRenderer();\n case 'renko':\n return new RenkoRenderer();\n case 'kagi':\n return new KagiRenderer();\n case 'pointAndFigure':\n return new PointAndFigureRenderer();\n case 'volumeCandles':\n return new VolumeCandleRenderer();\n case 'equivolume':\n return new EquivolumeRenderer();\n case 'hlcArea':\n return new HLCAreaRenderer();\n case 'stepLine':\n return new StepLineRenderer();\n case 'lineWithMarkers':\n return new LineWithMarkersRenderer();\n default:\n return new CandlestickRenderer();\n }\n}\n\n/**\n * Transform raw OHLC bars into the display series for a given chart type.\n * Returns the input unchanged for chart types that render raw OHLC directly.\n *\n * Centralized so adding a new chart type only requires editing one file.\n */\nexport function transformDisplayData(type: ChartType, raw: DataSeries): DataSeries {\n if (raw.length === 0) return raw;\n\n switch (type) {\n case 'heikinAshi':\n return toHeikinAshi(raw);\n case 'renko':\n return toRenko(raw, { brickSize: 0, useATR: true, atrPeriod: 14 });\n case 'lineBreak':\n return toLineBreak(raw, 3);\n case 'kagi':\n return toKagi(raw, 4);\n case 'pointAndFigure': {\n const avgPrice = averageClose(raw);\n return toPointAndFigure(raw, avgPrice * 0.01, 3);\n }\n case 'rangeBars': {\n const avgPrice = averageClose(raw);\n return toRangeBars(raw, { rangeSize: avgPrice * 0.005 });\n }\n default:\n return raw;\n }\n}\n\n/** Chart types that materially transform raw OHLC into a different series. */\nexport function isTransformedChartType(type: ChartType): boolean {\n switch (type) {\n case 'heikinAshi':\n case 'renko':\n case 'lineBreak':\n case 'kagi':\n case 'pointAndFigure':\n case 'rangeBars':\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Transformed chart types that redraw the series into bars of their own\n * (bricks, lines, columns), so a drawn bar is not a data bar. Heikin-Ashi\n * keeps one bar per data bar.\n */\nexport function isReshapedChartType(type: ChartType): boolean {\n return type !== 'heikinAshi' && isTransformedChartType(type);\n}\n\nfunction averageClose(raw: DataSeries): number {\n let sum = 0;\n for (const b of raw) sum += b.close;\n return sum / raw.length;\n}\n\n/** Look up a registered custom chart-type plugin by its `type` string. */\nexport type ChartTypeLookup = (type: string) => ChartTypePlugin | undefined;\n\n/**\n * Resolve the renderer for a chart type, preferring a registered\n * `ChartTypePlugin` over the built-in mapping.\n */\nexport function resolveRenderer(type: string, lookup?: ChartTypeLookup): ChartRendererInterface {\n const plugin = lookup?.(type);\n if (plugin) return plugin.createRenderer();\n return createRendererFor(type as ChartType);\n}\n\n/**\n * Resolve the display series for a chart type, preferring a plugin's\n * `transform` over the built-in transforms.\n */\nexport function resolveDisplayData(\n type: string,\n raw: DataSeries,\n lookup?: ChartTypeLookup,\n): DataSeries {\n if (raw.length === 0) return raw;\n const plugin = lookup?.(type);\n if (plugin?.transform) return plugin.transform(raw);\n return transformDisplayData(type as ChartType, raw);\n}\n","import type { IndicatorOutput } from '@tradecanvas/commons';\r\n\r\nexport interface PriceRange {\r\n min: number;\r\n max: number;\r\n}\r\n\r\nconst DEFAULT_RANGE: PriceRange = { min: 0, max: 100 };\r\nconst PADDING = 0.1;\r\n\r\n/**\r\n * Compute a padded {min, max} price range for an indicator panel from the\r\n * visible slice of its output. Returns a sensible default range when the\r\n * output is empty or has no values inside [from, to].\r\n *\r\n * Pure — no canvas, no viewport object, just the output and bar bounds.\r\n * This runs on every autoScale render frame (pan/zoom), once per visible\r\n * panel indicator, so the hot path must stay O(visible range): it walks\r\n * `output.series` (array, indexed by bar position) directly over\r\n * `[from, to]`. Falls back to scanning the `values` Map in insertion order\r\n * (O(dataset length), treating index 0…N-1 as the bar index) only when a\r\n * plugin hasn't published `series` — real built-in indicators always do.\r\n */\r\nexport function computeIndicatorPriceRange(\r\n output: IndicatorOutput | null,\r\n from: number,\r\n to: number,\r\n): PriceRange {\r\n if (!output) return { ...DEFAULT_RANGE };\r\n\r\n let vMin = Infinity;\r\n let vMax = -Infinity;\r\n\r\n if (output.series) {\r\n const end = Math.min(to, output.series.length - 1);\r\n for (let idx = Math.max(0, from); idx <= end; idx++) {\r\n const val = output.series[idx];\r\n if (!val) continue;\r\n for (const key in val) {\r\n const v = val[key];\r\n if (v !== undefined && Number.isFinite(v)) {\r\n if (v < vMin) vMin = v;\r\n if (v > vMax) vMax = v;\r\n }\r\n }\r\n }\r\n } else {\r\n let idx = 0;\r\n for (const [, val] of output.values) {\r\n if (idx >= from && idx <= to) {\r\n for (const key in val) {\r\n const v = val[key];\r\n if (v !== undefined && Number.isFinite(v)) {\r\n if (v < vMin) vMin = v;\r\n if (v > vMax) vMax = v;\r\n }\r\n }\r\n }\r\n idx++;\r\n }\r\n }\r\n\r\n if (vMin === Infinity) return { ...DEFAULT_RANGE };\r\n\r\n const range = vMax - vMin || 1;\r\n return {\r\n min: vMin - range * PADDING,\r\n max: vMax + range * PADDING,\r\n };\r\n}\r\n","/**\r\n * Debounced auto-save scheduler. Coalesces a burst of `schedule()` calls into\r\n * a single `save(key)` invocation after `delayMs` of quiet time. Pure state\r\n * machine — owner injects the actual save callback so this stays testable.\r\n */\r\nexport class AutoSaveScheduler {\r\n private timer: ReturnType<typeof setTimeout> | null = null;\r\n private delayMs = 0;\r\n private key: string | null = null;\r\n\r\n constructor(private save: (key: string) => void) {}\r\n\r\n /** Enable auto-save with the given storage key and quiet-time debounce. */\r\n enable(key: string, delayMs: number): void {\r\n this.key = key;\r\n this.delayMs = delayMs;\r\n }\r\n\r\n /** Disable auto-save and cancel any pending fire. */\r\n disable(): void {\r\n this.key = null;\r\n this.delayMs = 0;\r\n this.cancel();\r\n }\r\n\r\n /**\r\n * Reset the quiet-time window. If currently disabled (no key or delay ≤ 0),\r\n * this is a no-op. Subsequent calls within the window restart the timer.\r\n */\r\n schedule(): void {\r\n if (this.delayMs <= 0 || !this.key) return;\r\n if (this.timer) clearTimeout(this.timer);\r\n this.timer = setTimeout(() => {\r\n this.timer = null;\r\n if (this.key) this.save(this.key);\r\n }, this.delayMs);\r\n }\r\n\r\n /** Cancel any pending fire without changing enabled state. */\r\n cancel(): void {\r\n if (this.timer) {\r\n clearTimeout(this.timer);\r\n this.timer = null;\r\n }\r\n }\r\n\r\n isEnabled(): boolean {\r\n return this.delayMs > 0 && this.key !== null;\r\n }\r\n\r\n hasPending(): boolean {\r\n return this.timer !== null;\r\n }\r\n}\r\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\r\nimport { mergeBar } from '@tradecanvas/commons';\r\n\r\n/** Validate a single OHLC bar. Returns true if bar is usable. */\r\nfunction isValidBar(bar: OHLCBar): boolean {\r\n if (!bar || typeof bar.time !== 'number') return false;\r\n const { open, high, low, close } = bar;\r\n // Reject NaN / Infinity\r\n if (!isFinite(open) || !isFinite(high) || !isFinite(low) || !isFinite(close)) return false;\r\n // Reject negative prices\r\n if (open < 0 || high < 0 || low < 0 || close < 0) return false;\r\n // High must be >= low\r\n if (high < low) return false;\r\n // Volume (optional) must be non-negative if present\r\n if (bar.volume !== undefined && (!isFinite(bar.volume) || bar.volume < 0)) return false;\r\n return true;\r\n}\r\n\r\n/** Whether a valid bar already satisfies everything `sanitizeBar` enforces. */\r\nfunction isSanitized(bar: OHLCBar): boolean {\r\n return bar.volume !== undefined\r\n && bar.high >= bar.open && bar.high >= bar.close\r\n && bar.low <= bar.open && bar.low <= bar.close;\r\n}\r\n\r\n/** Sanitize a bar: clamp high/low to envelope OHLC values. */\r\nfunction sanitizeBar(bar: OHLCBar): OHLCBar {\r\n return {\r\n ...bar,\r\n high: Math.max(bar.open, bar.high, bar.low, bar.close),\r\n low: Math.min(bar.open, bar.high, bar.low, bar.close),\r\n volume: bar.volume !== undefined ? Math.max(0, bar.volume) : 0,\r\n };\r\n}\r\n\r\nexport class DataManager {\r\n private data: DataSeries = [];\r\n\r\n getData(): DataSeries {\r\n return this.data;\r\n }\r\n\r\n setData(data: DataSeries): void {\r\n // Drop invalid bars and sanitize the rest in one pass. Bars that are\r\n // already well-formed (the norm for exchange data) are kept as-is rather\r\n // than copied — bar objects are never mutated here, only replaced, so\r\n // sharing them with the caller is safe, and it saves allocating a fresh\r\n // object per bar on every symbol/timeframe switch.\r\n const out: OHLCBar[] = [];\r\n for (let i = 0; i < data.length; i++) {\r\n const bar = data[i];\r\n if (!isValidBar(bar)) continue;\r\n out.push(isSanitized(bar) ? bar : sanitizeBar(bar));\r\n }\r\n this.data = out;\r\n }\r\n\r\n appendBar(bar: OHLCBar): void {\r\n if (!isValidBar(bar)) return;\r\n this.data.push(sanitizeBar(bar));\r\n }\r\n\r\n updateLastBar(bar: OHLCBar): void {\r\n if (!isValidBar(bar)) return;\r\n const sanitized = sanitizeBar(bar);\r\n if (this.data.length === 0) {\r\n this.data.push(sanitized);\r\n return;\r\n }\r\n this.data[this.data.length - 1] = sanitized;\r\n }\r\n\r\n updateLastBarFromTick(tick: { price: number; volume?: number; time: number }): void {\r\n if (this.data.length === 0) return;\r\n if (!isFinite(tick.price) || tick.price < 0) return;\r\n if (tick.volume !== undefined && (!isFinite(tick.volume) || tick.volume < 0)) return;\r\n this.data[this.data.length - 1] = mergeBar(this.data[this.data.length - 1], tick);\r\n }\r\n\r\n getLength(): number {\r\n return this.data.length;\r\n }\r\n\r\n clear(): void {\r\n this.data = [];\r\n }\r\n}\r\n","import type { Theme, ThemeName } from '@tradecanvas/commons';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\n\nexport class ThemeManager {\n private theme: Theme;\n\n constructor(themeOrName?: ThemeName | Theme) {\n if (!themeOrName || themeOrName === 'dark') {\n this.theme = { ...DARK_THEME };\n } else if (themeOrName === 'light') {\n this.theme = { ...LIGHT_THEME };\n } else {\n this.theme = { ...themeOrName };\n }\n }\n\n getTheme(): Theme {\n return this.theme;\n }\n\n setTheme(themeOrName: ThemeName | Theme): void {\n if (themeOrName === 'dark') {\n this.theme = { ...DARK_THEME };\n } else if (themeOrName === 'light') {\n this.theme = { ...LIGHT_THEME };\n } else {\n this.theme = { ...themeOrName };\n }\n }\n}\n","import type { PanelPosition, PanelConfig, ResolvedLayout, ResolvedPanel, DividerRect, Rect } from '@tradecanvas/commons';\r\nimport { DEFAULT_PANEL_HEIGHT, MIN_PANEL_HEIGHT, PRICE_AXIS_WIDTH, TIME_AXIS_HEIGHT } from '@tradecanvas/commons';\r\n\r\nconst DEFAULT_PANEL_WIDTH = 200;\r\nconst MIN_PANEL_WIDTH = 80;\r\n\r\nexport class LayoutManager {\r\n private panels: PanelConfig[] = [];\r\n private containerWidth = 0;\r\n private containerHeight = 0;\r\n private priceAxisWidth = PRICE_AXIS_WIDTH;\r\n\r\n resize(width: number, height: number): void {\r\n this.containerWidth = width;\r\n this.containerHeight = height;\r\n }\r\n\r\n addPanel(instanceId: string, position: PanelPosition = 'bottom', size?: number): void {\r\n const isVertical = position === 'left' || position === 'right';\r\n this.panels.push({\r\n id: instanceId,\r\n position,\r\n size: size ?? (isVertical ? DEFAULT_PANEL_WIDTH : DEFAULT_PANEL_HEIGHT),\r\n minSize: isVertical ? MIN_PANEL_WIDTH : MIN_PANEL_HEIGHT,\r\n content: { type: 'indicator', indicatorInstanceId: instanceId },\r\n });\r\n }\r\n\r\n removePanel(instanceId: string): void {\r\n this.panels = this.panels.filter((p) => p.id !== instanceId);\r\n }\r\n\r\n setPanelPosition(instanceId: string, position: PanelPosition): void {\r\n const panel = this.panels.find((p) => p.id === instanceId);\r\n if (panel) {\r\n const wasVertical = panel.position === 'left' || panel.position === 'right';\r\n const isVertical = position === 'left' || position === 'right';\r\n panel.position = position;\r\n if (wasVertical !== isVertical) {\r\n panel.size = isVertical ? DEFAULT_PANEL_WIDTH : DEFAULT_PANEL_HEIGHT;\r\n panel.minSize = isVertical ? MIN_PANEL_WIDTH : MIN_PANEL_HEIGHT;\r\n }\r\n }\r\n }\r\n\r\n setPanelSize(instanceId: string, size: number): void {\r\n const panel = this.panels.find((p) => p.id === instanceId);\r\n if (panel) {\r\n panel.size = Math.max(panel.minSize, size);\r\n }\r\n }\r\n\r\n /** Width reserved for the price axis right of the main chart. */\r\n setPriceAxisWidth(width: number): void {\r\n this.priceAxisWidth = width;\r\n }\r\n\r\n getPanels(): PanelConfig[] {\r\n return this.panels;\r\n }\r\n\r\n resolve(): ResolvedLayout {\r\n const leftPanels = this.panels.filter((p) => p.position === 'left');\r\n const rightPanels = this.panels.filter((p) => p.position === 'right');\r\n const topPanels = this.panels.filter((p) => p.position === 'top');\r\n const bottomPanels = this.panels.filter((p) => p.position === 'bottom');\r\n\r\n const leftWidth = leftPanels.reduce((s, p) => s + p.size, 0);\r\n const rightWidth = rightPanels.reduce((s, p) => s + p.size, 0);\r\n const topHeight = topPanels.reduce((s, p) => s + p.size, 0);\r\n const bottomHeight = bottomPanels.reduce((s, p) => s + p.size, 0);\r\n\r\n const mainChartRect: Rect = {\r\n x: leftWidth,\r\n y: topHeight,\r\n width: Math.max(0, this.containerWidth - leftWidth - rightWidth - this.priceAxisWidth),\r\n height: Math.max(0, this.containerHeight - topHeight - bottomHeight - TIME_AXIS_HEIGHT),\r\n };\r\n\r\n const resolvedPanels: ResolvedPanel[] = [];\r\n const dividers: DividerRect[] = [];\r\n\r\n // Left panels (stacked vertically)\r\n let x = 0;\r\n for (const panel of leftPanels) {\r\n resolvedPanels.push({\r\n config: panel,\r\n rect: { x, y: 0, width: panel.size, height: this.containerHeight - TIME_AXIS_HEIGHT },\r\n });\r\n dividers.push({\r\n panelId: panel.id,\r\n rect: { x: x + panel.size - 2, y: 0, width: 4, height: this.containerHeight },\r\n orientation: 'vertical',\r\n });\r\n x += panel.size;\r\n }\r\n\r\n // Top panels (stacked horizontally, full width minus left/right)\r\n let y = 0;\r\n for (const panel of topPanels) {\r\n resolvedPanels.push({\r\n config: panel,\r\n rect: { x: leftWidth, y, width: mainChartRect.width, height: panel.size },\r\n });\r\n dividers.push({\r\n panelId: panel.id,\r\n rect: { x: leftWidth, y: y + panel.size - 2, width: mainChartRect.width, height: 4 },\r\n orientation: 'horizontal',\r\n });\r\n y += panel.size;\r\n }\r\n\r\n // Bottom panels\r\n y = mainChartRect.y + mainChartRect.height;\r\n for (const panel of bottomPanels) {\r\n resolvedPanels.push({\r\n config: panel,\r\n rect: { x: leftWidth, y, width: mainChartRect.width, height: panel.size },\r\n });\r\n dividers.push({\r\n panelId: panel.id,\r\n rect: { x: leftWidth, y: y - 2, width: mainChartRect.width, height: 4 },\r\n orientation: 'horizontal',\r\n });\r\n y += panel.size;\r\n }\r\n\r\n // Right panels\r\n x = leftWidth + mainChartRect.width + this.priceAxisWidth;\r\n for (const panel of rightPanels) {\r\n resolvedPanels.push({\r\n config: panel,\r\n rect: { x, y: 0, width: panel.size, height: this.containerHeight - TIME_AXIS_HEIGHT },\r\n });\r\n dividers.push({\r\n panelId: panel.id,\r\n rect: { x: x - 2, y: 0, width: 4, height: this.containerHeight },\r\n orientation: 'vertical',\r\n });\r\n x += panel.size;\r\n }\r\n\r\n return { mainChartRect, panels: resolvedPanels, dividers };\r\n }\r\n\r\n getMainChartRect(): Rect {\r\n return this.resolve().mainChartRect;\r\n }\r\n}\r\n","import { PRICE_AXIS_WIDTH, autoPricePrecision, formatPrice } from '@tradecanvas/commons';\r\n\r\n/** Axis label: 8px tick notch + gap on the left, 6px margin on the right. */\r\nconst LABEL_CHROME = 14;\r\n/** Last-price tag: 12px badge padding + 2px margin. */\r\nconst PRICE_TAG_CHROME = 14;\r\n/** Crosshair pill: 16px padding + 5px notch + 1px margin. */\r\nconst CROSSHAIR_PILL_CHROME = 22;\r\n/** Widths snap to this grid so a one-pixel label change doesn't relayout. */\r\nconst WIDTH_GRANULARITY = 4;\r\n/** Shrinking waits until this much room is spare, so panning doesn't make the axis twitch. */\r\nexport const AXIS_SHRINK_SLACK = 12;\r\n\r\nexport interface PriceAxisWidthInput {\r\n min: number;\r\n max: number;\r\n lastPrice: number | null;\r\n /** Decimals for the price tags (a market's `pricePrecision`), or null to follow the axis. */\r\n tagPrecision: number | null;\r\n locale: string;\r\n fontFamily: string;\r\n fontSizeSmall: number;\r\n measure: (text: string, font: string) => number;\r\n}\r\n\r\n/**\r\n * Width the price axis needs for its widest label — tick labels, the\r\n * last-price tag and the crosshair pill — never below `PRICE_AXIS_WIDTH`.\r\n * A sub-cent asset (\"0,000004349\") needs ~90px where BTC fits the default.\r\n */\r\nexport function requiredPriceAxisWidth(input: PriceAxisWidthInput): number {\r\n const { min, max, lastPrice, locale, fontFamily, fontSizeSmall, measure } = input;\r\n const axisPrecision = autoPricePrecision(min, max);\r\n const tagPrecision = input.tagPrecision ?? axisPrecision;\r\n const prices = lastPrice !== null ? [min, max, lastPrice] : [min, max];\r\n\r\n let need = PRICE_AXIS_WIDTH;\r\n for (const price of prices) {\r\n if (!Number.isFinite(price)) continue;\r\n const label = formatPrice(price, axisPrecision, locale);\r\n const tag = formatPrice(price, tagPrecision, locale);\r\n need = Math.max(\r\n need,\r\n measure(label, `500 ${fontSizeSmall}px ${fontFamily}`) + LABEL_CHROME,\r\n measure(tag, `bold 11px ${fontFamily}`) + PRICE_TAG_CHROME,\r\n measure(tag, `600 ${fontSizeSmall}px ${fontFamily}`) + CROSSHAIR_PILL_CHROME,\r\n );\r\n }\r\n // The default stays exact; only widened axes snap to the grid.\r\n return need <= PRICE_AXIS_WIDTH ? PRICE_AXIS_WIDTH : Math.ceil(need / WIDTH_GRANULARITY) * WIDTH_GRANULARITY;\r\n}\r\n\r\n/** The axis width to use next: grow at once, shrink only once enough room is spare. */\r\nexport function nextPriceAxisWidth(current: number, required: number): number {\r\n if (required > current) return required;\r\n if (required <= current - AXIS_SHRINK_SLACK) return required;\r\n return current;\r\n}\r\n","/** Net vertical travel (px) a drag needs before it may move the price scale. */\r\nexport const VERTICAL_PAN_ENGAGE_PX = 24;\r\n/** …and that travel must be at least this share of the horizontal travel. */\r\nexport const VERTICAL_PAN_MIN_RATIO = 0.5;\r\n\r\n/**\r\n * Decides, per drag gesture, when a chart-body drag should also pan the price\r\n * scale (which turns auto-scale off). A horizontal drag always drifts a few\r\n * pixels vertically; engaging on that drift knocked the chart off auto-scale\r\n * mid-pan, so the price scale stopped following the bars and wobbled with the\r\n * hand — the drag felt stuck. Now it takes a deliberate vertical move.\r\n * With auto-scale already off the price scale pans freely, as before.\r\n */\r\nexport class VerticalPanGate {\r\n private netY = 0;\r\n private travelX = 0;\r\n private engaged = false;\r\n\r\n /** Start of a new drag gesture. */\r\n reset(): void {\r\n this.netY = 0;\r\n this.travelX = 0;\r\n this.engaged = false;\r\n }\r\n\r\n /** Feed one drag step; true once vertical panning is engaged for this gesture. */\r\n step(deltaX: number, deltaY: number, autoScaleOn: boolean): boolean {\r\n if (this.engaged) return true;\r\n this.netY += deltaY;\r\n this.travelX += Math.abs(deltaX);\r\n if (!autoScaleOn) {\r\n this.engaged = true;\r\n } else {\r\n const dy = Math.abs(this.netY);\r\n this.engaged = dy > VERTICAL_PAN_ENGAGE_PX && dy >= this.travelX * VERTICAL_PAN_MIN_RATIO;\r\n }\r\n return this.engaged;\r\n }\r\n}\r\n","import type {\r\n IndicatorPlugin,\r\n DrawingPlugin,\r\n DataSeries,\r\n ViewportState,\r\n Theme,\r\n Point,\r\n} from '@tradecanvas/commons';\r\nimport type { ChartRendererInterface } from '@tradecanvas/core';\r\n\r\n/**\r\n * Plugin SDK contracts — FROZEN for 1.0. Authors extend the chart along four\r\n * axes. `IndicatorPlugin` and `DrawingPlugin` are re-used verbatim from\r\n * commons; `ChartTypePlugin` and `OverlayPlugin` are defined here because they\r\n * reference core's renderer interface.\r\n */\r\nexport const PLUGIN_API_VERSION = 1;\r\n\r\n/** A custom chart type: a renderer plus an optional data transform. */\r\nexport interface ChartTypePlugin {\r\n descriptor: { type: string; name: string };\r\n createRenderer(): ChartRendererInterface;\r\n /** Derive the displayed series from raw OHLC (e.g. Heikin-Ashi, Renko). */\r\n transform?(data: DataSeries): DataSeries;\r\n}\r\n\r\n/** Render context handed to overlay plugins each frame. */\r\nexport interface OverlayRenderContext {\r\n viewport: ViewportState;\r\n data: DataSeries;\r\n theme: Theme;\r\n}\r\n\r\n/** A custom data overlay (e.g. a volume-profile-style layer). */\r\nexport interface OverlayPlugin {\r\n descriptor: { id: string; name: string; layer?: 'main' | 'overlay' | 'ui' };\r\n render(ctx: CanvasRenderingContext2D, context: OverlayRenderContext): void;\r\n hitTest?(point: Point, context: OverlayRenderContext): boolean;\r\n}\r\n\r\n/** Discriminated union accepted by `registerPlugin` and `chart.plugins.register`. */\r\nexport type ChartPlugin =\r\n | { kind: 'indicator'; plugin: IndicatorPlugin }\r\n | { kind: 'drawing'; plugin: DrawingPlugin }\r\n | { kind: 'chartType'; plugin: ChartTypePlugin }\r\n | { kind: 'overlay'; plugin: OverlayPlugin };\r\n\r\n/** Overlays whose target layer matches `layer` (the default layer is `overlay`). */\r\nexport function overlaysForLayer(\r\n overlays: OverlayPlugin[],\r\n layer: 'main' | 'overlay' | 'ui',\r\n): OverlayPlugin[] {\r\n return overlays.filter((o) => (o.descriptor.layer ?? 'overlay') === layer);\r\n}\r\n\r\n/** Stable identity for a plugin, used for registry de-duplication and `list()`. */\r\nexport function pluginKey(p: ChartPlugin): string {\r\n switch (p.kind) {\r\n case 'indicator':\r\n return `indicator:${p.plugin.descriptor.id}`;\r\n case 'drawing':\r\n return `drawing:${p.plugin.descriptor.type}`;\r\n case 'chartType':\r\n return `chartType:${p.plugin.descriptor.type}`;\r\n case 'overlay':\r\n return `overlay:${p.plugin.descriptor.id}`;\r\n }\r\n}\r\n","import type { ChartPlugin } from './contracts.js';\r\nimport { pluginKey } from './contracts.js';\r\n\r\n/**\r\n * Global default plugin registry. Every `Chart` created *after* a plugin is\r\n * registered inherits it (unless `inheritGlobal: false`). For per-chart scoping\r\n * use the constructor `plugins` option or `chart.plugins.register`.\r\n */\r\nconst globalPlugins = new Map<string, ChartPlugin>();\r\n\r\n/** Register a plugin globally. Re-registering the same key replaces it. */\r\nexport function registerPlugin(plugin: ChartPlugin): void {\r\n globalPlugins.set(pluginKey(plugin), plugin);\r\n}\r\n\r\n/** Remove a global plugin by its `pluginKey`. Returns true if it existed. */\r\nexport function unregisterPlugin(key: string): boolean {\r\n return globalPlugins.delete(key);\r\n}\r\n\r\n/** Snapshot of all globally registered plugins. */\r\nexport function getGlobalPlugins(): ChartPlugin[] {\r\n return [...globalPlugins.values()];\r\n}\r\n\r\n/** Clear the global registry (test/teardown helper). */\r\nexport function clearGlobalPlugins(): void {\r\n globalPlugins.clear();\r\n}\r\n","import type { IndicatorPlugin } from '@tradecanvas/commons';\r\nimport type { IndicatorEngine } from '@tradecanvas/core';\r\nimport type { ChartPlugin, ChartTypePlugin, OverlayPlugin } from './contracts.js';\r\nimport { pluginKey } from './contracts.js';\r\nimport { getGlobalPlugins } from './registry.js';\r\n\r\nexport interface PluginManagerOptions {\r\n /** Per-instance plugins (from `new Chart(el, { plugins })`); merged over globals. */\r\n plugins?: ChartPlugin[];\r\n /** Inherit the global registry at construction (default: true). */\r\n inheritGlobal?: boolean;\r\n}\r\n\r\n/**\r\n * Per-chart plugin registry. Resolves plugins in precedence order:\r\n * global defaults → constructor `plugins` → imperative `register()`.\r\n * Indicator plugins additionally flow into the `IndicatorEngine` so\r\n * `chart.addIndicator(id)` can find them by descriptor id.\r\n */\r\nexport class PluginManager {\r\n private plugins = new Map<string, ChartPlugin>();\r\n\r\n constructor(\r\n private indicatorEngine: IndicatorEngine,\r\n options: PluginManagerOptions = {},\r\n ) {\r\n if (options.inheritGlobal !== false) {\r\n for (const p of getGlobalPlugins()) this.add(p);\r\n }\r\n for (const p of options.plugins ?? []) this.add(p);\r\n }\r\n\r\n /** Register a plugin on this chart instance. */\r\n register(plugin: ChartPlugin): void {\r\n this.add(plugin);\r\n }\r\n\r\n /** Remove a plugin by its `pluginKey`. Returns true if it existed. */\r\n unregister(key: string): boolean {\r\n return this.plugins.delete(key);\r\n }\r\n\r\n /** All plugins active on this instance. */\r\n list(): ChartPlugin[] {\r\n return [...this.plugins.values()];\r\n }\r\n\r\n /** Back-compat shorthand for registering an indicator plugin. */\r\n registerIndicator(plugin: IndicatorPlugin): void {\r\n this.add({ kind: 'indicator', plugin });\r\n }\r\n\r\n /** Look up a registered custom chart type by its `type` string. */\r\n getChartType(type: string): ChartTypePlugin | undefined {\r\n const p = this.plugins.get(`chartType:${type}`);\r\n return p?.kind === 'chartType' ? p.plugin : undefined;\r\n }\r\n\r\n /** All registered overlay plugins. */\r\n getOverlays(): OverlayPlugin[] {\r\n const out: OverlayPlugin[] = [];\r\n for (const p of this.plugins.values()) {\r\n if (p.kind === 'overlay') out.push(p.plugin);\r\n }\r\n return out;\r\n }\r\n\r\n private add(plugin: ChartPlugin): void {\r\n this.plugins.set(pluginKey(plugin), plugin);\r\n // Indicator plugins must reach the engine so they're resolvable by id.\r\n if (plugin.kind === 'indicator') {\r\n this.indicatorEngine.register(plugin.plugin);\r\n }\r\n }\r\n}\r\n","import type {\r\n ExecutionAdapter,\r\n ExecutionEvent,\r\n ExecutionError,\r\n TradingOrder,\r\n TradingPosition,\r\n OrderPlaceIntent,\r\n OrderModifyIntent,\r\n OrderCancelIntent,\r\n PositionModifyIntent,\r\n PositionCloseIntent,\r\n} from '@tradecanvas/commons';\r\n\r\n/** The five order/position intents the chart emits and an adapter consumes. */\r\nexport type ExecutionIntentType =\r\n | 'orderPlace'\r\n | 'orderModify'\r\n | 'orderCancel'\r\n | 'positionModify'\r\n | 'positionClose';\r\n\r\n/**\r\n * Surface the host (the Chart) provides so execution can be bridged without\r\n * the helper knowing anything about chart internals — which keeps it pure and\r\n * unit-testable.\r\n */\r\nexport interface ExecutionHost {\r\n /** Subscribe to an emitted intent; returns an unsubscribe function. */\r\n onIntent(type: ExecutionIntentType, handler: (payload: unknown) => void): () => void;\r\n /** Render the adapter's authoritative pending orders. */\r\n setOrders(orders: TradingOrder[]): void;\r\n /** Render the adapter's authoritative open positions. */\r\n setPositions(positions: TradingPosition[]): void;\r\n /** Surface an execution failure (adapter-reported or a failed command). */\r\n onError(error: ExecutionError): void;\r\n}\r\n\r\nconst COMMANDS: Record<\r\n ExecutionIntentType,\r\n (adapter: ExecutionAdapter, payload: unknown) => Promise<unknown>\r\n> = {\r\n orderPlace: (a, p) => a.placeOrder(p as OrderPlaceIntent),\r\n orderModify: (a, p) => a.modifyOrder(p as OrderModifyIntent),\r\n orderCancel: (a, p) => a.cancelOrder(p as OrderCancelIntent),\r\n positionModify: (a, p) => a.modifyPosition(p as PositionModifyIntent),\r\n positionClose: (a, p) => a.closePosition(p as PositionCloseIntent),\r\n};\r\n\r\n/**\r\n * Bridge an `ExecutionAdapter` to a host: render the adapter's authoritative\r\n * orders/positions, and route the host's emitted intents into adapter\r\n * commands. The adapter is the single source of truth. Returns a teardown that\r\n * removes every subscription.\r\n */\r\nexport function wireExecution(adapter: ExecutionAdapter, host: ExecutionHost): () => void {\r\n const teardowns: Array<() => void> = [];\r\n\r\n // Adapter → host: authoritative state + errors.\r\n const onOrders = (e: ExecutionEvent<TradingOrder[]>) => host.setOrders(e.data ?? []);\r\n const onPositions = (e: ExecutionEvent<TradingPosition[]>) => host.setPositions(e.data ?? []);\r\n const onError = (e: ExecutionEvent<ExecutionError>) =>\r\n host.onError(e.data ?? { message: 'Execution error' });\r\n adapter.on<TradingOrder[]>('orders', onOrders);\r\n adapter.on<TradingPosition[]>('positions', onPositions);\r\n adapter.on<ExecutionError>('error', onError);\r\n teardowns.push(\r\n () => adapter.off('orders', onOrders),\r\n () => adapter.off('positions', onPositions),\r\n () => adapter.off('error', onError),\r\n );\r\n\r\n // Host → adapter: route each emitted intent into the matching command.\r\n for (const type of Object.keys(COMMANDS) as ExecutionIntentType[]) {\r\n const command = COMMANDS[type];\r\n const unsub = host.onIntent(type, (payload) => {\r\n Promise.resolve(command(adapter, payload)).catch((cause) =>\r\n host.onError({ message: `Execution command failed: ${type}`, cause }),\r\n );\r\n });\r\n teardowns.push(unsub);\r\n }\r\n\r\n return () => {\r\n for (const teardown of teardowns) teardown();\r\n };\r\n}\r\n","import type {\n ChartOptions,\n ChartType,\n OHLCBar,\n DataSeries,\n Theme,\n ThemeName,\n ChartEventType,\n ChartEvent,\n ChartEventMap,\n TauriBridgeOptions,\n IndicatorPlugin,\n IndicatorDescriptor,\n IndicatorOutput,\n ResolvedIndicatorStyle,\n DrawingToolType,\n DrawingState,\n DrawingStyle,\n DrawingPlugin,\n PanelPosition,\n TradingOrder,\n TradingPosition,\n DepthData,\n TradingConfig,\n MarketConfig,\n Locale,\n StreamConfig,\n ConnectionState,\n ConnectionInfo,\n TimeFrame,\n FeaturesConfig,\n ExecutionAdapter,\n ExecutionConfig,\n} from '@tradecanvas/commons';\nimport { LayerType, setLocale as setGlobalLocale, computePriceLimits, PRICE_AXIS_WIDTH, autoPricePrecision, formatPrice } from '@tradecanvas/commons';\nimport {\n RenderEngine,\n Viewport,\n GridRenderer,\n PriceAxis,\n TimeAxis,\n InteractionManager,\n PaneResizeHandler,\n PanHandler,\n ZoomHandler,\n AxisDragHandler,\n AlertDragHandler,\n CrosshairHandler,\n IndicatorEngine,\n registerBuiltInIndicators,\n EventBus,\n DrawingManager,\n DrawingRenderer,\n registerBuiltInDrawingTools,\n TradingManager,\n TradingRenderer,\n StreamManager,\n ChartLegend,\n Screenshot,\n Watermark,\n BarCountdown,\n VolumeRenderer,\n VolumeProfileRenderer,\n MarketProfileRenderer,\n DepthHeatmapRenderer,\n PeriodLevelsRenderer,\n PivotMarkersRenderer,\n AlertManager,\n SignalMarkerManager,\n TradeZoneManager,\n MeasureOverlay,\n SelectionBoxOverlay,\n timestampToBarIndex,\n barTimeStepMs,\n rangePresetStart,\n ReplayManager,\n ChartStateManager,\n UndoRedoManager,\n Animator,\n KeyboardHandler,\n CrosshairTooltip,\n PinnedTooltip,\n DataExporter,\n SessionBreaks,\n SessionShading,\n CompareRenderer,\n CurrentPriceLine,\n xToBarIndex,\n findDominantSwing,\n} from '@tradecanvas/core';\nimport type { ChartRendererInterface, RangePreset } from '@tradecanvas/core';\nimport { timeframeToMs } from '@tradecanvas/commons';\nimport { resolveRenderer, resolveDisplayData, isReshapedChartType } from './charts/ChartTypeStrategy.js';\nimport { computeIndicatorPriceRange } from './charts/IndicatorPriceRange.js';\nimport { AutoSaveScheduler } from './state/AutoSaveScheduler.js';\nimport { DataManager } from './DataManager.js';\nimport { ThemeManager } from './ThemeManager.js';\nimport { LayoutManager } from './layout/LayoutManager.js';\nimport { requiredPriceAxisWidth, nextPriceAxisWidth } from './layout/priceAxisWidth.js';\nimport { VerticalPanGate } from './interaction/verticalPanGate.js';\nimport { PluginManager } from './plugins/PluginManager.js';\nimport { wireExecution } from './trading/wireExecution.js';\nimport { overlaysForLayer, type ChartPlugin } from './plugins/contracts.js';\n\n// Replaced at build time by Vite `define` (see vite.config.ts). The `typeof`\n// guard keeps this safe when the source runs un-bundled (tests, ts-node).\ndeclare const __TC_VERSION__: string;\n\n/** Bar times at or below this are seconds, not milliseconds (as `normalizeBarTime`). */\nconst SECONDS_TIME_LIMIT = 1e12;\n\nexport class Chart {\n static version = typeof __TC_VERSION__ !== 'undefined' ? __TC_VERSION__ : '0.0.0-dev';\n\n private engine: RenderEngine;\n private viewport: Viewport;\n private dataManager: DataManager;\n private themeManager: ThemeManager;\n private layoutManager: LayoutManager;\n private pluginManager: PluginManager;\n private indicatorEngine: IndicatorEngine;\n private drawingManager: DrawingManager;\n private drawingRenderer: DrawingRenderer;\n private tradingManager: TradingManager;\n private tradingRenderer: TradingRenderer;\n private eventBus: EventBus;\n private streamManager: StreamManager | null = null;\n private executionAdapter: ExecutionAdapter | null = null;\n private execTeardown: (() => void) | null = null;\n private autoScrollOnNewBar = true;\n private displayDataCache: DataSeries | null = null;\n /** Earliest bar of an `indicatorUpdate` waiting to be emitted; null = none pending. */\n private indicatorUpdateFrom: number | null = null;\n private resolvedLayoutCache: import('@tradecanvas/commons').ResolvedLayout | null = null;\n private panelInfoCache: import('@tradecanvas/core').PanelRenderInfo[] | null = null;\n private renderScheduled = false;\n /** Current price-axis width; grows to fit long (e.g. sub-cent) labels. */\n private priceAxisWidth = PRICE_AXIS_WIDTH;\n private measureCtx: CanvasRenderingContext2D | null | undefined;\n private containerSizeCache: { width: number; height: number } | null = null;\n private containerSizeCacheTime = 0;\n // Last-emitted viewport values, used to fire visibleRangeChange /\n // priceRangeChange / zoomChange only when something actually moved.\n private lastEmittedRange: { from: number; to: number } | null = null;\n private lastEmittedPriceRange: { min: number; max: number } | null = null;\n private lastEmittedBarWidth: number | null = null;\n private chartLegend: ChartLegend;\n private watermark: Watermark;\n private barCountdown: BarCountdown;\n /**\n * Indicators of the loaded layout this chart could not add (an unknown or\n * not yet registered id, a whitelist): saved back as they were, so saving\n * the layout again doesn't drop them.\n */\n private unrestoredIndicators: import('@tradecanvas/core').SnapshotIndicator[] = [];\n /** Display timezone, minutes east of UTC; null = the browser's. */\n private displayTzOffset: number | null = null;\n private sessionBreaks: SessionBreaks;\n private sessionShading: SessionShading;\n private compareRenderer: CompareRenderer;\n private countdownInterval: ReturnType<typeof setInterval> | null = null;\n private volumeRenderer: VolumeRenderer;\n private volumeProfile: VolumeProfileRenderer;\n private marketProfile: MarketProfileRenderer;\n private depthHeatmap: DepthHeatmapRenderer;\n private periodLevels: PeriodLevelsRenderer;\n private pivotMarkers: PivotMarkersRenderer;\n private alertManager: AlertManager;\n private signalMarkerManager: SignalMarkerManager;\n private tradeZoneManager: TradeZoneManager;\n private measureOverlay: MeasureOverlay;\n private selectionBoxOverlay = new SelectionBoxOverlay();\n private replayManager: ReplayManager;\n private replayBarUnsub: (() => void) | null = null;\n /** True while `replaySeek` runs: its bar is a jump, not a replay step. */\n private replaySeeking = false;\n /**\n * While a replay runs, the live series keeps moving here — stream and\n * host updates land in `live` instead of the replayed slice — and comes\n * back on `replayStop()`. `price` is the latest live tick.\n */\n private replaySession: { live: DataManager; price: { price: number; previousClose?: number } | null } | null = null;\n private undoRedoManager: UndoRedoManager;\n private autoSaveScheduler = new AutoSaveScheduler((key) => this.saveState(key));\n private animator: Animator;\n private crosshairTooltip: CrosshairTooltip;\n private pinnedTooltip: PinnedTooltip;\n private interactionManager: InteractionManager;\n private crosshairHandler: CrosshairHandler;\n private chartRenderer: ChartRendererInterface;\n private gridRenderer: GridRenderer;\n private priceAxis: PriceAxis;\n private timeAxis: TimeAxis;\n private options: ChartOptions;\n private features: Required<FeaturesConfig>;\n private marketConfig: MarketConfig | null = null;\n private container: HTMLElement;\n private currentPriceLine: import('@tradecanvas/core').CurrentPriceLine;\n private numberLocale: string;\n /** The market's price precision, when set: otherwise it follows the visible range. */\n private marketPricePrecision: number | null = null;\n private paneTitles = true;\n /**\n * The `autoScale` the chart was constructed with — distinct from\n * `this.options.autoScale`, which drag-to-scale/vertical-pan mutate at\n * runtime to freeze the Y-axis. `setData()` restores this default so a\n * freeze on the old symbol doesn't silently carry over to a new one.\n */\n private defaultAutoScale: boolean;\n private keyboardHandler: KeyboardHandler | null = null;\n private onWindowKeyDown: ((e: KeyboardEvent) => void) | null = null;\n private currentSymbol: string = '';\n\n\n constructor(container: HTMLElement, options: ChartOptions & { plugins?: ChartPlugin[] }) {\n this.container = container;\n this.options = options;\n this.numberLocale = options.numberLocale ?? 'en-US';\n this.defaultAutoScale = options.autoScale !== false;\n\n // Resolve feature flags (all default to true)\n const f = options.features ?? {};\n this.features = {\n drawings: f.drawings ?? true,\n drawingTools: f.drawingTools ?? [],\n drawingMagnet: f.drawingMagnet ?? true,\n drawingUndoRedo: f.drawingUndoRedo ?? true,\n trading: f.trading ?? true,\n // Off by default: right-click is the browser's, and a stray right-click\n // shouldn't be one step from an order. Opt in with features.tradingContextMenu.\n tradingContextMenu: f.tradingContextMenu ?? false,\n indicators: f.indicators ?? true,\n indicatorIds: f.indicatorIds ?? [],\n panning: f.panning ?? true,\n zooming: f.zooming ?? true,\n crosshair: f.crosshair ?? true,\n crosshairTooltip: f.crosshairTooltip ?? true,\n keyboard: f.keyboard ?? true,\n priceAxis: f.priceAxis ?? true,\n timeAxis: f.timeAxis ?? true,\n grid: f.grid ?? (options.grid?.visible ?? true),\n legend: f.legend ?? true,\n volume: f.volume ?? true,\n watermark: f.watermark ?? true,\n saveLoad: f.saveLoad ?? true,\n screenshot: f.screenshot ?? true,\n alerts: f.alerts ?? true,\n replay: f.replay ?? true,\n sessionBreaks: f.sessionBreaks ?? true,\n barCountdown: f.barCountdown ?? true,\n compareSymbols: f.compareSymbols ?? true,\n dataExport: f.dataExport ?? true,\n logScale: f.logScale ?? true,\n timeframes: f.timeframes ?? [],\n defaultTimeframeFavorites: f.defaultTimeframeFavorites ?? [],\n };\n\n container.style.position = 'relative';\n container.style.overflow = 'hidden';\n container.tabIndex = 0; // Allow keyboard events\n container.style.outline = 'none';\n\n // Initialize managers\n this.dataManager = new DataManager();\n this.themeManager = new ThemeManager(options.theme);\n this.layoutManager = new LayoutManager();\n this.indicatorEngine = new IndicatorEngine();\n this.pluginManager = new PluginManager(this.indicatorEngine, { plugins: options.plugins });\n this.eventBus = new EventBus();\n\n registerBuiltInIndicators(this.indicatorEngine);\n\n // Drawing tools\n this.drawingManager = new DrawingManager();\n registerBuiltInDrawingTools(this.drawingManager);\n this.drawingRenderer = new DrawingRenderer(this.drawingManager);\n this.drawingManager.setRequestRender(() => {\n // Sync entire render context so drawings render with same viewport as candles\n this.syncRenderContext();\n this.engine.requestRender(LayerType.Overlay);\n this.scheduleAutoSave();\n });\n this.drawingManager.setEventCallback((event, data) => {\n this.eventBus.emit(event as ChartEventType, data);\n });\n // Pasted drawings obey the same switches as drawing tools.\n this.drawingManager.setToolFilter((type) =>\n this.features.drawings && (this.features.drawingTools.length === 0 || this.features.drawingTools.includes(type)));\n // Undo/redo\n this.undoRedoManager = new UndoRedoManager();\n this.drawingManager.setUndoRedoManager(this.undoRedoManager);\n this.drawingManager.setDataGetter(() => this.dataManager.getData());\n this.drawingManager.setDisplayDataGetter(() => this.getDisplayData());\n // Magnet mode\n if (options.crosshair?.mode === 'magnet' && this.features.drawingMagnet) {\n this.drawingManager.setMagnetMode('magnet');\n }\n\n // Trading\n this.tradingManager = new TradingManager({\n enabled: this.features.trading,\n contextMenu: { enabled: this.features.tradingContextMenu },\n });\n this.tradingRenderer = new TradingRenderer(this.tradingManager);\n this.tradingManager.setContainer(container);\n this.tradingManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\n this.tradingManager.setEventCallback((event, data) => {\n this.eventBus.emit(event as ChartEventType, data);\n });\n\n // Rendering\n this.engine = new RenderEngine(container);\n const size = this.engine.dprManager.getContainerSize();\n this.viewport = new Viewport(\n size.width,\n size.height,\n options.minBarSpacing ?? 2,\n options.maxBarSpacing ?? 30,\n options.rightMargin ?? 5,\n );\n this.viewport.setPanLimits({\n freePan: options.freePan ?? true,\n minVisibleBars: options.panLimits?.minVisibleBars ?? 3,\n });\n this.layoutManager.resize(size.width, size.height);\n\n // Sync viewport + layout when the container resizes. Without this hook\n // the chart's viewport keeps its construction-time chartRect forever\n // (which is wrong if the container started at 0 or got resized since),\n // and `scrollToEnd` / clampOffset compute against stale dimensions —\n // chart sticks at the wrong offset and the user can't scroll to the\n // latest bar.\n this.engine.onContainerResize = (newSize) => {\n if (newSize.width <= 0 || newSize.height <= 0) return;\n const wasAtEnd = this.viewport.isAtEnd();\n this.viewport.resize(newSize.width, newSize.height);\n this.layoutManager.resize(newSize.width, newSize.height);\n // wasAtEnd carries the user's intent: if they were tracking the live\n // edge before the resize, keep them there afterwards. Otherwise leave\n // their scroll position alone.\n this.updateViewportAndRender(wasAtEnd);\n };\n\n // Chart renderer\n this.chartRenderer = this.createChartRenderer(options.chartType);\n this.gridRenderer = new GridRenderer();\n if (options.grid?.visible === false) this.gridRenderer.setVisible(false);\n this.priceAxis = new PriceAxis();\n this.priceAxis.setLocale(this.numberLocale);\n this.timeAxis = new TimeAxis();\n\n // Crosshair\n this.crosshairHandler = new CrosshairHandler();\n this.crosshairHandler.setLocale(this.numberLocale);\n if (options.crosshair?.mode) {\n this.crosshairHandler.setMode(options.crosshair.mode);\n }\n // Crosshair callback — fired via microtask AFTER render, only when the bar\n // changes: no extra render requests, and the tooltip's one measurement\n // happens once per bar, not per mouse move.\n this.crosshairHandler.setCallback((barIndex, point) => {\n if (barIndex !== null && point) {\n const data = this.dataManager.getData();\n const bar = barIndex < data.length ? data[barIndex] : undefined;\n\n // Update legend (canvas-rendered, will show on next UI paint)\n this.chartLegend.setHoverBar(bar ?? null);\n\n // Update tooltip (DOM, lightweight update only when bar changes).\n // Over an indicator pane there is no price crosshair to sit beside.\n const vs = this.viewport.getState();\n const inPlot = point.y >= vs.chartRect.y && point.y <= vs.chartRect.y + vs.chartRect.height;\n if (bar && inPlot && this.features.crosshairTooltip) {\n this.crosshairTooltip.show(point, bar, this.themeManager.getTheme(), this.cachedContainerSize(), {\n prevClose: barIndex > 0 ? data[barIndex - 1]?.close : undefined,\n priceRange: vs.priceRange,\n plot: vs.chartRect,\n barStepMs: barTimeStepMs(data),\n });\n } else {\n this.crosshairTooltip.hide();\n }\n\n // Refresh the pinned tooltip's delta strip against the hovered bar.\n // Cheap when there's nothing pinned (early returns inside reposition).\n if (this.pinnedTooltip.isPinned()) {\n this.pinnedTooltip.reposition(\n this.viewport.getState(),\n bar ?? null,\n barIndex,\n this.themeManager.getTheme(),\n );\n }\n\n // Emit for external consumers\n this.eventBus.emit('crosshairMove', { point, bar, barIndex });\n } else {\n this.crosshairTooltip.hide();\n this.chartLegend.setHoverBar(null);\n this.eventBus.emit('crosshairLeave', {});\n }\n });\n\n // Chart legend (OHLCV overlay)\n this.chartLegend = new ChartLegend();\n this.chartLegend.setChartType(options.chartType);\n this.chartLegend.setLocale(this.numberLocale);\n\n // Watermark + Volume\n this.watermark = new Watermark();\n if (options.watermark) this.watermark.setConfig(options.watermark);\n this.volumeRenderer = new VolumeRenderer();\n this.volumeProfile = new VolumeProfileRenderer();\n this.marketProfile = new MarketProfileRenderer();\n this.depthHeatmap = new DepthHeatmapRenderer();\n this.periodLevels = new PeriodLevelsRenderer();\n this.pivotMarkers = new PivotMarkersRenderer();\n\n // Bar countdown timer\n this.barCountdown = new BarCountdown();\n this.barCountdown.setVisible(this.features.barCountdown);\n this.sessionBreaks = new SessionBreaks();\n this.sessionBreaks.setLocale(this.numberLocale);\n this.sessionShading = new SessionShading();\n this.compareRenderer = new CompareRenderer();\n\n // Apply session break config from options\n if (options.sessionBreaks) {\n this.sessionBreaks.setConfig({\n visible: options.sessionBreaks.visible ?? true,\n color: options.sessionBreaks.color,\n lineStyle: options.sessionBreaks.lineStyle,\n lineWidth: options.sessionBreaks.lineWidth,\n });\n } else if (options.features?.sessionBreaks !== false) {\n this.sessionBreaks.setVisible(true);\n }\n\n // Apply log scale from options\n if (options.logScale && this.features.logScale) {\n this.viewport.setLogScale(true);\n }\n\n // Animation\n this.animator = new Animator();\n\n // Crosshair tooltip (DOM)\n this.crosshairTooltip = new CrosshairTooltip();\n this.crosshairTooltip.create(container);\n this.crosshairTooltip.setLocale(this.numberLocale);\n this.pinnedTooltip = new PinnedTooltip();\n this.pinnedTooltip.create(container);\n\n // Keyboard navigation\n this.keyboardHandler = new KeyboardHandler({\n scrollBars: (count) => {\n const barUnit = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;\n this.viewport.scrollBy(count * barUnit);\n this.updateViewportAndRender();\n },\n zoom: (delta) => {\n const chartWidth = this.viewport.getState().chartRect.width;\n this.viewport.zoom(delta, chartWidth / 2);\n this.updateViewportAndRender();\n },\n goToStart: () => {\n this.viewport.scrollBy(-Infinity);\n this.updateViewportAndRender();\n },\n goToEnd: () => {\n this.viewport.scrollToEnd();\n this.updateViewportAndRender();\n },\n fitContent: () => this.fitContent(),\n });\n this.keyboardHandler.setEnabled(this.features.keyboard);\n\n // Attach keyboard listener to window. Only consume the event when the\n // chart actually handles the key AND the container is the focused element\n // (or an ancestor) — this prevents the chart from swallowing keystrokes\n // intended for inputs elsewhere on the page.\n this.onWindowKeyDown = (e: KeyboardEvent) => {\n if (!this.keyboardHandler) return;\n const active = document.activeElement as HTMLElement | null;\n if (active && active !== this.container && !this.container.contains(active)) {\n return;\n }\n // Ignore when typing in a form field that happens to live inside the chart.\n if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable)) {\n return;\n }\n if (this.keyboardHandler.handleKey(e)) {\n e.preventDefault();\n }\n };\n window.addEventListener('keydown', this.onWindowKeyDown);\n\n // Current price line (standalone, works without StreamManager)\n this.currentPriceLine = new CurrentPriceLine();\n this.currentPriceLine.setLocale(this.numberLocale);\n this.priceAxis.setReservedPriceProvider(() =>\n this.currentPriceLine.isVisible() ? this.currentPriceLine.getPrice() : null);\n\n // Alerts\n this.alertManager = new AlertManager();\n this.alertManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\n this.alertManager.on('triggered', (alert) => {\n const payload = { id: alert.id, price: alert.price, condition: alert.condition, message: alert.message, triggered: alert.triggered };\n this.eventBus.emit('alertTriggered', payload);\n // Back-compat: legacy listeners keyed off dataUpdate.\n this.eventBus.emit('dataUpdate', { alert: 'triggered', alertId: alert.id, price: alert.price, message: alert.message });\n });\n this.alertManager.on('added', (alert) => {\n this.eventBus.emit('alertAdd', { id: alert.id, price: alert.price, condition: alert.condition, message: alert.message, triggered: alert.triggered });\n });\n this.alertManager.on('removed', (id) => {\n this.eventBus.emit('alertRemove', { id });\n });\n this.alertManager.on('updated', (alert) => {\n this.eventBus.emit('alertUpdate', { id: alert.id, price: alert.price, condition: alert.condition, message: alert.message, triggered: alert.triggered });\n });\n\n // Signal markers\n this.signalMarkerManager = new SignalMarkerManager();\n this.signalMarkerManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\n this.signalMarkerManager.setDataGetter(() => this.dataManager.getData());\n this.signalMarkerManager.on('added', (m) => {\n this.eventBus.emit('signalMarkerAdd' as ChartEventType, { id: m.id, source: m.source, direction: m.direction });\n });\n this.signalMarkerManager.on('removed', (id) => {\n this.eventBus.emit('signalMarkerRemove' as ChartEventType, { id });\n });\n\n // Trade zones\n this.tradeZoneManager = new TradeZoneManager();\n this.tradeZoneManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\n this.tradeZoneManager.setDataGetter(() => this.dataManager.getData());\n this.tradeZoneManager.on('added', (z) => {\n this.eventBus.emit('tradeZoneAdd' as ChartEventType, { id: z.id, direction: z.direction });\n });\n this.tradeZoneManager.on('removed', (id) => {\n this.eventBus.emit('tradeZoneRemove' as ChartEventType, { id });\n });\n\n // Replay\n this.replayManager = new ReplayManager();\n\n // Measure overlay (shift-drag ruler)\n this.measureOverlay = new MeasureOverlay();\n\n // Interaction\n this.interactionManager = new InteractionManager(container);\n if (this.features.panning) {\n // Decides per gesture when a drag also moves the price scale.\n const verticalGate = new VerticalPanGate();\n this.interactionManager.setPanHandler(\n new PanHandler(\n (deltaX, deltaY) => {\n if (deltaX) this.viewport.scrollBy(deltaX);\n\n // Grab-and-drag the price scale vertically. Auto-scale would just\n // recompute the range on the next frame, so engaging the drag\n // turns it off (double-click the price axis to restore), mirroring\n // the price-axis drag-scale gesture.\n if (verticalGate.step(deltaX, deltaY, this.options.autoScale !== false) && deltaY) {\n this.options.autoScale = false;\n this.viewport.panPriceRange(deltaY);\n }\n\n this.updateViewportAndRender();\n },\n () => verticalGate.reset(),\n ),\n );\n }\n if (this.features.zooming) {\n this.interactionManager.setZoomHandler(\n new ZoomHandler((delta, centerX) => {\n this.viewport.zoom(delta, centerX);\n this.updateViewportAndRender();\n }),\n );\n\n // Axis drag-scaling:\n // drag price axis → scalePriceRange(factor), disables autoScale\n // drag time axis → zoom around chart center\n // dblclick axis → reset (price: re-enable autoScale; time: fitContent)\n const axisDrag = new AxisDragHandler(\n (factor) => {\n this.options.autoScale = false;\n this.viewport.scalePriceRange(factor);\n this.syncRenderContext();\n this.engine.requestRender();\n this.emitViewportEvents();\n },\n (factor) => {\n const cw = this.viewport.getState().chartRect.width;\n // factor > 1 means zoom OUT (compress time). Map to negative delta\n // because Viewport.zoom uses (1 + delta) on barWidth — positive\n // delta zooms in.\n this.viewport.zoom(1 / factor - 1, cw / 2);\n this.updateViewportAndRender();\n },\n );\n this.interactionManager.setAxisDragHandler(\n axisDrag,\n () => this.viewport.getState(),\n (axis) => {\n if (axis === 'price') {\n this.options.autoScale = true;\n this.updateViewportAndRender();\n } else {\n this.fitContent();\n }\n },\n );\n }\n if (this.features.crosshair) {\n this.interactionManager.setCrosshairHandler(this.crosshairHandler);\n }\n if (this.features.drawings) {\n this.interactionManager.setDrawingManager(\n this.drawingManager,\n // Inject current data so drawing anchors are stored/resolved as real\n // timestamps (survives timeframe/symbol switches).\n () => ({ ...this.viewport.getState(), data: this.getDisplayData() }),\n );\n }\n if (this.features.trading) {\n this.interactionManager.setTradingManager(\n this.tradingManager,\n () => ({ ...this.viewport.getState(), data: this.getDisplayData() }),\n );\n }\n if (this.features.alerts) {\n const alertDrag = new AlertDragHandler(this.alertManager, () => this.viewport.getState());\n this.interactionManager.setAlertDragHandler(alertDrag);\n }\n\n // Drag pane dividers to resize indicator panels.\n const paneResize = new PaneResizeHandler();\n paneResize.configure(\n () => this.getResolvedLayout(),\n (panelId, size) => this.setPanelSize(panelId, size),\n );\n this.interactionManager.setPaneResizeHandler(paneResize);\n // Alt-click pins the OHLC tooltip at the bar under the cursor. Hitting\n // it a second time on the same bar unpins.\n this.interactionManager.setAltClickHandler((pos) => {\n const data = this.getDisplayData();\n if (data.length === 0) return;\n const vp = this.viewport.getState();\n const barUnit = vp.barWidth + vp.barSpacing;\n const idx = Math.round((vp.offset + pos.x) / barUnit);\n if (idx < 0 || idx >= data.length) return;\n if (this.pinnedTooltip.isPinned() && this.pinnedTooltip.getPinnedIndex() === idx) {\n this.pinnedTooltip.unpin();\n } else {\n this.pinnedTooltip.pin(data[idx], idx, this.themeManager.getTheme());\n }\n this.pinnedTooltip.reposition(\n this.viewport.getState(),\n this.dataManager.getData()[idx] ?? null,\n idx,\n this.themeManager.getTheme(),\n );\n this.engine.requestRender(LayerType.Overlay);\n });\n\n this.interactionManager.setClickHandler((pos) => {\n const data = this.getDisplayData();\n this.eventBus.emit('click', { x: pos.x, y: pos.y });\n if (data.length === 0) return;\n // Canonical bar mapping (accounts for chartRect.x + bar centering) so the\n // clicked bar matches the crosshair / drawings.\n const idx = xToBarIndex(pos.x, this.viewport.getState());\n if (idx < 0 || idx >= data.length) return;\n this.eventBus.emit('barClick', { bar: data[idx], barIndex: idx, point: pos });\n });\n\n this.interactionManager.setEscapeHandler(() => {\n if (this.features.trading && this.tradingManager.isBracketActive()) {\n this.tradingManager.cancelBracket();\n this.eventBus.emit('dataUpdate', { bracket: 'cancelled' });\n return;\n }\n if (this.pinnedTooltip.isPinned()) {\n this.pinnedTooltip.unpin();\n this.engine.requestRender(LayerType.Overlay);\n }\n });\n\n this.interactionManager.setConfirmHandler(() => {\n if (this.features.trading && this.tradingManager.isBracketActive()) {\n this.tradingManager.confirmBracket();\n return true;\n }\n return false;\n });\n\n // Shift-drag measure tool — transient overlay. Coords resolved via\n // viewport + displayData so the ruler sticks to the data during zoom.\n this.interactionManager.setMeasureHandlers({\n begin: (pos) => {\n this.measureOverlay.begin(pos, this.viewport.getState(), this.getDisplayData());\n },\n move: (pos) => {\n this.measureOverlay.update(pos, this.viewport.getState(), this.getDisplayData());\n },\n end: () => {\n this.measureOverlay.end();\n },\n });\n\n // Ctrl/⌘-drag: select every drawing the box covers; Ctrl/⌘-click adds or\n // removes one. The box is kept inside the plot (moves are followed\n // off-chart), so the selection matches what the box showed.\n const inPlot = (pos: { x: number; y: number }) => {\n const r = this.viewport.getState().chartRect;\n return {\n x: Math.max(r.x, Math.min(r.x + r.width, pos.x)),\n y: Math.max(r.y, Math.min(r.y + r.height, pos.y)),\n };\n };\n this.interactionManager.setBoxSelectHandlers({\n begin: (pos) => this.selectionBoxOverlay.begin(inPlot(pos)),\n move: (pos) => this.selectionBoxOverlay.update(inPlot(pos)),\n end: () => {\n const box = this.selectionBoxOverlay.end();\n if (!box || !this.features.drawings) return;\n // With the bar series, so anchors resolve as timestamps (as for drawing hit-tests).\n const vs = { ...this.viewport.getState(), data: this.getDisplayData() };\n if (box.isClick) this.drawingManager.toggleSelectionAt({ x: box.x1, y: box.y1 }, vs);\n else this.drawingManager.selectInRect(box, vs);\n this.engine.requestRender(LayerType.Overlay);\n },\n cancel: () => this.selectionBoxOverlay.cancel(),\n });\n\n // A plain hover only moves pointer-tied visuals (crosshair, its axis\n // pills, measure ruler, selection box): repaint just the top canvas.\n this.interactionManager.setOverlayDirtyCallback((hoverOnly) => {\n this.engine.requestRender(hoverOnly ? LayerType.Hover : LayerType.Overlay);\n });\n this.interactionManager.attach();\n\n // Set render context\n this.syncRenderContext();\n this.engine.start();\n }\n\n // --- Data ---\n\n setData(data: DataSeries): void {\n // A full replace is a new series: any replay of the old one ends.\n this.endReplaySession();\n this.dataManager.setData(data);\n this.crosshairHandler.setData(this.dataManager.getData());\n this.displayDataCache = null;\n this.sessionBreaks.invalidateCache();\n // A full data replace means a new series (symbol/timeframe switch, not\n // a live tick — those go through appendBar/updateLastBar instead), so\n // un-freeze the Y-axis the same way scrollToEnd below resets the X-axis.\n // Otherwise a price-axis drag or vertical pan on the old symbol silently\n // keeps the new symbol's chart stuck on the old price range.\n this.options.autoScale = this.defaultAutoScale;\n // New data context (symbol / timeframe) — drop stale alert prev-values so\n // the next tick seeds cleanly instead of crossing against the old series.\n this.alertManager.clearLastValues();\n this.recalcIndicators(this.dataManager.getData());\n // Auto-set current price line from last bar's close\n if (data.length > 0) {\n this.currentPriceLine.setPrice(data[data.length - 1].close);\n }\n this.updateViewportAndRender(true);\n this.eventBus.emit('dataUpdate', { length: data.length });\n }\n\n appendBar(bar: OHLCBar): void {\n if (this.replaySession) {\n this.replaySession.live.appendBar(bar);\n return;\n }\n // Follow the live edge only if the view is already there — browsing\n // history shouldn't be yanked back to the end on every new bar.\n const follow = this.autoScrollOnNewBar && this.viewport.isAtEnd();\n this.dataManager.appendBar(bar);\n const data = this.dataManager.getData();\n this.crosshairHandler.setData(data);\n this.displayDataCache = null;\n // Re-finalise the bar that just closed (its last tick may differ from the\n // final close) and compute the new one; everything older is untouched.\n this.recalcIndicatorsFrom(data, data.length - 2);\n this.updateViewportAndRender(follow);\n }\n\n /**\n * Append multiple bars at once (e.g., catch-up after reconnect).\n * More efficient than calling appendBar() in a loop — recalculates\n * indicators only once at the end.\n */\n appendBars(bars: OHLCBar[]): void {\n if (bars.length === 0) return;\n if (this.replaySession) {\n for (const bar of bars) this.replaySession.live.appendBar(bar);\n return;\n }\n const follow = this.viewport.isAtEnd();\n const firstChanged = this.dataManager.getLength() - 1;\n for (const bar of bars) {\n this.dataManager.appendBar(bar);\n }\n this.displayDataCache = null;\n this.recalcIndicatorsFrom(this.dataManager.getData(), firstChanged);\n this.crosshairHandler.setData(this.dataManager.getData());\n this.updateViewportAndRender(follow);\n }\n\n updateLastBar(bar: OHLCBar): void {\n if (this.replaySession) {\n this.replaySession.live.updateLastBar(bar);\n return;\n }\n this.dataManager.updateLastBar(bar);\n this.currentPriceLine.setPrice(bar.close);\n // For non-transform chart types, the displayDataCache still points to the\n // same raw array (mutated in place), so no need to invalidate.\n // Only invalidate for transform types that produce derived arrays.\n if (this.options.chartType !== 'candlestick' && this.options.chartType !== 'line'\n && this.options.chartType !== 'area' && this.options.chartType !== 'bar'\n && this.options.chartType !== 'hollowCandle') {\n this.displayDataCache = null;\n }\n // Keep indicator lines in sync with the forming bar. Without this, panel\n // + overlay indicators freeze until bar close. Only the last bar changed.\n const data = this.dataManager.getData();\n this.recalcIndicatorsFrom(data, data.length - 1);\n this.scheduleRender();\n }\n\n /** Merge a price tick into the current last bar (convenience for live feeds) */\n updateLastBarFromTick(tick: { price: number; volume?: number; time: number }): void {\n if (this.replaySession) {\n this.replaySession.live.updateLastBarFromTick(tick);\n if (Number.isFinite(tick.price)) this.replaySession.price = { price: tick.price };\n return;\n }\n this.dataManager.updateLastBarFromTick(tick);\n this.currentPriceLine.setPrice(tick.price);\n if (this.options.chartType !== 'candlestick' && this.options.chartType !== 'line'\n && this.options.chartType !== 'area' && this.options.chartType !== 'bar'\n && this.options.chartType !== 'hollowCandle') {\n this.displayDataCache = null;\n }\n const data = this.dataManager.getData();\n this.recalcIndicatorsFrom(data, data.length - 1);\n this.scheduleRender();\n }\n\n // --- Chart type ---\n\n setChartType(type: ChartType | (string & {})): void {\n this.options.chartType = type as ChartType;\n this.chartRenderer = this.createChartRenderer(type);\n this.chartLegend.setChartType(type as ChartType);\n this.displayDataCache = null;\n this.updateViewportAndRender(true);\n }\n\n // --- Indicators ---\n\n addIndicator(id: string, params: Record<string, number | string | boolean> = {}, position: PanelPosition = 'bottom'): string | null {\n if (!this.features.indicators) return null;\n if (this.features.indicatorIds.length > 0 && !this.features.indicatorIds.includes(id)) return null;\n const instanceId = this.indicatorEngine.addIndicator(id, params, this.dataManager.getData());\n const descriptor = this.indicatorEngine.getAvailableIndicators().find((d) => d.id === id);\n if (descriptor?.placement === 'panel') {\n this.layoutManager.addPanel(instanceId, position);\n // Panel layout changed — must re-resolve layout, update viewport, and sync render context\n this.updateViewportAndRender();\n } else {\n this.engine.requestRender();\n }\n this.eventBus.emit('indicatorAdd', { instanceId, id });\n this.scheduleAutoSave();\n return instanceId;\n }\n\n updateIndicator(instanceId: string, params: Record<string, number | string | boolean>): void {\n this.indicatorEngine.updateIndicator(instanceId, params, this.dataManager.getData());\n this.announceIndicatorUpdate(0);\n this.engine.requestRender();\n this.scheduleAutoSave();\n }\n\n removeIndicator(instanceId: string): void {\n const hadPanel = this.layoutManager.getPanels().some(p => p.id === instanceId);\n this.indicatorEngine.removeIndicator(instanceId);\n this.layoutManager.removePanel(instanceId);\n this.eventBus.emit('indicatorRemove', { instanceId });\n this.scheduleAutoSave();\n if (hadPanel) {\n this.updateViewportAndRender();\n } else {\n this.engine.requestRender();\n }\n }\n\n /** The colours, line widths and opacity an indicator draws with (a copy), or null. */\n getIndicatorStyle(instanceId: string): ResolvedIndicatorStyle | null {\n return this.indicatorEngine.getIndicatorStyle(instanceId);\n }\n\n getIndicatorOutput(instanceId: string): IndicatorOutput | null {\n return this.indicatorEngine.getOutput(instanceId);\n }\n\n registerIndicator(plugin: IndicatorPlugin): void {\n this.pluginManager.registerIndicator(plugin);\n }\n\n /** The chart's plugin registry — register custom indicators / drawings / chart types / overlays. */\n get plugins(): PluginManager {\n return this.pluginManager;\n }\n\n static indicators(): IndicatorDescriptor[] {\n const engine = new IndicatorEngine();\n registerBuiltInIndicators(engine);\n return engine.getAvailableIndicators();\n }\n\n // --- Panel layout ---\n\n setPanelPosition(instanceId: string, position: PanelPosition): void {\n this.layoutManager.setPanelPosition(instanceId, position);\n this.engine.requestRender();\n }\n\n setPanelSize(instanceId: string, size: number): void {\n this.layoutManager.setPanelSize(instanceId, size);\n this.updateViewportAndRender();\n this.eventBus.emit('paneResize', { instanceId, size });\n }\n\n /**\n * Indicator panes, in CSS pixels relative to the container: the whole pane,\n * its 20 px header (where the name is written) included.\n */\n getIndicatorPanes(): { instanceId: string; rect: { x: number; y: number; width: number; height: number } }[] {\n return this.buildPanelRenderInfos().map((p) => ({ instanceId: p.instanceId, rect: { ...p.rect } }));\n }\n\n /** Write each pane's indicator name and hovered values in its header (default); off when you label panes yourself. */\n setPaneTitlesVisible(visible: boolean): void {\n this.paneTitles = visible;\n this.engine.requestRender();\n }\n\n /**\n * The y (CSS px, container-relative) just below the OHLCV legend — where\n * content stacked under it starts. The plot's top edge when it is hidden.\n */\n getLegendBottom(): number {\n const top = this.viewport.getState().chartRect.y;\n return this.features.legend ? top + this.chartLegend.getHeight() : top;\n }\n\n /**\n * Whether each drawn bar is one data bar (candles, lines, Heikin-Ashi…).\n * Renko, Kagi, point & figure, line break and range bars redraw the series,\n * so a bar index on screen is not an index into the data.\n */\n isTimeAligned(): boolean {\n if (isReshapedChartType(this.options.chartType)) return false;\n return this.getDisplayData().length === this.dataManager.getLength();\n }\n\n /** A price as the price axis writes it: the market's precision or the visible range's, in the number locale. */\n formatPrice(price: number): string {\n const { min, max } = this.viewport.getState().priceRange;\n return formatPrice(price, this.marketPricePrecision ?? autoPricePrecision(min, max), this.numberLocale);\n }\n\n // --- Drawing tools ---\n\n setDrawingTool(type: DrawingToolType | null): void {\n if (!this.features.drawings) return;\n // If whitelist is set, check it\n if (type && this.features.drawingTools.length > 0 && !this.features.drawingTools.includes(type)) return;\n this.drawingManager.setActiveTool(type);\n }\n\n getDrawingTool(): DrawingToolType | null {\n return this.drawingManager.getActiveTool();\n }\n\n /** Keep the drawing tool after each drawing, to draw several in a row (Esc ends). */\n setStayInDrawingMode(enabled: boolean): void {\n this.drawingManager.setStayInDrawingMode(enabled);\n }\n\n isStayInDrawingMode(): boolean {\n return this.drawingManager.isStayInDrawingMode();\n }\n\n /** Copy the selected drawings (also Ctrl/⌘+C on the chart). Returns how many. */\n copyDrawings(): number {\n return this.drawingManager.copySelection();\n }\n\n /**\n * Paste copied drawings (also Ctrl/⌘+V) — from this chart or another one on\n * the page. Returns the new drawings' ids.\n */\n pasteDrawings(): string[] {\n if (!this.features.drawings) return [];\n return this.drawingManager.paste();\n }\n\n setDrawingStyle(style: Partial<DrawingStyle>): void {\n this.drawingManager.setStyle(style);\n }\n\n getDrawingStyle(): DrawingStyle {\n return this.drawingManager.getActiveStyle();\n }\n\n getSelectedDrawingId(): string | null {\n return this.drawingManager.getSelectedDrawingId();\n }\n\n /** Restyle the selected drawing (or one by id). Returns true if applied. */\n setSelectedDrawingStyle(style: Partial<DrawingStyle>, id?: string): boolean {\n return this.drawingManager.setSelectedDrawingStyle(style, id);\n }\n\n getDrawings(): DrawingState[] {\n return this.drawingManager.getDrawings();\n }\n\n setDrawings(drawings: DrawingState[]): void {\n this.drawingManager.setDrawings(drawings);\n }\n\n /** Append a drawing (id auto-assigned, active style applied). Returns the id. */\n addDrawing(state: {\n type: import('@tradecanvas/commons').DrawingToolType;\n anchors: import('@tradecanvas/commons').AnchorPoint[];\n style?: Partial<DrawingStyle>;\n visible?: boolean;\n locked?: boolean;\n meta?: Record<string, unknown>;\n }): string | null {\n if (!this.features.drawings) return null;\n const id = this.drawingManager.addDrawing(state);\n this.scheduleAutoSave();\n return id;\n }\n\n /**\n * Draw a Fibonacci retracement over the dominant swing (extreme high/low) in\n * the visible range. Returns the new drawing's id, or null if no swing.\n */\n autoFib(): string | null {\n if (!this.features.drawings) return null;\n const data = this.getDisplayData();\n const vs = this.viewport.getState();\n const swing = findDominantSwing(data, vs.visibleRange.from, vs.visibleRange.to);\n if (!swing) return null;\n return this.addDrawing({ type: 'fibRetracement', anchors: [swing[0], swing[1]] });\n }\n\n removeDrawing(id: string): void {\n this.drawingManager.removeDrawing(id);\n }\n\n setDrawingVisible(id: string, visible: boolean): void {\n this.drawingManager.setDrawingVisible(id, visible);\n }\n\n setDrawingLocked(id: string, locked: boolean): void {\n this.drawingManager.setDrawingLocked(id, locked);\n }\n\n clearDrawings(): void {\n this.drawingManager.clearDrawings();\n }\n\n registerDrawingTool(plugin: DrawingPlugin): void {\n this.drawingManager.register(plugin);\n }\n\n // --- Undo/Redo ---\n\n undo(): boolean {\n if (!this.features.drawingUndoRedo) return false;\n return this.drawingManager.undo();\n }\n\n redo(): boolean {\n if (!this.features.drawingUndoRedo) return false;\n return this.drawingManager.redo();\n }\n\n getUndoRedoState(): { canUndo: boolean; canRedo: boolean } {\n return this.undoRedoManager.getState();\n }\n\n // --- Drawing magnet ---\n\n /** Ignored (stays off) when `features.drawingMagnet` is false. */\n setDrawingMagnet(enabled: boolean): void {\n this.drawingManager.setMagnetMode(enabled && this.features.drawingMagnet ? 'magnet' : 'none');\n }\n\n getDrawingMagnet(): boolean {\n return this.drawingManager.getMagnetMode() === 'magnet';\n }\n\n // --- Bulk drawing operations ---\n\n lockAllDrawings(): void {\n this.drawingManager.lockAllDrawings();\n }\n\n unlockAllDrawings(): void {\n this.drawingManager.unlockAllDrawings();\n }\n\n hideAllDrawings(): void {\n this.drawingManager.hideAllDrawings();\n }\n\n showAllDrawings(): void {\n this.drawingManager.showAllDrawings();\n }\n\n // --- Drawing duplication ---\n\n duplicateDrawing(id?: string): string | null {\n const targetId = id ?? this.drawingManager.getSelectedDrawingId();\n if (!targetId) return null;\n return this.drawingManager.duplicateDrawing(targetId);\n }\n\n // --- Data export ---\n\n /** Does nothing when `features.dataExport` is false. */\n exportVisibleData(format: 'csv' | 'json' = 'csv', filename?: string): void {\n if (!this.features.dataExport) return;\n const vp = this.viewport.getState();\n const data = this.dataManager.getData();\n const from = Math.max(0, vp.visibleRange.from);\n const to = Math.min(data.length - 1, vp.visibleRange.to);\n const slice = data.slice(from, to + 1);\n\n if (format === 'json') {\n const content = DataExporter.toJSON(slice);\n DataExporter.download(content, filename ?? 'chart-data.json', 'application/json');\n } else {\n const content = DataExporter.toCSV(slice);\n DataExporter.download(content, filename ?? 'chart-data.csv', 'text/csv');\n }\n }\n\n /** Does nothing when `features.dataExport` is false. */\n exportAllData(format: 'csv' | 'json' = 'csv', filename?: string): void {\n if (!this.features.dataExport) return;\n const data = this.dataManager.getData();\n if (format === 'json') {\n const content = DataExporter.toJSON(data);\n DataExporter.download(content, filename ?? 'chart-data.json', 'application/json');\n } else {\n const content = DataExporter.toCSV(data);\n DataExporter.download(content, filename ?? 'chart-data.csv', 'text/csv');\n }\n }\n\n // --- Auto-save ---\n\n setAutoSave(key: string, delayMs = 5000): void {\n this.autoSaveScheduler.enable(key, delayMs);\n }\n\n disableAutoSave(): void {\n this.autoSaveScheduler.disable();\n }\n\n private scheduleAutoSave(): void {\n this.autoSaveScheduler.schedule();\n }\n\n // --- Indicator introspection ---\n\n getAvailableIndicators(): IndicatorDescriptor[] {\n return this.indicatorEngine.getAvailableIndicators();\n }\n\n getIndicatorInputs(id: string): { id: string; params: Record<string, unknown> } | null {\n const indicators = this.indicatorEngine.getAvailableIndicators();\n const desc = indicators.find(i => i.id === id);\n if (!desc) return null;\n return { id: desc.id, params: desc.defaultConfig };\n }\n\n /** Get all active indicator instances with their current params */\n getActiveIndicators(): { instanceId: string; id: string; params: Record<string, unknown>; descriptor: IndicatorDescriptor; visible: boolean }[] {\n return this.indicatorEngine.getActiveIndicators();\n }\n\n /** Show or hide an indicator without removing it. */\n setIndicatorVisible(instanceId: string, visible: boolean): void {\n if (this.indicatorEngine.setVisible(instanceId, visible) !== null) {\n this.updateViewportAndRender();\n this.scheduleAutoSave();\n }\n }\n\n /** Get current config for a specific indicator instance */\n getIndicatorConfig(instanceId: string): { id: string; params: Record<string, unknown> } | null {\n const config = this.indicatorEngine.getIndicatorConfig(instanceId);\n if (!config) return null;\n return { id: config.id, params: { ...config.params } };\n }\n\n /** Update indicator colors/line widths at runtime */\n updateIndicatorStyle(instanceId: string, style: { colors?: string[]; lineWidths?: number[]; opacity?: number }): void {\n this.indicatorEngine.updateIndicatorStyle(instanceId, style);\n this.engine.requestRender();\n this.scheduleAutoSave();\n }\n\n // --- Trading ---\n\n setOrders(orders: TradingOrder[]): void {\n if (!this.features.trading) return;\n this.tradingManager.setOrders(orders);\n }\n\n /**\n * Begin placing a draggable bracket order (entry + stop-loss + take-profit).\n * Defaults the entry to the latest close when `entry` is omitted. Drag the\n * three lines to adjust; confirm with Enter (emits `bracketPlace`) or cancel\n * with Esc. Returns false if trading is disabled or no price is available.\n */\n startBracket(side: import('@tradecanvas/commons').OrderSide, entry?: number): boolean {\n if (!this.features.trading) return false;\n const data = this.dataManager.getData();\n const price = entry ?? (data.length > 0 ? data[data.length - 1].close : null);\n if (price === null) return false;\n this.tradingManager.startBracket(side, price);\n return true;\n }\n\n cancelBracket(): void {\n if (this.features.trading) this.tradingManager.cancelBracket();\n }\n\n confirmBracket(): boolean {\n return this.features.trading ? this.tradingManager.confirmBracket() : false;\n }\n\n isBracketActive(): boolean {\n return this.features.trading && this.tradingManager.isBracketActive();\n }\n\n /**\n * Begin a drag-to-create single order at `price` (default: latest close) for\n * `side`. Drag the line to a level — the order type (limit/stop) is inferred\n * from the level vs the current price. Confirm with `confirmOrderDraft()`\n * (emits `orderPlace`) or cancel with `cancelOrderDraft()`. Returns false if\n * trading is disabled or no price is available.\n */\n startOrderDraft(side: import('@tradecanvas/commons').OrderSide, price?: number): boolean {\n if (!this.features.trading) return false;\n const data = this.dataManager.getData();\n const p = price ?? (data.length > 0 ? data[data.length - 1].close : null);\n if (p === null) return false;\n this.tradingManager.startOrderDraft(side, p);\n return true;\n }\n\n cancelOrderDraft(): void {\n if (this.features.trading) this.tradingManager.cancelOrderDraft();\n }\n\n confirmOrderDraft(): boolean {\n return this.features.trading ? this.tradingManager.confirmOrderDraft() : false;\n }\n\n isOrderDraftActive(): boolean {\n return this.features.trading && this.tradingManager.isOrderDraftActive();\n }\n\n /**\n * Emit an `orderPlace` intent (e.g. from a depth-ladder click). The chart\n * does not create the order itself — the host listens via\n * `chart.on('orderPlace', …)` and submits to its OMS.\n */\n placeOrderIntent(intent: import('@tradecanvas/commons').OrderPlaceIntent): void {\n if (!this.features.trading) return;\n this.eventBus.emit('orderPlace', intent);\n }\n\n setPositions(positions: TradingPosition[]): void {\n if (!this.features.trading) return;\n this.tradingManager.setPositions(positions);\n }\n\n setDepthData(depth: DepthData | null): void {\n if (!this.features.trading) return;\n this.tradingManager.setDepthData(depth);\n }\n\n setCurrentPrice(price: number, _pulseColor?: string): void {\n this.tradingManager.setCurrentPrice(price);\n if (this.replaySession) {\n // During a replay the price line shows the replayed close; the live\n // price comes back with replayStop(). Orders and alerts stay live.\n this.replaySession.price = { price };\n } else {\n // Also update standalone price line (visible even without trading feature)\n this.currentPriceLine.setPrice(price);\n this.scheduleRender();\n }\n if (this.features.alerts) {\n this.alertManager.checkPrice(price);\n this.feedIndicatorAlerts();\n }\n }\n\n /**\n * Feed the latest indicator-line values to any indicator-channel alerts.\n * Channel format: `<instanceId>:<key>`; instanceIds are `tc_<id>_<n>` and\n * built-in keys are colon-free, so the first colon splits them. Values come\n * from the recalculated series, so indicator alerts evaluate at bar cadence\n * (the live intrabar tick doesn't repaint closed-bar indicator values).\n * Cheap — only walks alerts whose channel isn't `'price'`, usually none.\n */\n private feedIndicatorAlerts(): void {\n const alerts = this.alertManager.getAlerts();\n const data = this.dataManager.getData();\n if (data.length === 0) return;\n const lastIdx = data.length - 1;\n const seen = new Set<string>();\n for (const alert of alerts) {\n if (alert.channel === 'price' || seen.has(alert.channel)) continue;\n seen.add(alert.channel);\n const sep = alert.channel.indexOf(':');\n if (sep < 0) continue;\n const instanceId = alert.channel.slice(0, sep);\n const key = alert.channel.slice(sep + 1);\n const point = this.indicatorEngine.getOutput(instanceId)?.series?.[lastIdx];\n const value = point?.[key];\n if (typeof value === 'number' && Number.isFinite(value)) {\n this.alertManager.checkChannel(alert.channel, value);\n }\n }\n }\n\n setTradingConfig(config: Partial<TradingConfig>): void {\n if (!this.features.trading) return;\n this.tradingManager.setConfig(config);\n }\n\n // --- Real-time Streaming ---\n\n /**\n * Connect to a real-time data source.\n * Loads history, starts streaming, manages reconnection automatically.\n *\n * @example\n * import { BinanceAdapter } from '@tradecanvas/core';\n * chart.connect({\n * adapter: new BinanceAdapter(),\n * symbol: 'BTCUSDT',\n * timeframe: '1m',\n * });\n */\n async connect(config: StreamConfig): Promise<void> {\n // Back to the live series first, so a failed history load can't leave\n // the replayed slice on screen.\n this.replayStop();\n this.disconnectStream();\n\n this.streamManager = new StreamManager();\n\n this.streamManager.on('snapshot', (bars) => {\n if (this.replaySession) {\n this.replaySession.live.setData(bars);\n return;\n }\n this.setData(bars);\n });\n\n this.streamManager.on('barClose', (bar) => {\n if (this.replaySession) {\n this.replaySession.live.appendBar(bar);\n return;\n }\n const follow = this.autoScrollOnNewBar && this.viewport.isAtEnd();\n this.dataManager.appendBar(bar);\n const data = this.dataManager.getData();\n this.crosshairHandler.setData(data);\n this.displayDataCache = null;\n this.recalcIndicatorsFrom(data, data.length - 2);\n this.updateViewportAndRender(follow);\n });\n\n this.streamManager.on('barUpdate', (bar) => {\n if (this.replaySession) {\n this.replaySession.live.updateLastBar(bar);\n return;\n }\n this.dataManager.updateLastBar(bar);\n this.currentPriceLine.setPrice(bar.close);\n // Recalculate indicators so panel/overlay series track the forming bar\n // instead of freezing until bar close — incrementally, since only the\n // last bar changed.\n const data = this.dataManager.getData();\n this.recalcIndicatorsFrom(data, data.length - 1);\n this.scheduleRender();\n });\n\n this.streamManager.on('priceChange', ({ price, previousClose }) => {\n // Orders keep tracking the live market during a replay; the price line\n // shows the replayed close instead.\n this.tradingManager.setCurrentPrice(price);\n if (this.replaySession) {\n this.replaySession.price = { price, previousClose: previousClose ?? undefined };\n return;\n }\n this.currentPriceLine.setPrice(price, previousClose ?? undefined);\n this.engine.requestRender(LayerType.Overlay);\n });\n\n this.streamManager.on('connectionChange', (info) => {\n this.eventBus.emit('dataUpdate', { connection: info });\n });\n\n this.streamManager.on('error', (err) => {\n this.eventBus.emit('dataUpdate', { error: err.message });\n });\n\n this.autoScrollOnNewBar = config.autoScroll !== false;\n this.currentSymbol = config.symbol;\n\n const manager = this.streamManager;\n await manager.connect(config);\n // Superseded by a newer connect() (fast symbol/timeframe switching) or a\n // disconnect while history was loading — leave the countdown to it.\n if (this.streamManager !== manager) return;\n\n // Set up bar countdown timer based on timeframe\n const tfMs = timeframeToMs(config.timeframe);\n this.barCountdown.setTimeframeMs(tfMs);\n\n // Start countdown refresh interval\n if (this.countdownInterval) clearInterval(this.countdownInterval);\n this.countdownInterval = setInterval(() => {\n if (this.barCountdown.isVisible()) {\n this.engine.requestRender(LayerType.Hover);\n }\n }, 1000);\n }\n\n /**\n * Switch symbol or timeframe on an active stream without full reconnect.\n */\n async switchStream(symbol: string, timeframe: TimeFrame): Promise<void> {\n if (!this.streamManager) return;\n this.currentSymbol = symbol;\n this.barCountdown.setTimeframeMs(timeframeToMs(timeframe));\n await this.streamManager.switchTo(symbol, timeframe);\n }\n\n /** False when `features.timeframes` is set and does not list `timeframe`. */\n isTimeframeAllowed(timeframe: TimeFrame): boolean {\n const allowed = this.features.timeframes;\n return allowed.length === 0 || allowed.includes(timeframe);\n }\n\n /**\n * Switch to a new timeframe. Requires an active stream connection.\n * Ignored when `features.timeframes` does not list it.\n * Internally calls switchStream with the current symbol.\n */\n async setTimeframe(timeframe: TimeFrame): Promise<void> {\n if (!this.streamManager) throw new Error('No active stream. Call connect() first.');\n if (!this.isTimeframeAllowed(timeframe)) return;\n await this.switchStream(this.currentSymbol, timeframe);\n }\n\n /**\n * Disconnect the real-time stream.\n */\n disconnectStream(): void {\n if (this.streamManager) {\n this.streamManager.dispose();\n this.streamManager = null;\n }\n }\n\n /**\n * Connect an execution adapter, turning the trading overlay into a live\n * trading surface. The adapter is the source of truth: the chart routes its\n * emitted order/position intents into the adapter and renders the\n * `orders` / `positions` the adapter emits back. With no adapter connected,\n * those intents remain plain events (the default). Listen for failures via\n * `chart.on('executionError', …)`.\n */\n connectExecution(adapter: ExecutionAdapter, config: ExecutionConfig = {}): void {\n if (!this.features.trading) {\n throw new Error('connectExecution requires features.trading to be enabled');\n }\n this.disconnectExecution();\n this.executionAdapter = adapter;\n this.execTeardown = wireExecution(adapter, {\n onIntent: (type, handler) => {\n const wrapped = (e: ChartEvent) => handler(e.payload);\n this.eventBus.on(type, wrapped);\n return () => this.eventBus.off(type, wrapped);\n },\n setOrders: (orders) => this.setOrders(orders),\n setPositions: (positions) => this.setPositions(positions),\n onError: (error) => this.eventBus.emit('executionError', error),\n });\n Promise.resolve(adapter.connect(config)).catch((cause) =>\n this.eventBus.emit('executionError', { message: 'Execution connect failed', cause }),\n );\n }\n\n /** Tear down the active execution adapter (if any) and stop routing intents. */\n disconnectExecution(): void {\n if (this.execTeardown) {\n this.execTeardown();\n this.execTeardown = null;\n }\n if (this.executionAdapter) {\n this.executionAdapter.disconnect();\n this.executionAdapter = null;\n }\n }\n\n /** The connected execution adapter, or null (e.g. for adapter-specific calls). */\n getExecutionAdapter(): ExecutionAdapter | null {\n return this.executionAdapter;\n }\n\n /** Ignored (stays hidden) when `features.barCountdown` is false. */\n setBarCountdownVisible(visible: boolean): void {\n this.barCountdown.setVisible(visible && this.features.barCountdown);\n this.engine.requestRender(LayerType.Hover);\n }\n\n setSessionBreaksVisible(visible: boolean): void {\n this.sessionBreaks.setVisible(visible);\n this.engine.requestRender(LayerType.Background);\n }\n\n // --- Compare symbols ---\n\n /** Does nothing when `features.compareSymbols` is false. */\n addCompareSymbol(id: string, label: string, data: DataSeries, color: string): void {\n if (!this.features.compareSymbols) return;\n this.compareRenderer.addSymbol({ id, label, data, color, visible: true });\n this.engine.requestRender(LayerType.Main);\n }\n\n removeCompareSymbol(id: string): void {\n this.compareRenderer.removeSymbol(id);\n this.engine.requestRender(LayerType.Main);\n }\n\n updateCompareData(id: string, data: DataSeries): void {\n this.compareRenderer.setSymbolData(id, data);\n this.engine.requestRender(LayerType.Main);\n }\n\n setCompareMode(mode: 'percent' | 'absolute'): void {\n this.compareRenderer.setMode(mode);\n this.engine.requestRender(LayerType.Main);\n }\n\n clearCompareSymbols(): void {\n this.compareRenderer.clear();\n this.engine.requestRender(LayerType.Main);\n }\n\n // --- Price scale ---\n\n /** Turning it on is ignored when `features.logScale` is false. */\n setLogScale(enabled: boolean): void {\n if (enabled && !this.features.logScale) return;\n this.viewport.setLogScale(enabled);\n this.updateViewportAndRender();\n }\n\n isLogScale(): boolean {\n return this.viewport.isLogScale();\n }\n\n /** Turn the price scale upside down: higher prices lower on screen. */\n setInvertScale(inverted: boolean): void {\n this.viewport.setInvertScale(inverted);\n this.updateViewportAndRender();\n }\n\n isInvertScale(): boolean {\n return this.viewport.isInvertScale();\n }\n\n /**\n * Set the price-scale presentation: `regular`, `logarithmic`, `percentage`\n * (axis labels show % change from the first visible bar), or `indexedTo100`\n * (rebased so the first visible bar reads as 100).\n */\n setScaleMode(mode: import('@tradecanvas/commons').PriceScaleMode): void {\n if (mode === 'logarithmic' && !this.features.logScale) return;\n this.viewport.setScaleMode(mode);\n this.updateViewportAndRender();\n }\n\n getScaleMode(): import('@tradecanvas/commons').PriceScaleMode {\n return this.viewport.getScaleMode();\n }\n\n setSessionBreaksConfig(config: { color?: string; lineStyle?: 'solid' | 'dashed' | 'dotted'; lineWidth?: number }): void {\n this.sessionBreaks.setConfig(config);\n this.engine.requestRender(LayerType.Background);\n }\n\n getConnectionState(): ConnectionState {\n return this.streamManager?.getConnectionState() ?? 'disconnected';\n }\n\n getConnectionInfo(): ConnectionInfo {\n return this.streamManager?.getConnectionInfo() ?? { state: 'disconnected' };\n }\n\n setAutoScroll(enabled: boolean): void {\n this.autoScrollOnNewBar = enabled;\n }\n\n // --- Viewport ---\n\n scrollTo(timestamp: number): void {\n const data = this.dataManager.getData();\n for (let i = 0; i < data.length; i++) {\n if (data[i].time >= timestamp) {\n const barUnit = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;\n this.viewport.scrollBy(i * barUnit - this.viewport.getState().offset);\n this.updateViewportAndRender();\n return;\n }\n }\n }\n\n /**\n * Centre the bar that contains `time` — in the bars' own unit, ms or s —\n * (the first or last bar when `time` lies outside the data), keeping the zoom. Returns that bar's index, or -1\n * without data.\n */\n goToTime(time: number): number {\n const data = this.getDisplayData(); // the series on screen (renko bricks, kagi lines…)\n if (data.length === 0 || !Number.isFinite(time)) return -1;\n const index = Math.max(0, Math.min(data.length - 1, Math.floor(timestampToBarIndex(time, data))));\n const vs = this.viewport.getState();\n const centredOffset = index * (vs.barWidth + vs.barSpacing) + vs.barWidth / 2 - vs.chartRect.width / 2;\n this.viewport.scrollBy(centredOffset - vs.offset);\n this.updateViewportAndRender();\n return index;\n }\n\n /**\n * Show a span that ends at the last bar: 1D, 5D, 1M, 3M, 6M, YTD, 1Y, 5Y or\n * All. Months and YTD follow the calendar in the display timezone. Only\n * loaded bars can be shown, so a span longer than the data shows all of it.\n */\n setVisibleRangePreset(preset: RangePreset): void {\n const data = this.getDisplayData();\n if (data.length === 0) return;\n const last = data.length - 1;\n // Bars may carry seconds rather than milliseconds; the calendar works in ms.\n const unit = data[last].time > SECONDS_TIME_LIMIT ? 1 : 1000;\n const startMs = rangePresetStart(preset, data[last].time * unit, this.displayTzOffset);\n const start = startMs === null ? null : startMs / unit;\n if (start === null || start < data[0].time) {\n this.fitContent();\n return;\n }\n // The first bar after `start`, so \"1D\" on 1-minute bars is 1440 bars, not 1441.\n const first = Math.min(last, Math.floor(timestampToBarIndex(start, data)) + 1);\n this.viewport.zoomToBarRange(first, last + this.viewport.getRightMargin());\n this.viewport.scrollToEnd();\n this.updateViewportAndRender();\n }\n\n scrollToEnd(): void {\n this.viewport.scrollToEnd();\n this.updateViewportAndRender();\n }\n\n /**\n * Show the bars between two timestamps edge to edge. Times past either end\n * of the data are allowed (they map into the empty future / past).\n */\n setVisibleRange(fromTimestamp: number, toTimestamp: number): void {\n const data = this.dataManager.getData();\n if (data.length === 0) return;\n const a = timestampToBarIndex(Math.min(fromTimestamp, toTimestamp), data);\n const b = timestampToBarIndex(Math.max(fromTimestamp, toTimestamp), data);\n // Previously this only changed the bar width around the centre, so the\n // requested range was not actually what ended up on screen.\n this.viewport.zoomToBarRange(a, b);\n this.updateViewportAndRender();\n }\n\n /** Change free-panning bounds at runtime — see `ChartOptions.freePan` / `panLimits`. */\n setPanLimits(limits: { freePan?: boolean; minVisibleBars?: number }): void {\n this.viewport.setPanLimits(limits);\n this.updateViewportAndRender();\n }\n\n zoomIn(): void {\n const chartWidth = this.viewport.getState().chartRect.width;\n this.viewport.zoom(0.2, chartWidth / 2);\n this.updateViewportAndRender();\n }\n\n zoomOut(): void {\n const chartWidth = this.viewport.getState().chartRect.width;\n this.viewport.zoom(-0.2, chartWidth / 2);\n this.updateViewportAndRender();\n }\n\n /**\n * Fit all bars on screen with the usual right margin, resting at the live\n * edge — so new bars keep following afterwards. If they can't all fit at\n * the minimum bar width, the newest ones are shown.\n */\n fitContent(): void {\n const n = this.dataManager.getLength();\n if (n === 0) return;\n this.viewport.zoomToBarRange(0, n - 1 + this.viewport.getRightMargin());\n this.viewport.scrollToEnd();\n this.updateViewportAndRender();\n }\n\n // --- Events ---\n\n on<K extends ChartEventType>(type: K, handler: (event: ChartEvent<K extends keyof ChartEventMap ? ChartEventMap[K] : unknown>) => void): void {\n this.eventBus.on(type, handler as (event: ChartEvent) => void);\n }\n\n off<K extends ChartEventType>(type: K, handler: (event: ChartEvent<K extends keyof ChartEventMap ? ChartEventMap[K] : unknown>) => void): void {\n this.eventBus.off(type, handler as (event: ChartEvent) => void);\n }\n\n enableTauriBridge(options?: Partial<TauriBridgeOptions>): void {\n this.eventBus.enableTauriBridge({ enabled: true, ...options });\n }\n\n disableTauriBridge(): void {\n this.eventBus.disableTauriBridge();\n }\n\n // --- Theme ---\n\n setTheme(themeOrName: ThemeName | Theme): void {\n this.themeManager.setTheme(themeOrName);\n this.syncRenderContext();\n this.container.style.backgroundColor = this.themeManager.getTheme().background;\n this.engine.requestRender();\n this.eventBus.emit('themeChange', { theme: themeOrName });\n }\n\n getTheme(): Theme {\n return this.themeManager.getTheme();\n }\n\n // --- Watermark ---\n\n setWatermark(text: string, opts?: { color?: string; fontSize?: number }): void {\n this.watermark.setConfig({ text, ...opts });\n this.engine.requestRender(LayerType.Background);\n }\n\n // --- Auto Scale ---\n\n setAutoScale(enabled: boolean): void {\n this.options.autoScale = enabled;\n // Unlike the drag-to-scale/vertical-pan gesture freeze, an explicit call\n // here is a deliberate preference — it should survive the next setData()\n // the same way a constructor-time `autoScale: false` would.\n this.defaultAutoScale = enabled;\n this.updateViewportAndRender();\n }\n\n isAutoScale(): boolean {\n return this.options.autoScale !== false;\n }\n\n // --- Crosshair ---\n\n setCrosshairMode(mode: 'normal' | 'magnet' | 'hidden'): void {\n this.crosshairHandler.setMode(mode);\n this.engine.requestRender(LayerType.Hover);\n }\n\n getCrosshairMode(): string {\n return this.crosshairHandler.getMode();\n }\n\n setCrosshairPosition(point: { x: number; y: number } | null): void {\n if (point) {\n this.crosshairHandler.onPointerMove(point);\n } else {\n this.crosshairHandler.onPointerLeave();\n }\n this.engine.requestRender(LayerType.Hover);\n }\n\n /**\n * Show a time-only crosshair — a vertical line and time label on the bar\n * that contains `time` — as when mirroring another chart; null clears it.\n * Fires no crosshair events, so linked charts don't echo each other.\n */\n setCrosshairTime(time: number | null): void {\n const data = this.getDisplayData();\n const slot = time === null || data.length === 0 ? null : Math.floor(timestampToBarIndex(time, data));\n if (slot === this.crosshairHandler.getSyncedSlot()) return;\n this.crosshairHandler.setSyncedSlot(slot);\n this.engine.requestRender(LayerType.Hover);\n }\n\n getData(): DataSeries {\n return this.dataManager.getData();\n }\n\n // --- Grid ---\n\n setGridVisible(visible: boolean): void {\n this.gridRenderer.setVisible(visible);\n this.engine.requestRender(LayerType.Background);\n }\n\n isGridVisible(): boolean {\n return this.gridRenderer.isVisible();\n }\n\n // --- Volume ---\n\n setVolumeVisible(visible: boolean): void {\n this.volumeRenderer.setVisible(visible);\n this.engine.requestRender(LayerType.Main);\n }\n\n // --- Volume Profile ---\n\n setVolumeProfileVisible(visible: boolean): void {\n this.volumeProfile.setVisible(visible);\n this.engine.requestRender(LayerType.Main);\n }\n\n isVolumeProfileVisible(): boolean {\n return this.volumeProfile.isVisible();\n }\n\n setVolumeProfileConfig(config: { buckets?: number; widthRatio?: number; opacity?: number; highlightPoC?: boolean }): void {\n if (config.buckets !== undefined) this.volumeProfile.setBuckets(config.buckets);\n if (config.widthRatio !== undefined) this.volumeProfile.setWidthRatio(config.widthRatio);\n if (config.opacity !== undefined) this.volumeProfile.setOpacity(config.opacity);\n if (config.highlightPoC !== undefined) this.volumeProfile.setHighlightPoC(config.highlightPoC);\n this.engine.requestRender(LayerType.Main);\n }\n\n // --- Market Profile (TPO) ---\n\n setMarketProfileVisible(visible: boolean): void {\n this.marketProfile.setVisible(visible);\n this.engine.requestRender(LayerType.Main);\n }\n\n isMarketProfileVisible(): boolean {\n return this.marketProfile.isVisible();\n }\n\n setMarketProfileConfig(config: { buckets?: number; widthRatio?: number; opacity?: number; valueAreaPct?: number; highlightPoC?: boolean; showStats?: boolean; splitBySession?: boolean; letters?: boolean }): void {\n if (config.buckets !== undefined) this.marketProfile.setBuckets(config.buckets);\n if (config.widthRatio !== undefined) this.marketProfile.setWidthRatio(config.widthRatio);\n if (config.opacity !== undefined) this.marketProfile.setOpacity(config.opacity);\n if (config.valueAreaPct !== undefined) this.marketProfile.setValueAreaPct(config.valueAreaPct);\n if (config.highlightPoC !== undefined) this.marketProfile.setHighlightPoC(config.highlightPoC);\n if (config.showStats !== undefined) this.marketProfile.setShowStats(config.showStats);\n if (config.splitBySession !== undefined) this.marketProfile.setSplitBySession(config.splitBySession);\n if (config.letters !== undefined) this.marketProfile.setLetters(config.letters);\n this.engine.requestRender(LayerType.Main);\n }\n\n /** POC / VAH / VAL of the currently rendered Market Profile, or null. */\n getMarketProfileStats(): import('@tradecanvas/core').MarketProfileStats | null {\n return this.marketProfile.getStats();\n }\n\n // --- Liquidity heatmap ---\n\n setDepthHeatmapVisible(visible: boolean): void {\n this.depthHeatmap.setVisible(visible);\n this.engine.requestRender(LayerType.Main);\n }\n\n isDepthHeatmapVisible(): boolean {\n return this.depthHeatmap.isVisible();\n }\n\n setDepthHeatmapConfig(config: { opacity?: number; capacity?: number }): void {\n if (config.opacity !== undefined) this.depthHeatmap.setOpacity(config.opacity);\n if (config.capacity !== undefined) this.depthHeatmap.setCapacity(config.capacity);\n this.engine.requestRender(LayerType.Main);\n }\n\n /**\n * Record an order-book snapshot for the liquidity heatmap, stamped at the\n * latest bar's time. Call alongside `setDepthData` on each book update.\n */\n pushDepthSnapshot(depth: import('@tradecanvas/commons').DepthData): void {\n const data = this.dataManager.getData();\n if (data.length === 0) return;\n this.depthHeatmap.push(data[data.length - 1].time, depth);\n if (this.depthHeatmap.isVisible()) this.engine.requestRender(LayerType.Main);\n }\n\n clearDepthHeatmap(): void {\n this.depthHeatmap.clear();\n this.engine.requestRender(LayerType.Main);\n }\n\n // --- Prior-period levels (PDH / PDL / PDC) ---\n\n setPeriodLevelsVisible(visible: boolean): void {\n this.periodLevels.setVisible(visible);\n this.engine.requestRender(LayerType.Main);\n }\n\n isPeriodLevelsVisible(): boolean {\n return this.periodLevels.isVisible();\n }\n\n setPeriodLevelsPeriod(period: import('@tradecanvas/core').LevelPeriod): void {\n this.periodLevels.setPeriod(period);\n this.engine.requestRender(LayerType.Main);\n }\n\n /**\n * Set the timezone for time-axis labels and the crosshair time pill.\n * `null` = browser-local; a number = fixed UTC offset in minutes (e.g. -300\n * for EST, 330 for IST).\n */\n setTimezoneOffset(minutes: number | null): void {\n this.displayTzOffset = minutes;\n this.timeAxis.setTimezoneOffset(minutes);\n this.crosshairHandler.setTimezoneOffset(minutes);\n this.crosshairTooltip.setTimezoneOffset(minutes);\n this.engine.requestRender(LayerType.UI);\n }\n\n // --- Pivot / swing markers ---\n\n setPivotMarkersVisible(visible: boolean): void {\n this.pivotMarkers.setVisible(visible);\n this.engine.requestRender(LayerType.Overlay);\n }\n\n isPivotMarkersVisible(): boolean {\n return this.pivotMarkers.isVisible();\n }\n\n setPivotMarkersConfig(config: { left?: number; right?: number; showLabels?: boolean; structureLabels?: boolean }): void {\n if (config.left !== undefined || config.right !== undefined) {\n this.pivotMarkers.setStrength(config.left ?? 5, config.right ?? config.left ?? 5);\n }\n if (config.showLabels !== undefined) this.pivotMarkers.setShowLabels(config.showLabels);\n if (config.structureLabels !== undefined) this.pivotMarkers.setStructureLabels(config.structureLabels);\n this.engine.requestRender(LayerType.Overlay);\n }\n\n // --- Session (RTH) shading ---\n\n setSessionShadingVisible(visible: boolean): void {\n this.sessionShading.setVisible(visible);\n this.engine.requestRender(LayerType.Background);\n }\n\n isSessionShadingVisible(): boolean {\n return this.sessionShading.isVisible();\n }\n\n /**\n * Configure the regular session window (minutes-of-day + tz offset). Pass\n * `windows` for a split session — a market with a midday recess (e.g. SET's\n * 10:00–12:30 and 14:30–16:30) — so the lunch break dims like pre-/post-market.\n */\n setSessionShadingConfig(config: Partial<import('@tradecanvas/core').SessionHoursConfig>): void {\n this.sessionShading.setConfig(config);\n this.engine.requestRender(LayerType.Background);\n }\n\n // --- Tooltip ---\n\n setTooltipVisible(visible: boolean): void {\n if (!visible) this.crosshairTooltip.hide();\n }\n\n // --- Legend ---\n\n setLegend(config: Partial<import('@tradecanvas/core').LegendConfig>): void {\n this.chartLegend.setConfig(config);\n this.engine.requestRender(LayerType.Hover);\n }\n\n setSymbolName(symbol: string): void {\n this.chartLegend.setSymbol(symbol);\n this.engine.requestRender(LayerType.Hover);\n }\n\n /**\n * Set a status text displayed in the chart legend area (e.g., \"LIVE . 8ms\").\n * Pass null to clear.\n */\n setStatusText(text: string | null): void {\n this.chartLegend.setStatusText(text);\n this.engine.requestRender(LayerType.Hover);\n }\n\n // --- Screenshot ---\n\n screenshot(filename?: string): void {\n if (!this.features.screenshot) return;\n Screenshot.download(this.container, filename, this.themeManager.getTheme().background);\n }\n\n /** Copy the chart image to the clipboard. Returns false if unsupported/blocked. */\n async copyScreenshot(): Promise<boolean> {\n if (!this.features.screenshot) return false;\n try {\n const blob = await Screenshot.toBlob(this.container, this.themeManager.getTheme().background);\n const ClipboardItemCtor = (globalThis as { ClipboardItem?: typeof ClipboardItem }).ClipboardItem;\n if (!blob || !navigator.clipboard?.write || !ClipboardItemCtor) return false;\n await navigator.clipboard.write([new ClipboardItemCtor({ 'image/png': blob })]);\n return true;\n } catch {\n return false;\n }\n }\n\n screenshotDataURL(): string | null {\n if (!this.features.screenshot) return null;\n return Screenshot.toDataURL(this.container, this.themeManager.getTheme().background);\n }\n\n async screenshotBlob(): Promise<Blob | null> {\n if (!this.features.screenshot) return null;\n return Screenshot.toBlob(this.container, this.themeManager.getTheme().background);\n }\n\n // --- Alerts ---\n\n addAlert(\n price: number,\n condition: import('@tradecanvas/core').AlertCondition = 'crossing',\n message?: string,\n channel = 'price',\n label?: string,\n ): string | null {\n if (!this.features.alerts) return null;\n const id = this.alertManager.addAlert(price, condition, message, false, channel, label);\n this.scheduleAutoSave();\n return id;\n }\n\n removeAlert(id: string): void {\n this.alertManager.removeAlert(id);\n this.scheduleAutoSave();\n }\n\n getAlerts(): import('@tradecanvas/core').PriceAlert[] {\n return this.alertManager.getAlerts();\n }\n\n clearAlerts(): void {\n this.alertManager.clearAlerts();\n this.scheduleAutoSave();\n }\n\n saveAlerts(key: string): void {\n this.alertManager.saveToStorage(key);\n }\n\n loadAlerts(key: string): void {\n this.alertManager.loadFromStorage(key);\n this.engine.requestRender(LayerType.Overlay);\n }\n\n // --- Signal Markers ---\n\n addSignalMarker(marker: Omit<import('@tradecanvas/commons').SignalMarker, 'id'> & { id?: string }): string {\n return this.signalMarkerManager.addMarker(marker);\n }\n\n removeSignalMarker(id: string): void {\n this.signalMarkerManager.removeMarker(id);\n }\n\n getSignalMarkers(): import('@tradecanvas/commons').SignalMarker[] {\n return this.signalMarkerManager.getMarkers();\n }\n\n setSignalMarkers(markers: import('@tradecanvas/commons').SignalMarker[]): void {\n this.signalMarkerManager.setMarkers(markers);\n }\n\n clearSignalMarkers(): void {\n this.signalMarkerManager.clearMarkers();\n }\n\n setSignalMarkerStyle(style: Partial<import('@tradecanvas/commons').SignalMarkerStyle>): void {\n this.signalMarkerManager.setStyle(style);\n }\n\n // --- Trade Zones ---\n\n addTradeZone(zone: Omit<import('@tradecanvas/commons').TradeZone, 'id'> & { id?: string }): string {\n return this.tradeZoneManager.addZone(zone);\n }\n\n updateTradeZone(id: string, updates: Partial<Omit<import('@tradecanvas/commons').TradeZone, 'id'>>): void {\n this.tradeZoneManager.updateZone(id, updates);\n }\n\n removeTradeZone(id: string): void {\n this.tradeZoneManager.removeZone(id);\n }\n\n getTradeZones(): import('@tradecanvas/commons').TradeZone[] {\n return this.tradeZoneManager.getZones();\n }\n\n setTradeZones(zones: import('@tradecanvas/commons').TradeZone[]): void {\n this.tradeZoneManager.setZones(zones);\n }\n\n clearTradeZones(): void {\n this.tradeZoneManager.clearZones();\n }\n\n setTradeZoneStyle(style: Partial<import('@tradecanvas/commons').TradeZoneStyle>): void {\n this.tradeZoneManager.setStyle(style);\n }\n\n // --- Replay ---\n\n /**\n * Replay the series bar by bar. While it runs the chart is detached from\n * live data: stream ticks and `appendBar`/`updateLastBar` calls are kept\n * aside (orders still track the live price), the price line shows the\n * replayed close, and auto-scale refits every step. `replayStop()` brings\n * back the live series, including everything that arrived meanwhile.\n */\n replayStart(config?: Partial<import('@tradecanvas/core').ReplayConfig>): void {\n if (!this.features.replay) return;\n if (!this.replaySession) {\n if (this.dataManager.getLength() === 0) return; // nothing to replay\n const live = new DataManager();\n live.setData(this.dataManager.getData());\n this.replaySession = { live, price: null };\n }\n // Replay the live series as it stands now (a restart includes bars that\n // arrived during the previous run).\n const data = this.replaySession.live.getData().slice();\n // A replay fits each step; a price-axis drag from before shouldn't pin it.\n this.options.autoScale = true;\n this.replayManager.load(data);\n let loaded = -1; // bars of `data` currently in the DataManager, as of the last step\n // Each replayStart used to stack another 'bar' listener, so a restarted\n // replay ran every step once per previous start.\n this.replayBarUnsub?.();\n this.replayBarUnsub = this.replayManager.on('bar', ({ bar: _bar, index }) => {\n const nextLen = index + 1;\n const forward = loaded > 0 && nextLen > loaded && this.dataManager.getLength() === loaded;\n // Like live data: a replay step follows the newest bar while the view\n // rests at the end, and leaves it alone while the user looks at history.\n // The first step and any seek (back or forward) show the replay\n // position. (Read before the new bars land: `isAtEnd` compares against\n // the old length.)\n const step = forward && !this.replaySeeking;\n const follow = !step || (this.autoScrollOnNewBar && this.viewport.isAtEnd());\n if (forward) {\n // Forward step: append just the newly revealed bars and update\n // indicators from there — not re-copy, re-sanitize and recompute the\n // whole prefix on every tick of the replay clock.\n for (let j = loaded; j < nextLen; j++) this.dataManager.appendBar(data[j]);\n this.recalcIndicatorsFrom(this.dataManager.getData(), loaded);\n } else {\n // First step, or a seek backwards: reload the prefix.\n this.dataManager.setData(data.slice(0, nextLen));\n this.recalcIndicators(this.dataManager.getData());\n }\n loaded = nextLen;\n // The price line follows the replay, not the live market.\n this.currentPriceLine.setPrice(data[index].close, index > 0 ? data[index - 1].close : undefined);\n this.crosshairHandler.setData(this.dataManager.getData());\n // The display cache isn't keyed to the data array — without this the\n // chart kept drawing the pre-replay series.\n this.displayDataCache = null;\n this.updateViewportAndRender(follow);\n });\n this.replayManager.play(config);\n }\n\n replayPause(): void { this.replayManager.pause(); }\n replayResume(): void { this.replayManager.resume(); }\n /** End the replay and return to the live series (with updates that arrived meanwhile). */\n replayStop(): void {\n const session = this.replaySession;\n this.endReplaySession();\n if (!session) return;\n this.setData(session.live.getData());\n if (session.price) this.currentPriceLine.setPrice(session.price.price, session.price.previousClose);\n }\n\n /** Whether a replay session is open (playing or paused). */\n isReplayActive(): boolean {\n return this.replaySession !== null;\n }\n\n /** The plot area in CSS pixels, relative to the chart container (no axes). */\n getPlotRect(): { x: number; y: number; width: number; height: number } {\n const { x, y, width, height } = this.viewport.getState().chartRect;\n return { x, y, width, height };\n }\n\n /** Stop the replay clock and drop the session without touching the data. */\n private endReplaySession(): void {\n if (!this.replaySession) return;\n this.replaySession = null;\n this.replayBarUnsub?.();\n this.replayBarUnsub = null;\n this.replayManager.stop();\n }\n\n replaySeek(index: number): void {\n this.replaySeeking = true;\n try {\n this.replayManager.seekTo(index);\n } finally {\n this.replaySeeking = false;\n }\n }\n setReplaySpeed(speed: number): void { this.replayManager.setSpeed(speed); }\n getReplayState(): 'playing' | 'paused' | 'stopped' { return this.replayManager.getState(); }\n getReplayProgress(): { current: number; total: number; percent: number } { return this.replayManager.getProgress(); }\n\n // --- Save / Load ---\n\n /** Everything `loadState` restores: chart type, theme, drawings, indicators, alerts. */\n private captureSnapshot(): import('@tradecanvas/core').ChartSnapshot {\n const panels = this.layoutManager.getPanels();\n return ChartStateManager.capture(\n {\n getDrawings: () => this.getDrawings(),\n getTheme: () => this.getTheme(),\n getAlerts: () => this.getAlerts(),\n getIndicators: () => [\n ...this.indicatorEngine.getActiveIndicators().map((ind) => ({\n id: ind.id,\n instanceId: ind.instanceId,\n params: ind.params,\n position: panels.find((p) => p.id === ind.instanceId)?.position,\n style: this.indicatorEngine.getIndicatorStyle(ind.instanceId) ?? undefined,\n visible: ind.visible,\n })),\n ...this.unrestoredIndicators,\n ],\n },\n { chartType: this.options.chartType, symbol: this.currentSymbol || undefined },\n );\n }\n\n saveState(key?: string): string | null {\n if (!this.features.saveLoad) return null;\n const snapshot = this.captureSnapshot();\n const json = ChartStateManager.serialize(snapshot);\n if (key) ChartStateManager.saveToStorage(key, snapshot);\n return json;\n }\n\n loadState(json: string): void {\n if (!this.features.saveLoad) return;\n const snapshot = ChartStateManager.deserialize(json);\n if (snapshot.chartType) this.setChartType(snapshot.chartType);\n if (snapshot.drawings) this.setDrawings(snapshot.drawings);\n if (snapshot.theme) this.setTheme(snapshot.theme as any);\n\n // Indicators get new instance ids: remember old → new for alert channels.\n // Version-1 saves never captured indicators, so they leave them alone.\n const instanceIds = new Map<string, string>();\n if (snapshot.version >= 2 && this.features.indicators) {\n this.unrestoredIndicators = [];\n const known = new Set(this.indicatorEngine.getAvailableIndicators().map((d) => d.id));\n for (const active of this.indicatorEngine.getActiveIndicators()) this.removeIndicator(active.instanceId);\n for (const ind of snapshot.indicators) {\n const position = (['top', 'bottom', 'left', 'right'] as const).find((p) => p === ind.position) ?? 'bottom';\n let instanceId: string | null = null;\n try {\n if (!known.has(ind.id)) throw new Error('no such indicator is registered');\n instanceId = this.addIndicator(ind.id, ind.params as Record<string, number | string | boolean>, position);\n } catch (err) {\n console.warn(`Layout indicator \"${ind.id}\" kept but not shown:`, err);\n }\n if (!instanceId) {\n this.unrestoredIndicators.push(ind);\n continue;\n }\n instanceIds.set(ind.instanceId, instanceId);\n if (ind.style) this.updateIndicatorStyle(instanceId, ind.style);\n if (ind.visible === false) this.setIndicatorVisible(instanceId, false);\n }\n }\n\n if (snapshot.alerts && this.features.alerts) {\n this.alertManager.clearAlerts();\n for (const a of snapshot.alerts) {\n // A one-shot alert that already fired stays fired (as AlertManager's own storage does).\n if (a.triggered && !a.repeating) continue;\n // `<instanceId>:<key>` channels follow their indicator to its new id.\n const sep = a.channel.indexOf(':');\n const renamed = sep > 0 ? instanceIds.get(a.channel.slice(0, sep)) : undefined;\n const channel = renamed ? renamed + a.channel.slice(sep) : a.channel;\n this.alertManager.addAlert(a.price, a.condition, a.message, a.repeating, channel, a.label);\n }\n }\n this.scheduleAutoSave();\n }\n\n loadStateFromStorage(key: string): boolean {\n if (!this.features.saveLoad) return false;\n const snapshot = ChartStateManager.loadFromStorage(key);\n if (!snapshot) return false;\n this.loadState(ChartStateManager.serialize(snapshot));\n return true;\n }\n\n downloadState(filename?: string): void {\n if (!this.features.saveLoad) return;\n ChartStateManager.downloadFile(this.captureSnapshot(), filename);\n }\n\n async loadStateFromFile(): Promise<void> {\n if (!this.features.saveLoad) return;\n const snapshot = await ChartStateManager.loadFromFile();\n this.loadState(ChartStateManager.serialize(snapshot));\n }\n\n // --- Locale ---\n\n setLocale(locale: Locale): void {\n setGlobalLocale(locale);\n this.engine.requestRender();\n }\n\n /**\n * Update the BCP 47 locale used for number formatting\n * (e.g. price axis labels, crosshair value badges).\n * Defaults to 'en-US'. Example values: 'de-DE', 'vi-VN', 'fr-FR'.\n */\n setNumberLocale(locale: string): void {\n this.numberLocale = locale;\n this.priceAxis.setLocale(locale);\n this.crosshairHandler.setLocale(locale);\n this.chartLegend.setLocale(locale);\n this.crosshairTooltip.setLocale(locale);\n this.sessionBreaks.setLocale(locale);\n this.currentPriceLine.setLocale(locale);\n // Separators change label widths; the axis may need to refit.\n this.updateViewportAndRender();\n }\n\n getNumberLocale(): string {\n return this.numberLocale;\n }\n\n // --- Market ---\n\n setMarket(config: MarketConfig): void {\n this.marketConfig = config;\n\n // Apply market color scheme to theme\n if (config.colorScheme) {\n const base = this.themeManager.getTheme();\n const marketTheme: Theme = {\n ...base,\n candleUp: config.colorScheme.up,\n candleDown: config.colorScheme.down,\n candleUpWick: config.colorScheme.up,\n candleDownWick: config.colorScheme.down,\n volumeUp: config.colorScheme.up.replace(')', ', 0.3)').replace('rgb(', 'rgba(') || `${config.colorScheme.up}4D`,\n volumeDown: config.colorScheme.down.replace(')', ', 0.3)').replace('rgb(', 'rgba(') || `${config.colorScheme.down}4D`,\n };\n this.themeManager.setTheme(marketTheme);\n }\n\n // Apply price precision to trading, alerts, and price line\n if (config.pricePrecision !== undefined) {\n this.marketPricePrecision = config.pricePrecision;\n this.tradingManager.setConfig({ pricePrecision: config.pricePrecision });\n this.alertManager.setPricePrecision(config.pricePrecision);\n this.streamManager?.priceLine.setPricePrecision(config.pricePrecision);\n this.currentPriceLine.setPricePrecision(config.pricePrecision);\n this.crosshairHandler.setPricePrecision(config.pricePrecision);\n this.chartLegend.setPricePrecision(config.pricePrecision);\n this.crosshairTooltip.setPricePrecision(config.pricePrecision);\n }\n\n // Longer price labels may need a wider axis.\n this.updateViewportAndRender();\n }\n\n getMarket(): MarketConfig | null {\n return this.marketConfig;\n }\n\n setPriceLimits(referencePrice: number): void {\n if (!this.marketConfig) return;\n const limits = computePriceLimits(referencePrice, this.marketConfig);\n if (limits) {\n this.marketConfig.priceLimits = {\n ...this.marketConfig.priceLimits!,\n referencePrice,\n };\n }\n this.engine.requestRender();\n }\n\n // --- Features ---\n\n /** Get the resolved feature configuration */\n getFeatures(): Readonly<Required<FeaturesConfig>> {\n return this.features;\n }\n\n /** Update feature flags at runtime. Only provided keys are changed. */\n setFeatures(patch: Partial<FeaturesConfig>): void {\n Object.assign(this.features, patch);\n\n // Apply immediate side-effects\n if (patch.crosshair === false || patch.crosshairTooltip === false) {\n this.crosshairTooltip.hide();\n }\n if (patch.grid !== undefined) {\n this.engine.requestRender(LayerType.Background);\n }\n if (patch.volume !== undefined) {\n this.volumeRenderer.setVisible(patch.volume);\n this.engine.requestRender(LayerType.Main);\n }\n if (patch.drawings === false) {\n this.drawingManager.setActiveTool(null);\n }\n if (patch.trading === false) {\n this.tradingManager.setOrders([]);\n this.tradingManager.setPositions([]);\n }\n if (patch.keyboard !== undefined) {\n this.keyboardHandler?.setEnabled(patch.keyboard);\n }\n\n this.engine.requestRender();\n }\n\n // --- Lifecycle ---\n\n resize(): void {\n const size = this.engine.dprManager.readContainerSize();\n if (size.width <= 0 || size.height <= 0) return;\n this.containerSizeCache = size;\n this.containerSizeCacheTime = Date.now();\n // Resize canvas layers immediately (don't wait for DPRManager's debounced callback)\n const dpr = this.engine.dprManager.getDpr();\n this.engine.layerManager.resize(size, dpr);\n // Check if viewport was at the end before resize\n const wasAtEnd = this.viewport.isAtEnd();\n this.viewport.resize(size.width, size.height);\n this.layoutManager.resize(size.width, size.height);\n this.updateViewportAndRender(wasAtEnd);\n this.eventBus.emit('resize', size);\n }\n\n destroy(): void {\n if (this.countdownInterval) clearInterval(this.countdownInterval);\n this.disableAutoSave();\n this.disconnectStream();\n this.disconnectExecution();\n if (this.onWindowKeyDown) {\n window.removeEventListener('keydown', this.onWindowKeyDown);\n this.onWindowKeyDown = null;\n }\n this.keyboardHandler = null;\n this.interactionManager.detach();\n this.tradingManager.destroy();\n this.animator.dispose();\n this.crosshairTooltip.destroy();\n this.pinnedTooltip.destroy();\n this.replayManager.dispose();\n this.undoRedoManager.clear();\n this.engine.destroy();\n this.eventBus.destroy();\n this.container.innerHTML = '';\n }\n\n // --- Internal ---\n\n private createChartRenderer(type: ChartType | string): ChartRendererInterface {\n return resolveRenderer(type, (t) => this.pluginManager.getChartType(t));\n }\n\n /** Cached display data. Invalidated when raw data or chart type changes. */\n private getDisplayData(): DataSeries {\n if (this.displayDataCache) return this.displayDataCache;\n const raw = this.dataManager.getData();\n if (raw.length === 0) return raw;\n const result = resolveDisplayData(this.options.chartType, raw, (t) => this.pluginManager.getChartType(t));\n this.displayDataCache = result;\n return result;\n }\n\n /** Recompute indicators from bar `from` on, and say so (live ticks, closes, replay steps). */\n private recalcIndicatorsFrom(data: DataSeries, from: number): void {\n this.indicatorEngine.recalculateFrom(data, from);\n this.announceIndicatorUpdate(from);\n }\n\n private recalcIndicators(data: DataSeries): void {\n this.indicatorEngine.recalculateAll(data);\n this.announceIndicatorUpdate(0);\n }\n\n /**\n * Emit `indicatorUpdate` once per task, from the earliest changed bar, after\n * the update that caused it has finished and scheduled its redraw: a\n * listener can neither interrupt a live tick nor read the layout before\n * the chart has updated it.\n */\n private announceIndicatorUpdate(from: number): void {\n if (this.indicatorUpdateFrom !== null) {\n this.indicatorUpdateFrom = Math.min(this.indicatorUpdateFrom, from);\n return;\n }\n this.indicatorUpdateFrom = from;\n queueMicrotask(() => {\n const first = this.indicatorUpdateFrom;\n this.indicatorUpdateFrom = null;\n if (first !== null) this.eventBus.emit('indicatorUpdate', { from: first });\n });\n }\n\n /** Lightweight render for streaming updates. No layout resolve, no indicator recalc. */\n private scheduleRender(): void {\n if (this.renderScheduled) return;\n this.renderScheduled = true;\n requestAnimationFrame(() => {\n this.renderScheduled = false;\n this.applyDataToViewport();\n if (this.fitPriceAxisWidth()) this.applyDataToViewport();\n this.syncRenderContext();\n this.engine.requestRender();\n this.emitViewportEvents();\n });\n }\n\n /**\n * Push the display data into the viewport and apply auto-scale. The single\n * place auto-scale is computed — both the live-tick path (`scheduleRender`)\n * and the pan/zoom/data path (`updateViewportAndRender`) go through it.\n * They used to diverge: ticks fit candles only while pan/zoom also fit\n * overlay indicators (Bollinger, Keltner, Ichimoku…), so the price scale\n * jumped on every tick and jumped back on every pan frame.\n */\n private applyDataToViewport(scrollToEnd = false): DataSeries {\n const displayData = this.getDisplayData();\n const autoScale = this.options.autoScale !== false;\n\n // updateData first so dataLength is current for scrollToEnd — but only\n // fit the price range once the FINAL visible window is known. Fitting\n // before scrollToEnd measured the old window (e.g. deep history) and left\n // every bar of a freshly loaded series off-screen.\n this.viewport.updateData(displayData, autoScale && !scrollToEnd);\n if (scrollToEnd) {\n this.viewport.scrollToEnd();\n if (autoScale) this.viewport.updateData(displayData, true);\n }\n\n const vs = this.viewport.getState();\n\n // Baseline for percentage / indexed-to-100 axis labels: the close of the\n // first visible bar. Ignored by other scale modes.\n if (displayData.length > 0) {\n const baseIdx = Math.max(0, Math.min(vs.visibleRange.from, displayData.length - 1));\n this.viewport.setScaleBaseline(displayData[baseIdx]?.close);\n }\n\n // Expand the fitted range to include overlay indicator values (BB, Ichimoku, etc.)\n if (autoScale) {\n const overlayRange = this.indicatorEngine.getOverlayPriceRange(\n vs.visibleRange.from,\n Math.min(vs.visibleRange.to, displayData.length - 1),\n );\n if (overlayRange) {\n const current = vs.priceRange;\n const expandedMin = Math.min(current.min, overlayRange.min);\n const expandedMax = Math.max(current.max, overlayRange.max);\n if (expandedMin < current.min || expandedMax > current.max) {\n const range = expandedMax - expandedMin || 1;\n this.viewport.setPriceRange(\n expandedMin - range * 0.02,\n expandedMax + range * 0.02,\n );\n }\n }\n }\n return displayData;\n }\n\n /** Full update: resolve layout, update viewport, sync context, request render. */\n private updateViewportAndRender(scrollToEnd = false): void {\n // Invalidate layout cache\n this.resolvedLayoutCache = null;\n this.panelInfoCache = null;\n\n const resolved = this.getResolvedLayout();\n this.viewport.setChartRect(resolved.mainChartRect);\n\n this.applyDataToViewport(scrollToEnd);\n // A wider/narrower axis changes the plot width, so fit the data again.\n if (this.fitPriceAxisWidth()) this.applyDataToViewport(scrollToEnd);\n\n this.syncRenderContext();\n this.engine.requestRender();\n\n this.emitViewportEvents();\n }\n\n /**\n * Size the price axis to its widest label (tick labels, last-price tag,\n * crosshair pill), as an auto-width scale — so a sub-cent\n * price isn't clipped. Returns true when the width, and so the layout,\n * changed.\n */\n private fitPriceAxisWidth(): boolean {\n if (!this.features.priceAxis) return false;\n const { priceRange } = this.viewport.getState();\n const theme = this.themeManager.getTheme();\n const required = requiredPriceAxisWidth({\n min: priceRange.min,\n max: priceRange.max,\n lastPrice: this.currentPriceLine.getPrice(),\n tagPrecision: this.marketConfig?.pricePrecision ?? null,\n locale: this.numberLocale,\n fontFamily: theme.font.family,\n fontSizeSmall: theme.font.sizeSmall,\n measure: (text, font) => this.measureText(text, font),\n });\n const next = nextPriceAxisWidth(this.priceAxisWidth, required);\n if (next === this.priceAxisWidth) return false;\n\n this.priceAxisWidth = next;\n this.layoutManager.setPriceAxisWidth(next);\n this.viewport.setPriceAxisWidth(next);\n this.resolvedLayoutCache = null;\n this.panelInfoCache = null;\n this.viewport.setChartRect(this.getResolvedLayout().mainChartRect);\n return true;\n }\n\n private measureText(text: string, font: string): number {\n if (this.measureCtx === undefined) {\n this.measureCtx = typeof document !== 'undefined'\n ? document.createElement('canvas').getContext('2d')\n : null;\n }\n const ctx = this.measureCtx;\n if (!ctx) return text.length * 7; // no canvas (SSR/tests): a generous estimate\n ctx.font = font;\n return ctx.measureText(text).width;\n }\n\n /**\n * Fire the public viewport events (`visibleRangeChange`, `priceRangeChange`,\n * `zoomChange`) whenever the corresponding piece of viewport state changed\n * since the last render. Called at the end of every updateViewportAndRender,\n * so panning, zooming, resizing, and data updates all surface to consumers.\n */\n private emitViewportEvents(): void {\n const vs = this.viewport.getState();\n\n const from = Math.max(0, Math.floor(vs.visibleRange.from));\n const to = Math.max(from, Math.ceil(vs.visibleRange.to));\n if (\n !this.lastEmittedRange ||\n this.lastEmittedRange.from !== from ||\n this.lastEmittedRange.to !== to\n ) {\n this.lastEmittedRange = { from, to };\n this.eventBus.emit('visibleRangeChange', { from, to });\n }\n\n const { min, max } = vs.priceRange;\n if (\n !this.lastEmittedPriceRange ||\n this.lastEmittedPriceRange.min !== min ||\n this.lastEmittedPriceRange.max !== max\n ) {\n this.lastEmittedPriceRange = { min, max };\n this.eventBus.emit('priceRangeChange', { min, max });\n }\n\n // `barWidth` here is pixels-per-bar — the value Viewport.zoom() mutates.\n if (this.lastEmittedBarWidth !== vs.barWidth) {\n this.lastEmittedBarWidth = vs.barWidth;\n this.eventBus.emit('zoomChange', { barWidth: vs.barWidth });\n }\n }\n\n private getResolvedLayout() {\n if (!this.resolvedLayoutCache) {\n this.resolvedLayoutCache = this.layoutManager.resolve();\n this.syncCrosshairBounds(this.resolvedLayoutCache);\n }\n return this.resolvedLayoutCache;\n }\n\n /** The hovered bar is reported over the price pane and the panes above and below it. */\n private syncCrosshairBounds(layout: import('@tradecanvas/commons').ResolvedLayout): void {\n const main = layout.mainChartRect;\n let top = main.y;\n let bottom = main.y + main.height;\n for (const panel of layout.panels) {\n if (panel.config.position !== 'top' && panel.config.position !== 'bottom') continue;\n top = Math.min(top, panel.rect.y);\n bottom = Math.max(bottom, panel.rect.y + panel.rect.height);\n }\n this.crosshairHandler.setReportBounds({ top, bottom });\n }\n\n /** Cache container size for 500ms to avoid layout thrashing on rapid calls */\n private cachedContainerSize(): { width: number; height: number } {\n const now = Date.now();\n if (!this.containerSizeCache || now - this.containerSizeCacheTime > 500) {\n this.containerSizeCache = this.engine.dprManager.getContainerSize();\n this.containerSizeCacheTime = now;\n }\n return this.containerSizeCache;\n }\n\n private buildPanelRenderInfos(): import('@tradecanvas/core').PanelRenderInfo[] {\n if (this.panelInfoCache) return this.panelInfoCache;\n\n const resolved = this.getResolvedLayout();\n const mainVP = this.viewport.getState();\n\n const { from, to } = mainVP.visibleRange;\n const panels = resolved.panels.map((panel) => {\n const output = this.indicatorEngine.getOutput(panel.config.id);\n const priceRange = computeIndicatorPriceRange(output, from, to);\n\n // Inset the indicator drawing area below the panel header (title + divider)\n const PANEL_HEADER_HEIGHT = 20;\n const insetRect = {\n x: panel.rect.x,\n y: panel.rect.y + PANEL_HEADER_HEIGHT,\n width: panel.rect.width,\n height: Math.max(0, panel.rect.height - PANEL_HEADER_HEIGHT),\n };\n\n return {\n instanceId: panel.config.id,\n rect: panel.rect,\n viewport: {\n ...mainVP,\n chartRect: insetRect,\n priceRange,\n // Panes keep their own upright, linear value scale; log and\n // inverted belong to the price pane only.\n logScale: false,\n scaleMode: 'regular' as const,\n invertScale: false,\n },\n };\n });\n\n this.panelInfoCache = panels;\n return panels;\n }\n\n private syncRenderContext(): void {\n // Keep the pinned tooltip anchored to its bar through pans / zooms.\n if (this.pinnedTooltip.isPinned()) {\n this.pinnedTooltip.reposition(\n this.viewport.getState(),\n null,\n null,\n this.themeManager.getTheme(),\n );\n }\n\n const resolved = this.getResolvedLayout();\n const panels = this.features.indicators ? this.buildPanelRenderInfos() : [];\n\n // Compute where the time axis should render: below main chart + all bottom panels\n const bottomPanelHeight = resolved.panels\n .filter(p => p.config.position === 'bottom')\n .reduce((sum, p) => sum + p.rect.height, 0);\n const timeAxisY = resolved.mainChartRect.y + resolved.mainChartRect.height + bottomPanelHeight;\n\n const displayData = this.getDisplayData();\n this.engine.setRenderContext({\n chartRenderer: this.chartRenderer,\n gridRenderer: this.features.grid ? this.gridRenderer : null,\n priceAxis: this.features.priceAxis ? this.priceAxis : null,\n timeAxis: this.features.timeAxis ? this.timeAxis : null,\n crosshairHandler: this.features.crosshair ? this.crosshairHandler : null,\n indicatorEngine: this.features.indicators ? this.indicatorEngine : null,\n drawingRenderer: this.features.drawings ? this.drawingRenderer : null,\n tradingRenderer: this.features.trading ? this.tradingRenderer : null,\n currentPriceLine: this.currentPriceLine,\n chartLegend: this.features.legend ? this.chartLegend : null,\n volumeRenderer: this.features.volume ? this.volumeRenderer : null,\n volumeProfile: this.volumeProfile,\n marketProfile: this.marketProfile,\n depthHeatmap: this.depthHeatmap,\n periodLevels: this.periodLevels,\n pivotMarkers: this.pivotMarkers,\n watermark: this.features.watermark ? this.watermark : null,\n barCountdown: this.barCountdown,\n sessionBreaks: this.sessionBreaks,\n sessionShading: this.sessionShading,\n compareRenderer: this.compareRenderer,\n alertManager: this.features.alerts ? this.alertManager : null,\n measureOverlay: this.measureOverlay,\n selectionBoxOverlay: this.selectionBoxOverlay,\n signalMarkerManager: this.signalMarkerManager,\n tradeZoneManager: this.tradeZoneManager,\n panels,\n priceLimits: this.buildPriceLimits(),\n timeAxisY,\n // Attach data to the viewport so drawings/indicators can treat\n // `anchor.time` as a real timestamp and convert via timestampToBarIndex.\n viewport: { ...this.viewport.getState(), data: displayData },\n theme: this.themeManager.getTheme(),\n data: displayData,\n numberLocale: this.numberLocale,\n paneTitles: this.paneTitles,\n renderOverlayPlugins: (c, layer) => this.drawOverlayPlugins(c, layer),\n });\n }\n\n /** Draw registered overlay plugins for a layer (called by the engine). */\n private drawOverlayPlugins(\n ctx: CanvasRenderingContext2D,\n layer: 'main' | 'overlay' | 'ui',\n ): void {\n const overlays = overlaysForLayer(this.pluginManager.getOverlays(), layer);\n if (overlays.length === 0) return;\n const context = {\n viewport: this.viewport.getState(),\n data: this.getDisplayData(),\n theme: this.themeManager.getTheme(),\n };\n for (const overlay of overlays) {\n overlay.render(ctx, context);\n }\n }\n\n private buildPriceLimits() {\n if (!this.marketConfig?.priceLimits?.enabled || !this.marketConfig.priceLimits.referencePrice) return null;\n const limits = computePriceLimits(this.marketConfig.priceLimits.referencePrice, this.marketConfig);\n if (!limits) return null;\n return {\n ...limits,\n colors: this.marketConfig.colorScheme ? {\n ceiling: this.marketConfig.colorScheme.ceiling,\n floor: this.marketConfig.colorScheme.floor,\n reference: this.marketConfig.colorScheme.reference,\n } : undefined,\n };\n }\n}\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\n\n/**\n * Best-effort parser for OHLCV CSV / JSON drops.\n *\n * Recognises:\n * - CSV (header-driven, comma / semicolon / tab delimiters)\n * - JSON array of objects (`[{ time, open, high, low, close, volume }]`)\n * - JSON array of arrays (`[[time, open, high, low, close, volume]]`)\n *\n * Time columns auto-detect ISO strings, unix-seconds, and unix-ms. Returned\n * bars are sorted ascending by time and de-duplicated on collision.\n */\nexport interface ParseResult {\n data: DataSeries;\n /** Total rows seen — useful for \"imported 4321 of 5000 rows\" style toasts. */\n rowCount: number;\n /** Rows skipped because of missing/invalid required fields. */\n skipped: number;\n}\n\nconst TIME_KEYS = ['time', 'timestamp', 'date', 'datetime', 't'];\nconst OPEN_KEYS = ['open', 'o'];\nconst HIGH_KEYS = ['high', 'h'];\nconst LOW_KEYS = ['low', 'l'];\nconst CLOSE_KEYS = ['close', 'c'];\nconst VOL_KEYS = ['volume', 'vol', 'v'];\n\nexport function parseOHLCV(text: string): ParseResult {\n const trimmed = text.trim();\n if (!trimmed) return { data: [], rowCount: 0, skipped: 0 };\n\n if (trimmed[0] === '[' || trimmed[0] === '{') {\n return parseJson(trimmed);\n }\n return parseCsv(trimmed);\n}\n\nfunction parseJson(text: string): ParseResult {\n let raw: unknown;\n try {\n raw = JSON.parse(text);\n } catch (e) {\n throw new Error(`Invalid JSON: ${(e as Error).message}`);\n }\n if (!Array.isArray(raw)) {\n throw new Error('Expected a JSON array of OHLCV rows');\n }\n const bars: OHLCBar[] = [];\n let skipped = 0;\n for (const row of raw) {\n const bar = Array.isArray(row) ? coerceArrayRow(row) : coerceObjectRow(row as Record<string, unknown>);\n if (bar) bars.push(bar); else skipped++;\n }\n return finalize(bars, raw.length, skipped);\n}\n\nfunction parseCsv(text: string): ParseResult {\n const lines = text.split(/\\r?\\n/).filter(l => l.trim().length > 0);\n if (lines.length === 0) return { data: [], rowCount: 0, skipped: 0 };\n\n const delimiter = detectDelimiter(lines[0]);\n const header = splitLine(lines[0], delimiter).map(h => h.trim().toLowerCase());\n\n // If the first row doesn't look like a header (all numeric), assume the\n // canonical order: time, open, high, low, close, volume.\n const looksLikeHeader = header.some(h => isNaN(Number(h)) && h.length > 0);\n const colIdx = looksLikeHeader\n ? buildColumnMap(header)\n : { time: 0, open: 1, high: 2, low: 3, close: 4, volume: 5 };\n\n if (colIdx.time < 0 || colIdx.open < 0 || colIdx.high < 0 || colIdx.low < 0 || colIdx.close < 0) {\n throw new Error('CSV is missing required column(s): time, open, high, low, close');\n }\n\n const bars: OHLCBar[] = [];\n let skipped = 0;\n for (let i = looksLikeHeader ? 1 : 0; i < lines.length; i++) {\n const cols = splitLine(lines[i], delimiter);\n const time = parseTimeCell(cols[colIdx.time]);\n // Empty cells parse to `Number('') === 0`, which would silently produce\n // bogus zero bars. Treat empty as invalid up-front so the row gets\n // skipped instead of polluting the series.\n const open = numCell(cols[colIdx.open]);\n const high = numCell(cols[colIdx.high]);\n const low = numCell(cols[colIdx.low]);\n const close = numCell(cols[colIdx.close]);\n const volume = colIdx.volume >= 0 ? Number(cols[colIdx.volume]) : 0;\n if (time === null || ![open, high, low, close].every(Number.isFinite)) {\n skipped++;\n continue;\n }\n bars.push({ time, open: open!, high: high!, low: low!, close: close!, volume: Number.isFinite(volume) ? volume : 0 });\n }\n\n return finalize(bars, lines.length - (looksLikeHeader ? 1 : 0), skipped);\n}\n\nfunction detectDelimiter(headerLine: string): string {\n const counts: Record<string, number> = { ',': 0, ';': 0, '\\t': 0, '|': 0 };\n for (const ch of headerLine) {\n if (ch in counts) counts[ch]++;\n }\n let best = ',';\n let bestCount = 0;\n for (const [d, n] of Object.entries(counts)) {\n if (n > bestCount) { best = d; bestCount = n; }\n }\n return best;\n}\n\n/** Minimal CSV splitter — handles double-quoted fields, doesn't try to be RFC-perfect. */\nfunction splitLine(line: string, delimiter: string): string[] {\n const out: string[] = [];\n let buf = '';\n let inQuote = false;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (ch === '\"') {\n if (inQuote && line[i + 1] === '\"') { buf += '\"'; i++; }\n else inQuote = !inQuote;\n } else if (ch === delimiter && !inQuote) {\n out.push(buf);\n buf = '';\n } else {\n buf += ch;\n }\n }\n out.push(buf);\n return out;\n}\n\nfunction buildColumnMap(header: string[]): { time: number; open: number; high: number; low: number; close: number; volume: number } {\n const find = (keys: string[]) => header.findIndex(h => keys.includes(h));\n return {\n time: find(TIME_KEYS),\n open: find(OPEN_KEYS),\n high: find(HIGH_KEYS),\n low: find(LOW_KEYS),\n close: find(CLOSE_KEYS),\n volume: find(VOL_KEYS),\n };\n}\n\nfunction coerceObjectRow(row: Record<string, unknown>): OHLCBar | null {\n const get = (keys: string[]) => {\n for (const k of keys) {\n if (row[k] !== undefined) return row[k];\n const upper = k.toUpperCase();\n if (row[upper] !== undefined) return row[upper];\n }\n return undefined;\n };\n const time = parseTimeCell(String(get(TIME_KEYS) ?? ''));\n const open = Number(get(OPEN_KEYS));\n const high = Number(get(HIGH_KEYS));\n const low = Number(get(LOW_KEYS));\n const close = Number(get(CLOSE_KEYS));\n const volume = Number(get(VOL_KEYS) ?? 0);\n if (time === null || ![open, high, low, close].every(Number.isFinite)) return null;\n return { time, open, high, low, close, volume: Number.isFinite(volume) ? volume : 0 };\n}\n\nfunction coerceArrayRow(row: unknown[]): OHLCBar | null {\n if (row.length < 5) return null;\n const time = parseTimeCell(String(row[0]));\n const open = Number(row[1]);\n const high = Number(row[2]);\n const low = Number(row[3]);\n const close = Number(row[4]);\n const volume = row.length >= 6 ? Number(row[5]) : 0;\n if (time === null || ![open, high, low, close].every(Number.isFinite)) return null;\n return { time, open, high, low, close, volume: Number.isFinite(volume) ? volume : 0 };\n}\n\n/**\n * Returns milliseconds since epoch, or null if unparseable. Heuristic:\n * - numeric < 1e12 → seconds, multiply by 1000\n * - numeric >= 1e12 → already ms\n * - non-numeric → Date.parse fallback (handles ISO, RFC 2822, etc.)\n */\nfunction numCell(raw: string | undefined): number {\n if (raw === undefined || raw.trim() === '') return NaN;\n return Number(raw);\n}\n\nfunction parseTimeCell(raw: string): number | null {\n const trimmed = raw.trim();\n if (!trimmed) return null;\n const asNum = Number(trimmed);\n if (Number.isFinite(asNum) && asNum > 0) {\n return asNum < 1e12 ? asNum * 1000 : asNum;\n }\n const parsed = Date.parse(trimmed);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction finalize(bars: OHLCBar[], rowCount: number, skipped: number): ParseResult {\n bars.sort((a, b) => a.time - b.time);\n // De-dup on identical time — keep the last (later rows are typically more\n // authoritative if the source updated a bar after publishing it).\n const out: OHLCBar[] = [];\n for (const bar of bars) {\n if (out.length > 0 && out[out.length - 1].time === bar.time) {\n out[out.length - 1] = bar;\n } else {\n out.push(bar);\n }\n }\n return { data: out, rowCount, skipped };\n}\n","import type { DataSeries } from '@tradecanvas/commons';\r\nimport { parseOHLCV, type ParseResult } from './parseOHLCV.js';\r\n\r\nexport interface DragDropImporterCallbacks {\r\n /** Called with the parsed series. Hook into chart.setData() here. */\r\n onData: (data: DataSeries, result: ParseResult, file: File) => void;\r\n /** Called when parsing throws. Hook a toast/banner here. */\r\n onError?: (err: Error, file: File) => void;\r\n}\r\n\r\n/**\r\n * Hooks `dragover` / `drop` on a host element so users can drop a CSV / JSON\r\n * file onto the chart and get it loaded. A subtle dashed-outline overlay\r\n * shows up during the drag for visual confirmation.\r\n *\r\n * The host owns calling `chart.setData()` via the `onData` callback — the\r\n * importer stays decoupled from Chart so it can be reused in other surfaces\r\n * (backtester UI, comparison views, etc.).\r\n */\r\nexport class DragDropImporter {\r\n private host: HTMLElement;\r\n private overlay: HTMLDivElement | null = null;\r\n private callbacks: DragDropImporterCallbacks;\r\n private bound: { dragenter: (e: DragEvent) => void; dragover: (e: DragEvent) => void; dragleave: (e: DragEvent) => void; drop: (e: DragEvent) => void };\r\n private depth = 0;\r\n\r\n constructor(host: HTMLElement, callbacks: DragDropImporterCallbacks) {\r\n this.host = host;\r\n this.callbacks = callbacks;\r\n this.bound = {\r\n dragenter: (e) => this.onDragEnter(e),\r\n dragover: (e) => this.onDragOver(e),\r\n dragleave: (e) => this.onDragLeave(e),\r\n drop: (e) => this.onDrop(e),\r\n };\r\n }\r\n\r\n attach(): void {\r\n this.host.addEventListener('dragenter', this.bound.dragenter);\r\n this.host.addEventListener('dragover', this.bound.dragover);\r\n this.host.addEventListener('dragleave', this.bound.dragleave);\r\n this.host.addEventListener('drop', this.bound.drop);\r\n }\r\n\r\n detach(): void {\r\n this.host.removeEventListener('dragenter', this.bound.dragenter);\r\n this.host.removeEventListener('dragover', this.bound.dragover);\r\n this.host.removeEventListener('dragleave', this.bound.dragleave);\r\n this.host.removeEventListener('drop', this.bound.drop);\r\n this.hideOverlay();\r\n }\r\n\r\n private onDragEnter(e: DragEvent): void {\r\n if (!hasFiles(e)) return;\r\n e.preventDefault();\r\n this.depth++;\r\n this.showOverlay();\r\n }\r\n\r\n private onDragOver(e: DragEvent): void {\r\n if (!hasFiles(e)) return;\r\n e.preventDefault();\r\n if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';\r\n }\r\n\r\n private onDragLeave(e: DragEvent): void {\r\n if (!hasFiles(e)) return;\r\n this.depth = Math.max(0, this.depth - 1);\r\n if (this.depth === 0) this.hideOverlay();\r\n }\r\n\r\n private async onDrop(e: DragEvent): Promise<void> {\r\n e.preventDefault();\r\n this.depth = 0;\r\n this.hideOverlay();\r\n\r\n const file = e.dataTransfer?.files?.[0];\r\n if (!file) return;\r\n\r\n try {\r\n const text = await file.text();\r\n const result = parseOHLCV(text);\r\n if (result.data.length === 0) {\r\n throw new Error(`No valid OHLCV rows found in \"${file.name}\"`);\r\n }\r\n this.callbacks.onData(result.data, result, file);\r\n } catch (err) {\r\n this.callbacks.onError?.(err as Error, file);\r\n }\r\n }\r\n\r\n private showOverlay(): void {\r\n if (this.overlay) return;\r\n this.overlay = document.createElement('div');\r\n Object.assign(this.overlay.style, {\r\n position: 'absolute',\r\n inset: '8px',\r\n zIndex: '90',\r\n pointerEvents: 'none',\r\n borderRadius: '10px',\r\n border: '2px dashed var(--tcw-accent, #f2a93b)',\r\n background: 'rgba(79, 136, 255, 0.06)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n color: 'var(--tcw-accent, #f2a93b)',\r\n fontSize: '14px',\r\n fontWeight: '600',\r\n letterSpacing: '-0.005em',\r\n fontFamily: 'inherit',\r\n backdropFilter: 'blur(2px)',\r\n });\r\n this.overlay.textContent = 'Drop CSV or JSON to load chart data';\r\n // The host needs `position: relative` for absolute inset to work; Chart\r\n // already sets this, but guard for arbitrary hosts.\r\n const cs = getComputedStyle(this.host);\r\n if (cs.position === 'static') this.host.style.position = 'relative';\r\n this.host.appendChild(this.overlay);\r\n }\r\n\r\n private hideOverlay(): void {\r\n this.overlay?.remove();\r\n this.overlay = null;\r\n }\r\n}\r\n\r\nfunction hasFiles(e: DragEvent): boolean {\r\n return e.dataTransfer?.types?.includes('Files') ?? false;\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaneManager.d.ts","sourceRoot":"","sources":["../src/PaneManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAGhE,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,eAAe,CAAK;IAE5B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAM3C,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,SAAuB,GAAG,IAAI;IAKjE,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAKrC,SAAS,IAAI,QAAQ,EAAE;IAIvB,gBAAgB,IAAI,IAAI;IAUxB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,GAAG,aAAa;
|
|
1
|
+
{"version":3,"file":"PaneManager.d.ts","sourceRoot":"","sources":["../src/PaneManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAGhE,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,eAAe,CAAK;IAE5B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAM3C,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,SAAuB,GAAG,IAAI;IAKjE,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAKrC,SAAS,IAAI,QAAQ,EAAE;IAIvB,gBAAgB,IAAI,IAAI;IAUxB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,GAAG,aAAa;IAYhF,OAAO,CAAC,YAAY;CAarB"}
|
|
@@ -16,6 +16,12 @@ export declare function createRendererFor(type: ChartType): ChartRendererInterfa
|
|
|
16
16
|
export declare function transformDisplayData(type: ChartType, raw: DataSeries): DataSeries;
|
|
17
17
|
/** Chart types that materially transform raw OHLC into a different series. */
|
|
18
18
|
export declare function isTransformedChartType(type: ChartType): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Transformed chart types that redraw the series into bars of their own
|
|
21
|
+
* (bricks, lines, columns), so a drawn bar is not a data bar. Heikin-Ashi
|
|
22
|
+
* keeps one bar per data bar.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isReshapedChartType(type: ChartType): boolean;
|
|
19
25
|
/** Look up a registered custom chart-type plugin by its `type` string. */
|
|
20
26
|
export type ChartTypeLookup = (type: string) => ChartTypePlugin | undefined;
|
|
21
27
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChartTypeStrategy.d.ts","sourceRoot":"","sources":["../../src/charts/ChartTypeStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAuBlE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,sBAAsB,CAoCzE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,GAAG,UAAU,CAuBjF;AAED,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAY/D;AAQD,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,sBAAsB,CAI9F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,UAAU,EACf,MAAM,CAAC,EAAE,eAAe,GACvB,UAAU,CAKZ"}
|
|
1
|
+
{"version":3,"file":"ChartTypeStrategy.d.ts","sourceRoot":"","sources":["../../src/charts/ChartTypeStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAuBlE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,sBAAsB,CAoCzE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,GAAG,UAAU,CAuBjF;AAED,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAY/D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAE5D;AAQD,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,sBAAsB,CAI9F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,UAAU,EACf,MAAM,CAAC,EAAE,eAAe,GACvB,UAAU,CAKZ"}
|
package/dist/grid/ChartGrid.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare class ChartGrid {
|
|
|
25
25
|
constructor(container: HTMLElement, options?: ChartGridOptions);
|
|
26
26
|
private applyLayout;
|
|
27
27
|
private createCells;
|
|
28
|
+
private createCell;
|
|
28
29
|
setLayout(layout: GridLayout): void;
|
|
29
30
|
getChart(index: number): Chart | null;
|
|
30
31
|
getCharts(): Chart[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChartGrid.d.ts","sourceRoot":"","sources":["../../src/grid/ChartGrid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAClH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,KAAK,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACtC;AAoBD,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;gBAEZ,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,gBAAqB;IAYlE,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,WAAW;
|
|
1
|
+
{"version":3,"file":"ChartGrid.d.ts","sourceRoot":"","sources":["../../src/grid/ChartGrid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAClH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,KAAK,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACtC;AAoBD,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;gBAEZ,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,gBAAqB;IAYlE,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,UAAU;IA0ElB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAsBnC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAIrC,SAAS,IAAI,KAAK,EAAE;IAIpB,YAAY,IAAI,MAAM;IAItB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI;IAI9C,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAM5B,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,SAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAalH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAM5B,OAAO,IAAI,IAAI;CAUhB"}
|