@tradecanvas/chart 1.68.1 → 1.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/Chart.d.ts +20 -97
- package/dist/Chart.d.ts.map +1 -1
- package/dist/DataManager.d.ts +7 -0
- package/dist/DataManager.d.ts.map +1 -1
- package/dist/HistoryPager.d.ts.map +1 -1
- package/dist/{LayoutSession-EEUFJm3J.js → LayoutSession-Bcy79w0l.js} +1082 -873
- package/dist/LayoutSession-Bcy79w0l.js.map +1 -0
- package/dist/LayoutSession-D7S6GZgJ.cjs +2 -0
- package/dist/LayoutSession-D7S6GZgJ.cjs.map +1 -0
- package/dist/SeriesStore.d.ts +2 -0
- package/dist/SeriesStore.d.ts.map +1 -1
- package/dist/grid/ChartGrid.d.ts +5 -5
- package/dist/grid/ChartGrid.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +69 -69
- package/dist/index.js.map +1 -1
- package/dist/model/DisplaySeries.d.ts +50 -0
- package/dist/model/DisplaySeries.d.ts.map +1 -0
- package/dist/model/DrawingPanes.d.ts +24 -0
- package/dist/model/DrawingPanes.d.ts.map +1 -0
- package/dist/model/IndicatorHistory.d.ts +52 -0
- package/dist/model/IndicatorHistory.d.ts.map +1 -0
- package/dist/model/IndicatorPanes.d.ts +76 -0
- package/dist/model/IndicatorPanes.d.ts.map +1 -0
- package/dist/model/IndicatorSetup.d.ts +34 -0
- package/dist/model/IndicatorSetup.d.ts.map +1 -0
- package/dist/model/PaneLayout.d.ts +55 -0
- package/dist/model/PaneLayout.d.ts.map +1 -0
- package/dist/model/PriceFit.d.ts +75 -0
- package/dist/model/PriceFit.d.ts.map +1 -0
- package/dist/model/SymbolRequests.d.ts +34 -0
- package/dist/model/SymbolRequests.d.ts.map +1 -0
- package/dist/widget/ChartWidget.d.ts +1 -1
- package/dist/widget/ChartWidget.d.ts.map +1 -1
- package/dist/widget/ChartWidgetGrid.d.ts +2 -2
- package/dist/widget/ChartWidgetGrid.d.ts.map +1 -1
- package/dist/widget/index.cjs +22 -22
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +1774 -1761
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/types.d.ts +8 -1
- package/dist/widget/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/LayoutSession-DQLEWUw6.cjs +0 -2
- package/dist/LayoutSession-DQLEWUw6.cjs.map +0 -1
- package/dist/LayoutSession-EEUFJm3J.js.map +0 -1
- package/dist/PaneManager.d.ts +0 -19
- package/dist/PaneManager.d.ts.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/frameworks/syncIndicators.ts","../src/frameworks/feedBars.ts","../src/plugins/overlayScale.ts","../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","../src/finance/InteractiveChart.ts","../src/finance/BarChart.ts","../src/finance/DonutChart.ts","../src/finance/ScatterChart.ts","../src/finance/HistogramChart.ts","../src/finance/CalendarChart.ts","../src/finance/MatrixChart.ts","../src/finance/CounterClockChart.ts","../src/finance/performanceData.ts","../src/finance/PerformanceDashboard.ts"],"sourcesContent":["import type { IndicatorId, IndicatorParamValues, PanelPosition } from '@tradecanvas/commons';\n\n/**\n * An indicator a framework component shows: its id (`'rsi'`), or its id with\n * its inputs and, for one in a pane, where the pane goes.\n */\nexport type IndicatorSpec =\n | IndicatorId\n | { id: IndicatorId; params?: IndicatorParamValues; position?: PanelPosition };\n\n/** What the components need of a chart to keep its indicators in step. */\nexport interface IndicatorHost {\n addIndicator(...args: [string, Record<string, number | string | boolean>?, PanelPosition?]): string | null;\n removeIndicator(instanceId: string): void;\n}\n\n/** One spec as text: the same indicator with the same inputs (in any order) and place reads the same. */\nfunction specKey(spec: IndicatorSpec): string {\n const { id, params = {}, position = null } = typeof spec === 'string' ? { id: spec } : spec;\n return JSON.stringify([id, Object.keys(params).sort().map((k) => [k, params[k]]), position]);\n}\n\n/**\n * Brings the chart's indicators to `specs`: those no longer asked for go,\n * new ones come, and one whose inputs or place changed is put back with\n * them. `current` maps each spec (and its count, for two alike) to its\n * instance on the chart, and is kept up to date.\n */\nexport function syncIndicators(chart: IndicatorHost, specs: readonly IndicatorSpec[], current: Map<string, string>): void {\n const seen = new Map<string, number>();\n const wanted = specs.map((spec) => {\n const key = specKey(spec);\n const n = seen.get(key) ?? 0;\n seen.set(key, n + 1);\n return { spec, key: `${key}#${n}` };\n });\n const keys = new Set(wanted.map((w) => w.key));\n for (const [key, instanceId] of [...current]) {\n if (keys.has(key)) continue;\n chart.removeIndicator(instanceId);\n current.delete(key);\n }\n for (const { spec, key } of wanted) {\n if (current.has(key)) continue;\n const instanceId = typeof spec === 'string'\n ? chart.addIndicator(spec)\n : spec.position !== undefined\n ? chart.addIndicator(spec.id, spec.params ?? {}, spec.position)\n : chart.addIndicator(spec.id, spec.params ?? {});\n if (instanceId) current.set(key, instanceId);\n }\n}\n","import type { OHLCBar } from '@tradecanvas/commons';\nimport { isValidBar, sameBar } from '../DataManager.js';\n\n/**\n * How many bars before the forming one a component's `data` may correct\n * in place (the venue's final for the bar just closed, a late revision):\n * they go in as `updateBar`, the view kept. A change further back is a new\n * series. Vue and Svelte watch these bars, the forming one and the length.\n */\nexport const CORRECTABLE_BARS = 3;\n\n/** What the components need of a chart to give it their `data`. */\nexport interface BarFeedHost {\n setData(data: OHLCBar[]): void;\n updateLastBar(bar: OHLCBar): void;\n appendBar(bar: OHLCBar): void;\n appendBars(bars: OHLCBar[]): void;\n /**\n * A loaded bar corrected (`Chart.updateBar`): false when the chart has no\n * bar at its time. Without it, a correction is fed as a new series.\n */\n updateBar?(bar: OHLCBar): boolean;\n /** The bars shown: read to tell bars another writer gave the chart. */\n getData(): readonly OHLCBar[];\n isExtendedHoursVisible(): boolean;\n isReplayActive(): boolean;\n}\n\n/** What `feedBars` gave back, for its next call. */\nexport interface FedBars {\n /** The array given, and how many bars it had then. */\n readonly source: readonly OHLCBar[];\n readonly length: number;\n /** Its last bar as it was then (a copy: the array may change in place). */\n readonly last: OHLCBar | null;\n /** Up to `CORRECTABLE_BARS` bars before the last, as they were then (copies): a change to one is a correction. */\n readonly recent?: readonly OHLCBar[];\n /** The chart's last bar just after, the object itself: another writer's bar is another object. */\n readonly shownBar: OHLCBar | null;\n /** Fed during a replay: the bars went to the live series, out of sight. */\n readonly inReplay: boolean;\n}\n\n/**\n * A plain copy for the chart: a framework's state can be frozen, and its\n * proxies are not for reading in frames.\n */\nconst copy = (b: OHLCBar): OHLCBar => ({ time: b.time, open: b.open, high: b.high, low: b.low, close: b.close, volume: b.volume });\nconst lastOf = (bars: readonly OHLCBar[]): OHLCBar | null => (bars.length > 0 ? bars[bars.length - 1] : null);\n\n/** Whether the first `count` bars of `next` are those of `prev`. */\nfunction samePrefix(prev: readonly OHLCBar[], next: readonly OHLCBar[], count: number): boolean {\n for (let i = 0; i < count; i++) {\n if (!sameBar(prev[i], next[i])) return false;\n }\n return true;\n}\n\n/**\n * Whether the chart still shows what was fed: no stream or other code gave\n * it bars since. During a replay the bars shown are the replay's, and ticks\n * go to the live series beside them; after one, the live series is back,\n * and only its last time can tell. A last bar fed but not shown is fine\n * while extended hours are hidden: the chart keeps it aside.\n */\nfunction chartAsFed(chart: BarFeedHost, prev: FedBars): boolean {\n if (chart.isReplayActive()) return true;\n const shown = lastOf(chart.getData());\n if (prev.inReplay) return shown?.time === prev.last?.time;\n if (shown !== prev.shownBar) return false;\n return shown?.time === prev.last?.time || !chart.isExtendedHoursVisible();\n}\n\n/**\n * The bars of `next` from `from` on that differ from `recent` (the copies\n * kept of them): corrections, each with the same time and one the chart\n * can take; null when one isn't.\n */\nfunction correctionsIn(next: readonly OHLCBar[], recent: readonly OHLCBar[], from: number): OHLCBar[] | null {\n const corrections: OHLCBar[] = [];\n for (let i = 0; i < recent.length; i++) {\n const bar = next[from + i];\n if (sameBar(bar, recent[i])) continue;\n if (bar.time !== recent[i].time || !isValidBar(bar)) return null;\n corrections.push(copy(bar));\n }\n return corrections;\n}\n\n/** Each correction onto the chart; false when it has no `updateBar`, or refuses one. */\nfunction applyCorrections(chart: BarFeedHost, corrections: readonly OHLCBar[]): boolean {\n if (corrections.length === 0) return true;\n if (!chart.updateBar) return false;\n for (const bar of corrections) {\n if (!chart.updateBar(bar)) return false;\n }\n return true;\n}\n\n/** Copies of up to `CORRECTABLE_BARS` bars before the last of `bars`, never the first (another symbol on the same times changes it). */\nfunction recentOf(bars: readonly OHLCBar[]): OHLCBar[] {\n return bars.slice(Math.max(1, bars.length - 1 - CORRECTABLE_BARS), -1).map(copy);\n}\n\n/** The bars after the forming one, if each is valid and later than the one before; else null. */\nfunction addedAfter(next: readonly OHLCBar[], from: number): OHLCBar[] | null {\n const added: OHLCBar[] = [];\n for (let i = from; i < next.length; i++) {\n if (!isValidBar(next[i]) || !(next[i].time > next[i - 1].time)) return null;\n added.push(copy(next[i]));\n }\n return added;\n}\n\n/**\n * Feeds `next` as ticks when it goes on from what was fed: the bars before\n * the last as they were, or a few of them corrected, the last one changed\n * or bars added after it. Returns false when it doesn't, having fed no\n * tick and no bar added: the bars are then a new series.\n */\nfunction feedTicks(chart: BarFeedHost, next: readonly OHLCBar[], prev: FedBars): boolean {\n const p = prev.length;\n // A last bar the chart couldn't take was left out: what it shows isn't what was fed.\n if (p === 0 || !prev.last || !isValidBar(prev.last) || next.length < p || !chartAsFed(chart, prev)) return false;\n const recent = prev.recent ?? [];\n const settled = p - 1 - recent.length;\n // The same array, changed in place: only its end can have moved, and the\n // copies of its last bars tell. The one before, changed in place since\n // (cut short, say), can't be compared.\n if (next !== prev.source && (prev.source.length !== p || !samePrefix(prev.source, next, settled))) return false;\n const forming = next[p - 1];\n if (forming.time !== prev.last.time || !isValidBar(forming)) return false;\n const corrections = correctionsIn(next, recent, settled);\n const added = addedAfter(next, p);\n if (!corrections || !added) return false;\n // Before any tick: a chart that refuses one takes the bars as a new series instead.\n if (!applyCorrections(chart, corrections)) return false;\n if (!sameBar(forming, prev.last)) chart.updateLastBar(copy(forming));\n if (added.length === 1) chart.appendBar(added[0]);\n else if (added.length > 1) chart.appendBars(added);\n return true;\n}\n\n/**\n * Bars into the chart, as the framework components take their `data`. Bars\n * that go on from those fed before (the last one changed, or bars added after\n * it) go in as ticks (`updateLastBar`, `appendBar`, `appendBars`), as a live\n * feed's do: the view isn't reset, and only the end is computed again. A\n * change to one of the `CORRECTABLE_BARS` bars before the forming one (its\n * time the same) goes in as a correction (`updateBar`), the view kept too.\n * That holds for a new array (`[...bars, next]`) and for the same one\n * changed in place. Anything else is a new series (`setData`): other bars,\n * a bar the chart can't take, a correction it refuses or can't take (no\n * `updateBar`), or bars another writer gave the chart since. `prev` is what\n * the last call gave back (null for the first); the chart gets plain copies.\n */\nexport function feedBars(chart: BarFeedHost, next: readonly OHLCBar[], prev: FedBars | null): FedBars {\n if (!prev || !feedTicks(chart, next, prev)) chart.setData(next.map(copy));\n const last = next.length > 0 ? copy(next[next.length - 1]) : null;\n const inReplay = chart.isReplayActive();\n return { source: next, length: next.length, last, recent: recentOf(next), shownBar: inReplay ? null : lastOf(chart.getData()), inReplay };\n}\n","import type { DataSeries, ViewportState } from '@tradecanvas/commons';\nimport {\n barIndexToTime,\n barIndexToX,\n priceToYMapper,\n timestampToBarIndex,\n xToBarIndex,\n yToPrice,\n} from '@tradecanvas/core';\n\n/**\n * Where things go on screen in one frame, as the chart itself places them:\n * bars by time or index, prices on a log or upside-down scale too. For an\n * overlay plugin's `render`, built from the context it is handed.\n *\n * Bars are those of `context.data`, the series on screen: on a Renko, Kagi,\n * point & figure, line break or range-bar chart they are its bricks or\n * columns, not the feed's bars (`chart.isTimeAligned()` says which). Times\n * between bars and past either end are placed in proportion once there are\n * two bars; with fewer, a time lands on the nearest bar.\n */\nexport interface FrameScale {\n /** x of the middle of the bar at `time` (the data's own unit); between bars and past either end in proportion. */\n timeToX(time: number): number;\n /** The bar time at `x`, extrapolated past either end of the data. */\n xToTime(x: number): number;\n /** x of the middle of bar `index` of the data. */\n indexToX(index: number): number;\n /** The bar index at `x`, rounded to the nearest bar. */\n xToIndex(x: number): number;\n priceToY(price: number): number;\n yToPrice(y: number): number;\n /** A bar's body width in pixels at this zoom. */\n readonly barWidth: number;\n /** The first and last bar indexes on screen, within the data; `to < from` when there is none. */\n readonly visible: { readonly from: number; readonly to: number };\n}\n\n/**\n * The scale of an overlay plugin's frame:\n *\n * ```ts\n * render(ctx, context) {\n * const s = overlayScale(context);\n * for (let i = s.visible.from; i <= s.visible.to; i++) {\n * ctx.fillRect(s.indexToX(i) - s.barWidth / 2, s.priceToY(context.data[i].high), s.barWidth, 2);\n * }\n * }\n * ```\n */\nexport function overlayScale(context: { viewport: ViewportState; data: DataSeries }): FrameScale {\n const { viewport, data } = context;\n const toY = priceToYMapper(viewport);\n const last = data.length - 1;\n const from = Math.max(0, Math.floor(viewport.visibleRange.from));\n const to = Math.min(last, Math.ceil(viewport.visibleRange.to));\n const indexOf = (time: number) => (data.length > 0 ? timestampToBarIndex(time, data) : time);\n return {\n timeToX: (time) => barIndexToX(indexOf(time), viewport),\n xToTime: (x) => {\n const index = xToBarIndex(x, viewport);\n return data.length > 0 ? barIndexToTime(index, data) : index;\n },\n indexToX: (index) => barIndexToX(index, viewport),\n xToIndex: (x) => xToBarIndex(x, viewport),\n priceToY: toY,\n yToPrice: (y) => yToPrice(y, viewport),\n barWidth: viewport.barWidth,\n visible: to < from ? { from: 0, to: -1 } : { from, to },\n };\n}\n","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 for (let i = 0; i < count; i++) this.cells.push(this.createCell(i));\n }\n\n private createCell(i: number): GridCell {\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 // Charts can differ in symbol and timeframe, so the crosshair is linked by\n // time: the others show a vertical line on the bar containing that time.\n if (this.options.syncCrosshair !== false) {\n chart.on('crosshairMove', (e) => {\n const time = e.payload.bar?.time;\n if (time === undefined) return;\n for (const other of this.cells) {\n if (other.chart !== chart) other.chart.setCrosshairTime(time);\n }\n });\n chart.on('crosshairLeave', () => {\n for (const other of this.cells) {\n if (other.chart !== chart) other.chart.setCrosshairTime(null);\n }\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 return cell;\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 // New cells get the same options and linking as the first ones.\n for (let i = oldCount; i < newCount; i++) this.cells.push(this.createCell(i));\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 /**\n * Connect each chart to a symbol. An adapter keeps one stream, so pass a\n * function that makes one per chart (`() => new BinanceAdapter()`); a single\n * adapter object serves one chart only.\n */\n async connectAll(\n adapter: DataAdapter | ((symbol: string, index: number) => DataAdapter),\n symbols: string[],\n timeframe: TimeFrame,\n historyLimit = 500,\n ): 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: typeof adapter === 'function' ? adapter(symbols[i], i) : 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 layoutGroupedTreemap,\n renderHeatmap,\n GROUP_HEADER,\n} from '@tradecanvas/core';\nimport type { GroupRect, 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 cachedGroups: GroupRect[] = [];\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.applyLabel();\n this.recomputeLayout();\n this.requestRender();\n }\n\n /** What screen readers hear: `ariaLabel`, else the cells and groups it has. */\n private applyLabel(): void {\n const groups = new Set(this.currentData.map((c) => c.group).filter(Boolean)).size;\n const described = this.options.grouped && groups > 0\n ? `Market map of ${this.currentData.length} cells in ${groups} groups`\n : `Heatmap of ${this.currentData.length} cells`;\n this.setLabel(this.options.ariaLabel ?? described);\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 this.cachedGroups = [];\n if (this.options.grouped) {\n const weighted = this.currentData.map(c => ({\n id: c.id,\n weight: c.weight ?? (Math.abs(c.value) || 1),\n group: c.group,\n value: c.value,\n }));\n const { groups, cells } = layoutGroupedTreemap(weighted, bounds, padding, GROUP_HEADER);\n this.cachedRects = cells;\n this.cachedGroups = groups;\n } else 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, this.cachedGroups);\n }\n\n update(data: HeatmapCell[]): void {\n this.currentData = data;\n this.options = { ...this.options, data };\n this.applyLabel();\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.applyLabel();\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","import type { BaseFinanceChartOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, canvasMeasure, type Measure } from '@tradecanvas/core';\n\ntype HoverOptions = BaseFinanceChartOptions & { crosshair?: boolean };\n\n/**\n * A finance chart that follows the pointer and answers clicks: it keeps the\n * layout it last drew, so a click finds what is under it without redrawing.\n */\nexport abstract class InteractiveChart<O extends HoverOptions, L> extends BaseFinanceChart {\n protected options: O;\n protected layout: L | null = null;\n /** What the cached layout was worked out for: a pointer move redraws without laying out again. */\n private layoutFor: { options: O; width: number; height: number; theme: Theme } | null = null;\n private readonly crosshair: FinanceCrosshair;\n private readonly onClick = (e: MouseEvent) => {\n const rect = this.canvas.getBoundingClientRect();\n if (this.layout) this.clickAt(this.layout, e.clientX - rect.left, e.clientY - rect.top);\n };\n private readonly onMove = (e: PointerEvent) => {\n if (!this.layout || !this.clickable()) return;\n const rect = this.canvas.getBoundingClientRect();\n this.canvas.style.cursor = this.hits(this.layout, e.clientX - rect.left, e.clientY - rect.top) ? 'pointer' : '';\n };\n\n constructor(container: HTMLElement, options: O) {\n super(container, options.theme);\n this.options = options;\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n this.canvas.addEventListener('click', this.onClick);\n this.canvas.addEventListener('pointermove', this.onMove);\n // describe() reads only `options`, set above: subclasses keep no state of their own.\n this.applyLabel();\n this.requestRender();\n }\n\n /** Where everything goes, for the chart's size and theme. */\n protected abstract compute(width: number, height: number, theme: Theme, measure: Measure): L;\n /** Draws the chart from its layout. */\n protected abstract draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: L): void;\n /** A sentence for screen readers when the options give none. */\n protected abstract describe(): string;\n /** Whether a click callback is set. */\n protected abstract clickable(): boolean;\n /** Whether something clickable is at (x, y). */\n protected abstract hits(layout: L, x: number, y: number): boolean;\n /** Calls the click callback for what is at (x, y). */\n protected abstract clickAt(layout: L, x: number, y: number): void;\n\n protected renderChart(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme): void {\n const pointer = this.options.crosshair === false ? null : this.crosshair.getPosition();\n const was = this.layoutFor;\n if (!this.layout || !was || was.options !== this.options || was.width !== width || was.height !== height || was.theme !== theme) {\n this.layout = this.compute(width, height, theme, canvasMeasure(ctx, theme));\n this.layoutFor = { options: this.options, width, height, theme };\n }\n this.draw(ctx, width, height, theme, pointer, this.layout);\n }\n\n setOptions(options: Partial<O>): void {\n this.options = { ...this.options, ...options };\n if ('theme' in options) this.setTheme(options.theme ?? 'dark');\n this.applyLabel();\n this.requestRender();\n }\n\n private applyLabel(): void {\n this.setLabel(this.options.ariaLabel ?? this.describe());\n }\n\n destroy(): void {\n this.crosshair.destroy();\n this.canvas.removeEventListener('click', this.onClick);\n this.canvas.removeEventListener('pointermove', this.onMove);\n super.destroy();\n }\n}\n","import type { BarChartOptions, ChartSeries, Theme } from '@tradecanvas/commons';\nimport { computeBarLayout, hitBar, renderBarChart, type BarLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/**\n * Bars by category: series side by side or stacked, up and down from zero,\n * upright or sideways. Net flows, volumes by session, returns by period.\n */\nexport class BarChart extends InteractiveChart<BarChartOptions, BarLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): BarLayout {\n return computeBarLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: BarLayout): void {\n renderBarChart(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const names = this.options.series.map((s) => s.name).join(', ');\n return `Bar chart of ${names}, ${this.options.categories.length} categories`;\n }\n\n protected clickable(): boolean {\n return this.options.onBarClick !== undefined;\n }\n\n protected hits(layout: BarLayout, x: number, y: number): boolean {\n return hitBar(layout, x, y) !== null;\n }\n\n protected clickAt(layout: BarLayout, x: number, y: number): void {\n const bar = hitBar(layout, x, y);\n if (bar) this.options.onBarClick?.({ category: bar.category, series: bar.series, value: bar.value, index: bar.index });\n }\n\n /** New values: the categories and their series. */\n update(categories: string[], series: ChartSeries[]): void {\n this.setOptions({ categories, series });\n }\n}\n","import type { DonutChartOptions, DonutSlice, Theme } from '@tradecanvas/commons';\nimport { computeDonutLayout, hitSlice, renderDonut, type DonutLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Parts of a whole as a ring (or a pie): allocation, exposure, order flow by side. */\nexport class DonutChart extends InteractiveChart<DonutChartOptions, DonutLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): DonutLayout {\n return computeDonutLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: DonutLayout): void {\n renderDonut(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const parts = this.options.data.filter((s) => Number.isFinite(s.value) && s.value > 0).map((s) => s.label).join(', ');\n return `${(this.options.innerRadius ?? 0.6) > 0 ? 'Donut' : 'Pie'} chart of ${parts}`;\n }\n\n protected clickable(): boolean {\n return this.options.onSliceClick !== undefined;\n }\n\n protected hits(layout: DonutLayout, x: number, y: number): boolean {\n return hitSlice(layout, x, y) !== null;\n }\n\n protected clickAt(layout: DonutLayout, x: number, y: number): void {\n const arc = hitSlice(layout, x, y);\n if (arc) this.options.onSliceClick?.(arc.slice);\n }\n\n update(data: DonutSlice[]): void {\n this.setOptions({ data });\n }\n}\n","import type { ScatterChartOptions, ScatterSeries, Theme } from '@tradecanvas/commons';\nimport { computeScatterLayout, nearestPoint, renderScatter, type ScatterLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Points on two value axes, bubbles when they have a size: risk against return, value against growth. */\nexport class ScatterChart extends InteractiveChart<ScatterChartOptions, ScatterLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): ScatterLayout {\n return computeScatterLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: ScatterLayout): void {\n renderScatter(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const points = this.options.series.reduce((n, s) => n + s.points.length, 0);\n const axes = this.options.xLabel && this.options.yLabel ? ` of ${this.options.yLabel} against ${this.options.xLabel}` : '';\n return `Scatter chart${axes}, ${points} points`;\n }\n\n protected clickable(): boolean {\n return this.options.onPointClick !== undefined;\n }\n\n protected hits(layout: ScatterLayout, x: number, y: number): boolean {\n return nearestPoint(layout, x, y) !== null;\n }\n\n protected clickAt(layout: ScatterLayout, x: number, y: number): void {\n const p = nearestPoint(layout, x, y);\n if (p) this.options.onPointClick?.(p.point, p.series);\n }\n\n update(series: ScatterSeries[]): void {\n this.setOptions({ series });\n }\n}\n","import type { HistogramOptions, Theme } from '@tradecanvas/commons';\nimport { computeHistogramLayout, renderHistogram, type HistogramLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** How values spread: daily returns, trade results, with lines at the mean or a VaR. */\nexport class HistogramChart extends InteractiveChart<HistogramOptions, HistogramLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): HistogramLayout {\n return computeHistogramLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: HistogramLayout): void {\n renderHistogram(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n return `Histogram of ${this.options.values.length} values`;\n }\n\n protected clickable(): boolean {\n return false;\n }\n\n protected hits(): boolean {\n return false;\n }\n\n protected clickAt(): void {}\n\n update(values: number[]): void {\n this.setOptions({ values });\n }\n}\n","import type { CalendarChartOptions, CalendarDay, Theme } from '@tradecanvas/commons';\nimport { computeCalendarLayout, hitDay, renderCalendar, type CalendarLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** A value a day on a calendar: daily returns, P&L, volume, a trading journal. */\nexport class CalendarChart extends InteractiveChart<CalendarChartOptions, CalendarLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): CalendarLayout {\n return computeCalendarLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: CalendarLayout): void {\n renderCalendar(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const dates = this.options.data.map((d) => d.date).filter((d) => /^\\d{4}-\\d{2}-\\d{2}$/.test(d)).sort();\n const from = this.options.from ?? dates[0];\n const to = this.options.to ?? dates[dates.length - 1];\n return from && to ? `Calendar of daily values from ${from} to ${to}` : 'Calendar of daily values';\n }\n\n protected clickable(): boolean {\n return this.options.onDayClick !== undefined;\n }\n\n protected hits(layout: CalendarLayout, x: number, y: number): boolean {\n return hitDay(layout, x, y)?.day !== undefined;\n }\n\n protected clickAt(layout: CalendarLayout, x: number, y: number): void {\n const day = hitDay(layout, x, y)?.day;\n if (day) this.options.onDayClick?.(day);\n }\n\n update(data: CalendarDay[]): void {\n this.setOptions({ data });\n }\n}\n","import type { MatrixChartOptions, Theme } from '@tradecanvas/commons';\nimport { computeMatrixLayout, hitMatrixCell, renderMatrix, type MatrixLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Past this many names, the description gives counts instead. */\nconst MAX_NAMED = 12;\n\n/** A value for each row and column pair, coloured: correlations, volume by hour and weekday. */\nexport class MatrixChart extends InteractiveChart<MatrixChartOptions, MatrixLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): MatrixLayout {\n return computeMatrixLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: MatrixLayout): void {\n renderMatrix(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const { rows, columns } = this.options;\n if (!columns) return rows.length <= MAX_NAMED ? `Matrix of ${rows.join(', ')}` : `Matrix of ${rows.length} rows`;\n return rows.length + columns.length <= MAX_NAMED\n ? `Matrix of ${rows.join(', ')} by ${columns.join(', ')}`\n : `Matrix of ${rows.length} rows by ${columns.length} columns`;\n }\n\n protected clickable(): boolean {\n return this.options.onCellClick !== undefined;\n }\n\n protected hits(layout: MatrixLayout, x: number, y: number): boolean {\n return hitMatrixCell(layout, x, y) !== null;\n }\n\n protected clickAt(layout: MatrixLayout, x: number, y: number): void {\n const hit = hitMatrixCell(layout, x, y);\n if (hit) this.options.onCellClick?.(hit.cell);\n }\n\n /** New values for the same rows and columns; `setOptions` changes the names. */\n update(values: number[][]): void {\n this.setOptions({ values });\n }\n}\n","import type { CounterClockOptions, OHLCBar, Theme } from '@tradecanvas/commons';\nimport { computeCounterClockLayout, counterClockPhase, counterClockPoints, nearestCounterClockPoint, renderCounterClock, shownCount, type CounterClockLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/**\n * Counter-clock chart: average price against average volume, bar by bar, with\n * no time axis. A healthy cycle turns counter-clockwise: volume picks up,\n * price follows, volume fades, price follows it down.\n */\nexport class CounterClockChart extends InteractiveChart<CounterClockOptions, CounterClockLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): CounterClockLayout {\n return computeCounterClockLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: CounterClockLayout): void {\n renderCounterClock(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n return `Counter-clock chart of price against volume, ${this.options.period ?? 25}-bar averages`;\n }\n\n protected clickable(): boolean {\n return this.options.onPointClick !== undefined;\n }\n\n protected hits(layout: CounterClockLayout, x: number, y: number): boolean {\n return nearestCounterClockPoint(layout, x, y) !== null;\n }\n\n protected clickAt(layout: CounterClockLayout, x: number, y: number): void {\n const hit = nearestCounterClockPoint(layout, x, y);\n if (hit) this.options.onPointClick?.(hit.point);\n }\n\n /** The phase of the newest move, 1–8 counter-clockwise from volume rising (see `counterClockPhase`), or null. */\n getPhase(): number | null {\n return counterClockPhase(counterClockPoints(this.options.data, this.options.period ?? 25, shownCount(this.options)));\n }\n\n update(data: OHLCBar[]): void {\n this.setOptions({ data });\n }\n}\n","import type { EquityPoint, HeatmapCell } from '@tradecanvas/commons';\nimport { timeframeBucketStart } from '@tradecanvas/commons';\n\n/** Minimal equity sample shape — structurally satisfied by analytics' EquityPoint. */\nexport interface EquitySample {\n time: number;\n equity: number;\n}\n\n/**\n * Subset of analytics RiskMetrics needed to render the stats strip. The\n * percentages are fractions, as @tradecanvas/analytics returns them: a\n * totalReturnPct of 0.12 shows as +12.00%.\n */\nexport interface RiskMetricsLike {\n /** Total return as a fraction: 0.12 is +12%. */\n totalReturnPct: number;\n /** Compound annual growth rate as a fraction. */\n cagr: number;\n sharpe: number;\n sortino: number;\n /**\n * The deepest fall from a running peak, as a fraction: 0.5 is 50%. Either\n * sign reads as a fall, since some callers sign their drawdowns.\n */\n maxDrawdownPct: number;\n /** Share of winning trades as a fraction. */\n winRate: number;\n profitFactor: number;\n trades: number;\n}\n\nexport interface DashboardStat {\n label: string;\n value: string;\n tone: 'positive' | 'negative' | 'neutral';\n}\n\nconst MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\n/** Map an analytics equity curve to the finance EquityCurveChart point shape. */\nexport function toEquityPoints(curve: ReadonlyArray<EquitySample>): EquityPoint[] {\n return curve.map((p) => ({ time: p.time, value: p.equity }));\n}\n\n/**\n * Underwater drawdown curve as a percentage (<= 0). Each point is the equity's\n * shortfall from the running peak: `equity / peak - 1`, expressed in percent.\n */\nexport function computeDrawdownCurve(curve: ReadonlyArray<EquitySample>): EquityPoint[] {\n let peak = -Infinity;\n return curve.map((p) => {\n if (p.equity > peak) peak = p.equity;\n const dd = peak > 0 ? (p.equity / peak - 1) * 100 : 0;\n return { time: p.time, value: dd };\n });\n}\n\n/**\n * Calendar-month returns as heatmap cells. Each month's return is chained off\n * the prior month's closing equity (the first month chains off its own opening\n * equity), so the series reads as sequential monthly performance. `group` is\n * the year and `value` is the return in percent.\n */\nexport function computeMonthlyReturns(curve: ReadonlyArray<EquitySample>): HeatmapCell[] {\n if (curve.length === 0) return [];\n\n // Collapse the curve to one closing equity per calendar month, in order.\n const months: { key: number; close: number }[] = [];\n for (const p of curve) {\n const key = timeframeBucketStart(p.time, '1M');\n const last = months[months.length - 1];\n if (last && last.key === key) {\n last.close = p.equity;\n } else {\n months.push({ key, close: p.equity });\n }\n }\n\n let prevClose = curve[0].equity;\n const cells: HeatmapCell[] = [];\n for (const m of months) {\n const base = prevClose === 0 ? 1 : prevClose;\n const returnPct = (m.close / base - 1) * 100;\n prevClose = m.close;\n const d = new Date(m.key);\n const year = d.getUTCFullYear();\n const month = d.getUTCMonth();\n cells.push({\n id: `${year}-${String(month + 1).padStart(2, '0')}`,\n label: MONTH_LABELS[month],\n group: String(year),\n value: returnPct,\n });\n }\n return cells;\n}\n\n/** Metrics arrive as fractions (0.12); the cards show percent (12.00%). */\nconst PERCENT = 100;\n\nfunction pct(value: number): string {\n const sign = value > 0 ? '+' : '';\n return `${sign}${value.toFixed(2)}%`;\n}\n\nfunction tone(value: number): DashboardStat['tone'] {\n if (value > 0) return 'positive';\n if (value < 0) return 'negative';\n return 'neutral';\n}\n\n/**\n * The headline stats rendered as cards above the charts. The drawdown is a\n * fall, so it reads with a minus sign whichever sign it arrives with, as the\n * Drawdown panel below plots it.\n */\nexport function selectKeyStats(metrics: RiskMetricsLike): DashboardStat[] {\n return [\n { label: 'Total Return', value: pct(metrics.totalReturnPct * PERCENT), tone: tone(metrics.totalReturnPct) },\n { label: 'CAGR', value: pct(metrics.cagr * PERCENT), tone: tone(metrics.cagr) },\n { label: 'Sharpe', value: metrics.sharpe.toFixed(2), tone: tone(metrics.sharpe) },\n { label: 'Sortino', value: metrics.sortino.toFixed(2), tone: tone(metrics.sortino) },\n { label: 'Max Drawdown', value: pct(-Math.abs(metrics.maxDrawdownPct) * PERCENT), tone: 'negative' },\n { label: 'Win Rate', value: `${(metrics.winRate * PERCENT).toFixed(1)}%`, tone: 'neutral' },\n { label: 'Profit Factor', value: Number.isFinite(metrics.profitFactor) ? metrics.profitFactor.toFixed(2) : '∞', tone: tone(metrics.profitFactor - 1) },\n { label: 'Trades', value: String(metrics.trades), tone: 'neutral' },\n ];\n}\n","import type { Theme, ThemeName } from '@tradecanvas/commons';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\nimport { EquityCurveChart } from './EquityCurveChart.js';\nimport { HeatmapChart } from './HeatmapChart.js';\nimport {\n toEquityPoints,\n computeDrawdownCurve,\n computeMonthlyReturns,\n selectKeyStats,\n type EquitySample,\n type RiskMetricsLike,\n type DashboardStat,\n} from './performanceData.js';\n\n/** Structurally satisfied by analytics' `BacktestResult`. */\nexport interface PerformanceResult {\n equityCurve: ReadonlyArray<EquitySample>;\n metrics: RiskMetricsLike;\n}\n\nexport interface PerformanceDashboardOptions {\n result: PerformanceResult;\n theme?: ThemeName | Theme;\n title?: string;\n subtitle?: string;\n}\n\nfunction resolveTheme(theme?: ThemeName | Theme): Theme {\n if (!theme || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\n/**\n * A composed strategy-performance dashboard: a headline stats strip, an equity\n * curve, an underwater drawdown panel, and a monthly-returns heatmap. Built\n * entirely from a backtest `result`, reusing the finance chart renderers.\n *\n * ```ts\n * const result = new Backtester(opts).run(bars, strategy);\n * const dash = new PerformanceDashboard(el, { result, theme: 'dark' });\n * ```\n */\nexport class PerformanceDashboard {\n private options: PerformanceDashboardOptions;\n private theme: Theme;\n private root: HTMLDivElement;\n private equityChart: EquityCurveChart | null = null;\n private drawdownChart: EquityCurveChart | null = null;\n private heatmap: HeatmapChart | null = null;\n\n constructor(container: HTMLElement, options: PerformanceDashboardOptions) {\n this.options = options;\n this.theme = resolveTheme(options.theme);\n this.root = document.createElement('div');\n this.build();\n container.appendChild(this.root);\n }\n\n private build(): void {\n const t = this.theme;\n const { result, title, subtitle } = this.options;\n const surface = this.panelBackground();\n const border = t.grid;\n\n this.root.style.cssText = [\n 'display:flex',\n 'flex-direction:column',\n 'gap:14px',\n 'width:100%',\n 'box-sizing:border-box',\n 'padding:16px',\n `background:${t.background}`,\n `color:${t.text}`,\n `font-family:${t.font.family}`,\n ].join(';');\n\n if (title || subtitle) {\n const header = document.createElement('div');\n if (title) {\n const h = document.createElement('div');\n h.textContent = title;\n h.style.cssText = `font-size:${t.font.sizeLarge}px;font-weight:600;letter-spacing:-0.01em;`;\n header.appendChild(h);\n }\n if (subtitle) {\n const s = document.createElement('div');\n s.textContent = subtitle;\n s.style.cssText = `font-size:${t.font.sizeSmall}px;color:${t.textSecondary};margin-top:2px;`;\n header.appendChild(s);\n }\n this.root.appendChild(header);\n }\n\n // Stats strip\n this.root.appendChild(this.buildStatsStrip(selectKeyStats(result.metrics), surface, border));\n\n // Chart grid\n const grid = document.createElement('div');\n grid.style.cssText = [\n 'display:grid',\n 'grid-template-columns:repeat(auto-fit, minmax(280px, 1fr))',\n 'grid-auto-rows:220px',\n 'gap:14px',\n ].join(';');\n this.root.appendChild(grid);\n\n const equityPanel = this.buildPanel('Equity Curve', surface, border);\n equityPanel.wrap.style.gridColumn = '1 / -1';\n grid.appendChild(equityPanel.wrap);\n this.equityChart = new EquityCurveChart(equityPanel.body, {\n data: toEquityPoints(result.equityCurve),\n theme: t,\n lineColor: t.candleUp,\n fillArea: true,\n crosshair: true,\n });\n\n const ddPanel = this.buildPanel('Drawdown', surface, border);\n grid.appendChild(ddPanel.wrap);\n this.drawdownChart = new EquityCurveChart(ddPanel.body, {\n data: computeDrawdownCurve(result.equityCurve),\n theme: t,\n lineColor: t.candleDown,\n fillArea: true,\n crosshair: true,\n valueFormat: (v) => `${v.toFixed(1)}%`,\n });\n\n const monthlyCells = computeMonthlyReturns(result.equityCurve);\n const heatPanel = this.buildPanel('Monthly Returns', surface, border);\n grid.appendChild(heatPanel.wrap);\n this.heatmap = new HeatmapChart(heatPanel.body, {\n data: monthlyCells,\n theme: t,\n showValues: true,\n valueFormat: (v) => `${v >= 0 ? '+' : ''}${v.toFixed(1)}`,\n colorScale: { negative: t.candleDown, zero: surface, positive: t.candleUp },\n });\n }\n\n private buildStatsStrip(stats: DashboardStat[], surface: string, border: string): HTMLDivElement {\n const strip = document.createElement('div');\n strip.style.cssText = [\n 'display:grid',\n 'grid-template-columns:repeat(auto-fit, minmax(120px, 1fr))',\n 'gap:10px',\n ].join(';');\n\n const t = this.theme;\n for (const stat of stats) {\n const card = document.createElement('div');\n card.style.cssText = [\n `background:${surface}`,\n `border:1px solid ${border}`,\n 'border-radius:10px',\n 'padding:10px 12px',\n 'display:flex',\n 'flex-direction:column',\n 'gap:4px',\n ].join(';');\n\n const label = document.createElement('div');\n label.textContent = stat.label;\n label.style.cssText = `font-size:${t.font.sizeSmall}px;color:${t.textSecondary};text-transform:uppercase;letter-spacing:0.04em;`;\n\n const value = document.createElement('div');\n value.textContent = stat.value;\n const color = stat.tone === 'positive' ? t.candleUp : stat.tone === 'negative' ? t.candleDown : t.text;\n value.style.cssText = `font-size:${t.font.sizeLarge}px;font-weight:600;color:${color};font-variant-numeric:tabular-nums;`;\n\n card.appendChild(label);\n card.appendChild(value);\n strip.appendChild(card);\n }\n return strip;\n }\n\n private buildPanel(title: string, surface: string, border: string): { wrap: HTMLDivElement; body: HTMLDivElement } {\n const t = this.theme;\n const wrap = document.createElement('div');\n wrap.style.cssText = [\n `background:${surface}`,\n `border:1px solid ${border}`,\n 'border-radius:10px',\n 'overflow:hidden',\n 'display:flex',\n 'flex-direction:column',\n ].join(';');\n\n const head = document.createElement('div');\n head.textContent = title;\n head.style.cssText = [\n `font-size:${t.font.sizeSmall}px`,\n 'font-weight:600',\n `color:${t.textSecondary}`,\n 'padding:8px 12px',\n `border-bottom:1px solid ${border}`,\n 'text-transform:uppercase',\n 'letter-spacing:0.04em',\n ].join(';');\n\n const body = document.createElement('div');\n body.style.cssText = 'flex:1;min-height:0;position:relative;';\n\n wrap.appendChild(head);\n wrap.appendChild(body);\n return { wrap, body };\n }\n\n /** A subtle surface tint distinct from the page background, per theme. */\n private panelBackground(): string {\n return this.theme.name === 'light' ? 'rgba(0,0,0,0.02)' : 'rgba(255,255,255,0.03)';\n }\n\n /** Replace the displayed result and re-render all panels. */\n update(result: PerformanceResult): void {\n this.options = { ...this.options, result };\n this.destroyCharts();\n this.root.replaceChildren();\n this.build();\n }\n\n setTheme(theme: ThemeName | Theme): void {\n this.theme = resolveTheme(theme);\n this.options = { ...this.options, theme };\n this.destroyCharts();\n this.root.replaceChildren();\n this.build();\n }\n\n private destroyCharts(): void {\n this.equityChart?.destroy();\n this.drawdownChart?.destroy();\n this.heatmap?.destroy();\n this.equityChart = null;\n this.drawdownChart = null;\n this.heatmap = null;\n }\n\n destroy(): void {\n this.destroyCharts();\n this.root.remove();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/frameworks/syncIndicators.ts","../src/frameworks/feedBars.ts","../src/plugins/overlayScale.ts","../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","../src/finance/InteractiveChart.ts","../src/finance/BarChart.ts","../src/finance/DonutChart.ts","../src/finance/ScatterChart.ts","../src/finance/HistogramChart.ts","../src/finance/CalendarChart.ts","../src/finance/MatrixChart.ts","../src/finance/CounterClockChart.ts","../src/finance/performanceData.ts","../src/finance/PerformanceDashboard.ts"],"sourcesContent":["import type { IndicatorId, IndicatorParamValues, PanelPosition } from '@tradecanvas/commons';\n\n/**\n * An indicator a framework component shows: its id (`'rsi'`), or its id with\n * its inputs and, for one in a pane, where the pane goes.\n */\nexport type IndicatorSpec =\n | IndicatorId\n | { id: IndicatorId; params?: IndicatorParamValues; position?: PanelPosition };\n\n/** What the components need of a chart to keep its indicators in step. */\nexport interface IndicatorHost {\n addIndicator(...args: [string, Record<string, number | string | boolean>?, PanelPosition?]): string | null;\n removeIndicator(instanceId: string): void;\n}\n\n/** One spec as text: the same indicator with the same inputs (in any order) and place reads the same. */\nfunction specKey(spec: IndicatorSpec): string {\n const { id, params = {}, position = null } = typeof spec === 'string' ? { id: spec } : spec;\n return JSON.stringify([id, Object.keys(params).sort().map((k) => [k, params[k]]), position]);\n}\n\n/**\n * Brings the chart's indicators to `specs`: those no longer asked for go,\n * new ones come, and one whose inputs or place changed is put back with\n * them. `current` maps each spec (and its count, for two alike) to its\n * instance on the chart, and is kept up to date.\n */\nexport function syncIndicators(chart: IndicatorHost, specs: readonly IndicatorSpec[], current: Map<string, string>): void {\n const seen = new Map<string, number>();\n const wanted = specs.map((spec) => {\n const key = specKey(spec);\n const n = seen.get(key) ?? 0;\n seen.set(key, n + 1);\n return { spec, key: `${key}#${n}` };\n });\n const keys = new Set(wanted.map((w) => w.key));\n for (const [key, instanceId] of [...current]) {\n if (keys.has(key)) continue;\n chart.removeIndicator(instanceId);\n current.delete(key);\n }\n for (const { spec, key } of wanted) {\n if (current.has(key)) continue;\n const instanceId = typeof spec === 'string'\n ? chart.addIndicator(spec)\n : spec.position !== undefined\n ? chart.addIndicator(spec.id, spec.params ?? {}, spec.position)\n : chart.addIndicator(spec.id, spec.params ?? {});\n if (instanceId) current.set(key, instanceId);\n }\n}\n","import type { OHLCBar } from '@tradecanvas/commons';\nimport { isValidBar, sameBar } from '../DataManager.js';\n\n/**\n * How many bars before the forming one a component's `data` may correct\n * in place (the venue's final for the bar just closed, a late revision):\n * they go in as `updateBar`, the view kept. A change further back is a new\n * series. Vue and Svelte watch these bars, the forming one and the length.\n */\nexport const CORRECTABLE_BARS = 3;\n\n/** What the components need of a chart to give it their `data`. */\nexport interface BarFeedHost {\n setData(data: OHLCBar[]): void;\n updateLastBar(bar: OHLCBar): void;\n appendBar(bar: OHLCBar): void;\n appendBars(bars: OHLCBar[]): void;\n /**\n * A loaded bar corrected (`Chart.updateBar`): false when the chart has no\n * bar at its time. Without it, a correction is fed as a new series.\n */\n updateBar?(bar: OHLCBar): boolean;\n /** The bars shown: read to tell bars another writer gave the chart. */\n getData(): readonly OHLCBar[];\n isExtendedHoursVisible(): boolean;\n isReplayActive(): boolean;\n}\n\n/** What `feedBars` gave back, for its next call. */\nexport interface FedBars {\n /** The array given, and how many bars it had then. */\n readonly source: readonly OHLCBar[];\n readonly length: number;\n /** Its last bar as it was then (a copy: the array may change in place). */\n readonly last: OHLCBar | null;\n /** Up to `CORRECTABLE_BARS` bars before the last, as they were then (copies): a change to one is a correction. */\n readonly recent?: readonly OHLCBar[];\n /** The chart's last bar just after, the object itself: another writer's bar is another object. */\n readonly shownBar: OHLCBar | null;\n /** Fed during a replay: the bars went to the live series, out of sight. */\n readonly inReplay: boolean;\n}\n\n/**\n * A plain copy for the chart: a framework's state can be frozen, and its\n * proxies are not for reading in frames.\n */\nconst copy = (b: OHLCBar): OHLCBar => ({ time: b.time, open: b.open, high: b.high, low: b.low, close: b.close, volume: b.volume });\nconst lastOf = (bars: readonly OHLCBar[]): OHLCBar | null => (bars.length > 0 ? bars[bars.length - 1] : null);\n\n/** Whether the first `count` bars of `next` are those of `prev`. */\nfunction samePrefix(prev: readonly OHLCBar[], next: readonly OHLCBar[], count: number): boolean {\n for (let i = 0; i < count; i++) {\n if (!sameBar(prev[i], next[i])) return false;\n }\n return true;\n}\n\n/**\n * Whether the chart still shows what was fed: no stream or other code gave\n * it bars since. During a replay the bars shown are the replay's, and ticks\n * go to the live series beside them; after one, the live series is back,\n * and only its last time can tell. A last bar fed but not shown is fine\n * while extended hours are hidden: the chart keeps it aside.\n */\nfunction chartAsFed(chart: BarFeedHost, prev: FedBars): boolean {\n if (chart.isReplayActive()) return true;\n const shown = lastOf(chart.getData());\n if (prev.inReplay) return shown?.time === prev.last?.time;\n if (shown !== prev.shownBar) return false;\n return shown?.time === prev.last?.time || !chart.isExtendedHoursVisible();\n}\n\n/**\n * The bars of `next` from `from` on that differ from `recent` (the copies\n * kept of them): corrections, each with the same time and one the chart\n * can take; null when one isn't.\n */\nfunction correctionsIn(next: readonly OHLCBar[], recent: readonly OHLCBar[], from: number): OHLCBar[] | null {\n const corrections: OHLCBar[] = [];\n for (let i = 0; i < recent.length; i++) {\n const bar = next[from + i];\n if (sameBar(bar, recent[i])) continue;\n if (bar.time !== recent[i].time || !isValidBar(bar)) return null;\n corrections.push(copy(bar));\n }\n return corrections;\n}\n\n/** Each correction onto the chart; false when it has no `updateBar`, or refuses one. */\nfunction applyCorrections(chart: BarFeedHost, corrections: readonly OHLCBar[]): boolean {\n if (corrections.length === 0) return true;\n if (!chart.updateBar) return false;\n for (const bar of corrections) {\n if (!chart.updateBar(bar)) return false;\n }\n return true;\n}\n\n/** Copies of up to `CORRECTABLE_BARS` bars before the last of `bars`, never the first (another symbol on the same times changes it). */\nfunction recentOf(bars: readonly OHLCBar[]): OHLCBar[] {\n return bars.slice(Math.max(1, bars.length - 1 - CORRECTABLE_BARS), -1).map(copy);\n}\n\n/** The bars after the forming one, if each is valid and later than the one before; else null. */\nfunction addedAfter(next: readonly OHLCBar[], from: number): OHLCBar[] | null {\n const added: OHLCBar[] = [];\n for (let i = from; i < next.length; i++) {\n if (!isValidBar(next[i]) || !(next[i].time > next[i - 1].time)) return null;\n added.push(copy(next[i]));\n }\n return added;\n}\n\n/**\n * Feeds `next` as ticks when it goes on from what was fed: the bars before\n * the last as they were, or a few of them corrected, the last one changed\n * or bars added after it. Returns false when it doesn't, having fed no\n * tick and no bar added: the bars are then a new series.\n */\nfunction feedTicks(chart: BarFeedHost, next: readonly OHLCBar[], prev: FedBars): boolean {\n const p = prev.length;\n // A last bar the chart couldn't take was left out: what it shows isn't what was fed.\n if (p === 0 || !prev.last || !isValidBar(prev.last) || next.length < p || !chartAsFed(chart, prev)) return false;\n const recent = prev.recent ?? [];\n const settled = p - 1 - recent.length;\n // The same array, changed in place: only its end can have moved, and the\n // copies of its last bars tell. The one before, changed in place since\n // (cut short, say), can't be compared.\n if (next !== prev.source && (prev.source.length !== p || !samePrefix(prev.source, next, settled))) return false;\n const forming = next[p - 1];\n if (forming.time !== prev.last.time || !isValidBar(forming)) return false;\n const corrections = correctionsIn(next, recent, settled);\n const added = addedAfter(next, p);\n if (!corrections || !added) return false;\n // Before any tick: a chart that refuses one takes the bars as a new series instead.\n if (!applyCorrections(chart, corrections)) return false;\n if (!sameBar(forming, prev.last)) chart.updateLastBar(copy(forming));\n if (added.length === 1) chart.appendBar(added[0]);\n else if (added.length > 1) chart.appendBars(added);\n return true;\n}\n\n/**\n * Bars into the chart, as the framework components take their `data`. Bars\n * that go on from those fed before (the last one changed, or bars added after\n * it) go in as ticks (`updateLastBar`, `appendBar`, `appendBars`), as a live\n * feed's do: the view isn't reset, and only the end is computed again. A\n * change to one of the `CORRECTABLE_BARS` bars before the forming one (its\n * time the same) goes in as a correction (`updateBar`), the view kept too.\n * That holds for a new array (`[...bars, next]`) and for the same one\n * changed in place. Anything else is a new series (`setData`): other bars,\n * a bar the chart can't take, a correction it refuses or can't take (no\n * `updateBar`), or bars another writer gave the chart since. `prev` is what\n * the last call gave back (null for the first); the chart gets plain copies.\n */\nexport function feedBars(chart: BarFeedHost, next: readonly OHLCBar[], prev: FedBars | null): FedBars {\n if (!prev || !feedTicks(chart, next, prev)) chart.setData(next.map(copy));\n const last = next.length > 0 ? copy(next[next.length - 1]) : null;\n const inReplay = chart.isReplayActive();\n return { source: next, length: next.length, last, recent: recentOf(next), shownBar: inReplay ? null : lastOf(chart.getData()), inReplay };\n}\n","import type { DataSeries, ViewportState } from '@tradecanvas/commons';\nimport {\n barIndexToTime,\n barIndexToX,\n priceToYMapper,\n timestampToBarIndex,\n xToBarIndex,\n yToPrice,\n} from '@tradecanvas/core';\n\n/**\n * Where things go on screen in one frame, as the chart itself places them:\n * bars by time or index, prices on a log or upside-down scale too. For an\n * overlay plugin's `render`, built from the context it is handed.\n *\n * Bars are those of `context.data`, the series on screen: on a Renko, Kagi,\n * point & figure, line break or range-bar chart they are its bricks or\n * columns, not the feed's bars (`chart.isTimeAligned()` says which). Times\n * between bars and past either end are placed in proportion once there are\n * two bars; with fewer, a time lands on the nearest bar.\n */\nexport interface FrameScale {\n /** x of the middle of the bar at `time` (the data's own unit); between bars and past either end in proportion. */\n timeToX(time: number): number;\n /** The bar time at `x`, extrapolated past either end of the data. */\n xToTime(x: number): number;\n /** x of the middle of bar `index` of the data. */\n indexToX(index: number): number;\n /** The bar index at `x`, rounded to the nearest bar. */\n xToIndex(x: number): number;\n priceToY(price: number): number;\n yToPrice(y: number): number;\n /** A bar's body width in pixels at this zoom. */\n readonly barWidth: number;\n /** The first and last bar indexes on screen, within the data; `to < from` when there is none. */\n readonly visible: { readonly from: number; readonly to: number };\n}\n\n/**\n * The scale of an overlay plugin's frame:\n *\n * ```ts\n * render(ctx, context) {\n * const s = overlayScale(context);\n * for (let i = s.visible.from; i <= s.visible.to; i++) {\n * ctx.fillRect(s.indexToX(i) - s.barWidth / 2, s.priceToY(context.data[i].high), s.barWidth, 2);\n * }\n * }\n * ```\n */\nexport function overlayScale(context: { viewport: ViewportState; data: DataSeries }): FrameScale {\n const { viewport, data } = context;\n const toY = priceToYMapper(viewport);\n const last = data.length - 1;\n const from = Math.max(0, Math.floor(viewport.visibleRange.from));\n const to = Math.min(last, Math.ceil(viewport.visibleRange.to));\n const indexOf = (time: number) => (data.length > 0 ? timestampToBarIndex(time, data) : time);\n return {\n timeToX: (time) => barIndexToX(indexOf(time), viewport),\n xToTime: (x) => {\n const index = xToBarIndex(x, viewport);\n return data.length > 0 ? barIndexToTime(index, data) : index;\n },\n indexToX: (index) => barIndexToX(index, viewport),\n xToIndex: (x) => xToBarIndex(x, viewport),\n priceToY: toY,\n yToPrice: (y) => yToPrice(y, viewport),\n barWidth: viewport.barWidth,\n visible: to < from ? { from: 0, to: -1 } : { from, to },\n };\n}\n","import type { ChartOptions, Theme, TimeFrame, DataSeries, DataAdapter, DataFeed, StreamConfig } from '@tradecanvas/commons';\nimport { isDataFeed } from '@tradecanvas/core';\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 for (let i = 0; i < count; i++) this.cells.push(this.createCell(i));\n }\n\n private createCell(i: number): GridCell {\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 // Charts can differ in symbol and timeframe, so the crosshair is linked by\n // time: the others show a vertical line on the bar containing that time.\n if (this.options.syncCrosshair !== false) {\n chart.on('crosshairMove', (e) => {\n const time = e.payload.bar?.time;\n if (time === undefined) return;\n for (const other of this.cells) {\n if (other.chart !== chart) other.chart.setCrosshairTime(time);\n }\n });\n chart.on('crosshairLeave', () => {\n for (const other of this.cells) {\n if (other.chart !== chart) other.chart.setCrosshairTime(null);\n }\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 return cell;\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 // New cells get the same options and linking as the first ones.\n for (let i = oldCount; i < newCount; i++) this.cells.push(this.createCell(i));\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 /**\n * Connect each chart to a symbol. A feed (`DataFeed`) serves them all. An\n * adapter keeps one stream, so pass a function that makes one per chart\n * (`() => new BinanceAdapter()`); a single adapter object serves one chart only.\n */\n async connectAll(\n source: DataFeed | DataAdapter | ((symbol: string, index: number) => DataAdapter),\n symbols: string[],\n timeframe: TimeFrame,\n historyLimit = 500,\n ): 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 ...(typeof source === 'function'\n ? { adapter: source(symbols[i], i) }\n : isDataFeed(source) ? { feed: source } : { adapter: source }),\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 layoutGroupedTreemap,\n renderHeatmap,\n GROUP_HEADER,\n} from '@tradecanvas/core';\nimport type { GroupRect, 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 cachedGroups: GroupRect[] = [];\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.applyLabel();\n this.recomputeLayout();\n this.requestRender();\n }\n\n /** What screen readers hear: `ariaLabel`, else the cells and groups it has. */\n private applyLabel(): void {\n const groups = new Set(this.currentData.map((c) => c.group).filter(Boolean)).size;\n const described = this.options.grouped && groups > 0\n ? `Market map of ${this.currentData.length} cells in ${groups} groups`\n : `Heatmap of ${this.currentData.length} cells`;\n this.setLabel(this.options.ariaLabel ?? described);\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 this.cachedGroups = [];\n if (this.options.grouped) {\n const weighted = this.currentData.map(c => ({\n id: c.id,\n weight: c.weight ?? (Math.abs(c.value) || 1),\n group: c.group,\n value: c.value,\n }));\n const { groups, cells } = layoutGroupedTreemap(weighted, bounds, padding, GROUP_HEADER);\n this.cachedRects = cells;\n this.cachedGroups = groups;\n } else 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, this.cachedGroups);\n }\n\n update(data: HeatmapCell[]): void {\n this.currentData = data;\n this.options = { ...this.options, data };\n this.applyLabel();\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.applyLabel();\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","import type { BaseFinanceChartOptions, Theme } from '@tradecanvas/commons';\nimport { BaseFinanceChart, FinanceCrosshair, canvasMeasure, type Measure } from '@tradecanvas/core';\n\ntype HoverOptions = BaseFinanceChartOptions & { crosshair?: boolean };\n\n/**\n * A finance chart that follows the pointer and answers clicks: it keeps the\n * layout it last drew, so a click finds what is under it without redrawing.\n */\nexport abstract class InteractiveChart<O extends HoverOptions, L> extends BaseFinanceChart {\n protected options: O;\n protected layout: L | null = null;\n /** What the cached layout was worked out for: a pointer move redraws without laying out again. */\n private layoutFor: { options: O; width: number; height: number; theme: Theme } | null = null;\n private readonly crosshair: FinanceCrosshair;\n private readonly onClick = (e: MouseEvent) => {\n const rect = this.canvas.getBoundingClientRect();\n if (this.layout) this.clickAt(this.layout, e.clientX - rect.left, e.clientY - rect.top);\n };\n private readonly onMove = (e: PointerEvent) => {\n if (!this.layout || !this.clickable()) return;\n const rect = this.canvas.getBoundingClientRect();\n this.canvas.style.cursor = this.hits(this.layout, e.clientX - rect.left, e.clientY - rect.top) ? 'pointer' : '';\n };\n\n constructor(container: HTMLElement, options: O) {\n super(container, options.theme);\n this.options = options;\n this.crosshair = new FinanceCrosshair(this.canvas, () => this.requestRender());\n this.canvas.addEventListener('click', this.onClick);\n this.canvas.addEventListener('pointermove', this.onMove);\n // describe() reads only `options`, set above: subclasses keep no state of their own.\n this.applyLabel();\n this.requestRender();\n }\n\n /** Where everything goes, for the chart's size and theme. */\n protected abstract compute(width: number, height: number, theme: Theme, measure: Measure): L;\n /** Draws the chart from its layout. */\n protected abstract draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: L): void;\n /** A sentence for screen readers when the options give none. */\n protected abstract describe(): string;\n /** Whether a click callback is set. */\n protected abstract clickable(): boolean;\n /** Whether something clickable is at (x, y). */\n protected abstract hits(layout: L, x: number, y: number): boolean;\n /** Calls the click callback for what is at (x, y). */\n protected abstract clickAt(layout: L, x: number, y: number): void;\n\n protected renderChart(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme): void {\n const pointer = this.options.crosshair === false ? null : this.crosshair.getPosition();\n const was = this.layoutFor;\n if (!this.layout || !was || was.options !== this.options || was.width !== width || was.height !== height || was.theme !== theme) {\n this.layout = this.compute(width, height, theme, canvasMeasure(ctx, theme));\n this.layoutFor = { options: this.options, width, height, theme };\n }\n this.draw(ctx, width, height, theme, pointer, this.layout);\n }\n\n setOptions(options: Partial<O>): void {\n this.options = { ...this.options, ...options };\n if ('theme' in options) this.setTheme(options.theme ?? 'dark');\n this.applyLabel();\n this.requestRender();\n }\n\n private applyLabel(): void {\n this.setLabel(this.options.ariaLabel ?? this.describe());\n }\n\n destroy(): void {\n this.crosshair.destroy();\n this.canvas.removeEventListener('click', this.onClick);\n this.canvas.removeEventListener('pointermove', this.onMove);\n super.destroy();\n }\n}\n","import type { BarChartOptions, ChartSeries, Theme } from '@tradecanvas/commons';\nimport { computeBarLayout, hitBar, renderBarChart, type BarLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/**\n * Bars by category: series side by side or stacked, up and down from zero,\n * upright or sideways. Net flows, volumes by session, returns by period.\n */\nexport class BarChart extends InteractiveChart<BarChartOptions, BarLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): BarLayout {\n return computeBarLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: BarLayout): void {\n renderBarChart(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const names = this.options.series.map((s) => s.name).join(', ');\n return `Bar chart of ${names}, ${this.options.categories.length} categories`;\n }\n\n protected clickable(): boolean {\n return this.options.onBarClick !== undefined;\n }\n\n protected hits(layout: BarLayout, x: number, y: number): boolean {\n return hitBar(layout, x, y) !== null;\n }\n\n protected clickAt(layout: BarLayout, x: number, y: number): void {\n const bar = hitBar(layout, x, y);\n if (bar) this.options.onBarClick?.({ category: bar.category, series: bar.series, value: bar.value, index: bar.index });\n }\n\n /** New values: the categories and their series. */\n update(categories: string[], series: ChartSeries[]): void {\n this.setOptions({ categories, series });\n }\n}\n","import type { DonutChartOptions, DonutSlice, Theme } from '@tradecanvas/commons';\nimport { computeDonutLayout, hitSlice, renderDonut, type DonutLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Parts of a whole as a ring (or a pie): allocation, exposure, order flow by side. */\nexport class DonutChart extends InteractiveChart<DonutChartOptions, DonutLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): DonutLayout {\n return computeDonutLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: DonutLayout): void {\n renderDonut(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const parts = this.options.data.filter((s) => Number.isFinite(s.value) && s.value > 0).map((s) => s.label).join(', ');\n return `${(this.options.innerRadius ?? 0.6) > 0 ? 'Donut' : 'Pie'} chart of ${parts}`;\n }\n\n protected clickable(): boolean {\n return this.options.onSliceClick !== undefined;\n }\n\n protected hits(layout: DonutLayout, x: number, y: number): boolean {\n return hitSlice(layout, x, y) !== null;\n }\n\n protected clickAt(layout: DonutLayout, x: number, y: number): void {\n const arc = hitSlice(layout, x, y);\n if (arc) this.options.onSliceClick?.(arc.slice);\n }\n\n update(data: DonutSlice[]): void {\n this.setOptions({ data });\n }\n}\n","import type { ScatterChartOptions, ScatterSeries, Theme } from '@tradecanvas/commons';\nimport { computeScatterLayout, nearestPoint, renderScatter, type ScatterLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Points on two value axes, bubbles when they have a size: risk against return, value against growth. */\nexport class ScatterChart extends InteractiveChart<ScatterChartOptions, ScatterLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): ScatterLayout {\n return computeScatterLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: ScatterLayout): void {\n renderScatter(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const points = this.options.series.reduce((n, s) => n + s.points.length, 0);\n const axes = this.options.xLabel && this.options.yLabel ? ` of ${this.options.yLabel} against ${this.options.xLabel}` : '';\n return `Scatter chart${axes}, ${points} points`;\n }\n\n protected clickable(): boolean {\n return this.options.onPointClick !== undefined;\n }\n\n protected hits(layout: ScatterLayout, x: number, y: number): boolean {\n return nearestPoint(layout, x, y) !== null;\n }\n\n protected clickAt(layout: ScatterLayout, x: number, y: number): void {\n const p = nearestPoint(layout, x, y);\n if (p) this.options.onPointClick?.(p.point, p.series);\n }\n\n update(series: ScatterSeries[]): void {\n this.setOptions({ series });\n }\n}\n","import type { HistogramOptions, Theme } from '@tradecanvas/commons';\nimport { computeHistogramLayout, renderHistogram, type HistogramLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** How values spread: daily returns, trade results, with lines at the mean or a VaR. */\nexport class HistogramChart extends InteractiveChart<HistogramOptions, HistogramLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): HistogramLayout {\n return computeHistogramLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: HistogramLayout): void {\n renderHistogram(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n return `Histogram of ${this.options.values.length} values`;\n }\n\n protected clickable(): boolean {\n return false;\n }\n\n protected hits(): boolean {\n return false;\n }\n\n protected clickAt(): void {}\n\n update(values: number[]): void {\n this.setOptions({ values });\n }\n}\n","import type { CalendarChartOptions, CalendarDay, Theme } from '@tradecanvas/commons';\nimport { computeCalendarLayout, hitDay, renderCalendar, type CalendarLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** A value a day on a calendar: daily returns, P&L, volume, a trading journal. */\nexport class CalendarChart extends InteractiveChart<CalendarChartOptions, CalendarLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): CalendarLayout {\n return computeCalendarLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: CalendarLayout): void {\n renderCalendar(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const dates = this.options.data.map((d) => d.date).filter((d) => /^\\d{4}-\\d{2}-\\d{2}$/.test(d)).sort();\n const from = this.options.from ?? dates[0];\n const to = this.options.to ?? dates[dates.length - 1];\n return from && to ? `Calendar of daily values from ${from} to ${to}` : 'Calendar of daily values';\n }\n\n protected clickable(): boolean {\n return this.options.onDayClick !== undefined;\n }\n\n protected hits(layout: CalendarLayout, x: number, y: number): boolean {\n return hitDay(layout, x, y)?.day !== undefined;\n }\n\n protected clickAt(layout: CalendarLayout, x: number, y: number): void {\n const day = hitDay(layout, x, y)?.day;\n if (day) this.options.onDayClick?.(day);\n }\n\n update(data: CalendarDay[]): void {\n this.setOptions({ data });\n }\n}\n","import type { MatrixChartOptions, Theme } from '@tradecanvas/commons';\nimport { computeMatrixLayout, hitMatrixCell, renderMatrix, type MatrixLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/** Past this many names, the description gives counts instead. */\nconst MAX_NAMED = 12;\n\n/** A value for each row and column pair, coloured: correlations, volume by hour and weekday. */\nexport class MatrixChart extends InteractiveChart<MatrixChartOptions, MatrixLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): MatrixLayout {\n return computeMatrixLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: MatrixLayout): void {\n renderMatrix(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n const { rows, columns } = this.options;\n if (!columns) return rows.length <= MAX_NAMED ? `Matrix of ${rows.join(', ')}` : `Matrix of ${rows.length} rows`;\n return rows.length + columns.length <= MAX_NAMED\n ? `Matrix of ${rows.join(', ')} by ${columns.join(', ')}`\n : `Matrix of ${rows.length} rows by ${columns.length} columns`;\n }\n\n protected clickable(): boolean {\n return this.options.onCellClick !== undefined;\n }\n\n protected hits(layout: MatrixLayout, x: number, y: number): boolean {\n return hitMatrixCell(layout, x, y) !== null;\n }\n\n protected clickAt(layout: MatrixLayout, x: number, y: number): void {\n const hit = hitMatrixCell(layout, x, y);\n if (hit) this.options.onCellClick?.(hit.cell);\n }\n\n /** New values for the same rows and columns; `setOptions` changes the names. */\n update(values: number[][]): void {\n this.setOptions({ values });\n }\n}\n","import type { CounterClockOptions, OHLCBar, Theme } from '@tradecanvas/commons';\nimport { computeCounterClockLayout, counterClockPhase, counterClockPoints, nearestCounterClockPoint, renderCounterClock, shownCount, type CounterClockLayout, type Measure } from '@tradecanvas/core';\nimport { InteractiveChart } from './InteractiveChart.js';\n\n/**\n * Counter-clock chart: average price against average volume, bar by bar, with\n * no time axis. A healthy cycle turns counter-clockwise: volume picks up,\n * price follows, volume fades, price follows it down.\n */\nexport class CounterClockChart extends InteractiveChart<CounterClockOptions, CounterClockLayout> {\n protected compute(width: number, height: number, theme: Theme, measure: Measure): CounterClockLayout {\n return computeCounterClockLayout(this.options, width, height, theme, measure);\n }\n\n protected draw(ctx: CanvasRenderingContext2D, width: number, height: number, theme: Theme, pointer: { x: number; y: number } | null, layout: CounterClockLayout): void {\n renderCounterClock(ctx, width, height, this.options, theme, pointer, layout);\n }\n\n protected describe(): string {\n return `Counter-clock chart of price against volume, ${this.options.period ?? 25}-bar averages`;\n }\n\n protected clickable(): boolean {\n return this.options.onPointClick !== undefined;\n }\n\n protected hits(layout: CounterClockLayout, x: number, y: number): boolean {\n return nearestCounterClockPoint(layout, x, y) !== null;\n }\n\n protected clickAt(layout: CounterClockLayout, x: number, y: number): void {\n const hit = nearestCounterClockPoint(layout, x, y);\n if (hit) this.options.onPointClick?.(hit.point);\n }\n\n /** The phase of the newest move, 1–8 counter-clockwise from volume rising (see `counterClockPhase`), or null. */\n getPhase(): number | null {\n return counterClockPhase(counterClockPoints(this.options.data, this.options.period ?? 25, shownCount(this.options)));\n }\n\n update(data: OHLCBar[]): void {\n this.setOptions({ data });\n }\n}\n","import type { EquityPoint, HeatmapCell } from '@tradecanvas/commons';\nimport { timeframeBucketStart } from '@tradecanvas/commons';\n\n/** Minimal equity sample shape — structurally satisfied by analytics' EquityPoint. */\nexport interface EquitySample {\n time: number;\n equity: number;\n}\n\n/**\n * Subset of analytics RiskMetrics needed to render the stats strip. The\n * percentages are fractions, as @tradecanvas/analytics returns them: a\n * totalReturnPct of 0.12 shows as +12.00%.\n */\nexport interface RiskMetricsLike {\n /** Total return as a fraction: 0.12 is +12%. */\n totalReturnPct: number;\n /** Compound annual growth rate as a fraction. */\n cagr: number;\n sharpe: number;\n sortino: number;\n /**\n * The deepest fall from a running peak, as a fraction: 0.5 is 50%. Either\n * sign reads as a fall, since some callers sign their drawdowns.\n */\n maxDrawdownPct: number;\n /** Share of winning trades as a fraction. */\n winRate: number;\n profitFactor: number;\n trades: number;\n}\n\nexport interface DashboardStat {\n label: string;\n value: string;\n tone: 'positive' | 'negative' | 'neutral';\n}\n\nconst MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\n/** Map an analytics equity curve to the finance EquityCurveChart point shape. */\nexport function toEquityPoints(curve: ReadonlyArray<EquitySample>): EquityPoint[] {\n return curve.map((p) => ({ time: p.time, value: p.equity }));\n}\n\n/**\n * Underwater drawdown curve as a percentage (<= 0). Each point is the equity's\n * shortfall from the running peak: `equity / peak - 1`, expressed in percent.\n */\nexport function computeDrawdownCurve(curve: ReadonlyArray<EquitySample>): EquityPoint[] {\n let peak = -Infinity;\n return curve.map((p) => {\n if (p.equity > peak) peak = p.equity;\n const dd = peak > 0 ? (p.equity / peak - 1) * 100 : 0;\n return { time: p.time, value: dd };\n });\n}\n\n/**\n * Calendar-month returns as heatmap cells. Each month's return is chained off\n * the prior month's closing equity (the first month chains off its own opening\n * equity), so the series reads as sequential monthly performance. `group` is\n * the year and `value` is the return in percent.\n */\nexport function computeMonthlyReturns(curve: ReadonlyArray<EquitySample>): HeatmapCell[] {\n if (curve.length === 0) return [];\n\n // Collapse the curve to one closing equity per calendar month, in order.\n const months: { key: number; close: number }[] = [];\n for (const p of curve) {\n const key = timeframeBucketStart(p.time, '1M');\n const last = months[months.length - 1];\n if (last && last.key === key) {\n last.close = p.equity;\n } else {\n months.push({ key, close: p.equity });\n }\n }\n\n let prevClose = curve[0].equity;\n const cells: HeatmapCell[] = [];\n for (const m of months) {\n const base = prevClose === 0 ? 1 : prevClose;\n const returnPct = (m.close / base - 1) * 100;\n prevClose = m.close;\n const d = new Date(m.key);\n const year = d.getUTCFullYear();\n const month = d.getUTCMonth();\n cells.push({\n id: `${year}-${String(month + 1).padStart(2, '0')}`,\n label: MONTH_LABELS[month],\n group: String(year),\n value: returnPct,\n });\n }\n return cells;\n}\n\n/** Metrics arrive as fractions (0.12); the cards show percent (12.00%). */\nconst PERCENT = 100;\n\nfunction pct(value: number): string {\n const sign = value > 0 ? '+' : '';\n return `${sign}${value.toFixed(2)}%`;\n}\n\nfunction tone(value: number): DashboardStat['tone'] {\n if (value > 0) return 'positive';\n if (value < 0) return 'negative';\n return 'neutral';\n}\n\n/**\n * The headline stats rendered as cards above the charts. The drawdown is a\n * fall, so it reads with a minus sign whichever sign it arrives with, as the\n * Drawdown panel below plots it.\n */\nexport function selectKeyStats(metrics: RiskMetricsLike): DashboardStat[] {\n return [\n { label: 'Total Return', value: pct(metrics.totalReturnPct * PERCENT), tone: tone(metrics.totalReturnPct) },\n { label: 'CAGR', value: pct(metrics.cagr * PERCENT), tone: tone(metrics.cagr) },\n { label: 'Sharpe', value: metrics.sharpe.toFixed(2), tone: tone(metrics.sharpe) },\n { label: 'Sortino', value: metrics.sortino.toFixed(2), tone: tone(metrics.sortino) },\n { label: 'Max Drawdown', value: pct(-Math.abs(metrics.maxDrawdownPct) * PERCENT), tone: 'negative' },\n { label: 'Win Rate', value: `${(metrics.winRate * PERCENT).toFixed(1)}%`, tone: 'neutral' },\n { label: 'Profit Factor', value: Number.isFinite(metrics.profitFactor) ? metrics.profitFactor.toFixed(2) : '∞', tone: tone(metrics.profitFactor - 1) },\n { label: 'Trades', value: String(metrics.trades), tone: 'neutral' },\n ];\n}\n","import type { Theme, ThemeName } from '@tradecanvas/commons';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\nimport { EquityCurveChart } from './EquityCurveChart.js';\nimport { HeatmapChart } from './HeatmapChart.js';\nimport {\n toEquityPoints,\n computeDrawdownCurve,\n computeMonthlyReturns,\n selectKeyStats,\n type EquitySample,\n type RiskMetricsLike,\n type DashboardStat,\n} from './performanceData.js';\n\n/** Structurally satisfied by analytics' `BacktestResult`. */\nexport interface PerformanceResult {\n equityCurve: ReadonlyArray<EquitySample>;\n metrics: RiskMetricsLike;\n}\n\nexport interface PerformanceDashboardOptions {\n result: PerformanceResult;\n theme?: ThemeName | Theme;\n title?: string;\n subtitle?: string;\n}\n\nfunction resolveTheme(theme?: ThemeName | Theme): Theme {\n if (!theme || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\n/**\n * A composed strategy-performance dashboard: a headline stats strip, an equity\n * curve, an underwater drawdown panel, and a monthly-returns heatmap. Built\n * entirely from a backtest `result`, reusing the finance chart renderers.\n *\n * ```ts\n * const result = new Backtester(opts).run(bars, strategy);\n * const dash = new PerformanceDashboard(el, { result, theme: 'dark' });\n * ```\n */\nexport class PerformanceDashboard {\n private options: PerformanceDashboardOptions;\n private theme: Theme;\n private root: HTMLDivElement;\n private equityChart: EquityCurveChart | null = null;\n private drawdownChart: EquityCurveChart | null = null;\n private heatmap: HeatmapChart | null = null;\n\n constructor(container: HTMLElement, options: PerformanceDashboardOptions) {\n this.options = options;\n this.theme = resolveTheme(options.theme);\n this.root = document.createElement('div');\n this.build();\n container.appendChild(this.root);\n }\n\n private build(): void {\n const t = this.theme;\n const { result, title, subtitle } = this.options;\n const surface = this.panelBackground();\n const border = t.grid;\n\n this.root.style.cssText = [\n 'display:flex',\n 'flex-direction:column',\n 'gap:14px',\n 'width:100%',\n 'box-sizing:border-box',\n 'padding:16px',\n `background:${t.background}`,\n `color:${t.text}`,\n `font-family:${t.font.family}`,\n ].join(';');\n\n if (title || subtitle) {\n const header = document.createElement('div');\n if (title) {\n const h = document.createElement('div');\n h.textContent = title;\n h.style.cssText = `font-size:${t.font.sizeLarge}px;font-weight:600;letter-spacing:-0.01em;`;\n header.appendChild(h);\n }\n if (subtitle) {\n const s = document.createElement('div');\n s.textContent = subtitle;\n s.style.cssText = `font-size:${t.font.sizeSmall}px;color:${t.textSecondary};margin-top:2px;`;\n header.appendChild(s);\n }\n this.root.appendChild(header);\n }\n\n // Stats strip\n this.root.appendChild(this.buildStatsStrip(selectKeyStats(result.metrics), surface, border));\n\n // Chart grid\n const grid = document.createElement('div');\n grid.style.cssText = [\n 'display:grid',\n 'grid-template-columns:repeat(auto-fit, minmax(280px, 1fr))',\n 'grid-auto-rows:220px',\n 'gap:14px',\n ].join(';');\n this.root.appendChild(grid);\n\n const equityPanel = this.buildPanel('Equity Curve', surface, border);\n equityPanel.wrap.style.gridColumn = '1 / -1';\n grid.appendChild(equityPanel.wrap);\n this.equityChart = new EquityCurveChart(equityPanel.body, {\n data: toEquityPoints(result.equityCurve),\n theme: t,\n lineColor: t.candleUp,\n fillArea: true,\n crosshair: true,\n });\n\n const ddPanel = this.buildPanel('Drawdown', surface, border);\n grid.appendChild(ddPanel.wrap);\n this.drawdownChart = new EquityCurveChart(ddPanel.body, {\n data: computeDrawdownCurve(result.equityCurve),\n theme: t,\n lineColor: t.candleDown,\n fillArea: true,\n crosshair: true,\n valueFormat: (v) => `${v.toFixed(1)}%`,\n });\n\n const monthlyCells = computeMonthlyReturns(result.equityCurve);\n const heatPanel = this.buildPanel('Monthly Returns', surface, border);\n grid.appendChild(heatPanel.wrap);\n this.heatmap = new HeatmapChart(heatPanel.body, {\n data: monthlyCells,\n theme: t,\n showValues: true,\n valueFormat: (v) => `${v >= 0 ? '+' : ''}${v.toFixed(1)}`,\n colorScale: { negative: t.candleDown, zero: surface, positive: t.candleUp },\n });\n }\n\n private buildStatsStrip(stats: DashboardStat[], surface: string, border: string): HTMLDivElement {\n const strip = document.createElement('div');\n strip.style.cssText = [\n 'display:grid',\n 'grid-template-columns:repeat(auto-fit, minmax(120px, 1fr))',\n 'gap:10px',\n ].join(';');\n\n const t = this.theme;\n for (const stat of stats) {\n const card = document.createElement('div');\n card.style.cssText = [\n `background:${surface}`,\n `border:1px solid ${border}`,\n 'border-radius:10px',\n 'padding:10px 12px',\n 'display:flex',\n 'flex-direction:column',\n 'gap:4px',\n ].join(';');\n\n const label = document.createElement('div');\n label.textContent = stat.label;\n label.style.cssText = `font-size:${t.font.sizeSmall}px;color:${t.textSecondary};text-transform:uppercase;letter-spacing:0.04em;`;\n\n const value = document.createElement('div');\n value.textContent = stat.value;\n const color = stat.tone === 'positive' ? t.candleUp : stat.tone === 'negative' ? t.candleDown : t.text;\n value.style.cssText = `font-size:${t.font.sizeLarge}px;font-weight:600;color:${color};font-variant-numeric:tabular-nums;`;\n\n card.appendChild(label);\n card.appendChild(value);\n strip.appendChild(card);\n }\n return strip;\n }\n\n private buildPanel(title: string, surface: string, border: string): { wrap: HTMLDivElement; body: HTMLDivElement } {\n const t = this.theme;\n const wrap = document.createElement('div');\n wrap.style.cssText = [\n `background:${surface}`,\n `border:1px solid ${border}`,\n 'border-radius:10px',\n 'overflow:hidden',\n 'display:flex',\n 'flex-direction:column',\n ].join(';');\n\n const head = document.createElement('div');\n head.textContent = title;\n head.style.cssText = [\n `font-size:${t.font.sizeSmall}px`,\n 'font-weight:600',\n `color:${t.textSecondary}`,\n 'padding:8px 12px',\n `border-bottom:1px solid ${border}`,\n 'text-transform:uppercase',\n 'letter-spacing:0.04em',\n ].join(';');\n\n const body = document.createElement('div');\n body.style.cssText = 'flex:1;min-height:0;position:relative;';\n\n wrap.appendChild(head);\n wrap.appendChild(body);\n return { wrap, body };\n }\n\n /** A subtle surface tint distinct from the page background, per theme. */\n private panelBackground(): string {\n return this.theme.name === 'light' ? 'rgba(0,0,0,0.02)' : 'rgba(255,255,255,0.03)';\n }\n\n /** Replace the displayed result and re-render all panels. */\n update(result: PerformanceResult): void {\n this.options = { ...this.options, result };\n this.destroyCharts();\n this.root.replaceChildren();\n this.build();\n }\n\n setTheme(theme: ThemeName | Theme): void {\n this.theme = resolveTheme(theme);\n this.options = { ...this.options, theme };\n this.destroyCharts();\n this.root.replaceChildren();\n this.build();\n }\n\n private destroyCharts(): void {\n this.equityChart?.destroy();\n this.drawdownChart?.destroy();\n this.heatmap?.destroy();\n this.equityChart = null;\n this.drawdownChart = null;\n this.heatmap = null;\n }\n\n destroy(): void {\n this.destroyCharts();\n this.root.remove();\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ChartTypeOptions, DataSeries } from '@tradecanvas/commons';
|
|
2
|
+
import { ChartTypeLookup } from '../charts/ChartTypeStrategy.js';
|
|
3
|
+
/** What the series a chart type draws is made of, read each time it is asked for. */
|
|
4
|
+
export interface DisplaySources {
|
|
5
|
+
/** The bars shown. */
|
|
6
|
+
bars(): DataSeries;
|
|
7
|
+
/** Moves on every write to them, in place or not (`SeriesStore.version`). */
|
|
8
|
+
version(): number;
|
|
9
|
+
chartType(): string;
|
|
10
|
+
/** Replaced, never changed in place, when the options change. */
|
|
11
|
+
chartTypeOptions(): ChartTypeOptions;
|
|
12
|
+
/** A chart type of a plugin's, which draws its own series. */
|
|
13
|
+
lookup: ChartTypeLookup;
|
|
14
|
+
/** The market's price step at a price: range bars are built on it. */
|
|
15
|
+
stepAt(price: number): number | undefined;
|
|
16
|
+
/** The box the built-in point & figure columns were made on, for its renderer. */
|
|
17
|
+
onBoxSize(box: number): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The series the chart type draws (Heikin-Ashi candles, Renko bricks, Kagi
|
|
21
|
+
* lines…), made from the bars when something it is made of changed and
|
|
22
|
+
* kept between frames otherwise. It sees every change itself: a write to
|
|
23
|
+
* the bars moves their version, so no writer has to remember to drop it.
|
|
24
|
+
* No DOM.
|
|
25
|
+
*/
|
|
26
|
+
export declare class DisplaySeries {
|
|
27
|
+
private readonly sources;
|
|
28
|
+
private series;
|
|
29
|
+
private madeAt;
|
|
30
|
+
/** Moves on `invalidate`, for a change the sources don't show. */
|
|
31
|
+
private epoch;
|
|
32
|
+
/** What Renko, Kagi and point & figure keep from one build to the next, to make the end again only. */
|
|
33
|
+
private readonly memo;
|
|
34
|
+
constructor(sources: DisplaySources);
|
|
35
|
+
get(): DataSeries;
|
|
36
|
+
/** Made again on the next `get`: something it is made of changed where the sources don't show it. */
|
|
37
|
+
invalidate(): void;
|
|
38
|
+
/**
|
|
39
|
+
* A new series, a new chart type or new hours shown: nothing kept from the
|
|
40
|
+
* last build is of use, the end made again included.
|
|
41
|
+
*/
|
|
42
|
+
reset(): void;
|
|
43
|
+
/**
|
|
44
|
+
* The built-in point & figure's columns come with the box they were built
|
|
45
|
+
* on, which its renderer draws them at, in the one walk (a plugin's chart
|
|
46
|
+
* type keeps its own).
|
|
47
|
+
*/
|
|
48
|
+
private make;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=DisplaySeries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DisplaySeries.d.ts","sourceRoot":"","sources":["../../src/model/DisplaySeries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEzE,OAAO,EAA4D,KAAK,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEhI,qFAAqF;AACrF,MAAM,WAAW,cAAc;IAC7B,sBAAsB;IACtB,IAAI,IAAI,UAAU,CAAC;IACnB,6EAA6E;IAC7E,OAAO,IAAI,MAAM,CAAC;IAClB,SAAS,IAAI,MAAM,CAAC;IACpB,iEAAiE;IACjE,gBAAgB,IAAI,gBAAgB,CAAC;IACrC,8DAA8D;IAC9D,MAAM,EAAE,eAAe,CAAC;IACxB,sEAAsE;IACtE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1C,kFAAkF;IAClF,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,qBAAa,aAAa;IAQZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAsH;IACpI,kEAAkE;IAClE,OAAO,CAAC,KAAK,CAAK;IAClB,uGAAuG;IACvG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;gBAEb,OAAO,EAAE,cAAc;IAEpD,GAAG,IAAI,UAAU;IAkBjB,qGAAqG;IACrG,UAAU,IAAI,IAAI;IAIlB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAKb;;;;OAIG;IACH,OAAO,CAAC,IAAI;CAOb"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DataSeries, PanelConfig, Rect, ViewportState } from '@tradecanvas/commons';
|
|
2
|
+
/** A pane with less plot than this, px, takes no drawings: there is no room to place one. */
|
|
3
|
+
export declare const MIN_DRAWING_PANE_HEIGHT = 24;
|
|
4
|
+
/**
|
|
5
|
+
* The pane a drawing begun at `pos` goes on: undefined the price pane
|
|
6
|
+
* (whose plot is `priceRect`), an indicator pane's id, null where none
|
|
7
|
+
* takes drawings (an axis, a header, a side or folded pane).
|
|
8
|
+
*/
|
|
9
|
+
export declare function drawingPaneAt(pos: {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
}, priceRect: Rect, panels: readonly Pick<PanelConfig, 'id'>[], viewportOf: (paneId: string) => ViewportState | null): string | null | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* The viewport a pane's drawings are drawn and read with: its plot under
|
|
15
|
+
* the header, its value scale, the bars' times. Null for a pane that takes
|
|
16
|
+
* none: on a side (its x is not the time), folded, or too short to draw in.
|
|
17
|
+
* `paneViewport` and `data` are read only for a pane that takes them: this
|
|
18
|
+
* runs on every pointer move with a drawing tool, and a stale series is
|
|
19
|
+
* worked out again when read.
|
|
20
|
+
*/
|
|
21
|
+
export declare function drawingPaneViewport(panel: Pick<PanelConfig, 'position'> | undefined, shownCollapsed: boolean, paneViewport: () => ViewportState | undefined, data: () => DataSeries): ViewportState | null;
|
|
22
|
+
/** Whether pane `paneId` is among `panels` and takes a drawing: no price-only tool goes on a pane. */
|
|
23
|
+
export declare function takesDrawing(panels: readonly Pick<PanelConfig, 'id'>[], paneId: string, priceOnly: boolean): boolean;
|
|
24
|
+
//# sourceMappingURL=DrawingPanes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrawingPanes.d.ts","sourceRoot":"","sources":["../../src/model/DrawingPanes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEzF,6FAA6F;AAC7F,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAK1C;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAC7B,SAAS,EAAE,IAAI,EACf,MAAM,EAAE,SAAS,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,EAC1C,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,GAAG,IAAI,GACnD,MAAM,GAAG,IAAI,GAAG,SAAS,CAO3B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,GAAG,SAAS,EAChD,cAAc,EAAE,OAAO,EACvB,YAAY,EAAE,MAAM,aAAa,GAAG,SAAS,EAC7C,IAAI,EAAE,MAAM,UAAU,GACrB,aAAa,GAAG,IAAI,CAMtB;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAEpH"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { SnapshotIndicator, UndoRedoManager } from '@tradecanvas/core';
|
|
2
|
+
/** Changes to one indicator closer together than this are one undo step (a colour dragged, a period typed). */
|
|
3
|
+
export declare const INDICATOR_EDIT_MERGE_MS = 800;
|
|
4
|
+
/** The undo history the indicator steps go in. */
|
|
5
|
+
export type IndicatorSteps = Pick<UndoRedoManager, 'push' | 'last' | 'replaceLast' | 'dropLast'>;
|
|
6
|
+
export interface IndicatorHistoryOptions {
|
|
7
|
+
steps: IndicatorSteps;
|
|
8
|
+
/** The chart's indicators as a layout keeps them. */
|
|
9
|
+
snapshot: () => SnapshotIndicator[];
|
|
10
|
+
/** Whether undo is on (`features.drawingUndoRedo`). */
|
|
11
|
+
enabled: () => boolean;
|
|
12
|
+
now?: () => number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The indicators' undo steps: each change as the indicators before and
|
|
16
|
+
* after it, a burst of quick changes to one indicator merged into one step,
|
|
17
|
+
* an edit (a settings dialog) as one step from its begin to its end. The
|
|
18
|
+
* panes another indicator took over in a step go with it, so the drawings
|
|
19
|
+
* on them can follow. No DOM.
|
|
20
|
+
*/
|
|
21
|
+
export declare class IndicatorHistory {
|
|
22
|
+
private readonly steps;
|
|
23
|
+
private readonly snapshot;
|
|
24
|
+
private readonly enabled;
|
|
25
|
+
private readonly now;
|
|
26
|
+
/** Above 0 while a change is being recorded, or runs quietly: nested changes add no steps. */
|
|
27
|
+
private depth;
|
|
28
|
+
private edit;
|
|
29
|
+
/** The panes renamed by the change being recorded, null outside one. */
|
|
30
|
+
private renames;
|
|
31
|
+
constructor(options: IndicatorHistoryOptions);
|
|
32
|
+
/**
|
|
33
|
+
* Run an indicator change as one undo step. Quick changes about the same
|
|
34
|
+
* `subject` (an indicator, a pane) merge into one step; a burst that ends
|
|
35
|
+
* where it began leaves none.
|
|
36
|
+
*/
|
|
37
|
+
record<T>(subject: string | undefined, change: () => T): T;
|
|
38
|
+
private push;
|
|
39
|
+
/** Run `change` without recording undo steps for the indicators it changes. */
|
|
40
|
+
quietly<T>(change: () => T): T;
|
|
41
|
+
/** Pane `from` was handed to the indicator `to` in the change being recorded. */
|
|
42
|
+
renamed(from: string, to: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Start an edit of one indicator: its changes until `end` are one undo
|
|
45
|
+
* step, and none when they end where they began (a cancel that put
|
|
46
|
+
* everything back). An edit still open is ended first.
|
|
47
|
+
*/
|
|
48
|
+
begin(subject: string): void;
|
|
49
|
+
/** End the edit `begin` started, as one undo step when anything changed. */
|
|
50
|
+
end(): void;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=IndicatorHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndicatorHistory.d.ts","sourceRoot":"","sources":["../../src/model/IndicatorHistory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE5E,+GAA+G;AAC/G,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,kDAAkD;AAClD,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,CAAC,CAAC;AAEjG,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,cAAc,CAAC;IACtB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,iBAAiB,EAAE,CAAC;IACpC,uDAAuD;IACvD,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AASD;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,8FAA8F;IAC9F,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,IAAI,CAAiE;IAC7E,wEAAwE;IACxE,OAAO,CAAC,OAAO,CAAmC;gBAEtC,OAAO,EAAE,uBAAuB;IAO5C;;;;OAIG;IACH,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC;IAkB1D,OAAO,CAAC,IAAI;IAiBZ,+EAA+E;IAC/E,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC;IAS9B,iFAAiF;IACjF,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAIvC;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAO5B,4EAA4E;IAC5E,GAAG,IAAI,IAAI;CASZ"}
|