@tradecanvas/chart 0.8.2 → 0.9.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.
Files changed (42) hide show
  1. package/README.md +86 -4
  2. package/dist/Chart.d.ts +11 -0
  3. package/dist/Chart.d.ts.map +1 -1
  4. package/dist/{Chart-Cn_TSMO7.js → DragDropImporter-6QOjnfSj.js} +361 -85
  5. package/dist/DragDropImporter-6QOjnfSj.js.map +1 -0
  6. package/dist/DragDropImporter-CQ3EarQn.cjs +2 -0
  7. package/dist/DragDropImporter-CQ3EarQn.cjs.map +1 -0
  8. package/dist/index.cjs +1 -1
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +26 -26
  13. package/dist/index.js.map +1 -1
  14. package/dist/io/DragDropImporter.d.ts +34 -0
  15. package/dist/io/DragDropImporter.d.ts.map +1 -0
  16. package/dist/io/index.d.ts +5 -0
  17. package/dist/io/index.d.ts.map +1 -0
  18. package/dist/io/parseOHLCV.d.ts +21 -0
  19. package/dist/io/parseOHLCV.d.ts.map +1 -0
  20. package/dist/widget/ChartWidget.d.ts +46 -1
  21. package/dist/widget/ChartWidget.d.ts.map +1 -1
  22. package/dist/widget/WidgetHotkeySheet.d.ts +20 -0
  23. package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -0
  24. package/dist/widget/WidgetReplayBar.d.ts +41 -0
  25. package/dist/widget/WidgetReplayBar.d.ts.map +1 -0
  26. package/dist/widget/WidgetSettings.d.ts.map +1 -1
  27. package/dist/widget/WidgetSymbolSearch.d.ts +32 -0
  28. package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -0
  29. package/dist/widget/WidgetToolbar.d.ts.map +1 -1
  30. package/dist/widget/WidgetWatchlist.d.ts +39 -0
  31. package/dist/widget/WidgetWatchlist.d.ts.map +1 -0
  32. package/dist/widget/index.cjs +1455 -877
  33. package/dist/widget/index.cjs.map +1 -1
  34. package/dist/widget/index.js +695 -92
  35. package/dist/widget/index.js.map +1 -1
  36. package/dist/widget/types.d.ts +19 -0
  37. package/dist/widget/types.d.ts.map +1 -1
  38. package/dist/widget/widgetConfig.d.ts.map +1 -1
  39. package/package.json +3 -3
  40. package/dist/Chart-Br_N-BCL.cjs +0 -2
  41. package/dist/Chart-Br_N-BCL.cjs.map +0 -1
  42. package/dist/Chart-Cn_TSMO7.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DragDropImporter-CQ3EarQn.cjs","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/plugins/PluginManager.ts","../src/Chart.ts","../src/io/parseOHLCV.ts","../src/io/DragDropImporter.ts"],"sourcesContent":["import type { ChartType, DataSeries } from '@tradecanvas/commons';\r\nimport {\r\n AreaRenderer,\r\n BarRenderer,\r\n BaselineRenderer,\r\n CandlestickRenderer,\r\n EquivolumeRenderer,\r\n HLCAreaRenderer,\r\n HollowCandleRenderer,\r\n KagiRenderer,\r\n LineRenderer,\r\n LineWithMarkersRenderer,\r\n PointAndFigureRenderer,\r\n RenkoRenderer,\r\n StepLineRenderer,\r\n VolumeCandleRenderer,\r\n toHeikinAshi,\r\n toKagi,\r\n toLineBreak,\r\n toPointAndFigure,\r\n toRangeBars,\r\n toRenko,\r\n} from '@tradecanvas/core';\r\nimport type { ChartRendererInterface } from '@tradecanvas/core';\r\n\r\n/**\r\n * Pure mapping from `ChartType` to the renderer class that draws it. Several\r\n * chart types reuse `CandlestickRenderer` against transformed data\r\n * (heikinAshi, lineBreak, rangeBars).\r\n */\r\nexport function createRendererFor(type: ChartType): ChartRendererInterface {\r\n switch (type) {\r\n case 'candlestick':\r\n case 'heikinAshi':\r\n case 'lineBreak':\r\n case 'rangeBars':\r\n return new CandlestickRenderer();\r\n case 'line':\r\n return new LineRenderer();\r\n case 'area':\r\n return new AreaRenderer();\r\n case 'bar':\r\n return new BarRenderer();\r\n case 'hollowCandle':\r\n return new HollowCandleRenderer();\r\n case 'baseline':\r\n return new BaselineRenderer();\r\n case 'renko':\r\n return new RenkoRenderer();\r\n case 'kagi':\r\n return new KagiRenderer();\r\n case 'pointAndFigure':\r\n return new PointAndFigureRenderer();\r\n case 'volumeCandles':\r\n return new VolumeCandleRenderer();\r\n case 'equivolume':\r\n return new EquivolumeRenderer();\r\n case 'hlcArea':\r\n return new HLCAreaRenderer();\r\n case 'stepLine':\r\n return new StepLineRenderer();\r\n case 'lineWithMarkers':\r\n return new LineWithMarkersRenderer();\r\n default:\r\n return new CandlestickRenderer();\r\n }\r\n}\r\n\r\n/**\r\n * Transform raw OHLC bars into the display series for a given chart type.\r\n * Returns the input unchanged for chart types that render raw OHLC directly.\r\n *\r\n * Centralized so adding a new chart type only requires editing one file.\r\n */\r\nexport function transformDisplayData(type: ChartType, raw: DataSeries): DataSeries {\r\n if (raw.length === 0) return raw;\r\n\r\n switch (type) {\r\n case 'heikinAshi':\r\n return toHeikinAshi(raw);\r\n case 'renko':\r\n return toRenko(raw, { brickSize: 0, useATR: true, atrPeriod: 14 });\r\n case 'lineBreak':\r\n return toLineBreak(raw, 3);\r\n case 'kagi':\r\n return toKagi(raw, 4);\r\n case 'pointAndFigure': {\r\n const avgPrice = averageClose(raw);\r\n return toPointAndFigure(raw, avgPrice * 0.01, 3);\r\n }\r\n case 'rangeBars': {\r\n const avgPrice = averageClose(raw);\r\n return toRangeBars(raw, { rangeSize: avgPrice * 0.005 });\r\n }\r\n default:\r\n return raw;\r\n }\r\n}\r\n\r\n/** Chart types that materially transform raw OHLC into a different series. */\r\nexport function isTransformedChartType(type: ChartType): boolean {\r\n switch (type) {\r\n case 'heikinAshi':\r\n case 'renko':\r\n case 'lineBreak':\r\n case 'kagi':\r\n case 'pointAndFigure':\r\n case 'rangeBars':\r\n return true;\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\nfunction averageClose(raw: DataSeries): number {\r\n let sum = 0;\r\n for (const b of raw) sum += b.close;\r\n return sum / raw.length;\r\n}\r\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 values map and bar bounds.\r\n * Iterates the output's `values` map in insertion order; we treat its index\r\n * (0…N-1) as the bar index, matching how the engine inserts values.\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 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 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';\nimport { mergeBar } from '@tradecanvas/commons';\n\n/** Validate a single OHLC bar. Returns true if bar is usable. */\nfunction isValidBar(bar: OHLCBar): boolean {\n if (!bar || typeof bar.time !== 'number') return false;\n const { open, high, low, close } = bar;\n // Reject NaN / Infinity\n if (!isFinite(open) || !isFinite(high) || !isFinite(low) || !isFinite(close)) return false;\n // Reject negative prices\n if (open < 0 || high < 0 || low < 0 || close < 0) return false;\n // High must be >= low\n if (high < low) return false;\n // Volume (optional) must be non-negative if present\n if (bar.volume !== undefined && (!isFinite(bar.volume) || bar.volume < 0)) return false;\n return true;\n}\n\n/** Sanitize a bar: clamp high/low to envelope OHLC values. */\nfunction sanitizeBar(bar: OHLCBar): OHLCBar {\n return {\n ...bar,\n high: Math.max(bar.open, bar.high, bar.low, bar.close),\n low: Math.min(bar.open, bar.high, bar.low, bar.close),\n volume: bar.volume !== undefined ? Math.max(0, bar.volume) : 0,\n };\n}\n\nexport class DataManager {\n private data: DataSeries = [];\n\n getData(): DataSeries {\n return this.data;\n }\n\n setData(data: DataSeries): void {\n // Filter out completely invalid bars, sanitize the rest\n this.data = data\n .filter(isValidBar)\n .map(sanitizeBar);\n }\n\n appendBar(bar: OHLCBar): void {\n if (!isValidBar(bar)) return;\n this.data.push(sanitizeBar(bar));\n }\n\n updateLastBar(bar: OHLCBar): void {\n if (!isValidBar(bar)) return;\n const sanitized = sanitizeBar(bar);\n if (this.data.length === 0) {\n this.data.push(sanitized);\n return;\n }\n this.data[this.data.length - 1] = sanitized;\n }\n\n updateLastBarFromTick(tick: { price: number; volume?: number; time: number }): void {\n if (this.data.length === 0) return;\n if (!isFinite(tick.price) || tick.price < 0) return;\n if (tick.volume !== undefined && (!isFinite(tick.volume) || tick.volume < 0)) return;\n this.data[this.data.length - 1] = mergeBar(this.data[this.data.length - 1], tick);\n }\n\n getLength(): number {\n return this.data.length;\n }\n\n clear(): void {\n this.data = [];\n }\n}\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';\nimport { DEFAULT_PANEL_HEIGHT, MIN_PANEL_HEIGHT, PRICE_AXIS_WIDTH, TIME_AXIS_HEIGHT } from '@tradecanvas/commons';\n\nconst DEFAULT_PANEL_WIDTH = 200;\nconst MIN_PANEL_WIDTH = 80;\n\nexport class LayoutManager {\n private panels: PanelConfig[] = [];\n private containerWidth = 0;\n private containerHeight = 0;\n\n resize(width: number, height: number): void {\n this.containerWidth = width;\n this.containerHeight = height;\n }\n\n addPanel(instanceId: string, position: PanelPosition = 'bottom', size?: number): void {\n const isVertical = position === 'left' || position === 'right';\n this.panels.push({\n id: instanceId,\n position,\n size: size ?? (isVertical ? DEFAULT_PANEL_WIDTH : DEFAULT_PANEL_HEIGHT),\n minSize: isVertical ? MIN_PANEL_WIDTH : MIN_PANEL_HEIGHT,\n content: { type: 'indicator', indicatorInstanceId: instanceId },\n });\n }\n\n removePanel(instanceId: string): void {\n this.panels = this.panels.filter((p) => p.id !== instanceId);\n }\n\n setPanelPosition(instanceId: string, position: PanelPosition): void {\n const panel = this.panels.find((p) => p.id === instanceId);\n if (panel) {\n const wasVertical = panel.position === 'left' || panel.position === 'right';\n const isVertical = position === 'left' || position === 'right';\n panel.position = position;\n if (wasVertical !== isVertical) {\n panel.size = isVertical ? DEFAULT_PANEL_WIDTH : DEFAULT_PANEL_HEIGHT;\n panel.minSize = isVertical ? MIN_PANEL_WIDTH : MIN_PANEL_HEIGHT;\n }\n }\n }\n\n setPanelSize(instanceId: string, size: number): void {\n const panel = this.panels.find((p) => p.id === instanceId);\n if (panel) {\n panel.size = Math.max(panel.minSize, size);\n }\n }\n\n getPanels(): PanelConfig[] {\n return this.panels;\n }\n\n resolve(): ResolvedLayout {\n const leftPanels = this.panels.filter((p) => p.position === 'left');\n const rightPanels = this.panels.filter((p) => p.position === 'right');\n const topPanels = this.panels.filter((p) => p.position === 'top');\n const bottomPanels = this.panels.filter((p) => p.position === 'bottom');\n\n const leftWidth = leftPanels.reduce((s, p) => s + p.size, 0);\n const rightWidth = rightPanels.reduce((s, p) => s + p.size, 0);\n const topHeight = topPanels.reduce((s, p) => s + p.size, 0);\n const bottomHeight = bottomPanels.reduce((s, p) => s + p.size, 0);\n\n const mainChartRect: Rect = {\n x: leftWidth,\n y: topHeight,\n width: Math.max(0, this.containerWidth - leftWidth - rightWidth - PRICE_AXIS_WIDTH),\n height: Math.max(0, this.containerHeight - topHeight - bottomHeight - TIME_AXIS_HEIGHT),\n };\n\n const resolvedPanels: ResolvedPanel[] = [];\n const dividers: DividerRect[] = [];\n\n // Left panels (stacked vertically)\n let x = 0;\n for (const panel of leftPanels) {\n resolvedPanels.push({\n config: panel,\n rect: { x, y: 0, width: panel.size, height: this.containerHeight - TIME_AXIS_HEIGHT },\n });\n dividers.push({\n panelId: panel.id,\n rect: { x: x + panel.size - 2, y: 0, width: 4, height: this.containerHeight },\n orientation: 'vertical',\n });\n x += panel.size;\n }\n\n // Top panels (stacked horizontally, full width minus left/right)\n let y = 0;\n for (const panel of topPanels) {\n resolvedPanels.push({\n config: panel,\n rect: { x: leftWidth, y, width: mainChartRect.width, height: panel.size },\n });\n dividers.push({\n panelId: panel.id,\n rect: { x: leftWidth, y: y + panel.size - 2, width: mainChartRect.width, height: 4 },\n orientation: 'horizontal',\n });\n y += panel.size;\n }\n\n // Bottom panels\n y = mainChartRect.y + mainChartRect.height;\n for (const panel of bottomPanels) {\n resolvedPanels.push({\n config: panel,\n rect: { x: leftWidth, y, width: mainChartRect.width, height: panel.size },\n });\n dividers.push({\n panelId: panel.id,\n rect: { x: leftWidth, y: y - 2, width: mainChartRect.width, height: 4 },\n orientation: 'horizontal',\n });\n y += panel.size;\n }\n\n // Right panels\n x = leftWidth + mainChartRect.width + PRICE_AXIS_WIDTH;\n for (const panel of rightPanels) {\n resolvedPanels.push({\n config: panel,\n rect: { x, y: 0, width: panel.size, height: this.containerHeight - TIME_AXIS_HEIGHT },\n });\n dividers.push({\n panelId: panel.id,\n rect: { x: x - 2, y: 0, width: 4, height: this.containerHeight },\n orientation: 'vertical',\n });\n x += panel.size;\n }\n\n return { mainChartRect, panels: resolvedPanels, dividers };\n }\n\n getMainChartRect(): Rect {\n return this.resolve().mainChartRect;\n }\n}\n","import type { IndicatorPlugin } from '@tradecanvas/commons';\nimport type { IndicatorEngine } from '@tradecanvas/core';\n\nexport class PluginManager {\n constructor(private indicatorEngine: IndicatorEngine) {}\n\n registerIndicator(plugin: IndicatorPlugin): void {\n this.indicatorEngine.register(plugin);\n }\n}\n","import type {\r\n ChartOptions,\r\n ChartType,\r\n OHLCBar,\r\n DataSeries,\r\n Theme,\r\n ThemeName,\r\n ChartEventType,\r\n ChartEvent,\r\n ChartEventMap,\r\n TauriBridgeOptions,\r\n IndicatorPlugin,\r\n IndicatorDescriptor,\r\n IndicatorOutput,\r\n DrawingToolType,\r\n DrawingState,\r\n DrawingStyle,\r\n DrawingPlugin,\r\n PanelPosition,\r\n TradingOrder,\r\n TradingPosition,\r\n DepthData,\r\n TradingConfig,\r\n MarketConfig,\r\n Locale,\r\n StreamConfig,\r\n ConnectionState,\r\n ConnectionInfo,\r\n TimeFrame,\r\n FeaturesConfig,\r\n} from '@tradecanvas/commons';\r\nimport { LayerType, setLocale as setGlobalLocale, computePriceLimits } from '@tradecanvas/commons';\r\nimport {\r\n RenderEngine,\r\n Viewport,\r\n GridRenderer,\r\n PriceAxis,\r\n TimeAxis,\r\n InteractionManager,\r\n PanHandler,\r\n ZoomHandler,\r\n AxisDragHandler,\r\n CrosshairHandler,\r\n IndicatorEngine,\r\n registerBuiltInIndicators,\r\n EventBus,\r\n DrawingManager,\r\n DrawingRenderer,\r\n registerBuiltInDrawingTools,\r\n TradingManager,\r\n TradingRenderer,\r\n StreamManager,\r\n ChartLegend,\r\n Screenshot,\r\n Watermark,\r\n BarCountdown,\r\n VolumeRenderer,\r\n VolumeProfileRenderer,\r\n AlertManager,\r\n SignalMarkerManager,\r\n TradeZoneManager,\r\n MeasureOverlay,\r\n ReplayManager,\r\n ChartStateManager,\r\n UndoRedoManager,\r\n Animator,\r\n KeyboardHandler,\r\n CrosshairTooltip,\r\n PinnedTooltip,\r\n DataExporter,\r\n SessionBreaks,\r\n CompareRenderer,\r\n CurrentPriceLine,\r\n} from '@tradecanvas/core';\r\nimport type { ChartRendererInterface } from '@tradecanvas/core';\r\nimport { timeframeToMs } from '@tradecanvas/commons';\r\nimport { createRendererFor, transformDisplayData } from './charts/ChartTypeStrategy.js';\r\nimport { computeIndicatorPriceRange } from './charts/IndicatorPriceRange.js';\r\nimport { AutoSaveScheduler } from './state/AutoSaveScheduler.js';\r\nimport { DataManager } from './DataManager.js';\r\nimport { ThemeManager } from './ThemeManager.js';\r\nimport { LayoutManager } from './layout/LayoutManager.js';\r\nimport { PluginManager } from './plugins/PluginManager.js';\r\n\r\nexport class Chart {\r\n static version = '0.7.0';\r\n\r\n private engine: RenderEngine;\r\n private viewport: Viewport;\r\n private dataManager: DataManager;\r\n private themeManager: ThemeManager;\r\n private layoutManager: LayoutManager;\r\n private pluginManager: PluginManager;\r\n private indicatorEngine: IndicatorEngine;\r\n private drawingManager: DrawingManager;\r\n private drawingRenderer: DrawingRenderer;\r\n private tradingManager: TradingManager;\r\n private tradingRenderer: TradingRenderer;\r\n private eventBus: EventBus;\r\n private streamManager: StreamManager | null = null;\r\n private autoScrollOnNewBar = true;\r\n private displayDataCache: DataSeries | null = null;\r\n private resolvedLayoutCache: import('@tradecanvas/commons').ResolvedLayout | null = null;\r\n private panelInfoCache: import('@tradecanvas/core').PanelRenderInfo[] | null = null;\r\n private renderScheduled = false;\r\n private containerSizeCache: { width: number; height: number } | null = null;\r\n private containerSizeCacheTime = 0;\r\n private chartLegend: ChartLegend;\r\n private watermark: Watermark;\r\n private barCountdown: BarCountdown;\r\n private sessionBreaks: SessionBreaks;\r\n private compareRenderer: CompareRenderer;\r\n private countdownInterval: ReturnType<typeof setInterval> | null = null;\r\n private volumeRenderer: VolumeRenderer;\r\n private volumeProfile: VolumeProfileRenderer;\r\n private alertManager: AlertManager;\r\n private signalMarkerManager: SignalMarkerManager;\r\n private tradeZoneManager: TradeZoneManager;\r\n private measureOverlay: MeasureOverlay;\r\n private replayManager: ReplayManager;\r\n private undoRedoManager: UndoRedoManager;\r\n private autoSaveScheduler = new AutoSaveScheduler((key) => this.saveState(key));\r\n private animator: Animator;\r\n private crosshairTooltip: CrosshairTooltip;\r\n private pinnedTooltip: PinnedTooltip;\r\n private interactionManager: InteractionManager;\r\n private crosshairHandler: CrosshairHandler;\r\n private chartRenderer: ChartRendererInterface;\r\n private gridRenderer: GridRenderer;\r\n private priceAxis: PriceAxis;\r\n private timeAxis: TimeAxis;\r\n private options: ChartOptions;\r\n private features: Required<FeaturesConfig>;\r\n private marketConfig: MarketConfig | null = null;\r\n private container: HTMLElement;\r\n private currentPriceLine: import('@tradecanvas/core').CurrentPriceLine;\r\n private numberLocale: string;\r\n private keyboardHandler: KeyboardHandler | null = null;\r\n private onWindowKeyDown: ((e: KeyboardEvent) => void) | null = null;\r\n private currentSymbol: string = '';\r\n\r\n\r\n constructor(container: HTMLElement, options: ChartOptions) {\r\n this.container = container;\r\n this.options = options;\r\n this.numberLocale = options.numberLocale ?? 'en-US';\r\n\r\n // Resolve feature flags (all default to true)\r\n const f = options.features ?? {};\r\n this.features = {\r\n drawings: f.drawings ?? true,\r\n drawingTools: f.drawingTools ?? [],\r\n drawingMagnet: f.drawingMagnet ?? true,\r\n drawingUndoRedo: f.drawingUndoRedo ?? true,\r\n trading: f.trading ?? true,\r\n tradingContextMenu: f.tradingContextMenu ?? true,\r\n indicators: f.indicators ?? true,\r\n indicatorIds: f.indicatorIds ?? [],\r\n panning: f.panning ?? true,\r\n zooming: f.zooming ?? true,\r\n crosshair: f.crosshair ?? true,\r\n keyboard: f.keyboard ?? true,\r\n priceAxis: f.priceAxis ?? true,\r\n timeAxis: f.timeAxis ?? true,\r\n grid: f.grid ?? (options.grid?.visible ?? true),\r\n legend: f.legend ?? true,\r\n volume: f.volume ?? true,\r\n watermark: f.watermark ?? true,\r\n saveLoad: f.saveLoad ?? true,\r\n screenshot: f.screenshot ?? true,\r\n alerts: f.alerts ?? true,\r\n replay: f.replay ?? true,\r\n sessionBreaks: f.sessionBreaks ?? true,\r\n barCountdown: f.barCountdown ?? true,\r\n compareSymbols: f.compareSymbols ?? true,\r\n dataExport: f.dataExport ?? true,\r\n logScale: f.logScale ?? true,\r\n timeframes: f.timeframes ?? [],\r\n defaultTimeframeFavorites: f.defaultTimeframeFavorites ?? [],\r\n };\r\n\r\n container.style.position = 'relative';\r\n container.style.overflow = 'hidden';\r\n container.tabIndex = 0; // Allow keyboard events\r\n container.style.outline = 'none';\r\n\r\n // Initialize managers\r\n this.dataManager = new DataManager();\r\n this.themeManager = new ThemeManager(options.theme);\r\n this.layoutManager = new LayoutManager();\r\n this.indicatorEngine = new IndicatorEngine();\r\n this.pluginManager = new PluginManager(this.indicatorEngine);\r\n this.eventBus = new EventBus();\r\n\r\n registerBuiltInIndicators(this.indicatorEngine);\r\n\r\n // Drawing tools\r\n this.drawingManager = new DrawingManager();\r\n registerBuiltInDrawingTools(this.drawingManager);\r\n this.drawingRenderer = new DrawingRenderer(this.drawingManager);\r\n this.drawingManager.setRequestRender(() => {\r\n // Sync entire render context so drawings render with same viewport as candles\r\n this.syncRenderContext();\r\n this.engine.requestRender(LayerType.Overlay);\r\n this.scheduleAutoSave();\r\n });\r\n this.drawingManager.setEventCallback((event, data) => {\r\n this.eventBus.emit(event as ChartEventType, data);\r\n });\r\n // Undo/redo\r\n this.undoRedoManager = new UndoRedoManager();\r\n this.drawingManager.setUndoRedoManager(this.undoRedoManager);\r\n this.drawingManager.setDataGetter(() => this.dataManager.getData());\r\n this.drawingManager.setDisplayDataGetter(() => this.getDisplayData());\r\n // Magnet mode\r\n if (options.crosshair?.mode === 'magnet') {\r\n this.drawingManager.setMagnetMode('magnet');\r\n }\r\n\r\n // Trading\r\n this.tradingManager = new TradingManager({\r\n enabled: this.features.trading,\r\n contextMenu: { enabled: this.features.tradingContextMenu },\r\n });\r\n this.tradingRenderer = new TradingRenderer(this.tradingManager);\r\n this.tradingManager.setContainer(container);\r\n this.tradingManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\r\n this.tradingManager.setEventCallback((event, data) => {\r\n this.eventBus.emit(event as ChartEventType, data);\r\n });\r\n\r\n // Rendering\r\n this.engine = new RenderEngine(container);\r\n const size = this.engine.dprManager.getContainerSize();\r\n this.viewport = new Viewport(\r\n size.width,\r\n size.height,\r\n options.minBarSpacing ?? 2,\r\n options.maxBarSpacing ?? 30,\r\n options.rightMargin ?? 5,\r\n );\r\n this.layoutManager.resize(size.width, size.height);\r\n\r\n // Sync viewport + layout when the container resizes. Without this hook\r\n // the chart's viewport keeps its construction-time chartRect forever\r\n // (which is wrong if the container started at 0 or got resized since),\r\n // and `scrollToEnd` / clampOffset compute against stale dimensions —\r\n // chart sticks at the wrong offset and the user can't scroll to the\r\n // latest bar.\r\n this.engine.onContainerResize = (newSize) => {\r\n if (newSize.width <= 0 || newSize.height <= 0) return;\r\n const wasAtEnd = this.viewport.isAtEnd();\r\n this.viewport.resize(newSize.width, newSize.height);\r\n this.layoutManager.resize(newSize.width, newSize.height);\r\n // wasAtEnd carries the user's intent: if they were tracking the live\r\n // edge before the resize, keep them there afterwards. Otherwise leave\r\n // their scroll position alone.\r\n this.updateViewportAndRender(wasAtEnd);\r\n };\r\n\r\n // Chart renderer\r\n this.chartRenderer = this.createChartRenderer(options.chartType);\r\n this.gridRenderer = new GridRenderer();\r\n if (options.grid?.visible === false) this.gridRenderer.setVisible(false);\r\n this.priceAxis = new PriceAxis();\r\n this.priceAxis.setLocale(this.numberLocale);\r\n this.timeAxis = new TimeAxis();\r\n\r\n // Crosshair\r\n this.crosshairHandler = new CrosshairHandler();\r\n this.crosshairHandler.setLocale(this.numberLocale);\r\n if (options.crosshair?.mode) {\r\n this.crosshairHandler.setMode(options.crosshair.mode);\r\n }\r\n // Crosshair callback — fired via microtask AFTER render, only when bar changes.\r\n // No DOM writes, no layout reads, no extra render requests.\r\n this.crosshairHandler.setCallback((barIndex, point) => {\r\n if (barIndex !== null && point) {\r\n const data = this.dataManager.getData();\r\n const bar = barIndex < data.length ? data[barIndex] : undefined;\r\n\r\n // Update legend (canvas-rendered, will show on next UI paint)\r\n this.chartLegend.setHoverBar(bar ?? null);\r\n\r\n // Update tooltip (DOM, lightweight update only when bar changes)\r\n if (bar) {\r\n this.crosshairTooltip.show(point, bar, this.themeManager.getTheme(), this.cachedContainerSize());\r\n }\r\n\r\n // Refresh the pinned tooltip's delta strip against the hovered bar.\r\n // Cheap when there's nothing pinned (early returns inside reposition).\r\n if (this.pinnedTooltip.isPinned()) {\r\n this.pinnedTooltip.reposition(\r\n this.viewport.getState(),\r\n bar ?? null,\r\n barIndex,\r\n this.themeManager.getTheme(),\r\n );\r\n }\r\n\r\n // Emit for external consumers\r\n this.eventBus.emit('crosshairMove', { point, bar, barIndex });\r\n } else {\r\n this.crosshairTooltip.hide();\r\n this.chartLegend.setHoverBar(null);\r\n }\r\n });\r\n\r\n // Chart legend (OHLCV overlay)\r\n this.chartLegend = new ChartLegend();\r\n this.chartLegend.setChartType(options.chartType);\r\n\r\n // Watermark + Volume\r\n this.watermark = new Watermark();\r\n if (options.watermark) this.watermark.setConfig(options.watermark);\r\n this.volumeRenderer = new VolumeRenderer();\r\n this.volumeProfile = new VolumeProfileRenderer();\r\n\r\n // Bar countdown timer\r\n this.barCountdown = new BarCountdown();\r\n this.sessionBreaks = new SessionBreaks();\r\n this.compareRenderer = new CompareRenderer();\r\n\r\n // Apply session break config from options\r\n if (options.sessionBreaks) {\r\n this.sessionBreaks.setConfig({\r\n visible: options.sessionBreaks.visible ?? true,\r\n color: options.sessionBreaks.color,\r\n lineStyle: options.sessionBreaks.lineStyle,\r\n lineWidth: options.sessionBreaks.lineWidth,\r\n });\r\n } else if (options.features?.sessionBreaks !== false) {\r\n this.sessionBreaks.setVisible(true);\r\n }\r\n\r\n // Apply log scale from options\r\n if (options.logScale) {\r\n this.viewport.setLogScale(true);\r\n }\r\n\r\n // Animation\r\n this.animator = new Animator();\r\n\r\n // Crosshair tooltip (DOM)\r\n this.crosshairTooltip = new CrosshairTooltip();\r\n this.crosshairTooltip.create(container);\r\n this.pinnedTooltip = new PinnedTooltip();\r\n this.pinnedTooltip.create(container);\r\n\r\n // Keyboard navigation\r\n this.keyboardHandler = new KeyboardHandler({\r\n scrollBars: (count) => {\r\n const barUnit = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;\r\n this.viewport.scrollBy(count * barUnit);\r\n this.updateViewportAndRender();\r\n },\r\n zoom: (delta) => {\r\n const chartWidth = this.viewport.getState().chartRect.width;\r\n this.viewport.zoom(delta, chartWidth / 2);\r\n this.updateViewportAndRender();\r\n },\r\n goToStart: () => {\r\n this.viewport.scrollBy(-Infinity);\r\n this.updateViewportAndRender();\r\n },\r\n goToEnd: () => {\r\n this.viewport.scrollToEnd();\r\n this.updateViewportAndRender();\r\n },\r\n fitContent: () => this.fitContent(),\r\n });\r\n this.keyboardHandler.setEnabled(this.features.keyboard);\r\n\r\n // Attach keyboard listener to window. Only consume the event when the\r\n // chart actually handles the key AND the container is the focused element\r\n // (or an ancestor) — this prevents the chart from swallowing keystrokes\r\n // intended for inputs elsewhere on the page.\r\n this.onWindowKeyDown = (e: KeyboardEvent) => {\r\n if (!this.keyboardHandler) return;\r\n const active = document.activeElement as HTMLElement | null;\r\n if (active && active !== this.container && !this.container.contains(active)) {\r\n return;\r\n }\r\n // Ignore when typing in a form field that happens to live inside the chart.\r\n if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable)) {\r\n return;\r\n }\r\n if (this.keyboardHandler.handleKey(e)) {\r\n e.preventDefault();\r\n }\r\n };\r\n window.addEventListener('keydown', this.onWindowKeyDown);\r\n\r\n // Current price line (standalone, works without StreamManager)\r\n this.currentPriceLine = new CurrentPriceLine();\r\n\r\n // Alerts\r\n this.alertManager = new AlertManager();\r\n this.alertManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\r\n this.alertManager.on('triggered', (alert) => {\r\n this.eventBus.emit('dataUpdate', { alert: 'triggered', alertId: alert.id, price: alert.price, message: alert.message });\r\n });\r\n\r\n // Signal markers\r\n this.signalMarkerManager = new SignalMarkerManager();\r\n this.signalMarkerManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\r\n this.signalMarkerManager.setDataGetter(() => this.dataManager.getData());\r\n this.signalMarkerManager.on('added', (m) => {\r\n this.eventBus.emit('signalMarkerAdd' as ChartEventType, { id: m.id, source: m.source, direction: m.direction });\r\n });\r\n this.signalMarkerManager.on('removed', (id) => {\r\n this.eventBus.emit('signalMarkerRemove' as ChartEventType, { id });\r\n });\r\n\r\n // Trade zones\r\n this.tradeZoneManager = new TradeZoneManager();\r\n this.tradeZoneManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\r\n this.tradeZoneManager.setDataGetter(() => this.dataManager.getData());\r\n this.tradeZoneManager.on('added', (z) => {\r\n this.eventBus.emit('tradeZoneAdd' as ChartEventType, { id: z.id, direction: z.direction });\r\n });\r\n this.tradeZoneManager.on('removed', (id) => {\r\n this.eventBus.emit('tradeZoneRemove' as ChartEventType, { id });\r\n });\r\n\r\n // Replay\r\n this.replayManager = new ReplayManager();\r\n\r\n // Measure overlay (shift-drag ruler)\r\n this.measureOverlay = new MeasureOverlay();\r\n\r\n // Interaction\r\n this.interactionManager = new InteractionManager(container);\r\n if (this.features.panning) {\r\n this.interactionManager.setPanHandler(\r\n new PanHandler((deltaX) => {\r\n this.viewport.scrollBy(deltaX);\r\n this.updateViewportAndRender();\r\n }),\r\n );\r\n }\r\n if (this.features.zooming) {\r\n this.interactionManager.setZoomHandler(\r\n new ZoomHandler((delta, centerX) => {\r\n this.viewport.zoom(delta, centerX);\r\n this.updateViewportAndRender();\r\n }),\r\n );\r\n\r\n // Axis drag-scaling (TradingView-style):\r\n // drag price axis → scalePriceRange(factor), disables autoScale\r\n // drag time axis → zoom around chart center\r\n // dblclick axis → reset (price: re-enable autoScale; time: fitContent)\r\n const axisDrag = new AxisDragHandler(\r\n (factor) => {\r\n this.options.autoScale = false;\r\n this.viewport.scalePriceRange(factor);\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n },\r\n (factor) => {\r\n const cw = this.viewport.getState().chartRect.width;\r\n // factor > 1 means zoom OUT (compress time). Map to negative delta\r\n // because Viewport.zoom uses (1 + delta) on barWidth — positive\r\n // delta zooms in.\r\n this.viewport.zoom(1 / factor - 1, cw / 2);\r\n this.updateViewportAndRender();\r\n },\r\n );\r\n this.interactionManager.setAxisDragHandler(\r\n axisDrag,\r\n () => this.viewport.getState(),\r\n (axis) => {\r\n if (axis === 'price') {\r\n this.options.autoScale = true;\r\n this.updateViewportAndRender();\r\n } else {\r\n this.fitContent();\r\n }\r\n },\r\n );\r\n }\r\n if (this.features.crosshair) {\r\n this.interactionManager.setCrosshairHandler(this.crosshairHandler);\r\n }\r\n if (this.features.drawings) {\r\n this.interactionManager.setDrawingManager(\r\n this.drawingManager,\r\n // Inject current data so drawing anchors are stored/resolved as real\r\n // timestamps (survives timeframe/symbol switches).\r\n () => ({ ...this.viewport.getState(), data: this.getDisplayData() }),\r\n );\r\n }\r\n if (this.features.trading) {\r\n this.interactionManager.setTradingManager(\r\n this.tradingManager,\r\n () => ({ ...this.viewport.getState(), data: this.getDisplayData() }),\r\n );\r\n }\r\n // Alt-click pins the OHLC tooltip at the bar under the cursor. Hitting\r\n // it a second time on the same bar unpins.\r\n this.interactionManager.setAltClickHandler((pos) => {\r\n const data = this.getDisplayData();\r\n if (data.length === 0) return;\r\n const vp = this.viewport.getState();\r\n const barUnit = vp.barWidth + vp.barSpacing;\r\n const idx = Math.round((vp.offset + pos.x) / barUnit);\r\n if (idx < 0 || idx >= data.length) return;\r\n if (this.pinnedTooltip.isPinned() && this.pinnedTooltip.getPinnedIndex() === idx) {\r\n this.pinnedTooltip.unpin();\r\n } else {\r\n this.pinnedTooltip.pin(data[idx], idx, this.themeManager.getTheme());\r\n }\r\n this.pinnedTooltip.reposition(\r\n this.viewport.getState(),\r\n this.dataManager.getData()[idx] ?? null,\r\n idx,\r\n this.themeManager.getTheme(),\r\n );\r\n this.engine.requestRender(LayerType.Overlay);\r\n });\r\n\r\n this.interactionManager.setEscapeHandler(() => {\r\n if (this.pinnedTooltip.isPinned()) {\r\n this.pinnedTooltip.unpin();\r\n this.engine.requestRender(LayerType.Overlay);\r\n }\r\n });\r\n\r\n // Shift-drag measure tool — transient overlay. Coords resolved via\r\n // viewport + displayData so the ruler sticks to the data during zoom.\r\n this.interactionManager.setMeasureHandlers({\r\n begin: (pos) => {\r\n this.measureOverlay.begin(pos, this.viewport.getState(), this.getDisplayData());\r\n },\r\n move: (pos) => {\r\n this.measureOverlay.update(pos, this.viewport.getState(), this.getDisplayData());\r\n },\r\n end: () => {\r\n this.measureOverlay.end();\r\n },\r\n });\r\n\r\n this.interactionManager.setOverlayDirtyCallback(() => {\r\n this.engine.requestRender(LayerType.Overlay);\r\n // UI also dirties on every pointer move because the crosshair hover\r\n // pills (price + time axis labels) live on the UI layer so they\r\n // can sit above the static axis labels.\r\n this.engine.requestRender(LayerType.UI);\r\n });\r\n this.interactionManager.attach();\r\n\r\n // Set render context\r\n this.syncRenderContext();\r\n this.engine.start();\r\n }\r\n\r\n // --- Data ---\r\n\r\n setData(data: DataSeries): void {\r\n this.dataManager.setData(data);\r\n this.crosshairHandler.setData(this.dataManager.getData());\r\n this.displayDataCache = null;\r\n this.sessionBreaks.invalidateCache();\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n // Auto-set current price line from last bar's close\r\n if (data.length > 0) {\r\n this.currentPriceLine.setPrice(data[data.length - 1].close);\r\n }\r\n this.updateViewportAndRender(true);\r\n this.eventBus.emit('dataUpdate', { length: data.length });\r\n }\r\n\r\n appendBar(bar: OHLCBar): void {\r\n this.dataManager.appendBar(bar);\r\n this.crosshairHandler.setData(this.dataManager.getData());\r\n this.displayDataCache = null;\r\n if (this.autoScrollOnNewBar) this.viewport.scrollToEnd();\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.updateViewportAndRender();\r\n }\r\n\r\n /**\r\n * Append multiple bars at once (e.g., catch-up after reconnect).\r\n * More efficient than calling appendBar() in a loop — recalculates\r\n * indicators only once at the end.\r\n */\r\n appendBars(bars: OHLCBar[]): void {\r\n if (bars.length === 0) return;\r\n for (const bar of bars) {\r\n this.dataManager.appendBar(bar);\r\n }\r\n this.displayDataCache = null;\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.crosshairHandler.setData(this.dataManager.getData());\r\n this.updateViewportAndRender(this.viewport.isAtEnd());\r\n }\r\n\r\n updateLastBar(bar: OHLCBar): void {\r\n this.dataManager.updateLastBar(bar);\r\n this.currentPriceLine.setPrice(bar.close);\r\n // For non-transform chart types, the displayDataCache still points to the\r\n // same raw array (mutated in place), so no need to invalidate.\r\n // Only invalidate for transform types that produce derived arrays.\r\n if (this.options.chartType !== 'candlestick' && this.options.chartType !== 'line'\r\n && this.options.chartType !== 'area' && this.options.chartType !== 'bar'\r\n && this.options.chartType !== 'hollowCandle') {\r\n this.displayDataCache = null;\r\n }\r\n // Keep indicator lines in sync with the forming bar. Without this, panel\r\n // + overlay indicators freeze until bar close.\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.scheduleRender();\r\n }\r\n\r\n /** Merge a price tick into the current last bar (convenience for live feeds) */\r\n updateLastBarFromTick(tick: { price: number; volume?: number; time: number }): void {\r\n this.dataManager.updateLastBarFromTick(tick);\r\n this.currentPriceLine.setPrice(tick.price);\r\n if (this.options.chartType !== 'candlestick' && this.options.chartType !== 'line'\r\n && this.options.chartType !== 'area' && this.options.chartType !== 'bar'\r\n && this.options.chartType !== 'hollowCandle') {\r\n this.displayDataCache = null;\r\n }\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.scheduleRender();\r\n }\r\n\r\n // --- Chart type ---\r\n\r\n setChartType(type: ChartType): void {\r\n this.options.chartType = type;\r\n this.chartRenderer = this.createChartRenderer(type);\r\n this.chartLegend.setChartType(type);\r\n this.displayDataCache = null;\r\n this.updateViewportAndRender(true);\r\n }\r\n\r\n // --- Indicators ---\r\n\r\n addIndicator(id: string, params: Record<string, number | string | boolean> = {}, position: PanelPosition = 'bottom'): string | null {\r\n if (!this.features.indicators) return null;\r\n if (this.features.indicatorIds.length > 0 && !this.features.indicatorIds.includes(id)) return null;\r\n const instanceId = this.indicatorEngine.addIndicator(id, params, this.dataManager.getData());\r\n const descriptor = this.indicatorEngine.getAvailableIndicators().find((d) => d.id === id);\r\n if (descriptor?.placement === 'panel') {\r\n this.layoutManager.addPanel(instanceId, position);\r\n // Panel layout changed — must re-resolve layout, update viewport, and sync render context\r\n this.updateViewportAndRender();\r\n } else {\r\n this.engine.requestRender();\r\n }\r\n this.eventBus.emit('indicatorAdd', { instanceId, id });\r\n return instanceId;\r\n }\r\n\r\n updateIndicator(instanceId: string, params: Record<string, number | string | boolean>): void {\r\n this.indicatorEngine.updateIndicator(instanceId, params, this.dataManager.getData());\r\n this.engine.requestRender();\r\n }\r\n\r\n removeIndicator(instanceId: string): void {\r\n const hadPanel = this.layoutManager.getPanels().some(p => p.id === instanceId);\r\n this.indicatorEngine.removeIndicator(instanceId);\r\n this.layoutManager.removePanel(instanceId);\r\n this.eventBus.emit('indicatorRemove', { instanceId });\r\n if (hadPanel) {\r\n this.updateViewportAndRender();\r\n } else {\r\n this.engine.requestRender();\r\n }\r\n }\r\n\r\n getIndicatorOutput(instanceId: string): IndicatorOutput | null {\r\n return this.indicatorEngine.getOutput(instanceId);\r\n }\r\n\r\n registerIndicator(plugin: IndicatorPlugin): void {\r\n this.pluginManager.registerIndicator(plugin);\r\n }\r\n\r\n static indicators(): IndicatorDescriptor[] {\r\n const engine = new IndicatorEngine();\r\n registerBuiltInIndicators(engine);\r\n return engine.getAvailableIndicators();\r\n }\r\n\r\n // --- Panel layout ---\r\n\r\n setPanelPosition(instanceId: string, position: PanelPosition): void {\r\n this.layoutManager.setPanelPosition(instanceId, position);\r\n this.engine.requestRender();\r\n }\r\n\r\n setPanelSize(instanceId: string, size: number): void {\r\n this.layoutManager.setPanelSize(instanceId, size);\r\n this.engine.requestRender();\r\n }\r\n\r\n // --- Drawing tools ---\r\n\r\n setDrawingTool(type: DrawingToolType | null): void {\r\n if (!this.features.drawings) return;\r\n // If whitelist is set, check it\r\n if (type && this.features.drawingTools.length > 0 && !this.features.drawingTools.includes(type)) return;\r\n this.drawingManager.setActiveTool(type);\r\n }\r\n\r\n getDrawingTool(): DrawingToolType | null {\r\n return this.drawingManager.getActiveTool();\r\n }\r\n\r\n setDrawingStyle(style: Partial<DrawingStyle>): void {\r\n this.drawingManager.setStyle(style);\r\n }\r\n\r\n getDrawings(): DrawingState[] {\r\n return this.drawingManager.getDrawings();\r\n }\r\n\r\n setDrawings(drawings: DrawingState[]): void {\r\n this.drawingManager.setDrawings(drawings);\r\n }\r\n\r\n removeDrawing(id: string): void {\r\n this.drawingManager.removeDrawing(id);\r\n }\r\n\r\n clearDrawings(): void {\r\n this.drawingManager.clearDrawings();\r\n }\r\n\r\n registerDrawingTool(plugin: DrawingPlugin): void {\r\n this.drawingManager.register(plugin);\r\n }\r\n\r\n // --- Undo/Redo ---\r\n\r\n undo(): boolean {\r\n if (!this.features.drawingUndoRedo) return false;\r\n return this.drawingManager.undo();\r\n }\r\n\r\n redo(): boolean {\r\n if (!this.features.drawingUndoRedo) return false;\r\n return this.drawingManager.redo();\r\n }\r\n\r\n getUndoRedoState(): { canUndo: boolean; canRedo: boolean } {\r\n return this.undoRedoManager.getState();\r\n }\r\n\r\n // --- Drawing magnet ---\r\n\r\n setDrawingMagnet(enabled: boolean): void {\r\n this.drawingManager.setMagnetMode(enabled ? 'magnet' : 'none');\r\n }\r\n\r\n getDrawingMagnet(): boolean {\r\n return this.drawingManager.getMagnetMode() === 'magnet';\r\n }\r\n\r\n // --- Bulk drawing operations ---\r\n\r\n lockAllDrawings(): void {\r\n this.drawingManager.lockAllDrawings();\r\n }\r\n\r\n unlockAllDrawings(): void {\r\n this.drawingManager.unlockAllDrawings();\r\n }\r\n\r\n hideAllDrawings(): void {\r\n this.drawingManager.hideAllDrawings();\r\n }\r\n\r\n showAllDrawings(): void {\r\n this.drawingManager.showAllDrawings();\r\n }\r\n\r\n // --- Drawing duplication ---\r\n\r\n duplicateDrawing(id?: string): string | null {\r\n const targetId = id ?? this.drawingManager.getSelectedDrawingId();\r\n if (!targetId) return null;\r\n return this.drawingManager.duplicateDrawing(targetId);\r\n }\r\n\r\n // --- Data export ---\r\n\r\n exportVisibleData(format: 'csv' | 'json' = 'csv', filename?: string): void {\r\n const vp = this.viewport.getState();\r\n const data = this.dataManager.getData();\r\n const from = Math.max(0, vp.visibleRange.from);\r\n const to = Math.min(data.length - 1, vp.visibleRange.to);\r\n const slice = data.slice(from, to + 1);\r\n\r\n if (format === 'json') {\r\n const content = DataExporter.toJSON(slice);\r\n DataExporter.download(content, filename ?? 'chart-data.json', 'application/json');\r\n } else {\r\n const content = DataExporter.toCSV(slice);\r\n DataExporter.download(content, filename ?? 'chart-data.csv', 'text/csv');\r\n }\r\n }\r\n\r\n exportAllData(format: 'csv' | 'json' = 'csv', filename?: string): void {\r\n const data = this.dataManager.getData();\r\n if (format === 'json') {\r\n const content = DataExporter.toJSON(data);\r\n DataExporter.download(content, filename ?? 'chart-data.json', 'application/json');\r\n } else {\r\n const content = DataExporter.toCSV(data);\r\n DataExporter.download(content, filename ?? 'chart-data.csv', 'text/csv');\r\n }\r\n }\r\n\r\n // --- Auto-save ---\r\n\r\n setAutoSave(key: string, delayMs = 5000): void {\r\n this.autoSaveScheduler.enable(key, delayMs);\r\n }\r\n\r\n disableAutoSave(): void {\r\n this.autoSaveScheduler.disable();\r\n }\r\n\r\n private scheduleAutoSave(): void {\r\n this.autoSaveScheduler.schedule();\r\n }\r\n\r\n // --- Indicator introspection ---\r\n\r\n getAvailableIndicators(): IndicatorDescriptor[] {\r\n return this.indicatorEngine.getAvailableIndicators();\r\n }\r\n\r\n getIndicatorInputs(id: string): { id: string; params: Record<string, unknown> } | null {\r\n const indicators = this.indicatorEngine.getAvailableIndicators();\r\n const desc = indicators.find(i => i.id === id);\r\n if (!desc) return null;\r\n return { id: desc.id, params: desc.defaultConfig };\r\n }\r\n\r\n /** Get all active indicator instances with their current params */\r\n getActiveIndicators(): { instanceId: string; id: string; params: Record<string, unknown>; descriptor: IndicatorDescriptor }[] {\r\n return this.indicatorEngine.getActiveIndicators();\r\n }\r\n\r\n /** Get current config for a specific indicator instance */\r\n getIndicatorConfig(instanceId: string): { id: string; params: Record<string, unknown> } | null {\r\n const config = this.indicatorEngine.getIndicatorConfig(instanceId);\r\n if (!config) return null;\r\n return { id: config.id, params: { ...config.params } };\r\n }\r\n\r\n /** Update indicator colors/line widths at runtime */\r\n updateIndicatorStyle(instanceId: string, style: { colors?: string[]; lineWidths?: number[]; opacity?: number }): void {\r\n this.indicatorEngine.updateIndicatorStyle(instanceId, style);\r\n this.engine.requestRender();\r\n }\r\n\r\n // --- Trading ---\r\n\r\n setOrders(orders: TradingOrder[]): void {\r\n if (!this.features.trading) return;\r\n this.tradingManager.setOrders(orders);\r\n }\r\n\r\n setPositions(positions: TradingPosition[]): void {\r\n if (!this.features.trading) return;\r\n this.tradingManager.setPositions(positions);\r\n }\r\n\r\n setDepthData(depth: DepthData | null): void {\r\n if (!this.features.trading) return;\r\n this.tradingManager.setDepthData(depth);\r\n }\r\n\r\n setCurrentPrice(price: number, _pulseColor?: string): void {\r\n this.tradingManager.setCurrentPrice(price);\r\n // Also update standalone price line (visible even without trading feature)\r\n this.currentPriceLine.setPrice(price);\r\n this.scheduleRender();\r\n if (this.features.alerts) this.alertManager.checkPrice(price);\r\n }\r\n\r\n setTradingConfig(config: Partial<TradingConfig>): void {\r\n if (!this.features.trading) return;\r\n this.tradingManager.setConfig(config);\r\n }\r\n\r\n // --- Real-time Streaming ---\r\n\r\n /**\r\n * Connect to a real-time data source.\r\n * Loads history, starts streaming, manages reconnection automatically.\r\n *\r\n * @example\r\n * import { BinanceAdapter } from '@tradecanvas/core';\r\n * chart.connect({\r\n * adapter: new BinanceAdapter(),\r\n * symbol: 'BTCUSDT',\r\n * timeframe: '1m',\r\n * });\r\n */\r\n async connect(config: StreamConfig): Promise<void> {\r\n this.disconnectStream();\r\n\r\n this.streamManager = new StreamManager();\r\n\r\n this.streamManager.on('snapshot', (bars) => {\r\n this.setData(bars);\r\n });\r\n\r\n this.streamManager.on('barClose', (bar) => {\r\n this.dataManager.appendBar(bar);\r\n this.crosshairHandler.setData(this.dataManager.getData());\r\n if (this.autoScrollOnNewBar) this.viewport.scrollToEnd();\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.updateViewportAndRender();\r\n });\r\n\r\n this.streamManager.on('barUpdate', (bar) => {\r\n this.dataManager.updateLastBar(bar);\r\n this.currentPriceLine.setPrice(bar.close);\r\n // Recalculate indicators so panel/overlay series track the forming bar\r\n // instead of freezing until bar close.\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.scheduleRender();\r\n });\r\n\r\n this.streamManager.on('priceChange', ({ price }) => {\r\n this.tradingManager.setCurrentPrice(price);\r\n this.currentPriceLine.setPrice(price);\r\n this.engine.requestRender(LayerType.Overlay);\r\n this.engine.requestRender(LayerType.UI);\r\n });\r\n\r\n this.streamManager.on('connectionChange', (info) => {\r\n this.eventBus.emit('dataUpdate', { connection: info });\r\n });\r\n\r\n this.streamManager.on('error', (err) => {\r\n this.eventBus.emit('dataUpdate', { error: err.message });\r\n });\r\n\r\n this.autoScrollOnNewBar = config.autoScroll !== false;\r\n this.currentSymbol = config.symbol;\r\n\r\n await this.streamManager.connect(config);\r\n\r\n // Set up bar countdown timer based on timeframe\r\n const tfMs = timeframeToMs(config.timeframe);\r\n this.barCountdown.setTimeframeMs(tfMs);\r\n\r\n // Start countdown refresh interval\r\n if (this.countdownInterval) clearInterval(this.countdownInterval);\r\n this.countdownInterval = setInterval(() => {\r\n if (this.barCountdown.isVisible()) {\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n }, 1000);\r\n }\r\n\r\n /**\r\n * Switch symbol or timeframe on an active stream without full reconnect.\r\n */\r\n async switchStream(symbol: string, timeframe: TimeFrame): Promise<void> {\r\n if (!this.streamManager) return;\r\n this.currentSymbol = symbol;\r\n await this.streamManager.switchTo(symbol, timeframe);\r\n }\r\n\r\n /**\r\n * Switch to a new timeframe. Requires an active stream connection.\r\n * Internally calls switchStream with the current symbol.\r\n */\r\n async setTimeframe(timeframe: TimeFrame): Promise<void> {\r\n if (!this.streamManager) throw new Error('No active stream. Call connect() first.');\r\n await this.switchStream(this.currentSymbol, timeframe);\r\n }\r\n\r\n /**\r\n * Disconnect the real-time stream.\r\n */\r\n disconnectStream(): void {\r\n if (this.streamManager) {\r\n this.streamManager.dispose();\r\n this.streamManager = null;\r\n }\r\n }\r\n\r\n setBarCountdownVisible(visible: boolean): void {\r\n this.barCountdown.setVisible(visible);\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n\r\n setSessionBreaksVisible(visible: boolean): void {\r\n this.sessionBreaks.setVisible(visible);\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n\r\n // --- Compare symbols ---\r\n\r\n addCompareSymbol(id: string, label: string, data: DataSeries, color: string): void {\r\n this.compareRenderer.addSymbol({ id, label, data, color, visible: true });\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n removeCompareSymbol(id: string): void {\r\n this.compareRenderer.removeSymbol(id);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n updateCompareData(id: string, data: DataSeries): void {\r\n this.compareRenderer.setSymbolData(id, data);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n setCompareMode(mode: 'percent' | 'absolute'): void {\r\n this.compareRenderer.setMode(mode);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n clearCompareSymbols(): void {\r\n this.compareRenderer.clear();\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n // --- Log scale ---\r\n\r\n setLogScale(enabled: boolean): void {\r\n this.viewport.setLogScale(enabled);\r\n this.updateViewportAndRender();\r\n }\r\n\r\n isLogScale(): boolean {\r\n return this.viewport.isLogScale();\r\n }\r\n\r\n setSessionBreaksConfig(config: { color?: string; lineStyle?: 'solid' | 'dashed' | 'dotted'; lineWidth?: number }): void {\r\n this.sessionBreaks.setConfig(config);\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n\r\n getConnectionState(): ConnectionState {\r\n return this.streamManager?.getConnectionState() ?? 'disconnected';\r\n }\r\n\r\n getConnectionInfo(): ConnectionInfo {\r\n return this.streamManager?.getConnectionInfo() ?? { state: 'disconnected' };\r\n }\r\n\r\n setAutoScroll(enabled: boolean): void {\r\n this.autoScrollOnNewBar = enabled;\r\n }\r\n\r\n // --- Viewport ---\r\n\r\n scrollTo(timestamp: number): void {\r\n const data = this.dataManager.getData();\r\n for (let i = 0; i < data.length; i++) {\r\n if (data[i].time >= timestamp) {\r\n const barUnit = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;\r\n this.viewport.scrollBy(i * barUnit - this.viewport.getState().offset);\r\n this.updateViewportAndRender();\r\n return;\r\n }\r\n }\r\n }\r\n\r\n scrollToEnd(): void {\r\n this.viewport.scrollToEnd();\r\n this.updateViewportAndRender();\r\n }\r\n\r\n setVisibleRange(fromTimestamp: number, toTimestamp: number): void {\r\n const data = this.dataManager.getData();\r\n let fromIdx = 0;\r\n let toIdx = data.length - 1;\r\n for (let i = 0; i < data.length; i++) {\r\n if (data[i].time >= fromTimestamp) { fromIdx = i; break; }\r\n }\r\n for (let i = data.length - 1; i >= 0; i--) {\r\n if (data[i].time <= toTimestamp) { toIdx = i; break; }\r\n }\r\n const barCount = toIdx - fromIdx + 1;\r\n if (barCount > 0) {\r\n const chartWidth = this.viewport.getState().chartRect.width;\r\n const targetBarUnit = chartWidth / barCount;\r\n const newBarWidth = Math.max(2, targetBarUnit - this.viewport.getState().barSpacing);\r\n this.viewport.zoom(\r\n (newBarWidth - this.viewport.getState().barWidth) / this.viewport.getState().barWidth,\r\n chartWidth / 2,\r\n );\r\n }\r\n this.updateViewportAndRender();\r\n }\r\n\r\n zoomIn(): void {\r\n const chartWidth = this.viewport.getState().chartRect.width;\r\n this.viewport.zoom(0.2, chartWidth / 2);\r\n this.updateViewportAndRender();\r\n }\r\n\r\n zoomOut(): void {\r\n const chartWidth = this.viewport.getState().chartRect.width;\r\n this.viewport.zoom(-0.2, chartWidth / 2);\r\n this.updateViewportAndRender();\r\n }\r\n\r\n fitContent(): void {\r\n const data = this.dataManager.getData();\r\n if (data.length === 0) return;\r\n this.setVisibleRange(data[0].time, data[data.length - 1].time);\r\n }\r\n\r\n // --- Events ---\r\n\r\n on<K extends ChartEventType>(type: K, handler: (event: ChartEvent<K extends keyof ChartEventMap ? ChartEventMap[K] : unknown>) => void): void {\r\n this.eventBus.on(type, handler as (event: ChartEvent) => void);\r\n }\r\n\r\n off<K extends ChartEventType>(type: K, handler: (event: ChartEvent<K extends keyof ChartEventMap ? ChartEventMap[K] : unknown>) => void): void {\r\n this.eventBus.off(type, handler as (event: ChartEvent) => void);\r\n }\r\n\r\n enableTauriBridge(options?: Partial<TauriBridgeOptions>): void {\r\n this.eventBus.enableTauriBridge({ enabled: true, ...options });\r\n }\r\n\r\n disableTauriBridge(): void {\r\n this.eventBus.disableTauriBridge();\r\n }\r\n\r\n // --- Theme ---\r\n\r\n setTheme(themeOrName: ThemeName | Theme): void {\r\n this.themeManager.setTheme(themeOrName);\r\n this.syncRenderContext();\r\n this.container.style.backgroundColor = this.themeManager.getTheme().background;\r\n this.engine.requestRender();\r\n this.eventBus.emit('themeChange', { theme: themeOrName });\r\n }\r\n\r\n getTheme(): Theme {\r\n return this.themeManager.getTheme();\r\n }\r\n\r\n // --- Watermark ---\r\n\r\n setWatermark(text: string, opts?: { color?: string; fontSize?: number }): void {\r\n this.watermark.setConfig({ text, ...opts });\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n\r\n // --- Auto Scale ---\r\n\r\n setAutoScale(enabled: boolean): void {\r\n this.options.autoScale = enabled;\r\n this.updateViewportAndRender();\r\n }\r\n\r\n isAutoScale(): boolean {\r\n return this.options.autoScale !== false;\r\n }\r\n\r\n // --- Crosshair ---\r\n\r\n setCrosshairMode(mode: 'normal' | 'magnet' | 'hidden'): void {\r\n this.crosshairHandler.setMode(mode);\r\n this.engine.requestRender(LayerType.Overlay);\r\n }\r\n\r\n getCrosshairMode(): string {\r\n return this.crosshairHandler.getMode();\r\n }\r\n\r\n setCrosshairPosition(point: { x: number; y: number } | null): void {\r\n if (point) {\r\n this.crosshairHandler.onPointerMove(point);\r\n }\r\n this.engine.requestRender(LayerType.Overlay);\r\n }\r\n\r\n getData(): DataSeries {\r\n return this.dataManager.getData();\r\n }\r\n\r\n // --- Grid ---\r\n\r\n setGridVisible(visible: boolean): void {\r\n this.gridRenderer.setVisible(visible);\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n\r\n isGridVisible(): boolean {\r\n return this.gridRenderer.isVisible();\r\n }\r\n\r\n // --- Volume ---\r\n\r\n setVolumeVisible(visible: boolean): void {\r\n this.volumeRenderer.setVisible(visible);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n // --- Volume Profile ---\r\n\r\n setVolumeProfileVisible(visible: boolean): void {\r\n this.volumeProfile.setVisible(visible);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n isVolumeProfileVisible(): boolean {\r\n return this.volumeProfile.isVisible();\r\n }\r\n\r\n setVolumeProfileConfig(config: { buckets?: number; widthRatio?: number; opacity?: number; highlightPoC?: boolean }): void {\r\n if (config.buckets !== undefined) this.volumeProfile.setBuckets(config.buckets);\r\n if (config.widthRatio !== undefined) this.volumeProfile.setWidthRatio(config.widthRatio);\r\n if (config.opacity !== undefined) this.volumeProfile.setOpacity(config.opacity);\r\n if (config.highlightPoC !== undefined) this.volumeProfile.setHighlightPoC(config.highlightPoC);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n // --- Tooltip ---\r\n\r\n setTooltipVisible(visible: boolean): void {\r\n if (!visible) this.crosshairTooltip.hide();\r\n }\r\n\r\n // --- Legend ---\r\n\r\n setLegend(config: Partial<import('@tradecanvas/core').LegendConfig>): void {\r\n this.chartLegend.setConfig(config);\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n\r\n setSymbolName(symbol: string): void {\r\n this.chartLegend.setSymbol(symbol);\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n\r\n /**\r\n * Set a status text displayed in the chart legend area (e.g., \"LIVE . 8ms\").\r\n * Pass null to clear.\r\n */\r\n setStatusText(text: string | null): void {\r\n this.chartLegend.setStatusText(text);\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n\r\n // --- Screenshot ---\r\n\r\n screenshot(filename?: string): void {\r\n if (!this.features.screenshot) return;\r\n Screenshot.download(this.container, filename, this.themeManager.getTheme().background);\r\n }\r\n\r\n screenshotDataURL(): string | null {\r\n if (!this.features.screenshot) return null;\r\n return Screenshot.toDataURL(this.container, this.themeManager.getTheme().background);\r\n }\r\n\r\n async screenshotBlob(): Promise<Blob | null> {\r\n if (!this.features.screenshot) return null;\r\n return Screenshot.toBlob(this.container, this.themeManager.getTheme().background);\r\n }\r\n\r\n // --- Alerts ---\r\n\r\n addAlert(price: number, condition: import('@tradecanvas/core').AlertCondition = 'crossing', message?: string): string | null {\r\n if (!this.features.alerts) return null;\r\n const id = this.alertManager.addAlert(price, condition, message);\r\n this.scheduleAutoSave();\r\n return id;\r\n }\r\n\r\n removeAlert(id: string): void {\r\n this.alertManager.removeAlert(id);\r\n this.scheduleAutoSave();\r\n }\r\n\r\n getAlerts(): import('@tradecanvas/core').PriceAlert[] {\r\n return this.alertManager.getAlerts();\r\n }\r\n\r\n clearAlerts(): void {\r\n this.alertManager.clearAlerts();\r\n this.scheduleAutoSave();\r\n }\r\n\r\n saveAlerts(key: string): void {\r\n this.alertManager.saveToStorage(key);\r\n }\r\n\r\n loadAlerts(key: string): void {\r\n this.alertManager.loadFromStorage(key);\r\n this.engine.requestRender(LayerType.Overlay);\r\n }\r\n\r\n // --- Signal Markers ---\r\n\r\n addSignalMarker(marker: Omit<import('@tradecanvas/commons').SignalMarker, 'id'> & { id?: string }): string {\r\n return this.signalMarkerManager.addMarker(marker);\r\n }\r\n\r\n removeSignalMarker(id: string): void {\r\n this.signalMarkerManager.removeMarker(id);\r\n }\r\n\r\n getSignalMarkers(): import('@tradecanvas/commons').SignalMarker[] {\r\n return this.signalMarkerManager.getMarkers();\r\n }\r\n\r\n setSignalMarkers(markers: import('@tradecanvas/commons').SignalMarker[]): void {\r\n this.signalMarkerManager.setMarkers(markers);\r\n }\r\n\r\n clearSignalMarkers(): void {\r\n this.signalMarkerManager.clearMarkers();\r\n }\r\n\r\n setSignalMarkerStyle(style: Partial<import('@tradecanvas/commons').SignalMarkerStyle>): void {\r\n this.signalMarkerManager.setStyle(style);\r\n }\r\n\r\n // --- Trade Zones ---\r\n\r\n addTradeZone(zone: Omit<import('@tradecanvas/commons').TradeZone, 'id'> & { id?: string }): string {\r\n return this.tradeZoneManager.addZone(zone);\r\n }\r\n\r\n updateTradeZone(id: string, updates: Partial<Omit<import('@tradecanvas/commons').TradeZone, 'id'>>): void {\r\n this.tradeZoneManager.updateZone(id, updates);\r\n }\r\n\r\n removeTradeZone(id: string): void {\r\n this.tradeZoneManager.removeZone(id);\r\n }\r\n\r\n getTradeZones(): import('@tradecanvas/commons').TradeZone[] {\r\n return this.tradeZoneManager.getZones();\r\n }\r\n\r\n setTradeZones(zones: import('@tradecanvas/commons').TradeZone[]): void {\r\n this.tradeZoneManager.setZones(zones);\r\n }\r\n\r\n clearTradeZones(): void {\r\n this.tradeZoneManager.clearZones();\r\n }\r\n\r\n setTradeZoneStyle(style: Partial<import('@tradecanvas/commons').TradeZoneStyle>): void {\r\n this.tradeZoneManager.setStyle(style);\r\n }\r\n\r\n // --- Replay ---\r\n\r\n replay(config?: Partial<import('@tradecanvas/core').ReplayConfig>): void {\r\n if (!this.features.replay) return;\r\n const data = this.dataManager.getData();\r\n this.replayManager.load(data);\r\n this.replayManager.on('bar', ({ bar: _bar, index }) => {\r\n const slice = data.slice(0, index + 1);\r\n this.dataManager.setData(slice);\r\n this.crosshairHandler.setData(slice);\r\n this.indicatorEngine.recalculateAll(slice);\r\n this.updateViewportAndRender();\r\n });\r\n this.replayManager.play(config);\r\n }\r\n\r\n replayPause(): void { this.replayManager.pause(); }\r\n replayResume(): void { this.replayManager.resume(); }\r\n replayStop(): void { this.replayManager.stop(); }\r\n replaySeek(index: number): void { this.replayManager.seekTo(index); }\r\n setReplaySpeed(speed: number): void { this.replayManager.setSpeed(speed); }\r\n getReplayState(): 'playing' | 'paused' | 'stopped' { return this.replayManager.getState(); }\r\n getReplayProgress(): { current: number; total: number; percent: number } { return this.replayManager.getProgress(); }\r\n\r\n // --- Save / Load ---\r\n\r\n saveState(key?: string): string | null {\r\n if (!this.features.saveLoad) return null;\r\n const snapshot = ChartStateManager.capture(\r\n {\r\n getDrawings: () => this.getDrawings(),\r\n getTheme: () => this.getTheme(),\r\n getAlerts: () => this.getAlerts(),\r\n },\r\n { chartType: this.options.chartType },\r\n );\r\n const json = ChartStateManager.serialize(snapshot);\r\n if (key) ChartStateManager.saveToStorage(key, snapshot);\r\n return json;\r\n }\r\n\r\n loadState(json: string): void {\r\n if (!this.features.saveLoad) return;\r\n const snapshot = ChartStateManager.deserialize(json);\r\n if (snapshot.chartType) this.setChartType(snapshot.chartType);\r\n if (snapshot.drawings) this.setDrawings(snapshot.drawings);\r\n if (snapshot.theme) this.setTheme(snapshot.theme as any);\r\n if (snapshot.alerts) {\r\n this.clearAlerts();\r\n for (const a of snapshot.alerts) {\r\n this.addAlert(a.price, a.condition, a.message);\r\n }\r\n }\r\n }\r\n\r\n loadStateFromStorage(key: string): boolean {\r\n if (!this.features.saveLoad) return false;\r\n const snapshot = ChartStateManager.loadFromStorage(key);\r\n if (!snapshot) return false;\r\n this.loadState(ChartStateManager.serialize(snapshot));\r\n return true;\r\n }\r\n\r\n downloadState(filename?: string): void {\r\n if (!this.features.saveLoad) return;\r\n const snapshot = ChartStateManager.capture(\r\n { getDrawings: () => this.getDrawings(), getTheme: () => this.getTheme(), getAlerts: () => this.getAlerts() },\r\n { chartType: this.options.chartType },\r\n );\r\n ChartStateManager.downloadFile(snapshot, filename);\r\n }\r\n\r\n async loadStateFromFile(): Promise<void> {\r\n if (!this.features.saveLoad) return;\r\n const snapshot = await ChartStateManager.loadFromFile();\r\n this.loadState(ChartStateManager.serialize(snapshot));\r\n }\r\n\r\n // --- Locale ---\r\n\r\n setLocale(locale: Locale): void {\r\n setGlobalLocale(locale);\r\n this.engine.requestRender();\r\n }\r\n\r\n /**\r\n * Update the BCP 47 locale used for number formatting\r\n * (e.g. price axis labels, crosshair value badges).\r\n * Defaults to 'en-US'. Example values: 'de-DE', 'vi-VN', 'fr-FR'.\r\n */\r\n setNumberLocale(locale: string): void {\r\n this.numberLocale = locale;\r\n this.priceAxis.setLocale(locale);\r\n this.crosshairHandler.setLocale(locale);\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n }\r\n\r\n getNumberLocale(): string {\r\n return this.numberLocale;\r\n }\r\n\r\n // --- Market ---\r\n\r\n setMarket(config: MarketConfig): void {\r\n this.marketConfig = config;\r\n\r\n // Apply market color scheme to theme\r\n if (config.colorScheme) {\r\n const base = this.themeManager.getTheme();\r\n const marketTheme: Theme = {\r\n ...base,\r\n candleUp: config.colorScheme.up,\r\n candleDown: config.colorScheme.down,\r\n candleUpWick: config.colorScheme.up,\r\n candleDownWick: config.colorScheme.down,\r\n volumeUp: config.colorScheme.up.replace(')', ', 0.3)').replace('rgb(', 'rgba(') || `${config.colorScheme.up}4D`,\r\n volumeDown: config.colorScheme.down.replace(')', ', 0.3)').replace('rgb(', 'rgba(') || `${config.colorScheme.down}4D`,\r\n };\r\n this.themeManager.setTheme(marketTheme);\r\n }\r\n\r\n // Apply price precision to trading, alerts, and price line\r\n if (config.pricePrecision !== undefined) {\r\n this.tradingManager.setConfig({ pricePrecision: config.pricePrecision });\r\n this.alertManager.setPricePrecision(config.pricePrecision);\r\n this.streamManager?.priceLine.setPricePrecision(config.pricePrecision);\r\n this.crosshairHandler.setPricePrecision(config.pricePrecision);\r\n }\r\n\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n }\r\n\r\n getMarket(): MarketConfig | null {\r\n return this.marketConfig;\r\n }\r\n\r\n setPriceLimits(referencePrice: number): void {\r\n if (!this.marketConfig) return;\r\n const limits = computePriceLimits(referencePrice, this.marketConfig);\r\n if (limits) {\r\n this.marketConfig.priceLimits = {\r\n ...this.marketConfig.priceLimits!,\r\n referencePrice,\r\n };\r\n }\r\n this.engine.requestRender();\r\n }\r\n\r\n // --- Features ---\r\n\r\n /** Get the resolved feature configuration */\r\n getFeatures(): Readonly<Required<FeaturesConfig>> {\r\n return this.features;\r\n }\r\n\r\n /** Update feature flags at runtime. Only provided keys are changed. */\r\n setFeatures(patch: Partial<FeaturesConfig>): void {\r\n Object.assign(this.features, patch);\r\n\r\n // Apply immediate side-effects\r\n if (patch.crosshair === false) {\r\n this.crosshairTooltip.hide();\r\n }\r\n if (patch.grid !== undefined) {\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n if (patch.volume !== undefined) {\r\n this.volumeRenderer.setVisible(patch.volume);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n if (patch.drawings === false) {\r\n this.drawingManager.setActiveTool(null);\r\n }\r\n if (patch.trading === false) {\r\n this.tradingManager.setOrders([]);\r\n this.tradingManager.setPositions([]);\r\n }\r\n if (patch.keyboard !== undefined) {\r\n this.keyboardHandler?.setEnabled(patch.keyboard);\r\n }\r\n\r\n this.engine.requestRender();\r\n }\r\n\r\n // --- Lifecycle ---\r\n\r\n resize(): void {\r\n const size = this.engine.dprManager.readContainerSize();\r\n if (size.width <= 0 || size.height <= 0) return;\r\n this.containerSizeCache = size;\r\n this.containerSizeCacheTime = Date.now();\r\n // Resize canvas layers immediately (don't wait for DPRManager's debounced callback)\r\n const dpr = this.engine.dprManager.getDpr();\r\n this.engine.layerManager.resize(size, dpr);\r\n // Check if viewport was at the end before resize\r\n const wasAtEnd = this.viewport.isAtEnd();\r\n this.viewport.resize(size.width, size.height);\r\n this.layoutManager.resize(size.width, size.height);\r\n this.updateViewportAndRender(wasAtEnd);\r\n this.eventBus.emit('resize', size);\r\n }\r\n\r\n destroy(): void {\r\n if (this.countdownInterval) clearInterval(this.countdownInterval);\r\n this.disableAutoSave();\r\n this.disconnectStream();\r\n if (this.onWindowKeyDown) {\r\n window.removeEventListener('keydown', this.onWindowKeyDown);\r\n this.onWindowKeyDown = null;\r\n }\r\n this.keyboardHandler = null;\r\n this.interactionManager.detach();\r\n this.tradingManager.destroy();\r\n this.animator.dispose();\r\n this.crosshairTooltip.destroy();\r\n this.pinnedTooltip.destroy();\r\n this.replayManager.dispose();\r\n this.undoRedoManager.clear();\r\n this.engine.destroy();\r\n this.eventBus.destroy();\r\n this.container.innerHTML = '';\r\n }\r\n\r\n // --- Internal ---\r\n\r\n private createChartRenderer(type: ChartType): ChartRendererInterface {\r\n return createRendererFor(type);\r\n }\r\n\r\n /** Cached display data. Invalidated when raw data or chart type changes. */\r\n private getDisplayData(): DataSeries {\r\n if (this.displayDataCache) return this.displayDataCache;\r\n const raw = this.dataManager.getData();\r\n if (raw.length === 0) return raw;\r\n const result = transformDisplayData(this.options.chartType, raw);\r\n this.displayDataCache = result;\r\n return result;\r\n }\r\n\r\n /** Lightweight render for streaming updates. No layout resolve, no indicator recalc. */\r\n private scheduleRender(): void {\r\n if (this.renderScheduled) return;\r\n this.renderScheduled = true;\r\n requestAnimationFrame(() => {\r\n this.renderScheduled = false;\r\n const displayData = this.getDisplayData();\r\n this.viewport.updateData(displayData, this.options.autoScale !== false);\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n });\r\n }\r\n\r\n /** Full update: resolve layout, update viewport, sync context, request render. */\r\n private updateViewportAndRender(scrollToEnd = false): void {\r\n // Invalidate layout cache\r\n this.resolvedLayoutCache = null;\r\n this.panelInfoCache = null;\r\n\r\n const resolved = this.getResolvedLayout();\r\n this.viewport.setChartRect(resolved.mainChartRect);\r\n\r\n const displayData = this.getDisplayData();\r\n this.viewport.updateData(displayData, this.options.autoScale !== false);\r\n\r\n // Expand price range to include overlay indicator values (BB, Ichimoku, etc.)\r\n if (this.options.autoScale !== false) {\r\n const vs = this.viewport.getState();\r\n const overlayRange = this.indicatorEngine.getOverlayPriceRange(\r\n vs.visibleRange.from,\r\n Math.min(vs.visibleRange.to, displayData.length - 1),\r\n );\r\n if (overlayRange) {\r\n const current = vs.priceRange;\r\n const expandedMin = Math.min(current.min, overlayRange.min);\r\n const expandedMax = Math.max(current.max, overlayRange.max);\r\n if (expandedMin < current.min || expandedMax > current.max) {\r\n const range = expandedMax - expandedMin || 1;\r\n this.viewport.setPriceRange(\r\n expandedMin - range * 0.02,\r\n expandedMax + range * 0.02,\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Scroll to end AFTER updateData so dataLength is current\r\n if (scrollToEnd) this.viewport.scrollToEnd();\r\n\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n }\r\n\r\n private getResolvedLayout() {\r\n if (!this.resolvedLayoutCache) {\r\n this.resolvedLayoutCache = this.layoutManager.resolve();\r\n }\r\n return this.resolvedLayoutCache;\r\n }\r\n\r\n /** Cache container size for 500ms to avoid layout thrashing on rapid calls */\r\n private cachedContainerSize(): { width: number; height: number } {\r\n const now = Date.now();\r\n if (!this.containerSizeCache || now - this.containerSizeCacheTime > 500) {\r\n this.containerSizeCache = this.engine.dprManager.getContainerSize();\r\n this.containerSizeCacheTime = now;\r\n }\r\n return this.containerSizeCache;\r\n }\r\n\r\n private buildPanelRenderInfos(): import('@tradecanvas/core').PanelRenderInfo[] {\r\n if (this.panelInfoCache) return this.panelInfoCache;\r\n\r\n const resolved = this.getResolvedLayout();\r\n const mainVP = this.viewport.getState();\r\n\r\n const { from, to } = mainVP.visibleRange;\r\n const panels = resolved.panels.map((panel) => {\r\n const output = this.indicatorEngine.getOutput(panel.config.id);\r\n const priceRange = computeIndicatorPriceRange(output, from, to);\r\n\r\n // Inset the indicator drawing area below the panel header (title + divider)\r\n const PANEL_HEADER_HEIGHT = 20;\r\n const insetRect = {\r\n x: panel.rect.x,\r\n y: panel.rect.y + PANEL_HEADER_HEIGHT,\r\n width: panel.rect.width,\r\n height: Math.max(0, panel.rect.height - PANEL_HEADER_HEIGHT),\r\n };\r\n\r\n return {\r\n instanceId: panel.config.id,\r\n rect: panel.rect,\r\n viewport: {\r\n ...mainVP,\r\n chartRect: insetRect,\r\n priceRange,\r\n },\r\n };\r\n });\r\n\r\n this.panelInfoCache = panels;\r\n return panels;\r\n }\r\n\r\n private syncRenderContext(): void {\r\n // Keep the pinned tooltip anchored to its bar through pans / zooms.\r\n if (this.pinnedTooltip.isPinned()) {\r\n this.pinnedTooltip.reposition(\r\n this.viewport.getState(),\r\n null,\r\n null,\r\n this.themeManager.getTheme(),\r\n );\r\n }\r\n\r\n const resolved = this.getResolvedLayout();\r\n const panels = this.features.indicators ? this.buildPanelRenderInfos() : [];\r\n\r\n // Compute where the time axis should render: below main chart + all bottom panels\r\n const bottomPanelHeight = resolved.panels\r\n .filter(p => p.config.position === 'bottom')\r\n .reduce((sum, p) => sum + p.rect.height, 0);\r\n const timeAxisY = resolved.mainChartRect.y + resolved.mainChartRect.height + bottomPanelHeight;\r\n\r\n const displayData = this.getDisplayData();\r\n this.engine.setRenderContext({\r\n chartRenderer: this.chartRenderer,\r\n gridRenderer: this.features.grid ? this.gridRenderer : null,\r\n priceAxis: this.features.priceAxis ? this.priceAxis : null,\r\n timeAxis: this.features.timeAxis ? this.timeAxis : null,\r\n crosshairHandler: this.features.crosshair ? this.crosshairHandler : null,\r\n indicatorEngine: this.features.indicators ? this.indicatorEngine : null,\r\n drawingRenderer: this.features.drawings ? this.drawingRenderer : null,\r\n tradingRenderer: this.features.trading ? this.tradingRenderer : null,\r\n currentPriceLine: this.streamManager?.priceLine ?? this.currentPriceLine,\r\n chartLegend: this.features.legend ? this.chartLegend : null,\r\n volumeRenderer: this.features.volume ? this.volumeRenderer : null,\r\n volumeProfile: this.volumeProfile,\r\n watermark: this.features.watermark ? this.watermark : null,\r\n barCountdown: this.barCountdown,\r\n sessionBreaks: this.sessionBreaks,\r\n compareRenderer: this.compareRenderer,\r\n alertManager: this.features.alerts ? this.alertManager : null,\r\n measureOverlay: this.measureOverlay,\r\n signalMarkerManager: this.signalMarkerManager,\r\n tradeZoneManager: this.tradeZoneManager,\r\n panels,\r\n priceLimits: this.buildPriceLimits(),\r\n timeAxisY,\r\n // Attach data to the viewport so drawings/indicators can treat\r\n // `anchor.time` as a real timestamp and convert via timestampToBarIndex.\r\n viewport: { ...this.viewport.getState(), data: displayData },\r\n theme: this.themeManager.getTheme(),\r\n data: displayData,\r\n numberLocale: this.numberLocale,\r\n });\r\n }\r\n\r\n private buildPriceLimits() {\r\n if (!this.marketConfig?.priceLimits?.enabled || !this.marketConfig.priceLimits.referencePrice) return null;\r\n const limits = computePriceLimits(this.marketConfig.priceLimits.referencePrice, this.marketConfig);\r\n if (!limits) return null;\r\n return {\r\n ...limits,\r\n colors: this.marketConfig.colorScheme ? {\r\n ceiling: this.marketConfig.colorScheme.ceiling,\r\n floor: this.marketConfig.colorScheme.floor,\r\n reference: this.marketConfig.colorScheme.reference,\r\n } : undefined,\r\n };\r\n }\r\n}\r\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';\nimport { parseOHLCV, type ParseResult } from './parseOHLCV.js';\n\nexport interface DragDropImporterCallbacks {\n /** Called with the parsed series. Hook into chart.setData() here. */\n onData: (data: DataSeries, result: ParseResult, file: File) => void;\n /** Called when parsing throws. Hook a toast/banner here. */\n onError?: (err: Error, file: File) => void;\n}\n\n/**\n * Hooks `dragover` / `drop` on a host element so users can drop a CSV / JSON\n * file onto the chart and get it loaded. A subtle dashed-outline overlay\n * shows up during the drag for visual confirmation.\n *\n * The host owns calling `chart.setData()` via the `onData` callback — the\n * importer stays decoupled from Chart so it can be reused in other surfaces\n * (backtester UI, comparison views, etc.).\n */\nexport class DragDropImporter {\n private host: HTMLElement;\n private overlay: HTMLDivElement | null = null;\n private callbacks: DragDropImporterCallbacks;\n private bound: { dragenter: (e: DragEvent) => void; dragover: (e: DragEvent) => void; dragleave: (e: DragEvent) => void; drop: (e: DragEvent) => void };\n private depth = 0;\n\n constructor(host: HTMLElement, callbacks: DragDropImporterCallbacks) {\n this.host = host;\n this.callbacks = callbacks;\n this.bound = {\n dragenter: (e) => this.onDragEnter(e),\n dragover: (e) => this.onDragOver(e),\n dragleave: (e) => this.onDragLeave(e),\n drop: (e) => this.onDrop(e),\n };\n }\n\n attach(): void {\n this.host.addEventListener('dragenter', this.bound.dragenter);\n this.host.addEventListener('dragover', this.bound.dragover);\n this.host.addEventListener('dragleave', this.bound.dragleave);\n this.host.addEventListener('drop', this.bound.drop);\n }\n\n detach(): void {\n this.host.removeEventListener('dragenter', this.bound.dragenter);\n this.host.removeEventListener('dragover', this.bound.dragover);\n this.host.removeEventListener('dragleave', this.bound.dragleave);\n this.host.removeEventListener('drop', this.bound.drop);\n this.hideOverlay();\n }\n\n private onDragEnter(e: DragEvent): void {\n if (!hasFiles(e)) return;\n e.preventDefault();\n this.depth++;\n this.showOverlay();\n }\n\n private onDragOver(e: DragEvent): void {\n if (!hasFiles(e)) return;\n e.preventDefault();\n if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';\n }\n\n private onDragLeave(e: DragEvent): void {\n if (!hasFiles(e)) return;\n this.depth = Math.max(0, this.depth - 1);\n if (this.depth === 0) this.hideOverlay();\n }\n\n private async onDrop(e: DragEvent): Promise<void> {\n e.preventDefault();\n this.depth = 0;\n this.hideOverlay();\n\n const file = e.dataTransfer?.files?.[0];\n if (!file) return;\n\n try {\n const text = await file.text();\n const result = parseOHLCV(text);\n if (result.data.length === 0) {\n throw new Error(`No valid OHLCV rows found in \"${file.name}\"`);\n }\n this.callbacks.onData(result.data, result, file);\n } catch (err) {\n this.callbacks.onError?.(err as Error, file);\n }\n }\n\n private showOverlay(): void {\n if (this.overlay) return;\n this.overlay = document.createElement('div');\n Object.assign(this.overlay.style, {\n position: 'absolute',\n inset: '8px',\n zIndex: '90',\n pointerEvents: 'none',\n borderRadius: '10px',\n border: '2px dashed var(--tcw-accent, #4f88ff)',\n background: 'rgba(79, 136, 255, 0.06)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--tcw-accent, #4f88ff)',\n fontSize: '14px',\n fontWeight: '600',\n letterSpacing: '-0.005em',\n fontFamily: 'inherit',\n backdropFilter: 'blur(2px)',\n });\n this.overlay.textContent = 'Drop CSV or JSON to load chart data';\n // The host needs `position: relative` for absolute inset to work; Chart\n // already sets this, but guard for arbitrary hosts.\n const cs = getComputedStyle(this.host);\n if (cs.position === 'static') this.host.style.position = 'relative';\n this.host.appendChild(this.overlay);\n }\n\n private hideOverlay(): void {\n this.overlay?.remove();\n this.overlay = null;\n }\n}\n\nfunction hasFiles(e: DragEvent): boolean {\n return e.dataTransfer?.types?.includes('Files') ?? false;\n}\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./Chart-Br_N-BCL.cjs`);let t=require(`@tradecanvas/commons`),n=require(`@tradecanvas/core`);var r={"1x1":{cols:1,rows:1},"1x2":{cols:2,rows:1},"2x1":{cols:1,rows:2},"2x2":{cols:2,rows:2},"1x3":{cols:3,rows:1},"3x1":{cols:1,rows:3},"2x3":{cols:3,rows:2},"3x2":{cols:2,rows:3}},i=class{root;cells=[];layout;options;destroyed=!1;syncing=!1;constructor(e,t={}){this.options=t,this.layout=t.layout??`2x2`,this.root=document.createElement(`div`),this.root.style.cssText=`display:grid;width:100%;height:100%;overflow:hidden;`,e.appendChild(this.root),this.applyLayout(),this.createCells()}applyLayout(){let{cols:e,rows:t}=r[this.layout],n=this.options.gap??1;this.root.style.gridTemplateColumns=`repeat(${e}, 1fr)`,this.root.style.gridTemplateRows=`repeat(${t}, 1fr)`,this.root.style.gap=`${n}px`}createCells(){let{cols:t,rows:n}=r[this.layout],i=t*n;for(let t=0;t<i;t++){let n=this.options.cells?.[t]??{},r=document.createElement(`div`);r.style.cssText=`position:relative;overflow:hidden;min-width:0;min-height:0;`,this.root.appendChild(r);let i=new e.t(r,{chartType:`candlestick`,autoScale:!0,features:{crosshair:!0,keyboard:!0,volume:!0,legend:!0,priceAxis:!0,timeAxis:!0,grid:!0},...this.options.chartOptions,...n.chartOptions,theme:this.options.theme}),a={container:r,chart:i,symbol:n.symbol??`Chart ${t+1}`,timeframe:n.timeframe??`5m`};this.options.syncCrosshair!==!1&&i.on(`crosshairMove`,e=>{if(!this.syncing){this.syncing=!0;for(let t of this.cells)t.chart!==i&&t.chart.setCrosshairPosition(e.payload.point);this.syncing=!1}}),this.options.syncTimeAxis!==!1&&i.on(`visibleRangeChange`,e=>{if(this.syncing)return;this.syncing=!0;let{from:t,to:n}=e.payload,r=i.getData();if(r.length>0&&t>=0&&n<r.length){let e=r[t]?.time,a=r[n]?.time;if(e&&a)for(let t of this.cells)t.chart!==i&&t.chart.setVisibleRange(e,a)}this.syncing=!1}),this.cells.push(a)}}setLayout(t){if(t===this.layout)return;let n=this.cells.length,{cols:i,rows:a}=r[t],o=i*a;if(o<n)for(let e=n-1;e>=o;e--){let t=this.cells[e];t.chart.destroy(),t.container.remove(),this.cells.pop()}if(this.layout=t,this.applyLayout(),o>n)for(let t=n;t<o;t++){let n=this.options.cells?.[t]??{},r=document.createElement(`div`);r.style.cssText=`position:relative;overflow:hidden;min-width:0;min-height:0;`,this.root.appendChild(r);let i=new e.t(r,{chartType:`candlestick`,autoScale:!0,...this.options.chartOptions,...n.chartOptions,theme:this.options.theme});this.cells.push({container:r,chart:i,symbol:n.symbol??`Chart ${t+1}`,timeframe:n.timeframe??`5m`})}}getChart(e){return this.cells[e]?.chart??null}getCharts(){return this.cells.map(e=>e.chart)}getCellCount(){return this.cells.length}setData(e,t){this.cells[e]?.chart.setData(t)}setAllData(e){for(let t of this.cells)t.chart.setData(e)}async connectCell(e,t){let n=this.cells[e];n&&(n.symbol=t.symbol,n.timeframe=t.timeframe,await n.chart.connect(t))}async connectAll(e,t,n,r=500){let i=[];for(let a=0;a<this.cells.length&&a<t.length;a++)i.push(this.connectCell(a,{adapter:e,symbol:t[a],timeframe:n,historyLimit:r}));await Promise.all(i)}setTheme(e){for(let t of this.cells)t.chart.setTheme(e)}destroy(){if(!this.destroyed){this.destroyed=!0;for(let e of this.cells)e.chart.destroy(),e.container.remove();this.cells=[],this.root.remove()}}},a=class extends n.BaseFinanceChart{options;constructor(e,t){super(e,t.theme),this.options=t,this.requestRender()}renderChart(e,t,r,i){(0,n.renderSparkline)(e,t,r,this.options,i)}update(e){this.options={...this.options,data:e},this.requestRender()}setOptions(e){this.options={...this.options,...e},this.requestRender()}},o=class extends n.BaseFinanceChart{options;crosshair=null;constructor(e,t){super(e,t.theme),this.options=t,t.crosshair!==!1&&(this.crosshair=new n.FinanceCrosshair(this.canvas,()=>this.requestRender())),this.requestRender()}renderChart(e,t,r,i){let a=this.crosshair?.getPosition()??null;(0,n.renderDepthChart)(e,t,r,this.options,i,a)}update(e){this.options={...this.options,data:e},this.requestRender()}setOptions(e){this.options={...this.options,...e},this.requestRender()}destroy(){this.crosshair?.destroy(),super.destroy()}},s=class extends n.BaseFinanceChart{options;crosshair=null;constructor(e,t){super(e,t.theme),this.options=t,t.crosshair!==!1&&(this.crosshair=new n.FinanceCrosshair(this.canvas,()=>this.requestRender())),this.requestRender()}renderChart(e,t,r,i){let a=this.crosshair?.getPosition()??null;(0,n.renderEquityCurve)(e,t,r,this.options,i,a)}update(e,t){this.options={...this.options,data:e},t!==void 0&&(this.options={...this.options,benchmark:t}),this.requestRender()}setOptions(e){this.options={...this.options,...e},this.requestRender()}destroy(){this.crosshair?.destroy(),super.destroy()}},c=class extends n.BaseFinanceChart{options;crosshair=null;cachedRects=[];currentData=[];lastLayoutWidth=0;lastLayoutHeight=0;handleClick=null;constructor(e,t){super(e,t.theme),this.options=t,this.currentData=t.data??[],t.crosshair!==!1&&(this.crosshair=new n.FinanceCrosshair(this.canvas,()=>this.requestRender())),t.onCellClick&&(this.handleClick=e=>{let t=this.canvas.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top;this.onCanvasClick(n,r)},this.canvas.addEventListener(`click`,this.handleClick)),this.recomputeLayout(),this.requestRender()}recomputeLayout(){let e={x:0,y:0,width:this.width,height:this.height},t=this.options.cellPadding??2;if(this.lastLayoutWidth=this.width,this.lastLayoutHeight=this.height,this.options.weighted){let r=this.currentData.map(e=>({id:e.id,weight:e.weight??(Math.abs(e.value)||1)}));this.cachedRects=(0,n.layoutSquarifiedTreemap)(r,e,t)}else this.cachedRects=(0,n.layoutUniformGrid)(this.currentData.map(e=>({id:e.id})),e,t)}onCanvasClick(e,t){if(this.options.onCellClick)for(let n of this.cachedRects){let r=n.rect;if(e>=r.x&&e<=r.x+r.width&&t>=r.y&&t<=r.y+r.height){let e=this.currentData.find(e=>e.id===n.id);e&&this.options.onCellClick(e);return}}}renderChart(e,t,r,i){(t!==this.lastLayoutWidth||r!==this.lastLayoutHeight)&&this.recomputeLayout();let a=this.crosshair?.getPosition()??null;(0,n.renderHeatmap)(e,t,r,this.currentData,this.cachedRects,this.options,i,a)}update(e){this.currentData=e,this.options={...this.options,data:e},this.recomputeLayout(),this.requestRender()}setOptions(e){this.options={...this.options,...e},e.data&&(this.currentData=e.data),this.recomputeLayout(),this.requestRender()}destroy(){this.crosshair?.destroy(),this.handleClick&&this.canvas.removeEventListener(`click`,this.handleClick),super.destroy()}},l=class extends n.BaseFinanceChart{options;crosshair=null;constructor(e,t){super(e,t.theme),this.options=t,t.crosshair!==!1&&(this.crosshair=new n.FinanceCrosshair(this.canvas,()=>this.requestRender())),this.requestRender()}renderChart(e,t,r,i){let a=this.crosshair?.getPosition()??null;(0,n.renderWaterfall)(e,t,r,this.options,i,a)}update(e){this.options={...this.options,data:e},this.requestRender()}setOptions(e){this.options={...this.options,...e},this.requestRender()}destroy(){this.crosshair?.destroy(),super.destroy()}},u=500;function d(e){let t=1-e;return 1-t*t*t}var f=class extends n.BaseFinanceChart{options;currentValue;targetValue;animationStart=null;animationFrom=0;animationFrameId=null;constructor(e,t){super(e,t.theme),this.options=t,this.currentValue=t.value,this.targetValue=t.value,this.requestRender()}renderChart(e,t,r,i){(0,n.renderGauge)(e,t,r,this.options,i,this.currentValue)}setValue(e){if(this.options.animate===!1){this.cancelAnimation(),this.currentValue=e,this.targetValue=e,this.options={...this.options,value:e},this.requestRender();return}this.targetValue=e,this.animationFrom=this.currentValue,this.animationStart=performance.now(),this.options={...this.options,value:e},this.startAnimationLoop()}setOptions(e){let t={...this.options,...e};if(e.value!==void 0&&e.value!==this.targetValue){this.options=t,this.setValue(e.value);return}this.options=t,this.requestRender()}startAnimationLoop(){if(this.animationFrameId!==null)return;let e=()=>{if(this.animationFrameId=null,this.animationStart===null)return;let t=this.options.animationDuration??u,n=performance.now()-this.animationStart,r=Math.min(1,n/Math.max(1,t)),i=d(r);this.currentValue=this.animationFrom+(this.targetValue-this.animationFrom)*i,this.requestRender(),r<1?this.animationFrameId=requestAnimationFrame(e):(this.currentValue=this.targetValue,this.animationStart=null)};this.animationFrameId=requestAnimationFrame(e)}cancelAnimation(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.animationStart=null}destroy(){this.cancelAnimation(),super.destroy()}};Object.defineProperty(exports,`AlertManager`,{enumerable:!0,get:function(){return n.AlertManager}}),Object.defineProperty(exports,`Animator`,{enumerable:!0,get:function(){return n.Animator}}),Object.defineProperty(exports,`BarCountdown`,{enumerable:!0,get:function(){return n.BarCountdown}}),Object.defineProperty(exports,`BinanceAdapter`,{enumerable:!0,get:function(){return n.BinanceAdapter}}),exports.Chart=e.t,exports.ChartGrid=i,Object.defineProperty(exports,`ChartLegend`,{enumerable:!0,get:function(){return n.ChartLegend}}),Object.defineProperty(exports,`ChartStateManager`,{enumerable:!0,get:function(){return n.ChartStateManager}}),Object.defineProperty(exports,`CompareRenderer`,{enumerable:!0,get:function(){return n.CompareRenderer}}),Object.defineProperty(exports,`CrosshairTooltip`,{enumerable:!0,get:function(){return n.CrosshairTooltip}}),Object.defineProperty(exports,`CurrentPriceLine`,{enumerable:!0,get:function(){return n.CurrentPriceLine}}),Object.defineProperty(exports,`DARK_TERMINAL`,{enumerable:!0,get:function(){return t.DARK_TERMINAL}}),Object.defineProperty(exports,`DARK_THEME`,{enumerable:!0,get:function(){return t.DARK_THEME}}),Object.defineProperty(exports,`DEFAULT_DRAWING_STYLE`,{enumerable:!0,get:function(){return t.DEFAULT_DRAWING_STYLE}}),Object.defineProperty(exports,`DEFAULT_LEGEND_CONFIG`,{enumerable:!0,get:function(){return n.DEFAULT_LEGEND_CONFIG}}),Object.defineProperty(exports,`DEFAULT_RECONNECT`,{enumerable:!0,get:function(){return t.DEFAULT_RECONNECT}}),Object.defineProperty(exports,`DEFAULT_SIGNAL_STYLE`,{enumerable:!0,get:function(){return t.DEFAULT_SIGNAL_STYLE}}),Object.defineProperty(exports,`DEFAULT_STREAM_CONFIG`,{enumerable:!0,get:function(){return t.DEFAULT_STREAM_CONFIG}}),Object.defineProperty(exports,`DEFAULT_TIMEFRAME_FAVORITES`,{enumerable:!0,get:function(){return t.DEFAULT_TIMEFRAME_FAVORITES}}),Object.defineProperty(exports,`DEFAULT_TRADE_ZONE_STYLE`,{enumerable:!0,get:function(){return t.DEFAULT_TRADE_ZONE_STYLE}}),Object.defineProperty(exports,`DEFAULT_TRADING_CONFIG`,{enumerable:!0,get:function(){return t.DEFAULT_TRADING_CONFIG}}),Object.defineProperty(exports,`DataExporter`,{enumerable:!0,get:function(){return n.DataExporter}}),exports.DataManager=e.a,exports.DepthChart=o,Object.defineProperty(exports,`DrawingBase`,{enumerable:!0,get:function(){return n.DrawingBase}}),Object.defineProperty(exports,`Easing`,{enumerable:!0,get:function(){return n.Easing}}),exports.EquityCurveChart=s,exports.GaugeChart=f,exports.HeatmapChart=c,Object.defineProperty(exports,`IndicatorBase`,{enumerable:!0,get:function(){return n.IndicatorBase}}),Object.defineProperty(exports,`KeyboardHandler`,{enumerable:!0,get:function(){return n.KeyboardHandler}}),Object.defineProperty(exports,`LIGHT_THEME`,{enumerable:!0,get:function(){return t.LIGHT_THEME}}),exports.LayoutManager=e.r,Object.defineProperty(exports,`MARKET_CRYPTO`,{enumerable:!0,get:function(){return t.MARKET_CRYPTO}}),Object.defineProperty(exports,`MARKET_HNX`,{enumerable:!0,get:function(){return t.MARKET_HNX}}),Object.defineProperty(exports,`MARKET_HOSE`,{enumerable:!0,get:function(){return t.MARKET_HOSE}}),Object.defineProperty(exports,`MARKET_NYSE`,{enumerable:!0,get:function(){return t.MARKET_NYSE}}),Object.defineProperty(exports,`MARKET_UPCOM`,{enumerable:!0,get:function(){return t.MARKET_UPCOM}}),Object.defineProperty(exports,`MockAdapter`,{enumerable:!0,get:function(){return n.MockAdapter}}),exports.PluginManager=e.n,Object.defineProperty(exports,`ReplayManager`,{enumerable:!0,get:function(){return n.ReplayManager}}),Object.defineProperty(exports,`Screenshot`,{enumerable:!0,get:function(){return n.Screenshot}}),Object.defineProperty(exports,`SessionBreaks`,{enumerable:!0,get:function(){return n.SessionBreaks}}),Object.defineProperty(exports,`SignalMarkerManager`,{enumerable:!0,get:function(){return n.SignalMarkerManager}}),exports.SparklineChart=a,Object.defineProperty(exports,`StreamManager`,{enumerable:!0,get:function(){return n.StreamManager}}),Object.defineProperty(exports,`TIMEFRAMES_CRYPTO`,{enumerable:!0,get:function(){return t.TIMEFRAMES_CRYPTO}}),Object.defineProperty(exports,`TIMEFRAMES_FOREX`,{enumerable:!0,get:function(){return t.TIMEFRAMES_FOREX}}),Object.defineProperty(exports,`TIMEFRAMES_STOCK`,{enumerable:!0,get:function(){return t.TIMEFRAMES_STOCK}}),exports.ThemeManager=e.i,Object.defineProperty(exports,`TickAggregator`,{enumerable:!0,get:function(){return n.TickAggregator}}),Object.defineProperty(exports,`TradeZoneManager`,{enumerable:!0,get:function(){return n.TradeZoneManager}}),Object.defineProperty(exports,`UndoRedoManager`,{enumerable:!0,get:function(){return n.UndoRedoManager}}),Object.defineProperty(exports,`VN_COLORS`,{enumerable:!0,get:function(){return t.VN_COLORS}}),Object.defineProperty(exports,`VolumeRenderer`,{enumerable:!0,get:function(){return n.VolumeRenderer}}),exports.WaterfallChart=l,Object.defineProperty(exports,`Watermark`,{enumerable:!0,get:function(){return n.Watermark}}),Object.defineProperty(exports,`computePriceLimits`,{enumerable:!0,get:function(){return t.computePriceLimits}}),Object.defineProperty(exports,`createVNTheme`,{enumerable:!0,get:function(){return t.createVNTheme}}),Object.defineProperty(exports,`formatNumber`,{enumerable:!0,get:function(){return t.formatNumber}}),Object.defineProperty(exports,`formatVND`,{enumerable:!0,get:function(){return t.formatVND}}),Object.defineProperty(exports,`formatVolumeLoc`,{enumerable:!0,get:function(){return t.formatVolumeLoc}}),Object.defineProperty(exports,`getCurrentSession`,{enumerable:!0,get:function(){return t.getCurrentSession}}),Object.defineProperty(exports,`getLocale`,{enumerable:!0,get:function(){return t.getLocale}}),Object.defineProperty(exports,`normalizeBar`,{enumerable:!0,get:function(){return t.normalizeBar}}),Object.defineProperty(exports,`normalizeBarTime`,{enumerable:!0,get:function(){return t.normalizeBarTime}}),Object.defineProperty(exports,`registerLocale`,{enumerable:!0,get:function(){return t.registerLocale}}),Object.defineProperty(exports,`setLocale`,{enumerable:!0,get:function(){return t.setLocale}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return t.t}}),Object.defineProperty(exports,`toHeikinAshi`,{enumerable:!0,get:function(){return n.toHeikinAshi}}),Object.defineProperty(exports,`toKagi`,{enumerable:!0,get:function(){return n.toKagi}}),Object.defineProperty(exports,`toLineBreak`,{enumerable:!0,get:function(){return n.toLineBreak}}),Object.defineProperty(exports,`toPointAndFigure`,{enumerable:!0,get:function(){return n.toPointAndFigure}}),Object.defineProperty(exports,`toRangeBars`,{enumerable:!0,get:function(){return n.toRangeBars}}),Object.defineProperty(exports,`toRenko`,{enumerable:!0,get:function(){return n.toRenko}});
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./DragDropImporter-CQ3EarQn.cjs`);let t=require(`@tradecanvas/commons`),n=require(`@tradecanvas/core`);var r={"1x1":{cols:1,rows:1},"1x2":{cols:2,rows:1},"2x1":{cols:1,rows:2},"2x2":{cols:2,rows:2},"1x3":{cols:3,rows:1},"3x1":{cols:1,rows:3},"2x3":{cols:3,rows:2},"3x2":{cols:2,rows:3}},i=class{root;cells=[];layout;options;destroyed=!1;syncing=!1;constructor(e,t={}){this.options=t,this.layout=t.layout??`2x2`,this.root=document.createElement(`div`),this.root.style.cssText=`display:grid;width:100%;height:100%;overflow:hidden;`,e.appendChild(this.root),this.applyLayout(),this.createCells()}applyLayout(){let{cols:e,rows:t}=r[this.layout],n=this.options.gap??1;this.root.style.gridTemplateColumns=`repeat(${e}, 1fr)`,this.root.style.gridTemplateRows=`repeat(${t}, 1fr)`,this.root.style.gap=`${n}px`}createCells(){let{cols:t,rows:n}=r[this.layout],i=t*n;for(let t=0;t<i;t++){let n=this.options.cells?.[t]??{},r=document.createElement(`div`);r.style.cssText=`position:relative;overflow:hidden;min-width:0;min-height:0;`,this.root.appendChild(r);let i=new e.r(r,{chartType:`candlestick`,autoScale:!0,features:{crosshair:!0,keyboard:!0,volume:!0,legend:!0,priceAxis:!0,timeAxis:!0,grid:!0},...this.options.chartOptions,...n.chartOptions,theme:this.options.theme}),a={container:r,chart:i,symbol:n.symbol??`Chart ${t+1}`,timeframe:n.timeframe??`5m`};this.options.syncCrosshair!==!1&&i.on(`crosshairMove`,e=>{if(!this.syncing){this.syncing=!0;for(let t of this.cells)t.chart!==i&&t.chart.setCrosshairPosition(e.payload.point);this.syncing=!1}}),this.options.syncTimeAxis!==!1&&i.on(`visibleRangeChange`,e=>{if(this.syncing)return;this.syncing=!0;let{from:t,to:n}=e.payload,r=i.getData();if(r.length>0&&t>=0&&n<r.length){let e=r[t]?.time,a=r[n]?.time;if(e&&a)for(let t of this.cells)t.chart!==i&&t.chart.setVisibleRange(e,a)}this.syncing=!1}),this.cells.push(a)}}setLayout(t){if(t===this.layout)return;let n=this.cells.length,{cols:i,rows:a}=r[t],o=i*a;if(o<n)for(let e=n-1;e>=o;e--){let t=this.cells[e];t.chart.destroy(),t.container.remove(),this.cells.pop()}if(this.layout=t,this.applyLayout(),o>n)for(let t=n;t<o;t++){let n=this.options.cells?.[t]??{},r=document.createElement(`div`);r.style.cssText=`position:relative;overflow:hidden;min-width:0;min-height:0;`,this.root.appendChild(r);let i=new e.r(r,{chartType:`candlestick`,autoScale:!0,...this.options.chartOptions,...n.chartOptions,theme:this.options.theme});this.cells.push({container:r,chart:i,symbol:n.symbol??`Chart ${t+1}`,timeframe:n.timeframe??`5m`})}}getChart(e){return this.cells[e]?.chart??null}getCharts(){return this.cells.map(e=>e.chart)}getCellCount(){return this.cells.length}setData(e,t){this.cells[e]?.chart.setData(t)}setAllData(e){for(let t of this.cells)t.chart.setData(e)}async connectCell(e,t){let n=this.cells[e];n&&(n.symbol=t.symbol,n.timeframe=t.timeframe,await n.chart.connect(t))}async connectAll(e,t,n,r=500){let i=[];for(let a=0;a<this.cells.length&&a<t.length;a++)i.push(this.connectCell(a,{adapter:e,symbol:t[a],timeframe:n,historyLimit:r}));await Promise.all(i)}setTheme(e){for(let t of this.cells)t.chart.setTheme(e)}destroy(){if(!this.destroyed){this.destroyed=!0;for(let e of this.cells)e.chart.destroy(),e.container.remove();this.cells=[],this.root.remove()}}},a=class extends n.BaseFinanceChart{options;constructor(e,t){super(e,t.theme),this.options=t,this.requestRender()}renderChart(e,t,r,i){(0,n.renderSparkline)(e,t,r,this.options,i)}update(e){this.options={...this.options,data:e},this.requestRender()}setOptions(e){this.options={...this.options,...e},this.requestRender()}},o=class extends n.BaseFinanceChart{options;crosshair=null;constructor(e,t){super(e,t.theme),this.options=t,t.crosshair!==!1&&(this.crosshair=new n.FinanceCrosshair(this.canvas,()=>this.requestRender())),this.requestRender()}renderChart(e,t,r,i){let a=this.crosshair?.getPosition()??null;(0,n.renderDepthChart)(e,t,r,this.options,i,a)}update(e){this.options={...this.options,data:e},this.requestRender()}setOptions(e){this.options={...this.options,...e},this.requestRender()}destroy(){this.crosshair?.destroy(),super.destroy()}},s=class extends n.BaseFinanceChart{options;crosshair=null;constructor(e,t){super(e,t.theme),this.options=t,t.crosshair!==!1&&(this.crosshair=new n.FinanceCrosshair(this.canvas,()=>this.requestRender())),this.requestRender()}renderChart(e,t,r,i){let a=this.crosshair?.getPosition()??null;(0,n.renderEquityCurve)(e,t,r,this.options,i,a)}update(e,t){this.options={...this.options,data:e},t!==void 0&&(this.options={...this.options,benchmark:t}),this.requestRender()}setOptions(e){this.options={...this.options,...e},this.requestRender()}destroy(){this.crosshair?.destroy(),super.destroy()}},c=class extends n.BaseFinanceChart{options;crosshair=null;cachedRects=[];currentData=[];lastLayoutWidth=0;lastLayoutHeight=0;handleClick=null;constructor(e,t){super(e,t.theme),this.options=t,this.currentData=t.data??[],t.crosshair!==!1&&(this.crosshair=new n.FinanceCrosshair(this.canvas,()=>this.requestRender())),t.onCellClick&&(this.handleClick=e=>{let t=this.canvas.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top;this.onCanvasClick(n,r)},this.canvas.addEventListener(`click`,this.handleClick)),this.recomputeLayout(),this.requestRender()}recomputeLayout(){let e={x:0,y:0,width:this.width,height:this.height},t=this.options.cellPadding??2;if(this.lastLayoutWidth=this.width,this.lastLayoutHeight=this.height,this.options.weighted){let r=this.currentData.map(e=>({id:e.id,weight:e.weight??(Math.abs(e.value)||1)}));this.cachedRects=(0,n.layoutSquarifiedTreemap)(r,e,t)}else this.cachedRects=(0,n.layoutUniformGrid)(this.currentData.map(e=>({id:e.id})),e,t)}onCanvasClick(e,t){if(this.options.onCellClick)for(let n of this.cachedRects){let r=n.rect;if(e>=r.x&&e<=r.x+r.width&&t>=r.y&&t<=r.y+r.height){let e=this.currentData.find(e=>e.id===n.id);e&&this.options.onCellClick(e);return}}}renderChart(e,t,r,i){(t!==this.lastLayoutWidth||r!==this.lastLayoutHeight)&&this.recomputeLayout();let a=this.crosshair?.getPosition()??null;(0,n.renderHeatmap)(e,t,r,this.currentData,this.cachedRects,this.options,i,a)}update(e){this.currentData=e,this.options={...this.options,data:e},this.recomputeLayout(),this.requestRender()}setOptions(e){this.options={...this.options,...e},e.data&&(this.currentData=e.data),this.recomputeLayout(),this.requestRender()}destroy(){this.crosshair?.destroy(),this.handleClick&&this.canvas.removeEventListener(`click`,this.handleClick),super.destroy()}},l=class extends n.BaseFinanceChart{options;crosshair=null;constructor(e,t){super(e,t.theme),this.options=t,t.crosshair!==!1&&(this.crosshair=new n.FinanceCrosshair(this.canvas,()=>this.requestRender())),this.requestRender()}renderChart(e,t,r,i){let a=this.crosshair?.getPosition()??null;(0,n.renderWaterfall)(e,t,r,this.options,i,a)}update(e){this.options={...this.options,data:e},this.requestRender()}setOptions(e){this.options={...this.options,...e},this.requestRender()}destroy(){this.crosshair?.destroy(),super.destroy()}},u=500;function d(e){let t=1-e;return 1-t*t*t}var f=class extends n.BaseFinanceChart{options;currentValue;targetValue;animationStart=null;animationFrom=0;animationFrameId=null;constructor(e,t){super(e,t.theme),this.options=t,this.currentValue=t.value,this.targetValue=t.value,this.requestRender()}renderChart(e,t,r,i){(0,n.renderGauge)(e,t,r,this.options,i,this.currentValue)}setValue(e){if(this.options.animate===!1){this.cancelAnimation(),this.currentValue=e,this.targetValue=e,this.options={...this.options,value:e},this.requestRender();return}this.targetValue=e,this.animationFrom=this.currentValue,this.animationStart=performance.now(),this.options={...this.options,value:e},this.startAnimationLoop()}setOptions(e){let t={...this.options,...e};if(e.value!==void 0&&e.value!==this.targetValue){this.options=t,this.setValue(e.value);return}this.options=t,this.requestRender()}startAnimationLoop(){if(this.animationFrameId!==null)return;let e=()=>{if(this.animationFrameId=null,this.animationStart===null)return;let t=this.options.animationDuration??u,n=performance.now()-this.animationStart,r=Math.min(1,n/Math.max(1,t)),i=d(r);this.currentValue=this.animationFrom+(this.targetValue-this.animationFrom)*i,this.requestRender(),r<1?this.animationFrameId=requestAnimationFrame(e):(this.currentValue=this.targetValue,this.animationStart=null)};this.animationFrameId=requestAnimationFrame(e)}cancelAnimation(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.animationStart=null}destroy(){this.cancelAnimation(),super.destroy()}};Object.defineProperty(exports,`AlertManager`,{enumerable:!0,get:function(){return n.AlertManager}}),Object.defineProperty(exports,`Animator`,{enumerable:!0,get:function(){return n.Animator}}),Object.defineProperty(exports,`BarCountdown`,{enumerable:!0,get:function(){return n.BarCountdown}}),Object.defineProperty(exports,`BinanceAdapter`,{enumerable:!0,get:function(){return n.BinanceAdapter}}),exports.Chart=e.r,exports.ChartGrid=i,Object.defineProperty(exports,`ChartLegend`,{enumerable:!0,get:function(){return n.ChartLegend}}),Object.defineProperty(exports,`ChartStateManager`,{enumerable:!0,get:function(){return n.ChartStateManager}}),Object.defineProperty(exports,`CompareRenderer`,{enumerable:!0,get:function(){return n.CompareRenderer}}),Object.defineProperty(exports,`CrosshairTooltip`,{enumerable:!0,get:function(){return n.CrosshairTooltip}}),Object.defineProperty(exports,`CurrentPriceLine`,{enumerable:!0,get:function(){return n.CurrentPriceLine}}),Object.defineProperty(exports,`DARK_TERMINAL`,{enumerable:!0,get:function(){return t.DARK_TERMINAL}}),Object.defineProperty(exports,`DARK_THEME`,{enumerable:!0,get:function(){return t.DARK_THEME}}),Object.defineProperty(exports,`DEFAULT_DRAWING_STYLE`,{enumerable:!0,get:function(){return t.DEFAULT_DRAWING_STYLE}}),Object.defineProperty(exports,`DEFAULT_LEGEND_CONFIG`,{enumerable:!0,get:function(){return n.DEFAULT_LEGEND_CONFIG}}),Object.defineProperty(exports,`DEFAULT_RECONNECT`,{enumerable:!0,get:function(){return t.DEFAULT_RECONNECT}}),Object.defineProperty(exports,`DEFAULT_SIGNAL_STYLE`,{enumerable:!0,get:function(){return t.DEFAULT_SIGNAL_STYLE}}),Object.defineProperty(exports,`DEFAULT_STREAM_CONFIG`,{enumerable:!0,get:function(){return t.DEFAULT_STREAM_CONFIG}}),Object.defineProperty(exports,`DEFAULT_TIMEFRAME_FAVORITES`,{enumerable:!0,get:function(){return t.DEFAULT_TIMEFRAME_FAVORITES}}),Object.defineProperty(exports,`DEFAULT_TRADE_ZONE_STYLE`,{enumerable:!0,get:function(){return t.DEFAULT_TRADE_ZONE_STYLE}}),Object.defineProperty(exports,`DEFAULT_TRADING_CONFIG`,{enumerable:!0,get:function(){return t.DEFAULT_TRADING_CONFIG}}),Object.defineProperty(exports,`DataExporter`,{enumerable:!0,get:function(){return n.DataExporter}}),exports.DataManager=e.s,exports.DepthChart=o,exports.DragDropImporter=e.t,Object.defineProperty(exports,`DrawingBase`,{enumerable:!0,get:function(){return n.DrawingBase}}),Object.defineProperty(exports,`Easing`,{enumerable:!0,get:function(){return n.Easing}}),exports.EquityCurveChart=s,exports.GaugeChart=f,exports.HeatmapChart=c,Object.defineProperty(exports,`IndicatorBase`,{enumerable:!0,get:function(){return n.IndicatorBase}}),Object.defineProperty(exports,`KeyboardHandler`,{enumerable:!0,get:function(){return n.KeyboardHandler}}),Object.defineProperty(exports,`LIGHT_THEME`,{enumerable:!0,get:function(){return t.LIGHT_THEME}}),exports.LayoutManager=e.a,Object.defineProperty(exports,`MARKET_CRYPTO`,{enumerable:!0,get:function(){return t.MARKET_CRYPTO}}),Object.defineProperty(exports,`MARKET_HNX`,{enumerable:!0,get:function(){return t.MARKET_HNX}}),Object.defineProperty(exports,`MARKET_HOSE`,{enumerable:!0,get:function(){return t.MARKET_HOSE}}),Object.defineProperty(exports,`MARKET_NYSE`,{enumerable:!0,get:function(){return t.MARKET_NYSE}}),Object.defineProperty(exports,`MARKET_UPCOM`,{enumerable:!0,get:function(){return t.MARKET_UPCOM}}),Object.defineProperty(exports,`MockAdapter`,{enumerable:!0,get:function(){return n.MockAdapter}}),exports.PluginManager=e.i,Object.defineProperty(exports,`ReplayManager`,{enumerable:!0,get:function(){return n.ReplayManager}}),Object.defineProperty(exports,`Screenshot`,{enumerable:!0,get:function(){return n.Screenshot}}),Object.defineProperty(exports,`SessionBreaks`,{enumerable:!0,get:function(){return n.SessionBreaks}}),Object.defineProperty(exports,`SignalMarkerManager`,{enumerable:!0,get:function(){return n.SignalMarkerManager}}),exports.SparklineChart=a,Object.defineProperty(exports,`StreamManager`,{enumerable:!0,get:function(){return n.StreamManager}}),Object.defineProperty(exports,`TIMEFRAMES_CRYPTO`,{enumerable:!0,get:function(){return t.TIMEFRAMES_CRYPTO}}),Object.defineProperty(exports,`TIMEFRAMES_FOREX`,{enumerable:!0,get:function(){return t.TIMEFRAMES_FOREX}}),Object.defineProperty(exports,`TIMEFRAMES_STOCK`,{enumerable:!0,get:function(){return t.TIMEFRAMES_STOCK}}),exports.ThemeManager=e.o,Object.defineProperty(exports,`TickAggregator`,{enumerable:!0,get:function(){return n.TickAggregator}}),Object.defineProperty(exports,`TradeZoneManager`,{enumerable:!0,get:function(){return n.TradeZoneManager}}),Object.defineProperty(exports,`UndoRedoManager`,{enumerable:!0,get:function(){return n.UndoRedoManager}}),Object.defineProperty(exports,`VN_COLORS`,{enumerable:!0,get:function(){return t.VN_COLORS}}),Object.defineProperty(exports,`VolumeRenderer`,{enumerable:!0,get:function(){return n.VolumeRenderer}}),exports.WaterfallChart=l,Object.defineProperty(exports,`Watermark`,{enumerable:!0,get:function(){return n.Watermark}}),Object.defineProperty(exports,`computePriceLimits`,{enumerable:!0,get:function(){return t.computePriceLimits}}),Object.defineProperty(exports,`createVNTheme`,{enumerable:!0,get:function(){return t.createVNTheme}}),Object.defineProperty(exports,`formatNumber`,{enumerable:!0,get:function(){return t.formatNumber}}),Object.defineProperty(exports,`formatVND`,{enumerable:!0,get:function(){return t.formatVND}}),Object.defineProperty(exports,`formatVolumeLoc`,{enumerable:!0,get:function(){return t.formatVolumeLoc}}),Object.defineProperty(exports,`getCurrentSession`,{enumerable:!0,get:function(){return t.getCurrentSession}}),Object.defineProperty(exports,`getLocale`,{enumerable:!0,get:function(){return t.getLocale}}),Object.defineProperty(exports,`normalizeBar`,{enumerable:!0,get:function(){return t.normalizeBar}}),Object.defineProperty(exports,`normalizeBarTime`,{enumerable:!0,get:function(){return t.normalizeBarTime}}),exports.parseOHLCV=e.n,Object.defineProperty(exports,`registerLocale`,{enumerable:!0,get:function(){return t.registerLocale}}),Object.defineProperty(exports,`setLocale`,{enumerable:!0,get:function(){return t.setLocale}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return t.t}}),Object.defineProperty(exports,`toHeikinAshi`,{enumerable:!0,get:function(){return n.toHeikinAshi}}),Object.defineProperty(exports,`toKagi`,{enumerable:!0,get:function(){return n.toKagi}}),Object.defineProperty(exports,`toLineBreak`,{enumerable:!0,get:function(){return n.toLineBreak}}),Object.defineProperty(exports,`toPointAndFigure`,{enumerable:!0,get:function(){return n.toPointAndFigure}}),Object.defineProperty(exports,`toRangeBars`,{enumerable:!0,get:function(){return n.toRangeBars}}),Object.defineProperty(exports,`toRenko`,{enumerable:!0,get:function(){return n.toRenko}});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/grid/ChartGrid.ts","../src/finance/SparklineChart.ts","../src/finance/DepthChart.ts","../src/finance/EquityCurveChart.ts","../src/finance/HeatmapChart.ts","../src/finance/WaterfallChart.ts","../src/finance/GaugeChart.ts"],"sourcesContent":["import type { ChartOptions, Theme, TimeFrame, DataSeries, DataAdapter, StreamConfig } from '@tradecanvas/commons';\nimport { Chart } from '../Chart.js';\n\nexport type GridLayout = '1x1' | '1x2' | '2x1' | '2x2' | '1x3' | '3x1' | '2x3' | '3x2';\n\nexport interface GridCellConfig {\n symbol?: string;\n timeframe?: TimeFrame;\n chartOptions?: Partial<ChartOptions>;\n}\n\nexport interface ChartGridOptions {\n layout?: GridLayout;\n theme?: ChartOptions['theme'];\n syncCrosshair?: boolean;\n syncTimeAxis?: boolean;\n gap?: number;\n cells?: GridCellConfig[];\n chartOptions?: Partial<ChartOptions>;\n}\n\ninterface GridCell {\n container: HTMLDivElement;\n chart: Chart;\n symbol: string;\n timeframe: TimeFrame;\n}\n\nconst LAYOUT_MAP: Record<GridLayout, { cols: number; rows: number }> = {\n '1x1': { cols: 1, rows: 1 },\n '1x2': { cols: 2, rows: 1 },\n '2x1': { cols: 1, rows: 2 },\n '2x2': { cols: 2, rows: 2 },\n '1x3': { cols: 3, rows: 1 },\n '3x1': { cols: 1, rows: 3 },\n '2x3': { cols: 3, rows: 2 },\n '3x2': { cols: 2, rows: 3 },\n};\n\nexport class ChartGrid {\n private root: HTMLDivElement;\n private cells: GridCell[] = [];\n private layout: GridLayout;\n private options: ChartGridOptions;\n private destroyed = false;\n private syncing = false;\n\n constructor(container: HTMLElement, options: ChartGridOptions = {}) {\n this.options = options;\n this.layout = options.layout ?? '2x2';\n\n this.root = document.createElement('div');\n this.root.style.cssText = 'display:grid;width:100%;height:100%;overflow:hidden;';\n container.appendChild(this.root);\n\n this.applyLayout();\n this.createCells();\n }\n\n private applyLayout(): void {\n const { cols, rows } = LAYOUT_MAP[this.layout];\n const gap = this.options.gap ?? 1;\n this.root.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;\n this.root.style.gridTemplateRows = `repeat(${rows}, 1fr)`;\n this.root.style.gap = `${gap}px`;\n }\n\n private createCells(): void {\n const { cols, rows } = LAYOUT_MAP[this.layout];\n const count = cols * rows;\n\n for (let i = 0; i < count; i++) {\n const cellConfig = this.options.cells?.[i] ?? {};\n\n const cellEl = document.createElement('div');\n cellEl.style.cssText = 'position:relative;overflow:hidden;min-width:0;min-height:0;';\n this.root.appendChild(cellEl);\n\n const chartOpts: ChartOptions = {\n chartType: 'candlestick',\n autoScale: true,\n features: {\n crosshair: true,\n keyboard: true,\n volume: true,\n legend: true,\n priceAxis: true,\n timeAxis: true,\n grid: true,\n },\n ...this.options.chartOptions,\n ...cellConfig.chartOptions,\n theme: this.options.theme,\n };\n\n const chart = new Chart(cellEl, chartOpts);\n\n const cell: GridCell = {\n container: cellEl,\n chart,\n symbol: cellConfig.symbol ?? `Chart ${i + 1}`,\n timeframe: cellConfig.timeframe ?? '5m',\n };\n\n if (this.options.syncCrosshair !== false) {\n chart.on('crosshairMove', (e) => {\n if (this.syncing) return;\n this.syncing = true;\n for (const other of this.cells) {\n if (other.chart !== chart) {\n other.chart.setCrosshairPosition(e.payload.point);\n }\n }\n this.syncing = false;\n });\n }\n\n if (this.options.syncTimeAxis !== false) {\n chart.on('visibleRangeChange', (e) => {\n if (this.syncing) return;\n this.syncing = true;\n const { from, to } = e.payload;\n const srcData = chart.getData();\n if (srcData.length > 0 && from >= 0 && to < srcData.length) {\n const fromTime = srcData[from]?.time;\n const toTime = srcData[to]?.time;\n if (fromTime && toTime) {\n for (const other of this.cells) {\n if (other.chart !== chart) {\n other.chart.setVisibleRange(fromTime, toTime);\n }\n }\n }\n }\n this.syncing = false;\n });\n }\n\n this.cells.push(cell);\n }\n }\n\n setLayout(layout: GridLayout): void {\n if (layout === this.layout) return;\n const oldCount = this.cells.length;\n const { cols, rows } = LAYOUT_MAP[layout];\n const newCount = cols * rows;\n\n if (newCount < oldCount) {\n for (let i = oldCount - 1; i >= newCount; i--) {\n const cell = this.cells[i];\n cell.chart.destroy();\n cell.container.remove();\n this.cells.pop();\n }\n }\n\n this.layout = layout;\n this.applyLayout();\n\n if (newCount > oldCount) {\n for (let i = oldCount; i < newCount; i++) {\n const cellConfig = this.options.cells?.[i] ?? {};\n const cellEl = document.createElement('div');\n cellEl.style.cssText = 'position:relative;overflow:hidden;min-width:0;min-height:0;';\n this.root.appendChild(cellEl);\n\n const chart = new Chart(cellEl, {\n chartType: 'candlestick',\n autoScale: true,\n ...this.options.chartOptions,\n ...cellConfig.chartOptions,\n theme: this.options.theme,\n });\n\n this.cells.push({\n container: cellEl,\n chart,\n symbol: cellConfig.symbol ?? `Chart ${i + 1}`,\n timeframe: cellConfig.timeframe ?? '5m',\n });\n }\n }\n }\n\n getChart(index: number): Chart | null {\n return this.cells[index]?.chart ?? null;\n }\n\n getCharts(): Chart[] {\n return this.cells.map(c => c.chart);\n }\n\n getCellCount(): number {\n return this.cells.length;\n }\n\n setData(index: number, data: DataSeries): void {\n this.cells[index]?.chart.setData(data);\n }\n\n setAllData(data: DataSeries): void {\n for (const cell of this.cells) {\n cell.chart.setData(data);\n }\n }\n\n async connectCell(index: number, config: StreamConfig): Promise<void> {\n const cell = this.cells[index];\n if (!cell) return;\n cell.symbol = config.symbol;\n cell.timeframe = config.timeframe;\n await cell.chart.connect(config);\n }\n\n async connectAll(adapter: DataAdapter, symbols: string[], timeframe: TimeFrame, historyLimit = 500): Promise<void> {\n const promises: Promise<void>[] = [];\n for (let i = 0; i < this.cells.length && i < symbols.length; i++) {\n promises.push(this.connectCell(i, {\n adapter,\n symbol: symbols[i],\n timeframe,\n historyLimit,\n }));\n }\n await Promise.all(promises);\n }\n\n setTheme(theme: Theme): void {\n for (const cell of this.cells) {\n cell.chart.setTheme(theme);\n }\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n for (const cell of this.cells) {\n cell.chart.destroy();\n cell.container.remove();\n }\n this.cells = [];\n this.root.remove();\n }\n}\n","import type { SparklineOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, renderSparkline } from '@tradecanvas/core';\n\nexport class SparklineChart extends BaseFinanceChart {\n private options: SparklineOptions;\n\n constructor(container: HTMLElement, options: SparklineOptions) {\n super(container, options.theme);\n this.options = options;\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n renderSparkline(ctx, width, height, this.options, theme);\n }\n\n update(data: number[]): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<SparklineOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n}\n","import type { DepthChartOptions, DepthData, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderDepthChart } from '@tradecanvas/core';\n\nexport class DepthChart extends BaseFinanceChart {\n private options: DepthChartOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: DepthChartOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderDepthChart(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: DepthData): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<DepthChartOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { EquityCurveOptions, EquityPoint, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderEquityCurve } from '@tradecanvas/core';\n\nexport class EquityCurveChart extends BaseFinanceChart {\n private options: EquityCurveOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: EquityCurveOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderEquityCurve(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: EquityPoint[], benchmark?: EquityPoint[]): void {\n this.options = { ...this.options, data };\n if (benchmark !== undefined) {\n this.options = { ...this.options, benchmark };\n }\n this.requestRender();\n }\n\n setOptions(opts: Partial<EquityCurveOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { HeatmapCell, HeatmapOptions, Theme } from '@tradecanvas/commons';\nimport {\n BaseFinanceChart,\n FinanceCrosshair,\n layoutUniformGrid,\n layoutSquarifiedTreemap,\n renderHeatmap,\n} from '@tradecanvas/core';\nimport type { LayoutRect } from '@tradecanvas/core';\n\nexport class HeatmapChart extends BaseFinanceChart {\n private options: HeatmapOptions;\n private crosshair: FinanceCrosshair | null = null;\n private cachedRects: LayoutRect[] = [];\n private currentData: HeatmapCell[] = [];\n private lastLayoutWidth = 0;\n private lastLayoutHeight = 0;\n private handleClick: ((e: MouseEvent) => void) | null = null;\n\n constructor(container: HTMLElement, options: HeatmapOptions) {\n super(container, options.theme);\n this.options = options;\n this.currentData = options.data ?? [];\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n if (options.onCellClick) {\n this.handleClick = (e: MouseEvent) => {\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n this.onCanvasClick(x, y);\n };\n this.canvas.addEventListener('click', this.handleClick);\n }\n\n this.recomputeLayout();\n this.requestRender();\n }\n\n private recomputeLayout(): void {\n const bounds = { x: 0, y: 0, width: this.width, height: this.height };\n const padding = this.options.cellPadding ?? 2;\n this.lastLayoutWidth = this.width;\n this.lastLayoutHeight = this.height;\n\n if (this.options.weighted) {\n const weighted = this.currentData.map(c => ({\n id: c.id,\n weight: c.weight ?? (Math.abs(c.value) || 1),\n }));\n this.cachedRects = layoutSquarifiedTreemap(weighted, bounds, padding);\n } else {\n this.cachedRects = layoutUniformGrid(\n this.currentData.map(c => ({ id: c.id })),\n bounds,\n padding,\n );\n }\n }\n\n private onCanvasClick(x: number, y: number): void {\n if (!this.options.onCellClick) return;\n\n for (const lr of this.cachedRects) {\n const r = lr.rect;\n if (x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height) {\n const cell = this.currentData.find(c => c.id === lr.id);\n if (cell) this.options.onCellClick(cell);\n return;\n }\n }\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n if (width !== this.lastLayoutWidth || height !== this.lastLayoutHeight) {\n this.recomputeLayout();\n }\n\n const pos = this.crosshair?.getPosition() ?? null;\n renderHeatmap(ctx, width, height, this.currentData, this.cachedRects, this.options, theme, pos);\n }\n\n update(data: HeatmapCell[]): void {\n this.currentData = data;\n this.options = { ...this.options, data };\n this.recomputeLayout();\n this.requestRender();\n }\n\n setOptions(opts: Partial<HeatmapOptions>): void {\n this.options = { ...this.options, ...opts };\n if (opts.data) {\n this.currentData = opts.data;\n }\n this.recomputeLayout();\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n if (this.handleClick) {\n this.canvas.removeEventListener('click', this.handleClick);\n }\n super.destroy();\n }\n}\n","import type { Theme, WaterfallBar, WaterfallOptions } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderWaterfall } from '@tradecanvas/core';\n\nexport class WaterfallChart extends BaseFinanceChart {\n private options: WaterfallOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: WaterfallOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderWaterfall(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: WaterfallBar[]): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<WaterfallOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { GaugeOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, renderGauge } from '@tradecanvas/core';\n\nconst DEFAULT_ANIMATION_MS = 500;\n\nfunction easeOutCubic(t: number): number {\n const inv = 1 - t;\n return 1 - inv * inv * inv;\n}\n\nexport class GaugeChart extends BaseFinanceChart {\n private options: GaugeOptions;\n private currentValue: number;\n private targetValue: number;\n private animationStart: number | null = null;\n private animationFrom = 0;\n private animationFrameId: number | null = null;\n\n constructor(container: HTMLElement, options: GaugeOptions) {\n super(container, options.theme);\n this.options = options;\n this.currentValue = options.value;\n this.targetValue = options.value;\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n renderGauge(ctx, width, height, this.options, theme, this.currentValue);\n }\n\n setValue(value: number): void {\n const animate = this.options.animate !== false;\n if (!animate) {\n this.cancelAnimation();\n this.currentValue = value;\n this.targetValue = value;\n this.options = { ...this.options, value };\n this.requestRender();\n return;\n }\n\n this.targetValue = value;\n this.animationFrom = this.currentValue;\n this.animationStart = performance.now();\n this.options = { ...this.options, value };\n this.startAnimationLoop();\n }\n\n setOptions(opts: Partial<GaugeOptions>): void {\n const next = { ...this.options, ...opts };\n // If `value` is part of the partial, route through animation path\n if (opts.value !== undefined && opts.value !== this.targetValue) {\n this.options = next;\n this.setValue(opts.value);\n return;\n }\n this.options = next;\n this.requestRender();\n }\n\n private startAnimationLoop(): void {\n if (this.animationFrameId !== null) return;\n const step = (): void => {\n this.animationFrameId = null;\n if (this.animationStart === null) return;\n\n const duration = this.options.animationDuration ?? DEFAULT_ANIMATION_MS;\n const elapsed = performance.now() - this.animationStart;\n const t = Math.min(1, elapsed / Math.max(1, duration));\n const eased = easeOutCubic(t);\n this.currentValue = this.animationFrom + (this.targetValue - this.animationFrom) * eased;\n\n this.requestRender();\n\n if (t < 1) {\n this.animationFrameId = requestAnimationFrame(step);\n } else {\n this.currentValue = this.targetValue;\n this.animationStart = null;\n }\n };\n this.animationFrameId = requestAnimationFrame(step);\n }\n\n private cancelAnimation(): void {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n this.animationStart = null;\n }\n\n destroy(): void {\n this.cancelAnimation();\n super.destroy();\n }\n}\n"],"mappings":"gLA4BA,IAAM,EAAiE,CACrE,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,CAC3B,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,CAC3B,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,CAC3B,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,CAC3B,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,CAC3B,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,CAC3B,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,CAC3B,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,CAC5B,CAEY,EAAb,KAAuB,CACrB,KACA,MAA4B,EAAE,CAC9B,OACA,QACA,UAAoB,GACpB,QAAkB,GAElB,YAAY,EAAwB,EAA4B,EAAE,CAAE,CAClE,KAAK,QAAU,EACf,KAAK,OAAS,EAAQ,QAAU,MAEhC,KAAK,KAAO,SAAS,cAAc,MAAM,CACzC,KAAK,KAAK,MAAM,QAAU,uDAC1B,EAAU,YAAY,KAAK,KAAK,CAEhC,KAAK,aAAa,CAClB,KAAK,aAAa,CAGpB,aAA4B,CAC1B,GAAM,CAAE,OAAM,QAAS,EAAW,KAAK,QACjC,EAAM,KAAK,QAAQ,KAAO,EAChC,KAAK,KAAK,MAAM,oBAAsB,UAAU,EAAK,QACrD,KAAK,KAAK,MAAM,iBAAmB,UAAU,EAAK,QAClD,KAAK,KAAK,MAAM,IAAM,GAAG,EAAI,IAG/B,aAA4B,CAC1B,GAAM,CAAE,OAAM,QAAS,EAAW,KAAK,QACjC,EAAQ,EAAO,EAErB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,IAAK,CAC9B,IAAM,EAAa,KAAK,QAAQ,QAAQ,IAAM,EAAE,CAE1C,EAAS,SAAS,cAAc,MAAM,CAC5C,EAAO,MAAM,QAAU,8DACvB,KAAK,KAAK,YAAY,EAAO,CAmB7B,IAAM,EAAQ,IAAI,EAAA,EAAM,EAAQ,CAhB9B,UAAW,cACX,UAAW,GACX,SAAU,CACR,UAAW,GACX,SAAU,GACV,OAAQ,GACR,OAAQ,GACR,UAAW,GACX,SAAU,GACV,KAAM,GACP,CACD,GAAG,KAAK,QAAQ,aAChB,GAAG,EAAW,aACd,MAAO,KAAK,QAAQ,MAGU,CAAU,CAEpC,EAAiB,CACrB,UAAW,EACX,QACA,OAAQ,EAAW,QAAU,SAAS,EAAI,IAC1C,UAAW,EAAW,WAAa,KACpC,CAEG,KAAK,QAAQ,gBAAkB,IACjC,EAAM,GAAG,gBAAkB,GAAM,CAC3B,SAAK,QACT,MAAK,QAAU,GACf,IAAK,IAAM,KAAS,KAAK,MACnB,EAAM,QAAU,GAClB,EAAM,MAAM,qBAAqB,EAAE,QAAQ,MAAM,CAGrD,KAAK,QAAU,KACf,CAGA,KAAK,QAAQ,eAAiB,IAChC,EAAM,GAAG,qBAAuB,GAAM,CACpC,GAAI,KAAK,QAAS,OAClB,KAAK,QAAU,GACf,GAAM,CAAE,OAAM,MAAO,EAAE,QACjB,EAAU,EAAM,SAAS,CAC/B,GAAI,EAAQ,OAAS,GAAK,GAAQ,GAAK,EAAK,EAAQ,OAAQ,CAC1D,IAAM,EAAW,EAAQ,IAAO,KAC1B,EAAS,EAAQ,IAAK,KAC5B,GAAI,GAAY,MACT,IAAM,KAAS,KAAK,MACnB,EAAM,QAAU,GAClB,EAAM,MAAM,gBAAgB,EAAU,EAAO,CAKrD,KAAK,QAAU,IACf,CAGJ,KAAK,MAAM,KAAK,EAAK,EAIzB,UAAU,EAA0B,CAClC,GAAI,IAAW,KAAK,OAAQ,OAC5B,IAAM,EAAW,KAAK,MAAM,OACtB,CAAE,OAAM,QAAS,EAAW,GAC5B,EAAW,EAAO,EAExB,GAAI,EAAW,EACb,IAAK,IAAI,EAAI,EAAW,EAAG,GAAK,EAAU,IAAK,CAC7C,IAAM,EAAO,KAAK,MAAM,GACxB,EAAK,MAAM,SAAS,CACpB,EAAK,UAAU,QAAQ,CACvB,KAAK,MAAM,KAAK,CAOpB,GAHA,KAAK,OAAS,EACd,KAAK,aAAa,CAEd,EAAW,EACb,IAAK,IAAI,EAAI,EAAU,EAAI,EAAU,IAAK,CACxC,IAAM,EAAa,KAAK,QAAQ,QAAQ,IAAM,EAAE,CAC1C,EAAS,SAAS,cAAc,MAAM,CAC5C,EAAO,MAAM,QAAU,8DACvB,KAAK,KAAK,YAAY,EAAO,CAE7B,IAAM,EAAQ,IAAI,EAAA,EAAM,EAAQ,CAC9B,UAAW,cACX,UAAW,GACX,GAAG,KAAK,QAAQ,aAChB,GAAG,EAAW,aACd,MAAO,KAAK,QAAQ,MACrB,CAAC,CAEF,KAAK,MAAM,KAAK,CACd,UAAW,EACX,QACA,OAAQ,EAAW,QAAU,SAAS,EAAI,IAC1C,UAAW,EAAW,WAAa,KACpC,CAAC,EAKR,SAAS,EAA6B,CACpC,OAAO,KAAK,MAAM,IAAQ,OAAS,KAGrC,WAAqB,CACnB,OAAO,KAAK,MAAM,IAAI,GAAK,EAAE,MAAM,CAGrC,cAAuB,CACrB,OAAO,KAAK,MAAM,OAGpB,QAAQ,EAAe,EAAwB,CAC7C,KAAK,MAAM,IAAQ,MAAM,QAAQ,EAAK,CAGxC,WAAW,EAAwB,CACjC,IAAK,IAAM,KAAQ,KAAK,MACtB,EAAK,MAAM,QAAQ,EAAK,CAI5B,MAAM,YAAY,EAAe,EAAqC,CACpE,IAAM,EAAO,KAAK,MAAM,GACnB,IACL,EAAK,OAAS,EAAO,OACrB,EAAK,UAAY,EAAO,UACxB,MAAM,EAAK,MAAM,QAAQ,EAAO,EAGlC,MAAM,WAAW,EAAsB,EAAmB,EAAsB,EAAe,IAAoB,CACjH,IAAM,EAA4B,EAAE,CACpC,IAAK,IAAI,EAAI,EAAG,EAAI,KAAK,MAAM,QAAU,EAAI,EAAQ,OAAQ,IAC3D,EAAS,KAAK,KAAK,YAAY,EAAG,CAChC,UACA,OAAQ,EAAQ,GAChB,YACA,eACD,CAAC,CAAC,CAEL,MAAM,QAAQ,IAAI,EAAS,CAG7B,SAAS,EAAoB,CAC3B,IAAK,IAAM,KAAQ,KAAK,MACtB,EAAK,MAAM,SAAS,EAAM,CAI9B,SAAgB,CACV,SAAK,UACT,MAAK,UAAY,GACjB,IAAK,IAAM,KAAQ,KAAK,MACtB,EAAK,MAAM,SAAS,CACpB,EAAK,UAAU,QAAQ,CAEzB,KAAK,MAAQ,EAAE,CACf,KAAK,KAAK,QAAQ,IC/OT,EAAb,cAAoC,EAAA,gBAAiB,CACnD,QAEA,YAAY,EAAwB,EAA2B,CAC7D,MAAM,EAAW,EAAQ,MAAM,CAC/B,KAAK,QAAU,EACf,KAAK,eAAe,CAGtB,YACE,EACA,EACA,EACA,EACM,EACN,EAAA,EAAA,iBAAgB,EAAK,EAAO,EAAQ,KAAK,QAAS,EAAM,CAG1D,OAAO,EAAsB,CAC3B,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,OAAM,CACxC,KAAK,eAAe,CAGtB,WAAW,EAAuC,CAChD,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,GAAG,EAAM,CAC3C,KAAK,eAAe,GCzBX,EAAb,cAAgC,EAAA,gBAAiB,CAC/C,QACA,UAA6C,KAE7C,YAAY,EAAwB,EAA4B,CAC9D,MAAM,EAAW,EAAQ,MAAM,CAC/B,KAAK,QAAU,EAEX,EAAQ,YAAc,KACxB,KAAK,UAAY,IAAI,EAAA,iBAAiB,KAAK,WAAc,KAAK,eAAe,CAAC,EAGhF,KAAK,eAAe,CAGtB,YACE,EACA,EACA,EACA,EACM,CACN,IAAM,EAAM,KAAK,WAAW,aAAa,EAAI,MAC7C,EAAA,EAAA,kBAAiB,EAAK,EAAO,EAAQ,KAAK,QAAS,EAAO,EAAI,CAGhE,OAAO,EAAuB,CAC5B,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,OAAM,CACxC,KAAK,eAAe,CAGtB,WAAW,EAAwC,CACjD,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,GAAG,EAAM,CAC3C,KAAK,eAAe,CAGtB,SAAgB,CACd,KAAK,WAAW,SAAS,CACzB,MAAM,SAAS,GCrCN,EAAb,cAAsC,EAAA,gBAAiB,CACrD,QACA,UAA6C,KAE7C,YAAY,EAAwB,EAA6B,CAC/D,MAAM,EAAW,EAAQ,MAAM,CAC/B,KAAK,QAAU,EAEX,EAAQ,YAAc,KACxB,KAAK,UAAY,IAAI,EAAA,iBAAiB,KAAK,WAAc,KAAK,eAAe,CAAC,EAGhF,KAAK,eAAe,CAGtB,YACE,EACA,EACA,EACA,EACM,CACN,IAAM,EAAM,KAAK,WAAW,aAAa,EAAI,MAC7C,EAAA,EAAA,mBAAkB,EAAK,EAAO,EAAQ,KAAK,QAAS,EAAO,EAAI,CAGjE,OAAO,EAAqB,EAAiC,CAC3D,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,OAAM,CACpC,IAAc,IAAA,KAChB,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,YAAW,EAE/C,KAAK,eAAe,CAGtB,WAAW,EAAyC,CAClD,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,GAAG,EAAM,CAC3C,KAAK,eAAe,CAGtB,SAAgB,CACd,KAAK,WAAW,SAAS,CACzB,MAAM,SAAS,GCjCN,EAAb,cAAkC,EAAA,gBAAiB,CACjD,QACA,UAA6C,KAC7C,YAAoC,EAAE,CACtC,YAAqC,EAAE,CACvC,gBAA0B,EAC1B,iBAA2B,EAC3B,YAAwD,KAExD,YAAY,EAAwB,EAAyB,CAC3D,MAAM,EAAW,EAAQ,MAAM,CAC/B,KAAK,QAAU,EACf,KAAK,YAAc,EAAQ,MAAQ,EAAE,CAEjC,EAAQ,YAAc,KACxB,KAAK,UAAY,IAAI,EAAA,iBAAiB,KAAK,WAAc,KAAK,eAAe,CAAC,EAG5E,EAAQ,cACV,KAAK,YAAe,GAAkB,CACpC,IAAM,EAAO,KAAK,OAAO,uBAAuB,CAC1C,EAAI,EAAE,QAAU,EAAK,KACrB,EAAI,EAAE,QAAU,EAAK,IAC3B,KAAK,cAAc,EAAG,EAAE,EAE1B,KAAK,OAAO,iBAAiB,QAAS,KAAK,YAAY,EAGzD,KAAK,iBAAiB,CACtB,KAAK,eAAe,CAGtB,iBAAgC,CAC9B,IAAM,EAAS,CAAE,EAAG,EAAG,EAAG,EAAG,MAAO,KAAK,MAAO,OAAQ,KAAK,OAAQ,CAC/D,EAAU,KAAK,QAAQ,aAAe,EAI5C,GAHA,KAAK,gBAAkB,KAAK,MAC5B,KAAK,iBAAmB,KAAK,OAEzB,KAAK,QAAQ,SAAU,CACzB,IAAM,EAAW,KAAK,YAAY,IAAI,IAAM,CAC1C,GAAI,EAAE,GACN,OAAQ,EAAE,SAAW,KAAK,IAAI,EAAE,MAAM,EAAI,GAC3C,EAAE,CACH,KAAK,aAAA,EAAA,EAAA,yBAAsC,EAAU,EAAQ,EAAQ,MAErE,KAAK,aAAA,EAAA,EAAA,mBACH,KAAK,YAAY,IAAI,IAAM,CAAE,GAAI,EAAE,GAAI,EAAE,CACzC,EACA,EACD,CAIL,cAAsB,EAAW,EAAiB,CAC3C,QAAK,QAAQ,YAElB,IAAK,IAAM,KAAM,KAAK,YAAa,CACjC,IAAM,EAAI,EAAG,KACb,GAAI,GAAK,EAAE,GAAK,GAAK,EAAE,EAAI,EAAE,OAAS,GAAK,EAAE,GAAK,GAAK,EAAE,EAAI,EAAE,OAAQ,CACrE,IAAM,EAAO,KAAK,YAAY,KAAK,GAAK,EAAE,KAAO,EAAG,GAAG,CACnD,GAAM,KAAK,QAAQ,YAAY,EAAK,CACxC,SAKN,YACE,EACA,EACA,EACA,EACM,EACF,IAAU,KAAK,iBAAmB,IAAW,KAAK,mBACpD,KAAK,iBAAiB,CAGxB,IAAM,EAAM,KAAK,WAAW,aAAa,EAAI,MAC7C,EAAA,EAAA,eAAc,EAAK,EAAO,EAAQ,KAAK,YAAa,KAAK,YAAa,KAAK,QAAS,EAAO,EAAI,CAGjG,OAAO,EAA2B,CAChC,KAAK,YAAc,EACnB,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,OAAM,CACxC,KAAK,iBAAiB,CACtB,KAAK,eAAe,CAGtB,WAAW,EAAqC,CAC9C,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,GAAG,EAAM,CACvC,EAAK,OACP,KAAK,YAAc,EAAK,MAE1B,KAAK,iBAAiB,CACtB,KAAK,eAAe,CAGtB,SAAgB,CACd,KAAK,WAAW,SAAS,CACrB,KAAK,aACP,KAAK,OAAO,oBAAoB,QAAS,KAAK,YAAY,CAE5D,MAAM,SAAS,GC5GN,EAAb,cAAoC,EAAA,gBAAiB,CACnD,QACA,UAA6C,KAE7C,YAAY,EAAwB,EAA2B,CAC7D,MAAM,EAAW,EAAQ,MAAM,CAC/B,KAAK,QAAU,EAEX,EAAQ,YAAc,KACxB,KAAK,UAAY,IAAI,EAAA,iBAAiB,KAAK,WAAc,KAAK,eAAe,CAAC,EAGhF,KAAK,eAAe,CAGtB,YACE,EACA,EACA,EACA,EACM,CACN,IAAM,EAAM,KAAK,WAAW,aAAa,EAAI,MAC7C,EAAA,EAAA,iBAAgB,EAAK,EAAO,EAAQ,KAAK,QAAS,EAAO,EAAI,CAG/D,OAAO,EAA4B,CACjC,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,OAAM,CACxC,KAAK,eAAe,CAGtB,WAAW,EAAuC,CAChD,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,GAAG,EAAM,CAC3C,KAAK,eAAe,CAGtB,SAAgB,CACd,KAAK,WAAW,SAAS,CACzB,MAAM,SAAS,GCrCb,EAAuB,IAE7B,SAAS,EAAa,EAAmB,CACvC,IAAM,EAAM,EAAI,EAChB,MAAO,GAAI,EAAM,EAAM,EAGzB,IAAa,EAAb,cAAgC,EAAA,gBAAiB,CAC/C,QACA,aACA,YACA,eAAwC,KACxC,cAAwB,EACxB,iBAA0C,KAE1C,YAAY,EAAwB,EAAuB,CACzD,MAAM,EAAW,EAAQ,MAAM,CAC/B,KAAK,QAAU,EACf,KAAK,aAAe,EAAQ,MAC5B,KAAK,YAAc,EAAQ,MAC3B,KAAK,eAAe,CAGtB,YACE,EACA,EACA,EACA,EACM,EACN,EAAA,EAAA,aAAY,EAAK,EAAO,EAAQ,KAAK,QAAS,EAAO,KAAK,aAAa,CAGzE,SAAS,EAAqB,CAE5B,GADgB,KAAK,QAAQ,UAAY,GAC3B,CACZ,KAAK,iBAAiB,CACtB,KAAK,aAAe,EACpB,KAAK,YAAc,EACnB,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,QAAO,CACzC,KAAK,eAAe,CACpB,OAGF,KAAK,YAAc,EACnB,KAAK,cAAgB,KAAK,aAC1B,KAAK,eAAiB,YAAY,KAAK,CACvC,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,QAAO,CACzC,KAAK,oBAAoB,CAG3B,WAAW,EAAmC,CAC5C,IAAM,EAAO,CAAE,GAAG,KAAK,QAAS,GAAG,EAAM,CAEzC,GAAI,EAAK,QAAU,IAAA,IAAa,EAAK,QAAU,KAAK,YAAa,CAC/D,KAAK,QAAU,EACf,KAAK,SAAS,EAAK,MAAM,CACzB,OAEF,KAAK,QAAU,EACf,KAAK,eAAe,CAGtB,oBAAmC,CACjC,GAAI,KAAK,mBAAqB,KAAM,OACpC,IAAM,MAAmB,CAEvB,GADA,KAAK,iBAAmB,KACpB,KAAK,iBAAmB,KAAM,OAElC,IAAM,EAAW,KAAK,QAAQ,mBAAqB,EAC7C,EAAU,YAAY,KAAK,CAAG,KAAK,eACnC,EAAI,KAAK,IAAI,EAAG,EAAU,KAAK,IAAI,EAAG,EAAS,CAAC,CAChD,EAAQ,EAAa,EAAE,CAC7B,KAAK,aAAe,KAAK,eAAiB,KAAK,YAAc,KAAK,eAAiB,EAEnF,KAAK,eAAe,CAEhB,EAAI,EACN,KAAK,iBAAmB,sBAAsB,EAAK,EAEnD,KAAK,aAAe,KAAK,YACzB,KAAK,eAAiB,OAG1B,KAAK,iBAAmB,sBAAsB,EAAK,CAGrD,iBAAgC,CAC1B,KAAK,mBAAqB,OAC5B,qBAAqB,KAAK,iBAAiB,CAC3C,KAAK,iBAAmB,MAE1B,KAAK,eAAiB,KAGxB,SAAgB,CACd,KAAK,iBAAiB,CACtB,MAAM,SAAS"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/grid/ChartGrid.ts","../src/finance/SparklineChart.ts","../src/finance/DepthChart.ts","../src/finance/EquityCurveChart.ts","../src/finance/HeatmapChart.ts","../src/finance/WaterfallChart.ts","../src/finance/GaugeChart.ts"],"sourcesContent":["import type { ChartOptions, Theme, TimeFrame, DataSeries, DataAdapter, StreamConfig } from '@tradecanvas/commons';\nimport { Chart } from '../Chart.js';\n\nexport type GridLayout = '1x1' | '1x2' | '2x1' | '2x2' | '1x3' | '3x1' | '2x3' | '3x2';\n\nexport interface GridCellConfig {\n symbol?: string;\n timeframe?: TimeFrame;\n chartOptions?: Partial<ChartOptions>;\n}\n\nexport interface ChartGridOptions {\n layout?: GridLayout;\n theme?: ChartOptions['theme'];\n syncCrosshair?: boolean;\n syncTimeAxis?: boolean;\n gap?: number;\n cells?: GridCellConfig[];\n chartOptions?: Partial<ChartOptions>;\n}\n\ninterface GridCell {\n container: HTMLDivElement;\n chart: Chart;\n symbol: string;\n timeframe: TimeFrame;\n}\n\nconst LAYOUT_MAP: Record<GridLayout, { cols: number; rows: number }> = {\n '1x1': { cols: 1, rows: 1 },\n '1x2': { cols: 2, rows: 1 },\n '2x1': { cols: 1, rows: 2 },\n '2x2': { cols: 2, rows: 2 },\n '1x3': { cols: 3, rows: 1 },\n '3x1': { cols: 1, rows: 3 },\n '2x3': { cols: 3, rows: 2 },\n '3x2': { cols: 2, rows: 3 },\n};\n\nexport class ChartGrid {\n private root: HTMLDivElement;\n private cells: GridCell[] = [];\n private layout: GridLayout;\n private options: ChartGridOptions;\n private destroyed = false;\n private syncing = false;\n\n constructor(container: HTMLElement, options: ChartGridOptions = {}) {\n this.options = options;\n this.layout = options.layout ?? '2x2';\n\n this.root = document.createElement('div');\n this.root.style.cssText = 'display:grid;width:100%;height:100%;overflow:hidden;';\n container.appendChild(this.root);\n\n this.applyLayout();\n this.createCells();\n }\n\n private applyLayout(): void {\n const { cols, rows } = LAYOUT_MAP[this.layout];\n const gap = this.options.gap ?? 1;\n this.root.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;\n this.root.style.gridTemplateRows = `repeat(${rows}, 1fr)`;\n this.root.style.gap = `${gap}px`;\n }\n\n private createCells(): void {\n const { cols, rows } = LAYOUT_MAP[this.layout];\n const count = cols * rows;\n\n for (let i = 0; i < count; i++) {\n const cellConfig = this.options.cells?.[i] ?? {};\n\n const cellEl = document.createElement('div');\n cellEl.style.cssText = 'position:relative;overflow:hidden;min-width:0;min-height:0;';\n this.root.appendChild(cellEl);\n\n const chartOpts: ChartOptions = {\n chartType: 'candlestick',\n autoScale: true,\n features: {\n crosshair: true,\n keyboard: true,\n volume: true,\n legend: true,\n priceAxis: true,\n timeAxis: true,\n grid: true,\n },\n ...this.options.chartOptions,\n ...cellConfig.chartOptions,\n theme: this.options.theme,\n };\n\n const chart = new Chart(cellEl, chartOpts);\n\n const cell: GridCell = {\n container: cellEl,\n chart,\n symbol: cellConfig.symbol ?? `Chart ${i + 1}`,\n timeframe: cellConfig.timeframe ?? '5m',\n };\n\n if (this.options.syncCrosshair !== false) {\n chart.on('crosshairMove', (e) => {\n if (this.syncing) return;\n this.syncing = true;\n for (const other of this.cells) {\n if (other.chart !== chart) {\n other.chart.setCrosshairPosition(e.payload.point);\n }\n }\n this.syncing = false;\n });\n }\n\n if (this.options.syncTimeAxis !== false) {\n chart.on('visibleRangeChange', (e) => {\n if (this.syncing) return;\n this.syncing = true;\n const { from, to } = e.payload;\n const srcData = chart.getData();\n if (srcData.length > 0 && from >= 0 && to < srcData.length) {\n const fromTime = srcData[from]?.time;\n const toTime = srcData[to]?.time;\n if (fromTime && toTime) {\n for (const other of this.cells) {\n if (other.chart !== chart) {\n other.chart.setVisibleRange(fromTime, toTime);\n }\n }\n }\n }\n this.syncing = false;\n });\n }\n\n this.cells.push(cell);\n }\n }\n\n setLayout(layout: GridLayout): void {\n if (layout === this.layout) return;\n const oldCount = this.cells.length;\n const { cols, rows } = LAYOUT_MAP[layout];\n const newCount = cols * rows;\n\n if (newCount < oldCount) {\n for (let i = oldCount - 1; i >= newCount; i--) {\n const cell = this.cells[i];\n cell.chart.destroy();\n cell.container.remove();\n this.cells.pop();\n }\n }\n\n this.layout = layout;\n this.applyLayout();\n\n if (newCount > oldCount) {\n for (let i = oldCount; i < newCount; i++) {\n const cellConfig = this.options.cells?.[i] ?? {};\n const cellEl = document.createElement('div');\n cellEl.style.cssText = 'position:relative;overflow:hidden;min-width:0;min-height:0;';\n this.root.appendChild(cellEl);\n\n const chart = new Chart(cellEl, {\n chartType: 'candlestick',\n autoScale: true,\n ...this.options.chartOptions,\n ...cellConfig.chartOptions,\n theme: this.options.theme,\n });\n\n this.cells.push({\n container: cellEl,\n chart,\n symbol: cellConfig.symbol ?? `Chart ${i + 1}`,\n timeframe: cellConfig.timeframe ?? '5m',\n });\n }\n }\n }\n\n getChart(index: number): Chart | null {\n return this.cells[index]?.chart ?? null;\n }\n\n getCharts(): Chart[] {\n return this.cells.map(c => c.chart);\n }\n\n getCellCount(): number {\n return this.cells.length;\n }\n\n setData(index: number, data: DataSeries): void {\n this.cells[index]?.chart.setData(data);\n }\n\n setAllData(data: DataSeries): void {\n for (const cell of this.cells) {\n cell.chart.setData(data);\n }\n }\n\n async connectCell(index: number, config: StreamConfig): Promise<void> {\n const cell = this.cells[index];\n if (!cell) return;\n cell.symbol = config.symbol;\n cell.timeframe = config.timeframe;\n await cell.chart.connect(config);\n }\n\n async connectAll(adapter: DataAdapter, symbols: string[], timeframe: TimeFrame, historyLimit = 500): Promise<void> {\n const promises: Promise<void>[] = [];\n for (let i = 0; i < this.cells.length && i < symbols.length; i++) {\n promises.push(this.connectCell(i, {\n adapter,\n symbol: symbols[i],\n timeframe,\n historyLimit,\n }));\n }\n await Promise.all(promises);\n }\n\n setTheme(theme: Theme): void {\n for (const cell of this.cells) {\n cell.chart.setTheme(theme);\n }\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n for (const cell of this.cells) {\n cell.chart.destroy();\n cell.container.remove();\n }\n this.cells = [];\n this.root.remove();\n }\n}\n","import type { SparklineOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, renderSparkline } from '@tradecanvas/core';\n\nexport class SparklineChart extends BaseFinanceChart {\n private options: SparklineOptions;\n\n constructor(container: HTMLElement, options: SparklineOptions) {\n super(container, options.theme);\n this.options = options;\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n renderSparkline(ctx, width, height, this.options, theme);\n }\n\n update(data: number[]): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<SparklineOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n}\n","import type { DepthChartOptions, DepthData, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderDepthChart } from '@tradecanvas/core';\n\nexport class DepthChart extends BaseFinanceChart {\n private options: DepthChartOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: DepthChartOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderDepthChart(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: DepthData): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<DepthChartOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { EquityCurveOptions, EquityPoint, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderEquityCurve } from '@tradecanvas/core';\n\nexport class EquityCurveChart extends BaseFinanceChart {\n private options: EquityCurveOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: EquityCurveOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderEquityCurve(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: EquityPoint[], benchmark?: EquityPoint[]): void {\n this.options = { ...this.options, data };\n if (benchmark !== undefined) {\n this.options = { ...this.options, benchmark };\n }\n this.requestRender();\n }\n\n setOptions(opts: Partial<EquityCurveOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { HeatmapCell, HeatmapOptions, Theme } from '@tradecanvas/commons';\nimport {\n BaseFinanceChart,\n FinanceCrosshair,\n layoutUniformGrid,\n layoutSquarifiedTreemap,\n renderHeatmap,\n} from '@tradecanvas/core';\nimport type { LayoutRect } from '@tradecanvas/core';\n\nexport class HeatmapChart extends BaseFinanceChart {\n private options: HeatmapOptions;\n private crosshair: FinanceCrosshair | null = null;\n private cachedRects: LayoutRect[] = [];\n private currentData: HeatmapCell[] = [];\n private lastLayoutWidth = 0;\n private lastLayoutHeight = 0;\n private handleClick: ((e: MouseEvent) => void) | null = null;\n\n constructor(container: HTMLElement, options: HeatmapOptions) {\n super(container, options.theme);\n this.options = options;\n this.currentData = options.data ?? [];\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n if (options.onCellClick) {\n this.handleClick = (e: MouseEvent) => {\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n this.onCanvasClick(x, y);\n };\n this.canvas.addEventListener('click', this.handleClick);\n }\n\n this.recomputeLayout();\n this.requestRender();\n }\n\n private recomputeLayout(): void {\n const bounds = { x: 0, y: 0, width: this.width, height: this.height };\n const padding = this.options.cellPadding ?? 2;\n this.lastLayoutWidth = this.width;\n this.lastLayoutHeight = this.height;\n\n if (this.options.weighted) {\n const weighted = this.currentData.map(c => ({\n id: c.id,\n weight: c.weight ?? (Math.abs(c.value) || 1),\n }));\n this.cachedRects = layoutSquarifiedTreemap(weighted, bounds, padding);\n } else {\n this.cachedRects = layoutUniformGrid(\n this.currentData.map(c => ({ id: c.id })),\n bounds,\n padding,\n );\n }\n }\n\n private onCanvasClick(x: number, y: number): void {\n if (!this.options.onCellClick) return;\n\n for (const lr of this.cachedRects) {\n const r = lr.rect;\n if (x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height) {\n const cell = this.currentData.find(c => c.id === lr.id);\n if (cell) this.options.onCellClick(cell);\n return;\n }\n }\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n if (width !== this.lastLayoutWidth || height !== this.lastLayoutHeight) {\n this.recomputeLayout();\n }\n\n const pos = this.crosshair?.getPosition() ?? null;\n renderHeatmap(ctx, width, height, this.currentData, this.cachedRects, this.options, theme, pos);\n }\n\n update(data: HeatmapCell[]): void {\n this.currentData = data;\n this.options = { ...this.options, data };\n this.recomputeLayout();\n this.requestRender();\n }\n\n setOptions(opts: Partial<HeatmapOptions>): void {\n this.options = { ...this.options, ...opts };\n if (opts.data) {\n this.currentData = opts.data;\n }\n this.recomputeLayout();\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n if (this.handleClick) {\n this.canvas.removeEventListener('click', this.handleClick);\n }\n super.destroy();\n }\n}\n","import type { Theme, WaterfallBar, WaterfallOptions } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, renderWaterfall } from '@tradecanvas/core';\n\nexport class WaterfallChart extends BaseFinanceChart {\n private options: WaterfallOptions;\n private crosshair: FinanceCrosshair | null = null;\n\n constructor(container: HTMLElement, options: WaterfallOptions) {\n super(container, options.theme);\n this.options = options;\n\n if (options.crosshair !== false) {\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n }\n\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n const pos = this.crosshair?.getPosition() ?? null;\n renderWaterfall(ctx, width, height, this.options, theme, pos);\n }\n\n update(data: WaterfallBar[]): void {\n this.options = { ...this.options, data };\n this.requestRender();\n }\n\n setOptions(opts: Partial<WaterfallOptions>): void {\n this.options = { ...this.options, ...opts };\n this.requestRender();\n }\n\n destroy(): void {\n this.crosshair?.destroy();\n super.destroy();\n }\n}\n","import type { GaugeOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, renderGauge } from '@tradecanvas/core';\n\nconst DEFAULT_ANIMATION_MS = 500;\n\nfunction easeOutCubic(t: number): number {\n const inv = 1 - t;\n return 1 - inv * inv * inv;\n}\n\nexport class GaugeChart extends BaseFinanceChart {\n private options: GaugeOptions;\n private currentValue: number;\n private targetValue: number;\n private animationStart: number | null = null;\n private animationFrom = 0;\n private animationFrameId: number | null = null;\n\n constructor(container: HTMLElement, options: GaugeOptions) {\n super(container, options.theme);\n this.options = options;\n this.currentValue = options.value;\n this.targetValue = options.value;\n this.requestRender();\n }\n\n protected renderChart(\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n theme: Theme,\n ): void {\n renderGauge(ctx, width, height, this.options, theme, this.currentValue);\n }\n\n setValue(value: number): void {\n const animate = this.options.animate !== false;\n if (!animate) {\n this.cancelAnimation();\n this.currentValue = value;\n this.targetValue = value;\n this.options = { ...this.options, value };\n this.requestRender();\n return;\n }\n\n this.targetValue = value;\n this.animationFrom = this.currentValue;\n this.animationStart = performance.now();\n this.options = { ...this.options, value };\n this.startAnimationLoop();\n }\n\n setOptions(opts: Partial<GaugeOptions>): void {\n const next = { ...this.options, ...opts };\n // If `value` is part of the partial, route through animation path\n if (opts.value !== undefined && opts.value !== this.targetValue) {\n this.options = next;\n this.setValue(opts.value);\n return;\n }\n this.options = next;\n this.requestRender();\n }\n\n private startAnimationLoop(): void {\n if (this.animationFrameId !== null) return;\n const step = (): void => {\n this.animationFrameId = null;\n if (this.animationStart === null) return;\n\n const duration = this.options.animationDuration ?? DEFAULT_ANIMATION_MS;\n const elapsed = performance.now() - this.animationStart;\n const t = Math.min(1, elapsed / Math.max(1, duration));\n const eased = easeOutCubic(t);\n this.currentValue = this.animationFrom + (this.targetValue - this.animationFrom) * eased;\n\n this.requestRender();\n\n if (t < 1) {\n this.animationFrameId = requestAnimationFrame(step);\n } else {\n this.currentValue = this.targetValue;\n this.animationStart = null;\n }\n };\n this.animationFrameId = requestAnimationFrame(step);\n }\n\n private cancelAnimation(): void {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n this.animationStart = null;\n }\n\n destroy(): void {\n this.cancelAnimation();\n super.destroy();\n }\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ export { DataManager } from './DataManager.js';
3
3
  export { ThemeManager } from './ThemeManager.js';
4
4
  export { LayoutManager } from './layout/LayoutManager.js';
5
5
  export { PluginManager } from './plugins/PluginManager.js';
6
+ export { parseOHLCV, DragDropImporter } from './io/index.js';
7
+ export type { ParseResult, DragDropImporterCallbacks } from './io/index.js';
6
8
  export type { OHLCBar, DataSeries, TimeFrame, ChartOptions, ChartType, Theme, ThemeName, ChartEventType, ChartEvent, ChartEventMap, IndicatorPlugin, IndicatorDescriptor, IndicatorConfig, IndicatorOutput, IndicatorValue, TauriBridgeOptions, ViewportState, CrosshairMovePayload, BarClickPayload, VisibleRangeChangePayload, OrderModifyPayload, OrderCancelPayload, PositionModifyPayload, PositionClosePayload, OrderPlacePayload, IndicatorChangePayload, ThemeChangePayload, ResizePayload, ZoomChangePayload, PriceRangeChangePayload, DrawingCreatePayload, DrawingRemovePayload, SignalMarkerAddPayload, SignalMarkerRemovePayload, TradeZoneAddPayload, TradeZoneRemovePayload, DrawingToolType, DrawingState, DrawingStyle, DrawingPlugin, DrawingDescriptor, FeaturesConfig, SessionBreakOptions, PriceAxisOptions, TimeAxisOptions, AnchorPoint, PanelPosition, PanelConfig, ResolvedLayout, TradingOrder, TradingPosition, DepthData, DepthLevel, TradingConfig, OrderSide, OrderType, OrderStatus, OrderLabel, OrderPlaceIntent, OrderModifyIntent, OrderCancelIntent, PositionModifyIntent, PositionCloseIntent, Locale, LocaleStrings, MarketConfig, MarketType, StockExchange, MarketColorScheme, TradingSession, PriceLimitInfo, DataAdapter, DataAdapterConfig, DataAdapterEventType, StreamConfig, ConnectionState, ConnectionInfo, RawTick, AggregatedBar, ReconnectConfig, ResolvedIndicatorStyle, WatermarkConfig, GridOptions, CrosshairOptions, SignalMarker, SignalDirection, SignalMarkerStyle, TradeZone, TradeZoneDirection, TradeZoneStyle, } from '@tradecanvas/commons';
7
9
  export { DARK_THEME, LIGHT_THEME, DARK_TERMINAL, DEFAULT_DRAWING_STYLE, DEFAULT_TRADING_CONFIG, DEFAULT_SIGNAL_STYLE, DEFAULT_TRADE_ZONE_STYLE, TIMEFRAMES_CRYPTO, TIMEFRAMES_STOCK, TIMEFRAMES_FOREX, DEFAULT_TIMEFRAME_FAVORITES, } from '@tradecanvas/commons';
8
10
  export { normalizeBarTime, normalizeBar } from '@tradecanvas/commons';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}