@tradecanvas/chart 1.81.0 → 1.83.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/dist/Chart.d.ts +14 -1
- package/dist/Chart.d.ts.map +1 -1
- package/dist/LayoutSession-B4qMfaP7.cjs +2 -0
- package/dist/LayoutSession-B4qMfaP7.cjs.map +1 -0
- package/dist/{LayoutSession-C4Lp1X6t.js → LayoutSession-BoiToS9y.js} +625 -369
- package/dist/LayoutSession-BoiToS9y.js.map +1 -0
- package/dist/{WidgetCommandPalette-Bvr6Od3p.js → WidgetCommandPalette-DHGvEl9n.js} +2 -2
- package/dist/{WidgetCommandPalette-Bvr6Od3p.js.map → WidgetCommandPalette-DHGvEl9n.js.map} +1 -1
- package/dist/{WidgetCommandPalette-B1jaXJ-I.cjs → WidgetCommandPalette-Ol8Z923q.cjs} +2 -2
- package/dist/{WidgetCommandPalette-B1jaXJ-I.cjs.map → WidgetCommandPalette-Ol8Z923q.cjs.map} +1 -1
- package/dist/{WidgetDrawingSettings-CsR3GuFG.js → WidgetDrawingSettings-CSB88SvC.js} +2 -2
- package/dist/{WidgetDrawingSettings-CsR3GuFG.js.map → WidgetDrawingSettings-CSB88SvC.js.map} +1 -1
- package/dist/{WidgetDrawingSettings-B8JKpke1.cjs → WidgetDrawingSettings-XL1Z9-ly.cjs} +2 -2
- package/dist/{WidgetDrawingSettings-B8JKpke1.cjs.map → WidgetDrawingSettings-XL1Z9-ly.cjs.map} +1 -1
- package/dist/{WidgetIndicatorPicker-B72LdJy1.cjs → WidgetIndicatorPicker-K01RJSLs.cjs} +2 -2
- package/dist/{WidgetIndicatorPicker-B72LdJy1.cjs.map → WidgetIndicatorPicker-K01RJSLs.cjs.map} +1 -1
- package/dist/{WidgetIndicatorPicker-Cb2m62oH.js → WidgetIndicatorPicker-a4rpptDc.js} +2 -2
- package/dist/{WidgetIndicatorPicker-Cb2m62oH.js.map → WidgetIndicatorPicker-a4rpptDc.js.map} +1 -1
- package/dist/{WidgetIndicatorSettings-BiX1ZOhS.js → WidgetIndicatorSettings-BmIFp19I.js} +3 -3
- package/dist/{WidgetIndicatorSettings-BiX1ZOhS.js.map → WidgetIndicatorSettings-BmIFp19I.js.map} +1 -1
- package/dist/{WidgetIndicatorSettings-DhFQasHT.cjs → WidgetIndicatorSettings-CJWR-x9q.cjs} +2 -2
- package/dist/{WidgetIndicatorSettings-DhFQasHT.cjs.map → WidgetIndicatorSettings-CJWR-x9q.cjs.map} +1 -1
- package/dist/{WidgetSettings-CkvK-3d9.js → WidgetSettings-9clgY3_1.js} +17 -4
- package/dist/WidgetSettings-9clgY3_1.js.map +1 -0
- package/dist/{WidgetSettings-bO72SYQ6.cjs → WidgetSettings-D6COgRaB.cjs} +2 -2
- package/dist/WidgetSettings-D6COgRaB.cjs.map +1 -0
- package/dist/{WidgetSymbolSearch-DeBxGj4a.cjs → WidgetSymbolSearch-6EB31v-O.cjs} +2 -2
- package/dist/{WidgetSymbolSearch-DeBxGj4a.cjs.map → WidgetSymbolSearch-6EB31v-O.cjs.map} +1 -1
- package/dist/{WidgetSymbolSearch-WOskcBJN.js → WidgetSymbolSearch-DToOqJoG.js} +2 -2
- package/dist/{WidgetSymbolSearch-WOskcBJN.js.map → WidgetSymbolSearch-DToOqJoG.js.map} +1 -1
- package/dist/grid/ChartGrid.d.ts +9 -1
- package/dist/grid/ChartGrid.d.ts.map +1 -1
- package/dist/grid/gridShapes.d.ts +43 -0
- package/dist/grid/gridShapes.d.ts.map +1 -0
- package/dist/i18n-D0SPfH2s.cjs +2 -0
- package/dist/i18n-D0SPfH2s.cjs.map +1 -0
- package/dist/{i18n-Ci4pfuXw.js → i18n-nWmX3G55.js} +21 -1
- package/dist/i18n-nWmX3G55.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +155 -179
- package/dist/index.js.map +1 -1
- package/dist/{indicatorInputWords-DpkxBon4.js → indicatorInputWords-D0SGBaUD.js} +2 -2
- package/dist/{indicatorInputWords-DpkxBon4.js.map → indicatorInputWords-D0SGBaUD.js.map} +1 -1
- package/dist/{indicatorInputWords-BfWHWL0K.cjs → indicatorInputWords-HqTGFokF.cjs} +2 -2
- package/dist/{indicatorInputWords-BfWHWL0K.cjs.map → indicatorInputWords-HqTGFokF.cjs.map} +1 -1
- package/dist/widget/ChartWidget.d.ts +11 -1
- package/dist/widget/ChartWidget.d.ts.map +1 -1
- package/dist/widget/ChartWidgetGrid.d.ts +7 -10
- package/dist/widget/ChartWidgetGrid.d.ts.map +1 -1
- package/dist/widget/GridLayoutPicker.d.ts +55 -0
- package/dist/widget/GridLayoutPicker.d.ts.map +1 -0
- package/dist/widget/WatchlistStore.d.ts +11 -0
- package/dist/widget/WatchlistStore.d.ts.map +1 -1
- package/dist/widget/WidgetChartSettings.d.ts +2 -0
- package/dist/widget/WidgetChartSettings.d.ts.map +1 -1
- package/dist/widget/WidgetDockArea.d.ts +1 -0
- package/dist/widget/WidgetDockArea.d.ts.map +1 -1
- package/dist/widget/WidgetDrawingSidebar.d.ts +27 -0
- package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
- package/dist/widget/WidgetSettings.d.ts.map +1 -1
- package/dist/widget/WidgetToolbar.d.ts.map +1 -1
- package/dist/widget/WidgetWatchlist.d.ts +3 -0
- package/dist/widget/WidgetWatchlist.d.ts.map +1 -1
- package/dist/widget/WidgetWatchlists.d.ts +1 -0
- package/dist/widget/WidgetWatchlists.d.ts.map +1 -1
- package/dist/widget/chartSettingsStore.d.ts.map +1 -1
- package/dist/widget/index.cjs +58 -4
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.d.ts +1 -0
- package/dist/widget/index.d.ts.map +1 -1
- package/dist/widget/index.js +1781 -1528
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/locales/ar.d.ts.map +1 -1
- package/dist/widget/locales/cs.d.ts.map +1 -1
- package/dist/widget/locales/da.d.ts.map +1 -1
- package/dist/widget/locales/de.d.ts.map +1 -1
- package/dist/widget/locales/el.d.ts.map +1 -1
- package/dist/widget/locales/en.d.ts +10 -0
- package/dist/widget/locales/en.d.ts.map +1 -1
- package/dist/widget/locales/es.d.ts.map +1 -1
- package/dist/widget/locales/et.d.ts.map +1 -1
- package/dist/widget/locales/fa.d.ts.map +1 -1
- package/dist/widget/locales/fr.d.ts.map +1 -1
- package/dist/widget/locales/he.d.ts.map +1 -1
- package/dist/widget/locales/hu.d.ts.map +1 -1
- package/dist/widget/locales/id.d.ts.map +1 -1
- package/dist/widget/locales/index.cjs +1 -1
- package/dist/widget/locales/index.cjs.map +1 -1
- package/dist/widget/locales/index.js +281 -1
- package/dist/widget/locales/index.js.map +1 -1
- package/dist/widget/locales/it.d.ts.map +1 -1
- package/dist/widget/locales/ja.d.ts.map +1 -1
- package/dist/widget/locales/ko.d.ts.map +1 -1
- package/dist/widget/locales/ms.d.ts.map +1 -1
- package/dist/widget/locales/nb.d.ts.map +1 -1
- package/dist/widget/locales/nl.d.ts.map +1 -1
- package/dist/widget/locales/pl.d.ts.map +1 -1
- package/dist/widget/locales/pt.d.ts.map +1 -1
- package/dist/widget/locales/ro.d.ts.map +1 -1
- package/dist/widget/locales/ru.d.ts.map +1 -1
- package/dist/widget/locales/sk.d.ts.map +1 -1
- package/dist/widget/locales/sv.d.ts.map +1 -1
- package/dist/widget/locales/th.d.ts.map +1 -1
- package/dist/widget/locales/tr.d.ts.map +1 -1
- package/dist/widget/locales/vi.d.ts.map +1 -1
- package/dist/widget/locales/zh.d.ts.map +1 -1
- package/dist/widget/locales/zhHant.d.ts.map +1 -1
- package/dist/widget/types.d.ts +11 -1
- package/dist/widget/types.d.ts.map +1 -1
- package/dist/widget/widgetConfig.d.ts.map +1 -1
- package/dist/{widgetLocales-D-QYU_9U.js → widgetLocales-BX7VRdl5.js} +2 -1
- package/dist/widgetLocales-BX7VRdl5.js.map +1 -0
- package/dist/widgetLocales-C_XTkni5.cjs +2 -0
- package/dist/widgetLocales-C_XTkni5.cjs.map +1 -0
- package/package.json +3 -3
- package/dist/LayoutSession-C4Lp1X6t.js.map +0 -1
- package/dist/LayoutSession-CeayqT91.cjs +0 -2
- package/dist/LayoutSession-CeayqT91.cjs.map +0 -1
- package/dist/WidgetSettings-CkvK-3d9.js.map +0 -1
- package/dist/WidgetSettings-bO72SYQ6.cjs.map +0 -1
- package/dist/i18n-Ci4pfuXw.js.map +0 -1
- package/dist/i18n-hMXCt55K.cjs +0 -2
- package/dist/i18n-hMXCt55K.cjs.map +0 -1
- package/dist/widgetLocales-D-QYU_9U.js.map +0 -1
- package/dist/widgetLocales-fhdzLs5l.cjs +0 -2
- package/dist/widgetLocales-fhdzLs5l.cjs.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/brand/poweredBy.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","/**\n * A \"Powered by TradeCanvas\" badge for an app built on TradeCanvas: the words, the\n * TC mark and the outlined wordmark in one link. The mark's ring and bar and the\n * wordmark take the text colour around them (`currentColor`), so the badge follows a\n * light or dark theme; only the candle keeps the brand's amber. The words are live\n * text in the host's own face.\n */\n\n/** Where the badge links to. */\nexport const TRADECANVAS_URL = 'https://tradecanvas.dev';\n\n/** The badge's accessible name. */\nexport const POWERED_BY_LABEL = 'Powered by TradeCanvas';\n\n/** The TC mark, its small-size cut: the ring and bar in `currentColor`, the candle amber. */\nexport const TRADECANVAS_MARK_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M186 70A82 82 0 1 0 186 186\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"22\" stroke-linecap=\"round\"/><rect x=\"92\" y=\"74\" width=\"72\" height=\"20\" rx=\"10\" fill=\"currentColor\"/><path fill=\"#E8961E\" d=\"M119 94H137V108H144a10 10 0 0 1 10 10V164a10 10 0 0 1-10 10H137V190H119V174H112a10 10 0 0 1-10-10V118a10 10 0 0 1 10-10H119Z\"/></svg>`;\n\n/** The outlined wordmark in `currentColor`, its box cropped to the capitals. */\nexport const TRADECANVAS_WORDMARK_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 16 686 88\" aria-hidden=\"true\" focusable=\"false\"><path fill=\"currentColor\" transform=\"translate(0 101.64)\" d=\"M27.24 0.00L27.24 -69.72L1.32 -69.72L1.32 -83.64L68.76 -83.64L68.76 -69.72L42.96 -69.72L42.96 0.00ZM70.90 0.00L70.90 -59.16L85.90 -59.16L85.90 -50.64Q86.26 -51.36 86.74 -51.96Q89.50 -55.92 93.52 -58.14Q97.54 -60.36 101.74 -60.36Q104.74 -60.36 107.44 -59.58Q110.14 -58.80 113.02 -57.00L105.82 -43.56Q104.50 -44.28 102.46 -44.88Q100.42 -45.48 98.38 -45.48Q95.98 -45.48 93.76 -44.64Q91.54 -43.80 89.80 -42.00Q88.06 -40.20 86.98 -37.20Q86.50 -35.52 86.20 -32.94Q85.90 -30.36 85.90 -25.44L85.90 0.00ZM156.44 0.00L155.36 -7.56Q155.00 -6.96 154.52 -6.36Q151.28 -2.40 147.20 -0.60Q143.12 1.20 138.56 1.20Q132.08 1.20 126.98 -1.20Q121.88 -3.60 118.94 -8.04Q116.00 -12.48 116.00 -18.24Q116.00 -23.40 118.10 -27.06Q120.20 -30.72 123.68 -32.64Q126.68 -34.44 130.34 -35.16Q134.00 -35.88 138.20 -35.88L155.24 -35.88L155.24 -37.32Q155.24 -42.60 151.94 -45.18Q148.64 -47.76 143.00 -47.76Q138.32 -47.76 133.46 -45.90Q128.60 -44.04 124.88 -40.68L117.32 -50.88Q123.56 -55.92 130.10 -58.14Q136.64 -60.36 144.20 -60.36Q156.44 -60.36 163.28 -54.24Q170.12 -48.12 170.12 -37.32L170.12 0.00ZM155.24 -24.84L140.36 -24.84Q138.44 -24.84 136.58 -24.54Q134.72 -24.24 133.40 -23.16Q132.20 -22.32 131.60 -21.06Q131.00 -19.80 131.00 -18.24Q131.00 -14.88 133.64 -12.84Q136.28 -10.80 140.72 -10.80Q144.68 -10.80 147.98 -12.54Q151.28 -14.28 153.26 -17.34Q155.24 -20.40 155.24 -24.36ZM202.98 1.20Q195.18 1.20 189.54 -2.82Q183.90 -6.84 180.84 -13.86Q177.78 -20.88 177.78 -29.64Q177.78 -39.36 181.20 -46.20Q184.62 -53.04 190.38 -56.70Q196.14 -60.36 202.98 -60.36Q207.78 -60.36 211.92 -58.38Q216.06 -56.40 219.06 -52.44Q219.54 -51.72 220.02 -51.00L220.02 -83.64L234.78 -83.64L234.78 0.00L220.02 0.00L220.02 -8.04Q219.54 -7.20 218.94 -6.48Q215.70 -2.28 211.56 -0.54Q207.42 1.20 202.98 1.20ZM207.06 -12.48Q211.50 -12.48 214.68 -14.64Q217.86 -16.80 219.60 -20.64Q221.34 -24.48 221.34 -29.64Q221.34 -34.80 219.60 -38.64Q217.86 -42.48 214.68 -44.58Q211.50 -46.68 207.06 -46.68Q202.74 -46.68 199.50 -44.58Q196.26 -42.48 194.52 -38.70Q192.78 -34.92 192.78 -29.64Q192.78 -24.36 194.52 -20.52Q196.26 -16.68 199.50 -14.58Q202.74 -12.48 207.06 -12.48ZM272.32 1.20Q264.64 1.20 259.12 -1.32Q253.60 -3.84 250.06 -8.10Q246.52 -12.36 244.84 -17.82Q243.16 -23.28 243.16 -29.28Q243.16 -35.04 244.84 -40.56Q246.52 -46.08 249.88 -50.52Q253.24 -54.96 258.58 -57.66Q263.92 -60.36 271.36 -60.36Q278.32 -60.36 283.48 -58.02Q288.64 -55.68 292.00 -51.54Q295.36 -47.40 297.10 -41.88Q298.84 -36.36 298.84 -30.12Q298.84 -29.28 298.78 -27.78Q298.72 -26.28 298.48 -24.60L258.04 -24.60Q258.64 -18.24 262.78 -15.00Q266.92 -11.76 273.16 -11.76Q277.72 -11.76 282.04 -13.38Q286.36 -15.00 289.72 -18.00L297.16 -7.92Q292.96 -4.68 289.24 -2.64Q285.52 -0.60 281.50 0.30Q277.48 1.20 272.32 1.20ZM284.68 -35.64Q284.68 -35.76 284.68 -35.76Q284.68 -38.28 283.72 -40.50Q282.76 -42.72 281.08 -44.40Q279.40 -46.08 277.06 -46.98Q274.72 -47.88 271.72 -47.88Q267.28 -47.88 264.28 -46.08Q261.28 -44.28 259.78 -41.46Q258.28 -38.64 257.92 -35.64ZM346.66 1.56Q335.02 1.56 326.20 -3.84Q317.38 -9.24 312.46 -19.08Q307.54 -28.92 307.54 -41.88Q307.54 -54.84 312.46 -64.62Q317.38 -74.40 326.20 -79.80Q335.02 -85.20 346.66 -85.20Q359.50 -85.20 368.92 -78.84Q378.34 -72.48 382.42 -61.20L371.02 -57.00Q368.02 -64.80 361.78 -69.18Q355.54 -73.56 346.66 -73.56Q338.50 -73.56 332.44 -69.66Q326.38 -65.76 323.08 -58.74Q319.78 -51.72 319.78 -41.88Q319.78 -32.04 323.08 -24.96Q326.38 -17.88 332.44 -13.98Q338.50 -10.08 346.66 -10.08Q355.54 -10.08 361.78 -14.46Q368.02 -18.84 371.02 -26.64L382.42 -22.56Q378.34 -11.40 368.92 -4.92Q359.50 1.56 346.66 1.56ZM429.04 0.00L428.32 -8.64Q428.20 -8.52 428.08 -8.40Q424.96 -3.72 420.34 -1.32Q415.72 1.08 409.96 1.08Q403.36 1.08 398.32 -1.32Q393.28 -3.72 390.52 -7.98Q387.76 -12.24 387.76 -17.88Q387.76 -22.80 389.80 -26.34Q391.84 -29.88 395.08 -31.80Q398.08 -33.72 401.98 -34.50Q405.88 -35.28 410.32 -35.28L428.08 -35.28L428.08 -37.20Q428.08 -43.44 424.48 -46.80Q420.88 -50.16 414.04 -50.16Q409.24 -50.16 404.86 -48.24Q400.48 -46.32 396.52 -42.00L389.20 -49.56Q394.48 -55.08 400.90 -57.66Q407.32 -60.24 414.88 -60.24Q426.76 -60.24 433.30 -54.18Q439.84 -48.12 439.84 -37.20L439.84 0.00ZM428.08 -26.40L412.00 -26.40Q409.60 -26.40 407.02 -25.98Q404.44 -25.56 402.64 -24.24Q401.20 -23.16 400.36 -21.54Q399.52 -19.92 399.52 -17.76Q399.52 -13.56 402.76 -11.04Q406.00 -8.52 411.40 -8.52Q415.96 -8.52 419.74 -10.62Q423.52 -12.72 425.80 -16.38Q428.08 -20.04 428.08 -24.72ZM451.94 0.00L451.94 -59.16L463.82 -59.16L463.82 -50.88Q464.78 -52.44 465.98 -53.76Q468.86 -56.88 472.88 -58.56Q476.90 -60.24 481.58 -60.24Q491.42 -60.24 497.00 -54.54Q502.58 -48.84 502.58 -37.92L502.58 0.00L490.82 0.00L490.82 -33.60Q490.82 -42.12 487.76 -46.08Q484.70 -50.04 478.34 -50.04Q473.54 -50.04 470.36 -47.88Q467.18 -45.72 465.50 -41.04Q463.82 -36.36 463.82 -29.16L463.82 0.00ZM533.28 0.00L509.04 -59.16L522.00 -59.16L538.08 -15.24L554.40 -59.16L567.12 -59.16L543.12 0.00ZM610.56 0.00L609.84 -8.64Q609.72 -8.52 609.60 -8.40Q606.48 -3.72 601.86 -1.32Q597.24 1.08 591.48 1.08Q584.88 1.08 579.84 -1.32Q574.80 -3.72 572.04 -7.98Q569.28 -12.24 569.28 -17.88Q569.28 -22.80 571.32 -26.34Q573.36 -29.88 576.60 -31.80Q579.60 -33.72 583.50 -34.50Q587.40 -35.28 591.84 -35.28L609.60 -35.28L609.60 -37.20Q609.60 -43.44 606.00 -46.80Q602.40 -50.16 595.56 -50.16Q590.76 -50.16 586.38 -48.24Q582.00 -46.32 578.04 -42.00L570.72 -49.56Q576.00 -55.08 582.42 -57.66Q588.84 -60.24 596.40 -60.24Q608.28 -60.24 614.82 -54.18Q621.36 -48.12 621.36 -37.20L621.36 0.00ZM609.60 -26.40L593.52 -26.40Q591.12 -26.40 588.54 -25.98Q585.96 -25.56 584.16 -24.24Q582.72 -23.16 581.88 -21.54Q581.04 -19.92 581.04 -17.76Q581.04 -13.56 584.28 -11.04Q587.52 -8.52 592.92 -8.52Q597.48 -8.52 601.26 -10.62Q605.04 -12.72 607.32 -16.38Q609.60 -20.04 609.60 -24.72ZM653.38 1.08Q647.14 1.08 642.34 -0.78Q637.54 -2.64 634.12 -5.58Q630.70 -8.52 628.66 -11.64L636.70 -18.60Q638.98 -14.52 643.24 -11.58Q647.50 -8.64 653.50 -8.64Q658.78 -8.64 661.84 -10.86Q664.90 -13.08 664.90 -16.68Q664.90 -19.56 662.98 -21.30Q661.06 -23.04 657.94 -24.18Q654.82 -25.32 651.10 -26.16Q647.74 -27.12 644.26 -28.32Q640.78 -29.52 637.96 -31.38Q635.14 -33.24 633.40 -36.18Q631.66 -39.12 631.66 -43.44Q631.66 -51.00 637.48 -55.62Q643.30 -60.24 652.90 -60.24Q659.74 -60.24 665.38 -57.42Q671.02 -54.60 674.14 -49.08L666.82 -43.44Q664.42 -47.40 660.64 -49.20Q656.86 -51.00 652.42 -51.00Q648.22 -51.00 645.40 -49.26Q642.58 -47.52 642.58 -44.52Q642.58 -42.36 643.84 -40.98Q645.10 -39.60 647.80 -38.58Q650.50 -37.56 654.46 -36.60Q658.18 -35.76 662.02 -34.56Q665.86 -33.36 669.10 -31.44Q672.34 -29.52 674.38 -26.28Q676.42 -23.04 676.42 -17.88Q676.42 -12.24 673.54 -7.98Q670.66 -3.72 665.50 -1.32Q660.34 1.08 653.38 1.08Z\"/></svg>`;\n\n/** Below this the mark's ring closes up and the words fall under 10 px. */\nconst MIN_HEIGHT = 12;\nconst DEFAULT_HEIGHT = 16;\n/** The words' size, and the wordmark's cap height, as parts of the mark's height. */\nconst TEXT_RATIO = 0.58;\nconst MIN_TEXT_PX = 10;\nconst WORDMARK_RATIO = 0.56;\n/** The wordmark's box is 686 × 88. */\nconst WORDMARK_ASPECT = 686 / 88;\n/** The cap height is 83.64 of the box's 88. */\nconst WORDMARK_CAP_SHARE = 83.64 / 88;\nconst GAP_RATIO = 0.25;\n\nexport interface PoweredByOptions {\n /** The mark's height in CSS pixels; the words and the wordmark follow it. Default 16, at least 12. */\n height?: number;\n /** Where the link goes. Default {@link TRADECANVAS_URL}. */\n href?: string;\n /** The link's target. Default `'_blank'`, which also sets `rel=\"noopener noreferrer\"`. */\n target?: string;\n}\n\n/** The badge's sizes in CSS pixels at a mark height. */\nexport interface PoweredByLayout {\n height: number;\n fontSize: number;\n gap: number;\n wordmarkWidth: number;\n wordmarkHeight: number;\n}\n\nexport function poweredByLayout(height: number = DEFAULT_HEIGHT): PoweredByLayout {\n const h = Number.isFinite(height) ? Math.max(MIN_HEIGHT, height) : DEFAULT_HEIGHT;\n const wordmarkHeight = round1((h * WORDMARK_RATIO) / WORDMARK_CAP_SHARE);\n return {\n height: h,\n fontSize: round1(Math.max(MIN_TEXT_PX, h * TEXT_RATIO)),\n gap: round1(h * GAP_RATIO),\n wordmarkWidth: round1(wordmarkHeight * WORDMARK_ASPECT),\n wordmarkHeight,\n };\n}\n\nfunction round1(n: number): number {\n return Math.round(n * 10) / 10;\n}\n\nfunction escapeAttr(value: string): string {\n return value.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<');\n}\n\n/** Only web links: anything else (a `javascript:` URL) falls back to the site. */\nexport function safeBadgeHref(href: string | undefined): string {\n if (!href) return TRADECANVAS_URL;\n return /^(https?:)?\\/\\//i.test(href) || href.startsWith('/') ? href : TRADECANVAS_URL;\n}\n\n/** A target other than this tab or its frames opens a page that could reach back through `window.opener`. */\nexport function opensElsewhere(target: string | undefined): boolean {\n return !!target && !/^_(self|parent|top)$/i.test(target);\n}\n\nfunction sized(svg: string, width: number, height: number): string {\n return svg.replace('<svg ', `<svg width=\"${width}\" height=\"${height}\" style=\"display:block;flex:none\" `);\n}\n\n/**\n * The badge as HTML, for a page built from strings or a framework without a\n * wrapper: `el.innerHTML = poweredByHtml({ height: 14 })`.\n */\nexport function poweredByHtml(options: PoweredByOptions = {}): string {\n const l = poweredByLayout(options.height);\n const href = escapeAttr(safeBadgeHref(options.href));\n const target = options.target ?? '_blank';\n const targetAttrs = target ? ` target=\"${escapeAttr(target)}\"${opensElsewhere(target) ? ' rel=\"noopener noreferrer\"' : ''}` : '';\n const style = `display:inline-flex;align-items:center;gap:${l.gap}px;height:${l.height}px;color:inherit;text-decoration:none;font-size:${l.fontSize}px;line-height:1;white-space:nowrap`;\n return `<a class=\"tc-powered-by\" href=\"${href}\"${targetAttrs} aria-label=\"${POWERED_BY_LABEL}\" style=\"${style}\">`\n + `<span aria-hidden=\"true\">Powered by</span>`\n + sized(TRADECANVAS_MARK_SVG, l.height, l.height)\n + sized(TRADECANVAS_WORDMARK_SVG, l.wordmarkWidth, l.wordmarkHeight)\n + `</a>`;\n}\n\n/** The badge as an element, ready to append. It needs a document: on a server, use {@link poweredByHtml}. */\nexport function createPoweredBy(options: PoweredByOptions = {}, doc: Document = document): HTMLAnchorElement {\n const holder = doc.createElement('div');\n holder.innerHTML = poweredByHtml(options);\n return holder.firstElementChild as HTMLAnchorElement;\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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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/frameworks/syncIndicators.ts","../src/frameworks/feedBars.ts","../src/brand/poweredBy.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","/**\n * A \"Powered by TradeCanvas\" badge for an app built on TradeCanvas: the words, the\n * TC mark and the outlined wordmark in one link. The mark's ring and bar and the\n * wordmark take the text colour around them (`currentColor`), so the badge follows a\n * light or dark theme; only the candle keeps the brand's amber. The words are live\n * text in the host's own face.\n */\n\n/** Where the badge links to. */\nexport const TRADECANVAS_URL = 'https://tradecanvas.dev';\n\n/** The badge's accessible name. */\nexport const POWERED_BY_LABEL = 'Powered by TradeCanvas';\n\n/** The TC mark, its small-size cut: the ring and bar in `currentColor`, the candle amber. */\nexport const TRADECANVAS_MARK_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M186 70A82 82 0 1 0 186 186\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"22\" stroke-linecap=\"round\"/><rect x=\"92\" y=\"74\" width=\"72\" height=\"20\" rx=\"10\" fill=\"currentColor\"/><path fill=\"#E8961E\" d=\"M119 94H137V108H144a10 10 0 0 1 10 10V164a10 10 0 0 1-10 10H137V190H119V174H112a10 10 0 0 1-10-10V118a10 10 0 0 1 10-10H119Z\"/></svg>`;\n\n/** The outlined wordmark in `currentColor`, its box cropped to the capitals. */\nexport const TRADECANVAS_WORDMARK_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 16 686 88\" aria-hidden=\"true\" focusable=\"false\"><path fill=\"currentColor\" transform=\"translate(0 101.64)\" d=\"M27.24 0.00L27.24 -69.72L1.32 -69.72L1.32 -83.64L68.76 -83.64L68.76 -69.72L42.96 -69.72L42.96 0.00ZM70.90 0.00L70.90 -59.16L85.90 -59.16L85.90 -50.64Q86.26 -51.36 86.74 -51.96Q89.50 -55.92 93.52 -58.14Q97.54 -60.36 101.74 -60.36Q104.74 -60.36 107.44 -59.58Q110.14 -58.80 113.02 -57.00L105.82 -43.56Q104.50 -44.28 102.46 -44.88Q100.42 -45.48 98.38 -45.48Q95.98 -45.48 93.76 -44.64Q91.54 -43.80 89.80 -42.00Q88.06 -40.20 86.98 -37.20Q86.50 -35.52 86.20 -32.94Q85.90 -30.36 85.90 -25.44L85.90 0.00ZM156.44 0.00L155.36 -7.56Q155.00 -6.96 154.52 -6.36Q151.28 -2.40 147.20 -0.60Q143.12 1.20 138.56 1.20Q132.08 1.20 126.98 -1.20Q121.88 -3.60 118.94 -8.04Q116.00 -12.48 116.00 -18.24Q116.00 -23.40 118.10 -27.06Q120.20 -30.72 123.68 -32.64Q126.68 -34.44 130.34 -35.16Q134.00 -35.88 138.20 -35.88L155.24 -35.88L155.24 -37.32Q155.24 -42.60 151.94 -45.18Q148.64 -47.76 143.00 -47.76Q138.32 -47.76 133.46 -45.90Q128.60 -44.04 124.88 -40.68L117.32 -50.88Q123.56 -55.92 130.10 -58.14Q136.64 -60.36 144.20 -60.36Q156.44 -60.36 163.28 -54.24Q170.12 -48.12 170.12 -37.32L170.12 0.00ZM155.24 -24.84L140.36 -24.84Q138.44 -24.84 136.58 -24.54Q134.72 -24.24 133.40 -23.16Q132.20 -22.32 131.60 -21.06Q131.00 -19.80 131.00 -18.24Q131.00 -14.88 133.64 -12.84Q136.28 -10.80 140.72 -10.80Q144.68 -10.80 147.98 -12.54Q151.28 -14.28 153.26 -17.34Q155.24 -20.40 155.24 -24.36ZM202.98 1.20Q195.18 1.20 189.54 -2.82Q183.90 -6.84 180.84 -13.86Q177.78 -20.88 177.78 -29.64Q177.78 -39.36 181.20 -46.20Q184.62 -53.04 190.38 -56.70Q196.14 -60.36 202.98 -60.36Q207.78 -60.36 211.92 -58.38Q216.06 -56.40 219.06 -52.44Q219.54 -51.72 220.02 -51.00L220.02 -83.64L234.78 -83.64L234.78 0.00L220.02 0.00L220.02 -8.04Q219.54 -7.20 218.94 -6.48Q215.70 -2.28 211.56 -0.54Q207.42 1.20 202.98 1.20ZM207.06 -12.48Q211.50 -12.48 214.68 -14.64Q217.86 -16.80 219.60 -20.64Q221.34 -24.48 221.34 -29.64Q221.34 -34.80 219.60 -38.64Q217.86 -42.48 214.68 -44.58Q211.50 -46.68 207.06 -46.68Q202.74 -46.68 199.50 -44.58Q196.26 -42.48 194.52 -38.70Q192.78 -34.92 192.78 -29.64Q192.78 -24.36 194.52 -20.52Q196.26 -16.68 199.50 -14.58Q202.74 -12.48 207.06 -12.48ZM272.32 1.20Q264.64 1.20 259.12 -1.32Q253.60 -3.84 250.06 -8.10Q246.52 -12.36 244.84 -17.82Q243.16 -23.28 243.16 -29.28Q243.16 -35.04 244.84 -40.56Q246.52 -46.08 249.88 -50.52Q253.24 -54.96 258.58 -57.66Q263.92 -60.36 271.36 -60.36Q278.32 -60.36 283.48 -58.02Q288.64 -55.68 292.00 -51.54Q295.36 -47.40 297.10 -41.88Q298.84 -36.36 298.84 -30.12Q298.84 -29.28 298.78 -27.78Q298.72 -26.28 298.48 -24.60L258.04 -24.60Q258.64 -18.24 262.78 -15.00Q266.92 -11.76 273.16 -11.76Q277.72 -11.76 282.04 -13.38Q286.36 -15.00 289.72 -18.00L297.16 -7.92Q292.96 -4.68 289.24 -2.64Q285.52 -0.60 281.50 0.30Q277.48 1.20 272.32 1.20ZM284.68 -35.64Q284.68 -35.76 284.68 -35.76Q284.68 -38.28 283.72 -40.50Q282.76 -42.72 281.08 -44.40Q279.40 -46.08 277.06 -46.98Q274.72 -47.88 271.72 -47.88Q267.28 -47.88 264.28 -46.08Q261.28 -44.28 259.78 -41.46Q258.28 -38.64 257.92 -35.64ZM346.66 1.56Q335.02 1.56 326.20 -3.84Q317.38 -9.24 312.46 -19.08Q307.54 -28.92 307.54 -41.88Q307.54 -54.84 312.46 -64.62Q317.38 -74.40 326.20 -79.80Q335.02 -85.20 346.66 -85.20Q359.50 -85.20 368.92 -78.84Q378.34 -72.48 382.42 -61.20L371.02 -57.00Q368.02 -64.80 361.78 -69.18Q355.54 -73.56 346.66 -73.56Q338.50 -73.56 332.44 -69.66Q326.38 -65.76 323.08 -58.74Q319.78 -51.72 319.78 -41.88Q319.78 -32.04 323.08 -24.96Q326.38 -17.88 332.44 -13.98Q338.50 -10.08 346.66 -10.08Q355.54 -10.08 361.78 -14.46Q368.02 -18.84 371.02 -26.64L382.42 -22.56Q378.34 -11.40 368.92 -4.92Q359.50 1.56 346.66 1.56ZM429.04 0.00L428.32 -8.64Q428.20 -8.52 428.08 -8.40Q424.96 -3.72 420.34 -1.32Q415.72 1.08 409.96 1.08Q403.36 1.08 398.32 -1.32Q393.28 -3.72 390.52 -7.98Q387.76 -12.24 387.76 -17.88Q387.76 -22.80 389.80 -26.34Q391.84 -29.88 395.08 -31.80Q398.08 -33.72 401.98 -34.50Q405.88 -35.28 410.32 -35.28L428.08 -35.28L428.08 -37.20Q428.08 -43.44 424.48 -46.80Q420.88 -50.16 414.04 -50.16Q409.24 -50.16 404.86 -48.24Q400.48 -46.32 396.52 -42.00L389.20 -49.56Q394.48 -55.08 400.90 -57.66Q407.32 -60.24 414.88 -60.24Q426.76 -60.24 433.30 -54.18Q439.84 -48.12 439.84 -37.20L439.84 0.00ZM428.08 -26.40L412.00 -26.40Q409.60 -26.40 407.02 -25.98Q404.44 -25.56 402.64 -24.24Q401.20 -23.16 400.36 -21.54Q399.52 -19.92 399.52 -17.76Q399.52 -13.56 402.76 -11.04Q406.00 -8.52 411.40 -8.52Q415.96 -8.52 419.74 -10.62Q423.52 -12.72 425.80 -16.38Q428.08 -20.04 428.08 -24.72ZM451.94 0.00L451.94 -59.16L463.82 -59.16L463.82 -50.88Q464.78 -52.44 465.98 -53.76Q468.86 -56.88 472.88 -58.56Q476.90 -60.24 481.58 -60.24Q491.42 -60.24 497.00 -54.54Q502.58 -48.84 502.58 -37.92L502.58 0.00L490.82 0.00L490.82 -33.60Q490.82 -42.12 487.76 -46.08Q484.70 -50.04 478.34 -50.04Q473.54 -50.04 470.36 -47.88Q467.18 -45.72 465.50 -41.04Q463.82 -36.36 463.82 -29.16L463.82 0.00ZM533.28 0.00L509.04 -59.16L522.00 -59.16L538.08 -15.24L554.40 -59.16L567.12 -59.16L543.12 0.00ZM610.56 0.00L609.84 -8.64Q609.72 -8.52 609.60 -8.40Q606.48 -3.72 601.86 -1.32Q597.24 1.08 591.48 1.08Q584.88 1.08 579.84 -1.32Q574.80 -3.72 572.04 -7.98Q569.28 -12.24 569.28 -17.88Q569.28 -22.80 571.32 -26.34Q573.36 -29.88 576.60 -31.80Q579.60 -33.72 583.50 -34.50Q587.40 -35.28 591.84 -35.28L609.60 -35.28L609.60 -37.20Q609.60 -43.44 606.00 -46.80Q602.40 -50.16 595.56 -50.16Q590.76 -50.16 586.38 -48.24Q582.00 -46.32 578.04 -42.00L570.72 -49.56Q576.00 -55.08 582.42 -57.66Q588.84 -60.24 596.40 -60.24Q608.28 -60.24 614.82 -54.18Q621.36 -48.12 621.36 -37.20L621.36 0.00ZM609.60 -26.40L593.52 -26.40Q591.12 -26.40 588.54 -25.98Q585.96 -25.56 584.16 -24.24Q582.72 -23.16 581.88 -21.54Q581.04 -19.92 581.04 -17.76Q581.04 -13.56 584.28 -11.04Q587.52 -8.52 592.92 -8.52Q597.48 -8.52 601.26 -10.62Q605.04 -12.72 607.32 -16.38Q609.60 -20.04 609.60 -24.72ZM653.38 1.08Q647.14 1.08 642.34 -0.78Q637.54 -2.64 634.12 -5.58Q630.70 -8.52 628.66 -11.64L636.70 -18.60Q638.98 -14.52 643.24 -11.58Q647.50 -8.64 653.50 -8.64Q658.78 -8.64 661.84 -10.86Q664.90 -13.08 664.90 -16.68Q664.90 -19.56 662.98 -21.30Q661.06 -23.04 657.94 -24.18Q654.82 -25.32 651.10 -26.16Q647.74 -27.12 644.26 -28.32Q640.78 -29.52 637.96 -31.38Q635.14 -33.24 633.40 -36.18Q631.66 -39.12 631.66 -43.44Q631.66 -51.00 637.48 -55.62Q643.30 -60.24 652.90 -60.24Q659.74 -60.24 665.38 -57.42Q671.02 -54.60 674.14 -49.08L666.82 -43.44Q664.42 -47.40 660.64 -49.20Q656.86 -51.00 652.42 -51.00Q648.22 -51.00 645.40 -49.26Q642.58 -47.52 642.58 -44.52Q642.58 -42.36 643.84 -40.98Q645.10 -39.60 647.80 -38.58Q650.50 -37.56 654.46 -36.60Q658.18 -35.76 662.02 -34.56Q665.86 -33.36 669.10 -31.44Q672.34 -29.52 674.38 -26.28Q676.42 -23.04 676.42 -17.88Q676.42 -12.24 673.54 -7.98Q670.66 -3.72 665.50 -1.32Q660.34 1.08 653.38 1.08Z\"/></svg>`;\n\n/** Below this the mark's ring closes up and the words fall under 10 px. */\nconst MIN_HEIGHT = 12;\nconst DEFAULT_HEIGHT = 16;\n/** The words' size, and the wordmark's cap height, as parts of the mark's height. */\nconst TEXT_RATIO = 0.58;\nconst MIN_TEXT_PX = 10;\nconst WORDMARK_RATIO = 0.56;\n/** The wordmark's box is 686 × 88. */\nconst WORDMARK_ASPECT = 686 / 88;\n/** The cap height is 83.64 of the box's 88. */\nconst WORDMARK_CAP_SHARE = 83.64 / 88;\nconst GAP_RATIO = 0.25;\n\nexport interface PoweredByOptions {\n /** The mark's height in CSS pixels; the words and the wordmark follow it. Default 16, at least 12. */\n height?: number;\n /** Where the link goes. Default {@link TRADECANVAS_URL}. */\n href?: string;\n /** The link's target. Default `'_blank'`, which also sets `rel=\"noopener noreferrer\"`. */\n target?: string;\n}\n\n/** The badge's sizes in CSS pixels at a mark height. */\nexport interface PoweredByLayout {\n height: number;\n fontSize: number;\n gap: number;\n wordmarkWidth: number;\n wordmarkHeight: number;\n}\n\nexport function poweredByLayout(height: number = DEFAULT_HEIGHT): PoweredByLayout {\n const h = Number.isFinite(height) ? Math.max(MIN_HEIGHT, height) : DEFAULT_HEIGHT;\n const wordmarkHeight = round1((h * WORDMARK_RATIO) / WORDMARK_CAP_SHARE);\n return {\n height: h,\n fontSize: round1(Math.max(MIN_TEXT_PX, h * TEXT_RATIO)),\n gap: round1(h * GAP_RATIO),\n wordmarkWidth: round1(wordmarkHeight * WORDMARK_ASPECT),\n wordmarkHeight,\n };\n}\n\nfunction round1(n: number): number {\n return Math.round(n * 10) / 10;\n}\n\nfunction escapeAttr(value: string): string {\n return value.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<');\n}\n\n/** Only web links: anything else (a `javascript:` URL) falls back to the site. */\nexport function safeBadgeHref(href: string | undefined): string {\n if (!href) return TRADECANVAS_URL;\n return /^(https?:)?\\/\\//i.test(href) || href.startsWith('/') ? href : TRADECANVAS_URL;\n}\n\n/** A target other than this tab or its frames opens a page that could reach back through `window.opener`. */\nexport function opensElsewhere(target: string | undefined): boolean {\n return !!target && !/^_(self|parent|top)$/i.test(target);\n}\n\nfunction sized(svg: string, width: number, height: number): string {\n return svg.replace('<svg ', `<svg width=\"${width}\" height=\"${height}\" style=\"display:block;flex:none\" `);\n}\n\n/**\n * The badge as HTML, for a page built from strings or a framework without a\n * wrapper: `el.innerHTML = poweredByHtml({ height: 14 })`.\n */\nexport function poweredByHtml(options: PoweredByOptions = {}): string {\n const l = poweredByLayout(options.height);\n const href = escapeAttr(safeBadgeHref(options.href));\n const target = options.target ?? '_blank';\n const targetAttrs = target ? ` target=\"${escapeAttr(target)}\"${opensElsewhere(target) ? ' rel=\"noopener noreferrer\"' : ''}` : '';\n const style = `display:inline-flex;align-items:center;gap:${l.gap}px;height:${l.height}px;color:inherit;text-decoration:none;font-size:${l.fontSize}px;line-height:1;white-space:nowrap`;\n return `<a class=\"tc-powered-by\" href=\"${href}\"${targetAttrs} aria-label=\"${POWERED_BY_LABEL}\" style=\"${style}\">`\n + `<span aria-hidden=\"true\">Powered by</span>`\n + sized(TRADECANVAS_MARK_SVG, l.height, l.height)\n + sized(TRADECANVAS_WORDMARK_SVG, l.wordmarkWidth, l.wordmarkHeight)\n + `</a>`;\n}\n\n/** The badge as an element, ready to append. It needs a document: on a server, use {@link poweredByHtml}. */\nexport function createPoweredBy(options: PoweredByOptions = {}, doc: Document = document): HTMLAnchorElement {\n const holder = doc.createElement('div');\n holder.innerHTML = poweredByHtml(options);\n return holder.firstElementChild as HTMLAnchorElement;\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';\nimport { GRID_LAYOUT_SHAPES, gridAreas, gridChartCount, isGridLayout, placeGridCell, type GridLayout } from './gridShapes.js';\n\nexport type { GridArea, GridLayout, GridShape } from './gridShapes.js';\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\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 = isGridLayout(options.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 } = GRID_LAYOUT_SHAPES[this.layout];\n const gap = this.options.gap ?? 1;\n this.root.style.gridTemplateColumns = `repeat(${cols}, minmax(0, 1fr))`;\n this.root.style.gridTemplateRows = `repeat(${rows}, minmax(0, 1fr))`;\n this.root.style.gap = `${gap}px`;\n this.placeCells();\n }\n\n /** Each chart in its place in the arrangement (a large one spans several cells). */\n private placeCells(): void {\n const areas = gridAreas(GRID_LAYOUT_SHAPES[this.layout]);\n this.cells.forEach((cell, i) => placeGridCell(cell.container, areas[i]));\n }\n\n private createCells(): void {\n const count = gridChartCount(GRID_LAYOUT_SHAPES[this.layout]);\n for (let i = 0; i < count; i++) this.cells.push(this.createCell(i));\n this.placeCells();\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 /**\n * Arrange the charts. Charts that no longer fit are destroyed; new ones get\n * the grid's options and links.\n */\n setLayout(layout: GridLayout): void {\n if (layout === this.layout || !isGridLayout(layout)) return;\n const oldCount = this.cells.length;\n const newCount = gridChartCount(GRID_LAYOUT_SHAPES[layout]);\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 this.placeCells();\n }\n\n getLayout(): GridLayout {\n return this.layout;\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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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./indicatorLabel-BsidWCv1.js";
|
|
2
|
-
import { c as t } from "./i18n-
|
|
2
|
+
import { c as t } from "./i18n-nWmX3G55.js";
|
|
3
3
|
//#region src/widget/indicatorInputWords.ts
|
|
4
4
|
function n(e) {
|
|
5
5
|
return Object.prototype.hasOwnProperty.call(t, e);
|
|
@@ -22,4 +22,4 @@ function a(t, n) {
|
|
|
22
22
|
//#endregion
|
|
23
23
|
export { r as n, a as r, i as t };
|
|
24
24
|
|
|
25
|
-
//# sourceMappingURL=indicatorInputWords-
|
|
25
|
+
//# sourceMappingURL=indicatorInputWords-D0SGBaUD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indicatorInputWords-
|
|
1
|
+
{"version":3,"file":"indicatorInputWords-D0SGBaUD.js","names":[],"sources":["../src/widget/indicatorInputWords.ts"],"sourcesContent":["import type { IndicatorDescriptor } from '@tradecanvas/commons';\nimport { indicatorChipLabel } from '../indicatorLabel.js';\nimport { EN_MESSAGES, type MessageKey, type Translator } from './i18n.js';\n\n/**\n * Words for an indicator's inputs in the widget's language: an input named\n * `anchor` is `indicatorInput.anchor`, its choice `'week'` is\n * `indicatorInput.anchor.week`. Only inputs the widget has words for; any\n * other keeps its own label and its values as they are.\n */\n\n/** Whether the widget has a message under `key`, one built from an input's name. */\nfunction isMessageKey(key: string): key is MessageKey {\n return Object.prototype.hasOwnProperty.call(EN_MESSAGES, key);\n}\n\n/** An input's label in the widget's language, or null for one it has no word for. */\nexport function inputLabel(name: string, t: Translator): string | null {\n const key = `indicatorInput.${name}`;\n return isMessageKey(key) ? t(key) : null;\n}\n\n/** A choice of an input in the widget's language, or null for one it has no word for. */\nexport function choiceLabel(name: string, choice: string | number, t: Translator): string | null {\n const key = `indicatorInput.${name}.${choice}`;\n return isMessageKey(key) ? t(key) : null;\n}\n\n/** An indicator on the chart, as the widget names it. */\nexport interface NamedIndicator {\n id: string;\n params: Record<string, unknown>;\n descriptor: Pick<IndicatorDescriptor, 'defaultConfig' | 'shortName' | 'inputs'>;\n}\n\n/**\n * The indicator's name in the legend, the chips and the Objects panel: its\n * chip label ('EMA 21'), then the word for each choice off its default, so\n * two read apart ('VWAP', 'VWAP Week'). The CSV column keeps the chip label.\n */\nexport function widgetIndicatorLabel(ind: NamedIndicator, t: Translator): string {\n const { defaultConfig, shortName, inputs } = ind.descriptor;\n const words = Object.entries(inputs ?? {}).flatMap(([name, spec]) => {\n const value = ind.params[name];\n if (!spec.options || (typeof value !== 'string' && typeof value !== 'number') || value === defaultConfig[name]) return [];\n return choiceLabel(name, value, t) ?? [];\n });\n return [indicatorChipLabel(ind.id, ind.params, defaultConfig, shortName), ...words].join(' ');\n}\n"],"mappings":";;;AAYA,SAAS,EAAa,GAAgC;AACpD,QAAO,OAAO,UAAU,eAAe,KAAK,GAAa,EAAI;;AAI/D,SAAgB,EAAW,GAAc,GAA8B;CACrE,IAAM,IAAM,kBAAkB;AAC9B,QAAO,EAAa,EAAI,GAAG,EAAE,EAAI,GAAG;;AAItC,SAAgB,EAAY,GAAc,GAAyB,GAA8B;CAC/F,IAAM,IAAM,kBAAkB,EAAK,GAAG;AACtC,QAAO,EAAa,EAAI,GAAG,EAAE,EAAI,GAAG;;AAetC,SAAgB,EAAqB,GAAqB,GAAuB;CAC/E,IAAM,EAAE,kBAAe,cAAW,cAAW,EAAI,YAC3C,IAAQ,OAAO,QAAQ,KAAU,EAAE,CAAC,CAAC,SAAS,CAAC,GAAM,OAAU;EACnE,IAAM,IAAQ,EAAI,OAAO;AAEzB,SADI,CAAC,EAAK,WAAY,OAAO,KAAU,YAAY,OAAO,KAAU,YAAa,MAAU,EAAc,KAAc,EAAE,GAClH,EAAY,GAAM,GAAO,EAAE,IAAI,EAAE;GACxC;AACF,QAAO,CAAC,EAAmB,EAAI,IAAI,EAAI,QAAQ,GAAe,EAAU,EAAE,GAAG,EAAM,CAAC,KAAK,IAAI"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`./indicatorLabel-BQ6Kdry2.cjs`),t=require(`./i18n-
|
|
2
|
-
//# sourceMappingURL=indicatorInputWords-
|
|
1
|
+
const e=require(`./indicatorLabel-BQ6Kdry2.cjs`),t=require(`./i18n-D0SPfH2s.cjs`);function n(e){return Object.prototype.hasOwnProperty.call(t.c,e)}function r(e,t){let r=`indicatorInput.${e}`;return n(r)?t(r):null}function i(e,t,r){let i=`indicatorInput.${e}.${t}`;return n(i)?r(i):null}function a(t,n){let{defaultConfig:r,shortName:a,inputs:o}=t.descriptor,s=Object.entries(o??{}).flatMap(([e,a])=>{let o=t.params[e];return!a.options||typeof o!=`string`&&typeof o!=`number`||o===r[e]?[]:i(e,o,n)??[]});return[e.t(t.id,t.params,r,a),...s].join(` `)}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return i}});
|
|
2
|
+
//# sourceMappingURL=indicatorInputWords-HqTGFokF.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indicatorInputWords-
|
|
1
|
+
{"version":3,"file":"indicatorInputWords-HqTGFokF.cjs","names":[],"sources":["../src/widget/indicatorInputWords.ts"],"sourcesContent":["import type { IndicatorDescriptor } from '@tradecanvas/commons';\nimport { indicatorChipLabel } from '../indicatorLabel.js';\nimport { EN_MESSAGES, type MessageKey, type Translator } from './i18n.js';\n\n/**\n * Words for an indicator's inputs in the widget's language: an input named\n * `anchor` is `indicatorInput.anchor`, its choice `'week'` is\n * `indicatorInput.anchor.week`. Only inputs the widget has words for; any\n * other keeps its own label and its values as they are.\n */\n\n/** Whether the widget has a message under `key`, one built from an input's name. */\nfunction isMessageKey(key: string): key is MessageKey {\n return Object.prototype.hasOwnProperty.call(EN_MESSAGES, key);\n}\n\n/** An input's label in the widget's language, or null for one it has no word for. */\nexport function inputLabel(name: string, t: Translator): string | null {\n const key = `indicatorInput.${name}`;\n return isMessageKey(key) ? t(key) : null;\n}\n\n/** A choice of an input in the widget's language, or null for one it has no word for. */\nexport function choiceLabel(name: string, choice: string | number, t: Translator): string | null {\n const key = `indicatorInput.${name}.${choice}`;\n return isMessageKey(key) ? t(key) : null;\n}\n\n/** An indicator on the chart, as the widget names it. */\nexport interface NamedIndicator {\n id: string;\n params: Record<string, unknown>;\n descriptor: Pick<IndicatorDescriptor, 'defaultConfig' | 'shortName' | 'inputs'>;\n}\n\n/**\n * The indicator's name in the legend, the chips and the Objects panel: its\n * chip label ('EMA 21'), then the word for each choice off its default, so\n * two read apart ('VWAP', 'VWAP Week'). The CSV column keeps the chip label.\n */\nexport function widgetIndicatorLabel(ind: NamedIndicator, t: Translator): string {\n const { defaultConfig, shortName, inputs } = ind.descriptor;\n const words = Object.entries(inputs ?? {}).flatMap(([name, spec]) => {\n const value = ind.params[name];\n if (!spec.options || (typeof value !== 'string' && typeof value !== 'number') || value === defaultConfig[name]) return [];\n return choiceLabel(name, value, t) ?? [];\n });\n return [indicatorChipLabel(ind.id, ind.params, defaultConfig, shortName), ...words].join(' ');\n}\n"],"mappings":"kFAYA,SAAS,EAAa,EAAgC,CACpD,OAAO,OAAO,UAAU,eAAe,KAAK,EAAA,EAAa,EAAI,CAI/D,SAAgB,EAAW,EAAc,EAA8B,CACrE,IAAM,EAAM,kBAAkB,IAC9B,OAAO,EAAa,EAAI,CAAG,EAAE,EAAI,CAAG,KAItC,SAAgB,EAAY,EAAc,EAAyB,EAA8B,CAC/F,IAAM,EAAM,kBAAkB,EAAK,GAAG,IACtC,OAAO,EAAa,EAAI,CAAG,EAAE,EAAI,CAAG,KAetC,SAAgB,EAAqB,EAAqB,EAAuB,CAC/E,GAAM,CAAE,gBAAe,YAAW,UAAW,EAAI,WAC3C,EAAQ,OAAO,QAAQ,GAAU,EAAE,CAAC,CAAC,SAAS,CAAC,EAAM,KAAU,CACnE,IAAM,EAAQ,EAAI,OAAO,GAEzB,MADI,CAAC,EAAK,SAAY,OAAO,GAAU,UAAY,OAAO,GAAU,UAAa,IAAU,EAAc,GAAc,EAAE,CAClH,EAAY,EAAM,EAAO,EAAE,EAAI,EAAE,EACxC,CACF,MAAO,CAAC,EAAA,EAAmB,EAAI,GAAI,EAAI,OAAQ,EAAe,EAAU,CAAE,GAAG,EAAM,CAAC,KAAK,IAAI"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Quote, SymbolInfo, Theme, TimeFrame, DepthData, DataSeries } from '@tradecanvas/commons';
|
|
1
|
+
import { CrosshairCursor, Quote, SymbolInfo, Theme, TimeFrame, DepthData, DataSeries } from '@tradecanvas/commons';
|
|
2
2
|
import { Chart } from '../Chart.js';
|
|
3
3
|
import { ChartWidgetOptions, ChartSettingsState, WidgetPanel } from './types.js';
|
|
4
4
|
import { WatchlistEntry } from './WidgetWatchlist.js';
|
|
@@ -228,6 +228,8 @@ export declare class ChartWidget {
|
|
|
228
228
|
setSymbols(symbols: readonly (string | SymbolInfo)[]): void;
|
|
229
229
|
/** The symbols on offer, each with what came with it, for the search and compare dialogs. */
|
|
230
230
|
private symbolEntries;
|
|
231
|
+
/** What `symbols` gave of one symbol (its names, kind, logo), or undefined. */
|
|
232
|
+
private symbolInfoOf;
|
|
231
233
|
/**
|
|
232
234
|
* What the chart knows of its symbol, to name it; null while it is still
|
|
233
235
|
* another symbol's. It is this symbol's when it names it (in any case, or
|
|
@@ -616,6 +618,14 @@ export declare class ChartWidget {
|
|
|
616
618
|
* `getChart()` itself is in it.
|
|
617
619
|
*/
|
|
618
620
|
getSettings(): ChartSettingsState;
|
|
621
|
+
/**
|
|
622
|
+
* What the pointer looks like over the chart: `'cross'`, `'dot'` (the
|
|
623
|
+
* crosshair's lines with a dot for a cursor) or `'arrow'` (no lines; the
|
|
624
|
+
* price and the time still follow it on the axes). A Chart Setting, the
|
|
625
|
+
* viewer's own: kept with `persistSettings`, never in a layout or a link.
|
|
626
|
+
*/
|
|
627
|
+
setCrosshairCursor(kind: CrosshairCursor): void;
|
|
628
|
+
getCrosshairCursor(): CrosshairCursor;
|
|
619
629
|
/**
|
|
620
630
|
* Change some of the Chart Settings, as the settings dialog does (an open
|
|
621
631
|
* one shows them). What isn't a setting, or not of its kind, is left out,
|