@coderyo/core 1.0.0-rc.2
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/index.d.ts +213 -0
- package/dist/index.js +749 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import * as _coderyo_drawings from '@coderyo/drawings';
|
|
2
|
+
import { DrawingRecord, DrawingStyleMeta } from '@coderyo/drawings';
|
|
3
|
+
import * as _coderyo_data from '@coderyo/data';
|
|
4
|
+
import { RealtimeStreamMode, Interval, DataProvider, SymbolResolver } from '@coderyo/data';
|
|
5
|
+
import { IndicatorConfig } from '@coderyo/indicators';
|
|
6
|
+
import { FetchPolicy } from '@coderyo/virtual-window';
|
|
7
|
+
import { BridgeAdapter, BridgeOutboundType } from '@coderyo/bridge';
|
|
8
|
+
|
|
9
|
+
interface ChartGapsFeatures {
|
|
10
|
+
whitespace?: boolean;
|
|
11
|
+
fillVisibleHoles?: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface ChartDrawingsFeatures {
|
|
14
|
+
/** Show interactive drawing overlay (default false). API remains available when false. */
|
|
15
|
+
layer?: boolean;
|
|
16
|
+
/** Persist drawings to localStorage (default true when layer/API used). */
|
|
17
|
+
persist?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface ChartFeatures {
|
|
20
|
+
fetchPolicy?: FetchPolicy;
|
|
21
|
+
streamMode?: RealtimeStreamMode;
|
|
22
|
+
gaps?: ChartGapsFeatures;
|
|
23
|
+
drawings?: ChartDrawingsFeatures;
|
|
24
|
+
/** Pass config to enable MA + indicator panes; omit/null = no indicators. */
|
|
25
|
+
indicators?: IndicatorConfig | null;
|
|
26
|
+
/** Save indicator params to storage (default false). */
|
|
27
|
+
indicatorPersist?: boolean;
|
|
28
|
+
/** Post-1.0 hooks — default false, no-op until implemented. */
|
|
29
|
+
pineEnabled?: boolean;
|
|
30
|
+
protobuf?: boolean;
|
|
31
|
+
telemetry?: boolean;
|
|
32
|
+
tickStream?: boolean;
|
|
33
|
+
}
|
|
34
|
+
interface ResolvedChartFeatures {
|
|
35
|
+
fetchPolicy: FetchPolicy;
|
|
36
|
+
streamMode: RealtimeStreamMode;
|
|
37
|
+
gaps: Required<ChartGapsFeatures>;
|
|
38
|
+
drawings: Required<ChartDrawingsFeatures>;
|
|
39
|
+
indicators: IndicatorConfig | null;
|
|
40
|
+
indicatorPersist: boolean;
|
|
41
|
+
pineEnabled: boolean;
|
|
42
|
+
protobuf: boolean;
|
|
43
|
+
telemetry: boolean;
|
|
44
|
+
tickStream: boolean;
|
|
45
|
+
}
|
|
46
|
+
declare const DEFAULT_CHART_FEATURES: ResolvedChartFeatures;
|
|
47
|
+
declare function resolveChartFeatures(partial?: ChartFeatures): ResolvedChartFeatures;
|
|
48
|
+
/** Empty chart until integrator calls setSymbol. */
|
|
49
|
+
declare const PENDING_SYMBOL = "";
|
|
50
|
+
|
|
51
|
+
interface ChartOptions {
|
|
52
|
+
width?: number;
|
|
53
|
+
height?: number;
|
|
54
|
+
theme?: 'dark' | 'light';
|
|
55
|
+
interval?: Interval;
|
|
56
|
+
/** Omit for empty chart until setSymbol(). */
|
|
57
|
+
symbol?: string;
|
|
58
|
+
chartId?: string;
|
|
59
|
+
/** Host element below main chart for MACD/RSI/KDJ panes (from ui-shell layout). */
|
|
60
|
+
indicatorHost?: HTMLElement;
|
|
61
|
+
dataProvider: DataProvider;
|
|
62
|
+
/** Integrator feature flags (minimal defaults). */
|
|
63
|
+
features?: ChartFeatures;
|
|
64
|
+
/** @deprecated Use features.fetchPolicy */
|
|
65
|
+
fetchPolicy?: FetchPolicy;
|
|
66
|
+
scaleMode?: 'linear' | 'log';
|
|
67
|
+
/** Grid lines on chart panes (default false). */
|
|
68
|
+
showGrid?: boolean;
|
|
69
|
+
symbolResolver?: SymbolResolver;
|
|
70
|
+
drawingDefaults?: {
|
|
71
|
+
returnToCursorAfterDraw?: boolean;
|
|
72
|
+
};
|
|
73
|
+
/** @deprecated Use features.indicators */
|
|
74
|
+
indicatorConfig?: IndicatorConfig;
|
|
75
|
+
}
|
|
76
|
+
type ChartEvent = 'connectionChange' | 'barUpdate' | 'error' | 'visibleRangeChange' | 'symbolChange' | 'intervalChange' | 'crosshairChange' | 'destroyed' | 'drawingSelectionChange' | 'drawingContextMenu' | 'requestCursorTool' | 'featuresChange';
|
|
77
|
+
type EventHandler = (payload?: unknown) => void;
|
|
78
|
+
declare class ChartController {
|
|
79
|
+
private readonly container;
|
|
80
|
+
private readonly options;
|
|
81
|
+
private readonly store;
|
|
82
|
+
private readonly virtualWindow;
|
|
83
|
+
private readonly orchestrator;
|
|
84
|
+
private readonly handlers;
|
|
85
|
+
private subscriptionId;
|
|
86
|
+
private destroyed;
|
|
87
|
+
private readonly resizeObserver;
|
|
88
|
+
private loadingMore;
|
|
89
|
+
private visibleRangeInitialized;
|
|
90
|
+
/** Bumped on symbol/interval change to drop stale bootstrap / loadMore / WS merges. */
|
|
91
|
+
private loadGeneration;
|
|
92
|
+
private drawingManager;
|
|
93
|
+
private offCrosshair;
|
|
94
|
+
private features;
|
|
95
|
+
constructor(container: HTMLElement, options: ChartOptions);
|
|
96
|
+
getFeatures(): ResolvedChartFeatures;
|
|
97
|
+
setFeatures(patch: ChartFeatures): this;
|
|
98
|
+
hasActiveSymbol(): boolean;
|
|
99
|
+
private applyFeatures;
|
|
100
|
+
private applyDrawingLayer;
|
|
101
|
+
private syncOverlayPointerEvents;
|
|
102
|
+
getContainer(): HTMLElement;
|
|
103
|
+
getSymbol(): string;
|
|
104
|
+
getInterval(): Interval;
|
|
105
|
+
searchSymbols(query: string): Promise<_coderyo_data.SymbolSearchHit[]>;
|
|
106
|
+
resolveSymbol(symbol: string): Promise<_coderyo_data.SymbolInfo | null>;
|
|
107
|
+
on(event: ChartEvent, handler: EventHandler): this;
|
|
108
|
+
off(event: ChartEvent, handler: EventHandler): this;
|
|
109
|
+
resize(size?: {
|
|
110
|
+
width?: number;
|
|
111
|
+
height?: number;
|
|
112
|
+
}): this;
|
|
113
|
+
setDrawingTool(tool: _coderyo_drawings.DrawingTool): this;
|
|
114
|
+
deleteSelectedDrawing(): boolean;
|
|
115
|
+
copySelectedDrawing(): DrawingRecord | null;
|
|
116
|
+
toggleLockSelectedDrawing(): boolean;
|
|
117
|
+
updateSelectedDrawingStyle(patch: DrawingStyleMeta): void;
|
|
118
|
+
deselectDrawing(): void;
|
|
119
|
+
setIndicatorConfig(config: IndicatorConfig | null): void;
|
|
120
|
+
setReturnToCursorAfterDraw(v: boolean): void;
|
|
121
|
+
setSymbol(symbol: string): Promise<void>;
|
|
122
|
+
setInterval(interval: Interval): Promise<void>;
|
|
123
|
+
setTheme(theme: 'dark' | 'light'): this;
|
|
124
|
+
setShowGrid(show: boolean): this;
|
|
125
|
+
fitContent(): this;
|
|
126
|
+
scrollToRealtime(): this;
|
|
127
|
+
setLogScale(enabled: boolean): this;
|
|
128
|
+
setFullscreen(_enabled: boolean): this;
|
|
129
|
+
exportImage(opts?: {
|
|
130
|
+
pixelRatio?: number;
|
|
131
|
+
}): Promise<Blob>;
|
|
132
|
+
destroy(): void;
|
|
133
|
+
private beginDataContextChange;
|
|
134
|
+
private isLoadGenerationCurrent;
|
|
135
|
+
private bootstrap;
|
|
136
|
+
private teardownSubscription;
|
|
137
|
+
private maybeLoadMore;
|
|
138
|
+
private refreshRender;
|
|
139
|
+
private emit;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
declare const TRADVIEW_API_VERSION: 1;
|
|
143
|
+
interface WireChartBridgeOptions {
|
|
144
|
+
controller: ChartController;
|
|
145
|
+
chart: IChart;
|
|
146
|
+
bridge: BridgeAdapter;
|
|
147
|
+
chartId?: string;
|
|
148
|
+
/** Allowlist of outbound bridge events; default all mapped events. */
|
|
149
|
+
outboundEvents?: BridgeOutboundType[];
|
|
150
|
+
crosshairThrottleMs?: number;
|
|
151
|
+
}
|
|
152
|
+
declare function wireChartBridge(opts: WireChartBridgeOptions): () => void;
|
|
153
|
+
|
|
154
|
+
/** Synced by scripts/sync-versions.mjs from repo VERSION file */
|
|
155
|
+
declare const TRADVIEW_VERSION: "1.0.0-rc.2";
|
|
156
|
+
|
|
157
|
+
/** Playground / docs: opt-in full TV-like chart features. */
|
|
158
|
+
declare function createDemoChartFeatures(opts: {
|
|
159
|
+
indicatorConfig?: IndicatorConfig;
|
|
160
|
+
returnToCursorAfterDraw?: boolean;
|
|
161
|
+
}): ChartFeatures;
|
|
162
|
+
declare function createDemoChartOptions(base: Pick<ChartOptions, 'dataProvider' | 'indicatorHost' | 'symbolResolver' | 'chartId'> & {
|
|
163
|
+
symbol: string;
|
|
164
|
+
interval: Interval;
|
|
165
|
+
theme?: 'dark' | 'light';
|
|
166
|
+
showGrid?: boolean;
|
|
167
|
+
indicatorConfig?: IndicatorConfig;
|
|
168
|
+
returnToCursorAfterDraw?: boolean;
|
|
169
|
+
}): ChartOptions;
|
|
170
|
+
|
|
171
|
+
interface CreateChartOptions extends Omit<ChartOptions, 'dataProvider'> {
|
|
172
|
+
dataProvider: DataProvider;
|
|
173
|
+
bridge?: BridgeAdapter;
|
|
174
|
+
chartId?: string;
|
|
175
|
+
/** If set, only these bridge outbound events are posted. */
|
|
176
|
+
bridgeOutboundEvents?: BridgeOutboundType[];
|
|
177
|
+
bridgeCrosshairThrottleMs?: number;
|
|
178
|
+
}
|
|
179
|
+
interface IChart {
|
|
180
|
+
setSymbol(symbol: string): IChart;
|
|
181
|
+
setInterval(interval: _coderyo_data.Interval): IChart;
|
|
182
|
+
setTheme(theme: 'dark' | 'light'): IChart;
|
|
183
|
+
setShowGrid(show: boolean): IChart;
|
|
184
|
+
setLogScale(enabled: boolean): IChart;
|
|
185
|
+
fitContent(): IChart;
|
|
186
|
+
scrollToRealtime(): IChart;
|
|
187
|
+
resize(size?: {
|
|
188
|
+
width?: number;
|
|
189
|
+
height?: number;
|
|
190
|
+
}): IChart;
|
|
191
|
+
setFullscreen(enabled: boolean): IChart;
|
|
192
|
+
exportImage(opts?: {
|
|
193
|
+
pixelRatio?: number;
|
|
194
|
+
}): Promise<Blob>;
|
|
195
|
+
on(event: ChartEvent, handler: (p?: unknown) => void): IChart;
|
|
196
|
+
off(event: ChartEvent, handler: (p?: unknown) => void): IChart;
|
|
197
|
+
searchSymbols(query: string): Promise<_coderyo_data.SymbolSearchHit[]>;
|
|
198
|
+
setDrawingTool(tool: _coderyo_drawings.DrawingTool): IChart;
|
|
199
|
+
deleteSelectedDrawing(): boolean;
|
|
200
|
+
copySelectedDrawing(): DrawingRecord | null;
|
|
201
|
+
toggleLockSelectedDrawing(): boolean;
|
|
202
|
+
updateSelectedDrawingStyle(patch: DrawingStyleMeta): void;
|
|
203
|
+
deselectDrawing(): void;
|
|
204
|
+
setIndicatorConfig(config: IndicatorConfig | null): void;
|
|
205
|
+
setReturnToCursorAfterDraw(v: boolean): void;
|
|
206
|
+
setFeatures(patch: ChartFeatures): IChart;
|
|
207
|
+
getFeatures(): ResolvedChartFeatures;
|
|
208
|
+
hasActiveSymbol(): boolean;
|
|
209
|
+
destroy(): void;
|
|
210
|
+
}
|
|
211
|
+
declare function createChart(target: HTMLElement | string, options: CreateChartOptions): IChart;
|
|
212
|
+
|
|
213
|
+
export { ChartController, type ChartEvent, type ChartFeatures, type ChartOptions, type CreateChartOptions, DEFAULT_CHART_FEATURES, type IChart, PENDING_SYMBOL, type ResolvedChartFeatures, TRADVIEW_API_VERSION, TRADVIEW_VERSION, type WireChartBridgeOptions, createChart, createDemoChartFeatures, createDemoChartOptions, resolveChartFeatures, wireChartBridge };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
// src/bridge-wire.ts
|
|
2
|
+
import {
|
|
3
|
+
BRIDGE_SCHEMA_VERSION,
|
|
4
|
+
isBridgeInbound
|
|
5
|
+
} from "@coderyo/bridge";
|
|
6
|
+
|
|
7
|
+
// src/version.ts
|
|
8
|
+
var TRADVIEW_VERSION = "1.0.0-rc.2";
|
|
9
|
+
|
|
10
|
+
// src/bridge-wire.ts
|
|
11
|
+
var TRADVIEW_API_VERSION = 1;
|
|
12
|
+
var CHART_EVENT_TO_BRIDGE = {
|
|
13
|
+
connectionChange: "chart.connectionChange",
|
|
14
|
+
visibleRangeChange: "chart.visibleRange",
|
|
15
|
+
error: "chart.error",
|
|
16
|
+
symbolChange: "chart.symbol",
|
|
17
|
+
intervalChange: "chart.interval",
|
|
18
|
+
crosshairChange: "chart.crosshair",
|
|
19
|
+
destroyed: "chart.destroyed"
|
|
20
|
+
};
|
|
21
|
+
function wireChartBridge(opts) {
|
|
22
|
+
const chartId = opts.chartId ?? `chart-${Date.now()}`;
|
|
23
|
+
const { bridge, chart, controller } = opts;
|
|
24
|
+
const allow = opts.outboundEvents ? new Set(opts.outboundEvents) : null;
|
|
25
|
+
const shouldPost = (type) => allow === null || allow.has(type);
|
|
26
|
+
const post = (type, payload) => {
|
|
27
|
+
if (!shouldPost(type)) return;
|
|
28
|
+
bridge.post({ type, payload });
|
|
29
|
+
};
|
|
30
|
+
post("chart.ready", {
|
|
31
|
+
chartId,
|
|
32
|
+
bridgeSchemaVersion: BRIDGE_SCHEMA_VERSION,
|
|
33
|
+
apiVersion: TRADVIEW_API_VERSION,
|
|
34
|
+
version: TRADVIEW_VERSION
|
|
35
|
+
});
|
|
36
|
+
const postResize = () => {
|
|
37
|
+
const el = controller.getContainer();
|
|
38
|
+
const r = el.getBoundingClientRect();
|
|
39
|
+
post("chart.resize", {
|
|
40
|
+
chartId,
|
|
41
|
+
width: Math.round(r.width),
|
|
42
|
+
height: Math.round(r.height)
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
if (shouldPost("chart.resize")) postResize();
|
|
46
|
+
let crosshairTimer = null;
|
|
47
|
+
let crosshairPending = null;
|
|
48
|
+
const throttleMs = opts.crosshairThrottleMs ?? 0;
|
|
49
|
+
const flushCrosshair = () => {
|
|
50
|
+
crosshairTimer = null;
|
|
51
|
+
const p = crosshairPending;
|
|
52
|
+
crosshairPending = null;
|
|
53
|
+
if (!p) return;
|
|
54
|
+
post("chart.crosshair", {
|
|
55
|
+
chartId,
|
|
56
|
+
time: p.time,
|
|
57
|
+
price: p.price,
|
|
58
|
+
ohlcv: p.ohlcv,
|
|
59
|
+
symbol: controller.getSymbol(),
|
|
60
|
+
interval: controller.getInterval()
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
64
|
+
handlers.set("connectionChange", (state) => {
|
|
65
|
+
post("chart.connectionChange", { chartId, state });
|
|
66
|
+
});
|
|
67
|
+
handlers.set("visibleRangeChange", (range) => {
|
|
68
|
+
const r = range;
|
|
69
|
+
post("chart.visibleRange", { chartId, from: r.from, to: r.to });
|
|
70
|
+
});
|
|
71
|
+
handlers.set("error", (err) => {
|
|
72
|
+
const e = err;
|
|
73
|
+
post("chart.error", {
|
|
74
|
+
chartId,
|
|
75
|
+
code: e?.code ?? "UNKNOWN",
|
|
76
|
+
message: e?.message ?? String(err)
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
handlers.set("symbolChange", (symbol) => {
|
|
80
|
+
post("chart.symbol", { chartId, symbol: String(symbol ?? "") });
|
|
81
|
+
});
|
|
82
|
+
handlers.set("intervalChange", (interval) => {
|
|
83
|
+
post("chart.interval", { chartId, interval: String(interval ?? "") });
|
|
84
|
+
});
|
|
85
|
+
handlers.set("crosshairChange", (payload) => {
|
|
86
|
+
const p = payload;
|
|
87
|
+
if (!p) return;
|
|
88
|
+
if (throttleMs <= 0) {
|
|
89
|
+
post("chart.crosshair", {
|
|
90
|
+
chartId,
|
|
91
|
+
time: p.time,
|
|
92
|
+
price: p.price,
|
|
93
|
+
ohlcv: p.ohlcv,
|
|
94
|
+
symbol: controller.getSymbol(),
|
|
95
|
+
interval: controller.getInterval()
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
crosshairPending = p;
|
|
100
|
+
if (!crosshairTimer) {
|
|
101
|
+
crosshairTimer = setTimeout(flushCrosshair, throttleMs);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
handlers.set("destroyed", () => {
|
|
105
|
+
post("chart.destroyed", { chartId });
|
|
106
|
+
});
|
|
107
|
+
for (const [ev, fn] of handlers) {
|
|
108
|
+
const bridgeType = CHART_EVENT_TO_BRIDGE[ev];
|
|
109
|
+
if (!bridgeType || shouldPost(bridgeType)) {
|
|
110
|
+
chart.on(ev, fn);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const offHost = bridge.onMessage((msg) => {
|
|
114
|
+
if (!isBridgeInbound(msg)) return;
|
|
115
|
+
const p = msg.payload ?? {};
|
|
116
|
+
switch (msg.type) {
|
|
117
|
+
case "host.setSymbol":
|
|
118
|
+
if (typeof p.symbol === "string") chart.setSymbol(p.symbol);
|
|
119
|
+
break;
|
|
120
|
+
case "host.setInterval":
|
|
121
|
+
if (typeof p.interval === "string") chart.setInterval(p.interval);
|
|
122
|
+
break;
|
|
123
|
+
case "host.setTheme":
|
|
124
|
+
if (p.theme === "dark" || p.theme === "light") chart.setTheme(p.theme);
|
|
125
|
+
break;
|
|
126
|
+
case "host.setShowGrid":
|
|
127
|
+
if (typeof p.showGrid === "boolean") chart.setShowGrid(p.showGrid);
|
|
128
|
+
break;
|
|
129
|
+
case "host.fitContent":
|
|
130
|
+
chart.fitContent();
|
|
131
|
+
break;
|
|
132
|
+
case "host.scrollToRealtime":
|
|
133
|
+
chart.scrollToRealtime();
|
|
134
|
+
break;
|
|
135
|
+
case "host.resize":
|
|
136
|
+
chart.resize({
|
|
137
|
+
width: typeof p.width === "number" ? p.width : void 0,
|
|
138
|
+
height: typeof p.height === "number" ? p.height : void 0
|
|
139
|
+
});
|
|
140
|
+
postResize();
|
|
141
|
+
break;
|
|
142
|
+
case "host.destroy":
|
|
143
|
+
chart.destroy();
|
|
144
|
+
break;
|
|
145
|
+
default:
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
return () => {
|
|
150
|
+
if (crosshairTimer) clearTimeout(crosshairTimer);
|
|
151
|
+
offHost();
|
|
152
|
+
for (const [ev, fn] of handlers) chart.off(ev, fn);
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/chart-controller.ts
|
|
157
|
+
import { parseInterval } from "@coderyo/data";
|
|
158
|
+
import { BarStore } from "@coderyo/series";
|
|
159
|
+
import { VirtualWindow } from "@coderyo/virtual-window";
|
|
160
|
+
import { DrawingManager } from "@coderyo/drawings";
|
|
161
|
+
import { PaneOrchestrator } from "@coderyo/renderer-lite";
|
|
162
|
+
|
|
163
|
+
// src/chart-features.ts
|
|
164
|
+
var DEFAULT_CHART_FEATURES = {
|
|
165
|
+
fetchPolicy: "lazy-left-only",
|
|
166
|
+
streamMode: "bar",
|
|
167
|
+
gaps: { whitespace: false, fillVisibleHoles: false },
|
|
168
|
+
drawings: { layer: false, persist: true },
|
|
169
|
+
indicators: null,
|
|
170
|
+
indicatorPersist: false,
|
|
171
|
+
pineEnabled: false,
|
|
172
|
+
protobuf: false,
|
|
173
|
+
telemetry: false,
|
|
174
|
+
tickStream: false
|
|
175
|
+
};
|
|
176
|
+
function resolveChartFeatures(partial) {
|
|
177
|
+
const d = DEFAULT_CHART_FEATURES;
|
|
178
|
+
return {
|
|
179
|
+
fetchPolicy: partial?.fetchPolicy ?? d.fetchPolicy,
|
|
180
|
+
streamMode: partial?.streamMode ?? d.streamMode,
|
|
181
|
+
gaps: {
|
|
182
|
+
whitespace: partial?.gaps?.whitespace ?? d.gaps.whitespace,
|
|
183
|
+
fillVisibleHoles: partial?.gaps?.fillVisibleHoles ?? d.gaps.fillVisibleHoles
|
|
184
|
+
},
|
|
185
|
+
drawings: {
|
|
186
|
+
layer: partial?.drawings?.layer ?? d.drawings.layer,
|
|
187
|
+
persist: partial?.drawings?.persist ?? d.drawings.persist
|
|
188
|
+
},
|
|
189
|
+
indicators: partial?.indicators !== void 0 ? partial.indicators : d.indicators,
|
|
190
|
+
indicatorPersist: partial?.indicatorPersist ?? d.indicatorPersist,
|
|
191
|
+
pineEnabled: partial?.pineEnabled ?? d.pineEnabled,
|
|
192
|
+
protobuf: partial?.protobuf ?? d.protobuf,
|
|
193
|
+
telemetry: partial?.telemetry ?? d.telemetry,
|
|
194
|
+
tickStream: partial?.tickStream ?? d.tickStream
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function mergeChartFeatures(current, patch) {
|
|
198
|
+
return resolveChartFeatures({
|
|
199
|
+
fetchPolicy: patch.fetchPolicy ?? current.fetchPolicy,
|
|
200
|
+
streamMode: patch.streamMode ?? current.streamMode,
|
|
201
|
+
gaps: { ...current.gaps, ...patch.gaps },
|
|
202
|
+
drawings: { ...current.drawings, ...patch.drawings },
|
|
203
|
+
indicators: patch.indicators !== void 0 ? patch.indicators : current.indicators,
|
|
204
|
+
indicatorPersist: patch.indicatorPersist ?? current.indicatorPersist,
|
|
205
|
+
pineEnabled: patch.pineEnabled ?? current.pineEnabled,
|
|
206
|
+
protobuf: patch.protobuf ?? current.protobuf,
|
|
207
|
+
telemetry: patch.telemetry ?? current.telemetry,
|
|
208
|
+
tickStream: patch.tickStream ?? current.tickStream
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
var PENDING_SYMBOL = "";
|
|
212
|
+
|
|
213
|
+
// src/chart-controller.ts
|
|
214
|
+
var ChartController = class {
|
|
215
|
+
constructor(container, options) {
|
|
216
|
+
this.container = container;
|
|
217
|
+
this.options = options;
|
|
218
|
+
this.features = resolveChartFeatures({
|
|
219
|
+
...options.features,
|
|
220
|
+
fetchPolicy: options.features?.fetchPolicy ?? options.fetchPolicy,
|
|
221
|
+
indicators: options.features?.indicators !== void 0 ? options.features.indicators : options.indicatorConfig !== void 0 ? options.indicatorConfig : void 0
|
|
222
|
+
});
|
|
223
|
+
const symbol = options.symbol?.trim() || PENDING_SYMBOL;
|
|
224
|
+
const interval = parseInterval(options.interval ?? "1h");
|
|
225
|
+
const fetchPolicy = this.features.gaps.fillVisibleHoles ? "fill-visible-holes" : this.features.fetchPolicy;
|
|
226
|
+
this.store = new BarStore(symbol || PENDING_SYMBOL, interval);
|
|
227
|
+
this.virtualWindow = new VirtualWindow(this.store, { fetchPolicy });
|
|
228
|
+
this.orchestrator = new PaneOrchestrator({
|
|
229
|
+
container,
|
|
230
|
+
indicatorRoot: options.indicatorHost,
|
|
231
|
+
theme: options.theme ?? "dark",
|
|
232
|
+
scaleMode: options.scaleMode ?? "linear",
|
|
233
|
+
showGrid: options.showGrid ?? false,
|
|
234
|
+
indicatorConfig: this.features.indicators
|
|
235
|
+
});
|
|
236
|
+
if (options.width) container.style.width = `${options.width}px`;
|
|
237
|
+
if (options.height) container.style.height = `${options.height}px`;
|
|
238
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
239
|
+
if (!this.destroyed) this.resize();
|
|
240
|
+
});
|
|
241
|
+
this.resizeObserver.observe(container);
|
|
242
|
+
this.orchestrator.bus.subscribeTransform(() => {
|
|
243
|
+
const bus = this.orchestrator.bus;
|
|
244
|
+
if (bus.visibleToMs > bus.visibleFromMs) {
|
|
245
|
+
this.virtualWindow.setVisibleRange({
|
|
246
|
+
fromMs: bus.visibleFromMs,
|
|
247
|
+
toMs: bus.visibleToMs
|
|
248
|
+
});
|
|
249
|
+
this.visibleRangeInitialized = true;
|
|
250
|
+
}
|
|
251
|
+
void this.maybeLoadMore();
|
|
252
|
+
this.drawingManager?.redraw();
|
|
253
|
+
});
|
|
254
|
+
const overlay = this.orchestrator.getOverlayCanvas();
|
|
255
|
+
if (overlay) {
|
|
256
|
+
this.orchestrator.setOverlayPointerEvents("none");
|
|
257
|
+
this.drawingManager = new DrawingManager({
|
|
258
|
+
canvas: overlay,
|
|
259
|
+
interactionHost: overlay.parentElement ?? void 0,
|
|
260
|
+
chartId: options.chartId ?? "default",
|
|
261
|
+
symbol,
|
|
262
|
+
interval,
|
|
263
|
+
priceToY: (p) => this.orchestrator.priceToY(p),
|
|
264
|
+
timeToX: (t) => this.orchestrator.timeToX(t),
|
|
265
|
+
xToTime: (x) => this.orchestrator.xToTime(x),
|
|
266
|
+
yToPrice: (y) => this.orchestrator.yToPrice(y),
|
|
267
|
+
returnToCursorAfterDraw: options.drawingDefaults?.returnToCursorAfterDraw ?? false,
|
|
268
|
+
onRequestCursorTool: () => this.emit("requestCursorTool"),
|
|
269
|
+
onSelectionChange: (id, record) => this.emit("drawingSelectionChange", { id, record }),
|
|
270
|
+
onContextMenu: (payload) => this.emit("drawingContextMenu", payload)
|
|
271
|
+
});
|
|
272
|
+
this.drawingManager.setPersistence(this.features.drawings.persist);
|
|
273
|
+
this.applyDrawingLayer();
|
|
274
|
+
}
|
|
275
|
+
this.offCrosshair = this.orchestrator.subscribeCrosshair((payload) => {
|
|
276
|
+
this.emit("crosshairChange", payload);
|
|
277
|
+
});
|
|
278
|
+
if (this.hasActiveSymbol()) {
|
|
279
|
+
void this.bootstrap(this.loadGeneration);
|
|
280
|
+
} else {
|
|
281
|
+
this.emit("connectionChange", "disconnected");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
container;
|
|
285
|
+
options;
|
|
286
|
+
store;
|
|
287
|
+
virtualWindow;
|
|
288
|
+
orchestrator;
|
|
289
|
+
handlers = /* @__PURE__ */ new Map();
|
|
290
|
+
subscriptionId = null;
|
|
291
|
+
destroyed = false;
|
|
292
|
+
resizeObserver;
|
|
293
|
+
loadingMore = false;
|
|
294
|
+
visibleRangeInitialized = false;
|
|
295
|
+
/** Bumped on symbol/interval change to drop stale bootstrap / loadMore / WS merges. */
|
|
296
|
+
loadGeneration = 0;
|
|
297
|
+
drawingManager = null;
|
|
298
|
+
offCrosshair = null;
|
|
299
|
+
features;
|
|
300
|
+
getFeatures() {
|
|
301
|
+
return { ...this.features };
|
|
302
|
+
}
|
|
303
|
+
setFeatures(patch) {
|
|
304
|
+
this.features = mergeChartFeatures(this.features, patch);
|
|
305
|
+
this.applyFeatures();
|
|
306
|
+
this.emit("featuresChange", this.getFeatures());
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
hasActiveSymbol() {
|
|
310
|
+
const s = this.store.symbol;
|
|
311
|
+
return s.length > 0 && s !== PENDING_SYMBOL;
|
|
312
|
+
}
|
|
313
|
+
applyFeatures() {
|
|
314
|
+
const fetchPolicy = this.features.gaps.fillVisibleHoles ? "fill-visible-holes" : this.features.fetchPolicy;
|
|
315
|
+
this.virtualWindow.setFetchPolicy(fetchPolicy);
|
|
316
|
+
this.orchestrator.setIndicatorConfig(this.features.indicators);
|
|
317
|
+
this.drawingManager?.setPersistence(this.features.drawings.persist);
|
|
318
|
+
this.applyDrawingLayer();
|
|
319
|
+
}
|
|
320
|
+
applyDrawingLayer() {
|
|
321
|
+
if (!this.drawingManager) return;
|
|
322
|
+
this.drawingManager.setLayerVisible(this.features.drawings.layer);
|
|
323
|
+
this.syncOverlayPointerEvents();
|
|
324
|
+
}
|
|
325
|
+
syncOverlayPointerEvents() {
|
|
326
|
+
if (!this.drawingManager) return;
|
|
327
|
+
const layer = this.features.drawings.layer;
|
|
328
|
+
if (!layer) {
|
|
329
|
+
this.orchestrator.setOverlayPointerEvents("none");
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const tool = this.drawingManager.getTool();
|
|
333
|
+
this.orchestrator.setOverlayPointerEvents(tool === "cursor" ? "none" : "auto");
|
|
334
|
+
}
|
|
335
|
+
getContainer() {
|
|
336
|
+
return this.container;
|
|
337
|
+
}
|
|
338
|
+
getSymbol() {
|
|
339
|
+
return this.store.symbol;
|
|
340
|
+
}
|
|
341
|
+
getInterval() {
|
|
342
|
+
return this.store.interval;
|
|
343
|
+
}
|
|
344
|
+
async searchSymbols(query) {
|
|
345
|
+
const resolver = this.options.symbolResolver;
|
|
346
|
+
if (resolver?.search) return resolver.search(query);
|
|
347
|
+
if (this.options.dataProvider.searchSymbols) {
|
|
348
|
+
return this.options.dataProvider.searchSymbols(query);
|
|
349
|
+
}
|
|
350
|
+
return [];
|
|
351
|
+
}
|
|
352
|
+
async resolveSymbol(symbol) {
|
|
353
|
+
if (this.options.symbolResolver) {
|
|
354
|
+
return this.options.symbolResolver.resolve(symbol);
|
|
355
|
+
}
|
|
356
|
+
return { symbol };
|
|
357
|
+
}
|
|
358
|
+
on(event, handler) {
|
|
359
|
+
if (!this.handlers.has(event)) this.handlers.set(event, /* @__PURE__ */ new Set());
|
|
360
|
+
this.handlers.get(event).add(handler);
|
|
361
|
+
return this;
|
|
362
|
+
}
|
|
363
|
+
off(event, handler) {
|
|
364
|
+
this.handlers.get(event)?.delete(handler);
|
|
365
|
+
return this;
|
|
366
|
+
}
|
|
367
|
+
resize(size) {
|
|
368
|
+
if (size?.width) this.container.style.width = `${size.width}px`;
|
|
369
|
+
if (size?.height) this.container.style.height = `${size.height}px`;
|
|
370
|
+
this.orchestrator.resize();
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
setDrawingTool(tool) {
|
|
374
|
+
this.drawingManager?.setTool(tool);
|
|
375
|
+
this.syncOverlayPointerEvents();
|
|
376
|
+
return this;
|
|
377
|
+
}
|
|
378
|
+
deleteSelectedDrawing() {
|
|
379
|
+
return this.drawingManager?.deleteSelected() ?? false;
|
|
380
|
+
}
|
|
381
|
+
copySelectedDrawing() {
|
|
382
|
+
return this.drawingManager?.copySelected() ?? null;
|
|
383
|
+
}
|
|
384
|
+
toggleLockSelectedDrawing() {
|
|
385
|
+
return this.drawingManager?.toggleLockSelected() ?? false;
|
|
386
|
+
}
|
|
387
|
+
updateSelectedDrawingStyle(patch) {
|
|
388
|
+
this.drawingManager?.updateSelectedStyle(patch);
|
|
389
|
+
}
|
|
390
|
+
deselectDrawing() {
|
|
391
|
+
this.drawingManager?.deselect();
|
|
392
|
+
}
|
|
393
|
+
setIndicatorConfig(config) {
|
|
394
|
+
this.features = mergeChartFeatures(this.features, { indicators: config });
|
|
395
|
+
this.orchestrator.setIndicatorConfig(config);
|
|
396
|
+
this.emit("featuresChange", this.getFeatures());
|
|
397
|
+
}
|
|
398
|
+
setReturnToCursorAfterDraw(v) {
|
|
399
|
+
this.drawingManager?.setReturnToCursorAfterDraw(v);
|
|
400
|
+
}
|
|
401
|
+
async setSymbol(symbol) {
|
|
402
|
+
const trimmed = symbol.trim();
|
|
403
|
+
if (!trimmed) return;
|
|
404
|
+
const gen = this.beginDataContextChange();
|
|
405
|
+
await this.teardownSubscription();
|
|
406
|
+
await this.store.setSymbolInterval(trimmed, this.store.interval);
|
|
407
|
+
this.drawingManager?.setContext(symbol, this.store.interval);
|
|
408
|
+
const info = await this.resolveSymbol(symbol);
|
|
409
|
+
await this.bootstrap(gen);
|
|
410
|
+
this.emit("symbolChange", info ?? { symbol });
|
|
411
|
+
}
|
|
412
|
+
async setInterval(interval) {
|
|
413
|
+
const gen = this.beginDataContextChange();
|
|
414
|
+
await this.teardownSubscription();
|
|
415
|
+
await this.store.setSymbolInterval(this.store.symbol, interval);
|
|
416
|
+
this.drawingManager?.setContext(this.store.symbol, interval);
|
|
417
|
+
if (this.hasActiveSymbol()) {
|
|
418
|
+
await this.bootstrap(gen);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
setTheme(theme) {
|
|
422
|
+
this.orchestrator.setTheme(theme);
|
|
423
|
+
return this;
|
|
424
|
+
}
|
|
425
|
+
setShowGrid(show) {
|
|
426
|
+
this.orchestrator.setShowGrid(show);
|
|
427
|
+
return this;
|
|
428
|
+
}
|
|
429
|
+
fitContent() {
|
|
430
|
+
this.orchestrator.fitContent();
|
|
431
|
+
return this;
|
|
432
|
+
}
|
|
433
|
+
scrollToRealtime() {
|
|
434
|
+
this.orchestrator.scrollToRealtime();
|
|
435
|
+
return this;
|
|
436
|
+
}
|
|
437
|
+
setLogScale(enabled) {
|
|
438
|
+
this.orchestrator.setLogScale(enabled);
|
|
439
|
+
return this;
|
|
440
|
+
}
|
|
441
|
+
setFullscreen(_enabled) {
|
|
442
|
+
if (_enabled && this.container.requestFullscreen) {
|
|
443
|
+
void this.container.requestFullscreen();
|
|
444
|
+
} else if (document.fullscreenElement) {
|
|
445
|
+
void document.exitFullscreen();
|
|
446
|
+
}
|
|
447
|
+
return this;
|
|
448
|
+
}
|
|
449
|
+
async exportImage(opts) {
|
|
450
|
+
const canvas = this.container.querySelector("canvas");
|
|
451
|
+
if (!canvas) throw new Error("No canvas to export");
|
|
452
|
+
const scale = opts?.pixelRatio ?? 2;
|
|
453
|
+
const exportCanvas = document.createElement("canvas");
|
|
454
|
+
exportCanvas.width = canvas.width * scale;
|
|
455
|
+
exportCanvas.height = canvas.height * scale;
|
|
456
|
+
const ctx = exportCanvas.getContext("2d");
|
|
457
|
+
ctx.scale(scale, scale);
|
|
458
|
+
ctx.drawImage(canvas, 0, 0);
|
|
459
|
+
return new Promise((resolve, reject) => {
|
|
460
|
+
exportCanvas.toBlob((b) => b ? resolve(b) : reject(new Error("export failed")), "image/png");
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
destroy() {
|
|
464
|
+
if (this.destroyed) return;
|
|
465
|
+
this.destroyed = true;
|
|
466
|
+
this.offCrosshair?.();
|
|
467
|
+
this.offCrosshair = null;
|
|
468
|
+
this.resizeObserver.disconnect();
|
|
469
|
+
this.drawingManager?.destroy();
|
|
470
|
+
void this.teardownSubscription();
|
|
471
|
+
this.orchestrator.destroy();
|
|
472
|
+
this.emit("destroyed", { chartId: this.options.chartId ?? "default" });
|
|
473
|
+
this.emit("connectionChange", "disconnected");
|
|
474
|
+
}
|
|
475
|
+
beginDataContextChange() {
|
|
476
|
+
this.loadGeneration += 1;
|
|
477
|
+
this.visibleRangeInitialized = false;
|
|
478
|
+
this.virtualWindow.setVisibleRange({ fromMs: 0, toMs: 0 });
|
|
479
|
+
this.orchestrator.resetViewState();
|
|
480
|
+
this.orchestrator.clearBars();
|
|
481
|
+
return this.loadGeneration;
|
|
482
|
+
}
|
|
483
|
+
isLoadGenerationCurrent(gen) {
|
|
484
|
+
return !this.destroyed && gen === this.loadGeneration;
|
|
485
|
+
}
|
|
486
|
+
async bootstrap(loadGen) {
|
|
487
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
488
|
+
const symbol = this.store.symbol;
|
|
489
|
+
const interval = this.store.interval;
|
|
490
|
+
const endTime = Date.now();
|
|
491
|
+
const history = await this.options.dataProvider.getHistory({
|
|
492
|
+
mode: "loadMore",
|
|
493
|
+
symbol,
|
|
494
|
+
interval,
|
|
495
|
+
endTime,
|
|
496
|
+
limit: 500
|
|
497
|
+
});
|
|
498
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
499
|
+
if (this.store.symbol !== symbol || this.store.interval !== interval) return;
|
|
500
|
+
await this.store.mergeBars(history.bars.map((bar) => ({ bar })));
|
|
501
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
502
|
+
this.refreshRender(loadGen);
|
|
503
|
+
void this.resolveSymbol(symbol).then((info) => {
|
|
504
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
505
|
+
this.emit("symbolChange", info ?? { symbol });
|
|
506
|
+
});
|
|
507
|
+
this.emit("intervalChange", interval);
|
|
508
|
+
const streamMode = this.features.tickStream ? "bar+tick" : this.features.streamMode;
|
|
509
|
+
const params = {
|
|
510
|
+
symbol,
|
|
511
|
+
interval,
|
|
512
|
+
channels: this.features.tickStream ? ["bar", "tick"] : ["bar"],
|
|
513
|
+
streamMode
|
|
514
|
+
};
|
|
515
|
+
await this.options.dataProvider.connect?.();
|
|
516
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
517
|
+
const sub = await this.options.dataProvider.subscribe(params, {
|
|
518
|
+
onBar: (bar, meta) => {
|
|
519
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
520
|
+
if (this.store.symbol !== symbol || this.store.interval !== interval) return;
|
|
521
|
+
void this.store.mergeRealtime({
|
|
522
|
+
bar,
|
|
523
|
+
partial: meta.partial
|
|
524
|
+
}).then(() => this.refreshRender(loadGen));
|
|
525
|
+
this.emit("barUpdate", bar);
|
|
526
|
+
},
|
|
527
|
+
onConnectionChange: (state) => this.emit("connectionChange", state),
|
|
528
|
+
onError: (err) => this.emit("error", err)
|
|
529
|
+
});
|
|
530
|
+
if (!this.isLoadGenerationCurrent(loadGen)) {
|
|
531
|
+
await this.options.dataProvider.unsubscribe(sub.id);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
this.subscriptionId = sub.id;
|
|
535
|
+
}
|
|
536
|
+
async teardownSubscription() {
|
|
537
|
+
if (this.subscriptionId) {
|
|
538
|
+
await this.options.dataProvider.unsubscribe(this.subscriptionId);
|
|
539
|
+
this.subscriptionId = null;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
async maybeLoadMore() {
|
|
543
|
+
if (this.destroyed || this.loadingMore) return;
|
|
544
|
+
const loadGen = this.loadGeneration;
|
|
545
|
+
const reqs = this.virtualWindow.planFetches();
|
|
546
|
+
if (reqs.length === 0) return;
|
|
547
|
+
this.loadingMore = true;
|
|
548
|
+
try {
|
|
549
|
+
for (const req of reqs) {
|
|
550
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
551
|
+
const history = await this.options.dataProvider.getHistory(toHistoryQuery(req));
|
|
552
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
553
|
+
if (history.bars.length === 0) continue;
|
|
554
|
+
await this.store.mergeBars(
|
|
555
|
+
history.bars.map((bar) => ({ bar, source: "rest" })),
|
|
556
|
+
req.mode === "loadMore"
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
560
|
+
this.refreshRender(loadGen);
|
|
561
|
+
} catch (err) {
|
|
562
|
+
this.emit("error", err);
|
|
563
|
+
} finally {
|
|
564
|
+
this.loadingMore = false;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
refreshRender(loadGen = this.loadGeneration) {
|
|
568
|
+
if (!this.isLoadGenerationCurrent(loadGen)) return;
|
|
569
|
+
const times = this.store.sortedTimes;
|
|
570
|
+
if (times.length === 0) return;
|
|
571
|
+
if (!this.visibleRangeInitialized) {
|
|
572
|
+
this.virtualWindow.setVisibleRange({
|
|
573
|
+
fromMs: times[0],
|
|
574
|
+
toMs: times[times.length - 1]
|
|
575
|
+
});
|
|
576
|
+
this.visibleRangeInitialized = true;
|
|
577
|
+
}
|
|
578
|
+
const bars = this.virtualWindow.getBarsForRender();
|
|
579
|
+
if (bars.length === 0) return;
|
|
580
|
+
this.orchestrator.setBars(bars);
|
|
581
|
+
this.drawingManager?.redraw();
|
|
582
|
+
this.emit("visibleRangeChange", {
|
|
583
|
+
from: bars[0].t,
|
|
584
|
+
to: bars[bars.length - 1].t
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
emit(event, payload) {
|
|
588
|
+
for (const h of this.handlers.get(event) ?? []) h(payload);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
function toHistoryQuery(req) {
|
|
592
|
+
if (req.mode === "loadMore") {
|
|
593
|
+
return {
|
|
594
|
+
mode: "loadMore",
|
|
595
|
+
symbol: req.symbol,
|
|
596
|
+
interval: req.interval,
|
|
597
|
+
endTime: req.endTime ?? Date.now(),
|
|
598
|
+
limit: req.limit
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
return {
|
|
602
|
+
mode: "range",
|
|
603
|
+
symbol: req.symbol,
|
|
604
|
+
interval: req.interval,
|
|
605
|
+
from: req.fromMs ?? 0,
|
|
606
|
+
to: req.toMs ?? Date.now()
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/demo-presets.ts
|
|
611
|
+
import { DEFAULT_INDICATOR_CONFIG } from "@coderyo/indicators";
|
|
612
|
+
function createDemoChartFeatures(opts) {
|
|
613
|
+
return {
|
|
614
|
+
fetchPolicy: "lazy-left-only",
|
|
615
|
+
streamMode: "bar",
|
|
616
|
+
gaps: { whitespace: false, fillVisibleHoles: false },
|
|
617
|
+
drawings: { layer: true, persist: true },
|
|
618
|
+
indicators: opts.indicatorConfig ?? DEFAULT_INDICATOR_CONFIG,
|
|
619
|
+
indicatorPersist: true
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
function createDemoChartOptions(base) {
|
|
623
|
+
const indicatorConfig = base.indicatorConfig ?? DEFAULT_INDICATOR_CONFIG;
|
|
624
|
+
return {
|
|
625
|
+
...base,
|
|
626
|
+
features: createDemoChartFeatures({
|
|
627
|
+
indicatorConfig,
|
|
628
|
+
returnToCursorAfterDraw: base.returnToCursorAfterDraw
|
|
629
|
+
}),
|
|
630
|
+
indicatorConfig,
|
|
631
|
+
drawingDefaults: { returnToCursorAfterDraw: base.returnToCursorAfterDraw ?? false }
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/create-chart.ts
|
|
636
|
+
function wrap(controller, beforeDestroy) {
|
|
637
|
+
return {
|
|
638
|
+
setSymbol: (s) => {
|
|
639
|
+
void controller.setSymbol(s);
|
|
640
|
+
return wrap(controller, beforeDestroy);
|
|
641
|
+
},
|
|
642
|
+
setInterval: (i) => {
|
|
643
|
+
void controller.setInterval(i);
|
|
644
|
+
return wrap(controller, beforeDestroy);
|
|
645
|
+
},
|
|
646
|
+
setTheme: (t) => {
|
|
647
|
+
controller.setTheme(t);
|
|
648
|
+
return wrap(controller, beforeDestroy);
|
|
649
|
+
},
|
|
650
|
+
setShowGrid: (show) => {
|
|
651
|
+
controller.setShowGrid(show);
|
|
652
|
+
return wrap(controller, beforeDestroy);
|
|
653
|
+
},
|
|
654
|
+
setLogScale: (enabled) => {
|
|
655
|
+
controller.setLogScale(enabled);
|
|
656
|
+
return wrap(controller, beforeDestroy);
|
|
657
|
+
},
|
|
658
|
+
fitContent: () => {
|
|
659
|
+
controller.fitContent();
|
|
660
|
+
return wrap(controller, beforeDestroy);
|
|
661
|
+
},
|
|
662
|
+
scrollToRealtime: () => {
|
|
663
|
+
controller.scrollToRealtime();
|
|
664
|
+
return wrap(controller, beforeDestroy);
|
|
665
|
+
},
|
|
666
|
+
resize: (s) => {
|
|
667
|
+
controller.resize(s);
|
|
668
|
+
return wrap(controller, beforeDestroy);
|
|
669
|
+
},
|
|
670
|
+
setFullscreen: (e) => {
|
|
671
|
+
controller.setFullscreen(e);
|
|
672
|
+
return wrap(controller, beforeDestroy);
|
|
673
|
+
},
|
|
674
|
+
exportImage: (o) => controller.exportImage(o),
|
|
675
|
+
on: (e, h) => {
|
|
676
|
+
controller.on(e, h);
|
|
677
|
+
return wrap(controller, beforeDestroy);
|
|
678
|
+
},
|
|
679
|
+
off: (e, h) => {
|
|
680
|
+
controller.off(e, h);
|
|
681
|
+
return wrap(controller, beforeDestroy);
|
|
682
|
+
},
|
|
683
|
+
searchSymbols: (q) => controller.searchSymbols(q),
|
|
684
|
+
setDrawingTool: (tool) => {
|
|
685
|
+
controller.setDrawingTool(tool);
|
|
686
|
+
return wrap(controller, beforeDestroy);
|
|
687
|
+
},
|
|
688
|
+
deleteSelectedDrawing: () => controller.deleteSelectedDrawing(),
|
|
689
|
+
copySelectedDrawing: () => controller.copySelectedDrawing(),
|
|
690
|
+
toggleLockSelectedDrawing: () => controller.toggleLockSelectedDrawing(),
|
|
691
|
+
updateSelectedDrawingStyle: (p) => {
|
|
692
|
+
controller.updateSelectedDrawingStyle(p);
|
|
693
|
+
return wrap(controller, beforeDestroy);
|
|
694
|
+
},
|
|
695
|
+
deselectDrawing: () => {
|
|
696
|
+
controller.deselectDrawing();
|
|
697
|
+
return wrap(controller, beforeDestroy);
|
|
698
|
+
},
|
|
699
|
+
setIndicatorConfig: (c) => {
|
|
700
|
+
controller.setIndicatorConfig(c);
|
|
701
|
+
return wrap(controller, beforeDestroy);
|
|
702
|
+
},
|
|
703
|
+
setReturnToCursorAfterDraw: (v) => {
|
|
704
|
+
controller.setReturnToCursorAfterDraw(v);
|
|
705
|
+
return wrap(controller, beforeDestroy);
|
|
706
|
+
},
|
|
707
|
+
setFeatures: (patch) => {
|
|
708
|
+
controller.setFeatures(patch);
|
|
709
|
+
return wrap(controller, beforeDestroy);
|
|
710
|
+
},
|
|
711
|
+
getFeatures: () => controller.getFeatures(),
|
|
712
|
+
hasActiveSymbol: () => controller.hasActiveSymbol(),
|
|
713
|
+
destroy: () => {
|
|
714
|
+
controller.destroy();
|
|
715
|
+
beforeDestroy?.();
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
function createChart(target, options) {
|
|
720
|
+
const el = typeof target === "string" ? document.querySelector(target) : target;
|
|
721
|
+
if (!el) throw new Error("Chart container not found");
|
|
722
|
+
const controller = new ChartController(el, options);
|
|
723
|
+
let bridgeTeardown;
|
|
724
|
+
const chart = wrap(controller, () => bridgeTeardown?.());
|
|
725
|
+
if (options.bridge) {
|
|
726
|
+
bridgeTeardown = wireChartBridge({
|
|
727
|
+
controller,
|
|
728
|
+
chart,
|
|
729
|
+
bridge: options.bridge,
|
|
730
|
+
chartId: options.chartId,
|
|
731
|
+
outboundEvents: options.bridgeOutboundEvents,
|
|
732
|
+
crosshairThrottleMs: options.bridgeCrosshairThrottleMs
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
return chart;
|
|
736
|
+
}
|
|
737
|
+
export {
|
|
738
|
+
ChartController,
|
|
739
|
+
DEFAULT_CHART_FEATURES,
|
|
740
|
+
PENDING_SYMBOL,
|
|
741
|
+
TRADVIEW_API_VERSION,
|
|
742
|
+
TRADVIEW_VERSION,
|
|
743
|
+
createChart,
|
|
744
|
+
createDemoChartFeatures,
|
|
745
|
+
createDemoChartOptions,
|
|
746
|
+
resolveChartFeatures,
|
|
747
|
+
wireChartBridge
|
|
748
|
+
};
|
|
749
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bridge-wire.ts","../src/version.ts","../src/chart-controller.ts","../src/chart-features.ts","../src/demo-presets.ts","../src/create-chart.ts"],"sourcesContent":["import type { BridgeAdapter } from '@coderyo/bridge';\nimport {\n BRIDGE_SCHEMA_VERSION,\n isBridgeInbound,\n type BridgeInboundType,\n type BridgeOutboundType,\n} from '@coderyo/bridge';\nimport type { Interval } from '@coderyo/data';\nimport type { CrosshairPayload } from '@coderyo/renderer-lite';\nimport type { ChartController, ChartEvent } from './chart-controller.js';\nimport type { IChart } from './create-chart.js';\nimport { TRADVIEW_VERSION } from './version.js';\n\nexport const TRADVIEW_API_VERSION = 1 as const;\n\nconst CHART_EVENT_TO_BRIDGE: Partial<Record<ChartEvent, BridgeOutboundType>> = {\n connectionChange: 'chart.connectionChange',\n visibleRangeChange: 'chart.visibleRange',\n error: 'chart.error',\n symbolChange: 'chart.symbol',\n intervalChange: 'chart.interval',\n crosshairChange: 'chart.crosshair',\n destroyed: 'chart.destroyed',\n};\n\nexport interface WireChartBridgeOptions {\n controller: ChartController;\n chart: IChart;\n bridge: BridgeAdapter;\n chartId?: string;\n /** Allowlist of outbound bridge events; default all mapped events. */\n outboundEvents?: BridgeOutboundType[];\n crosshairThrottleMs?: number;\n}\n\nexport function wireChartBridge(opts: WireChartBridgeOptions): () => void {\n const chartId = opts.chartId ?? `chart-${Date.now()}`;\n const { bridge, chart, controller } = opts;\n const allow = opts.outboundEvents ? new Set(opts.outboundEvents) : null;\n\n const shouldPost = (type: BridgeOutboundType): boolean =>\n allow === null || allow.has(type);\n\n const post = (type: BridgeOutboundType, payload: Record<string, unknown>) => {\n if (!shouldPost(type)) return;\n bridge.post({ type, payload });\n };\n\n post('chart.ready', {\n chartId,\n bridgeSchemaVersion: BRIDGE_SCHEMA_VERSION,\n apiVersion: TRADVIEW_API_VERSION,\n version: TRADVIEW_VERSION,\n });\n\n const postResize = () => {\n const el = controller.getContainer();\n const r = el.getBoundingClientRect();\n post('chart.resize', {\n chartId,\n width: Math.round(r.width),\n height: Math.round(r.height),\n });\n };\n if (shouldPost('chart.resize')) postResize();\n\n let crosshairTimer: ReturnType<typeof setTimeout> | null = null;\n let crosshairPending: CrosshairPayload | null = null;\n const throttleMs = opts.crosshairThrottleMs ?? 0;\n\n const flushCrosshair = () => {\n crosshairTimer = null;\n const p = crosshairPending;\n crosshairPending = null;\n if (!p) return;\n post('chart.crosshair', {\n chartId,\n time: p.time,\n price: p.price,\n ohlcv: p.ohlcv,\n symbol: controller.getSymbol(),\n interval: controller.getInterval(),\n });\n };\n\n const handlers = new Map<ChartEvent, (p?: unknown) => void>();\n\n handlers.set('connectionChange', (state) => {\n post('chart.connectionChange', { chartId, state });\n });\n handlers.set('visibleRangeChange', (range) => {\n const r = range as { from?: number; to?: number };\n post('chart.visibleRange', { chartId, from: r.from, to: r.to });\n });\n handlers.set('error', (err) => {\n const e = err as { code?: string; message?: string };\n post('chart.error', {\n chartId,\n code: e?.code ?? 'UNKNOWN',\n message: e?.message ?? String(err),\n });\n });\n handlers.set('symbolChange', (symbol) => {\n post('chart.symbol', { chartId, symbol: String(symbol ?? '') });\n });\n handlers.set('intervalChange', (interval) => {\n post('chart.interval', { chartId, interval: String(interval ?? '') });\n });\n handlers.set('crosshairChange', (payload) => {\n const p = payload as CrosshairPayload | null;\n if (!p) return;\n if (throttleMs <= 0) {\n post('chart.crosshair', {\n chartId,\n time: p.time,\n price: p.price,\n ohlcv: p.ohlcv,\n symbol: controller.getSymbol(),\n interval: controller.getInterval(),\n });\n return;\n }\n crosshairPending = p;\n if (!crosshairTimer) {\n crosshairTimer = setTimeout(flushCrosshair, throttleMs);\n }\n });\n handlers.set('destroyed', () => {\n post('chart.destroyed', { chartId });\n });\n\n for (const [ev, fn] of handlers) {\n const bridgeType = CHART_EVENT_TO_BRIDGE[ev];\n if (!bridgeType || shouldPost(bridgeType)) {\n chart.on(ev, fn);\n }\n }\n\n const offHost = bridge.onMessage((msg) => {\n if (!isBridgeInbound(msg)) return;\n const p = msg.payload ?? {};\n switch (msg.type as BridgeInboundType) {\n case 'host.setSymbol':\n if (typeof p.symbol === 'string') chart.setSymbol(p.symbol);\n break;\n case 'host.setInterval':\n if (typeof p.interval === 'string') chart.setInterval(p.interval as Interval);\n break;\n case 'host.setTheme':\n if (p.theme === 'dark' || p.theme === 'light') chart.setTheme(p.theme);\n break;\n case 'host.setShowGrid':\n if (typeof p.showGrid === 'boolean') chart.setShowGrid(p.showGrid);\n break;\n case 'host.fitContent':\n chart.fitContent();\n break;\n case 'host.scrollToRealtime':\n chart.scrollToRealtime();\n break;\n case 'host.resize':\n chart.resize({\n width: typeof p.width === 'number' ? p.width : undefined,\n height: typeof p.height === 'number' ? p.height : undefined,\n });\n postResize();\n break;\n case 'host.destroy':\n chart.destroy();\n break;\n default:\n break;\n }\n });\n\n return () => {\n if (crosshairTimer) clearTimeout(crosshairTimer);\n offHost();\n for (const [ev, fn] of handlers) chart.off(ev, fn);\n };\n}","/** Synced by scripts/sync-versions.mjs from repo VERSION file */\nexport const TRADVIEW_VERSION = '1.0.0-rc.2' as const;\n","import type { DrawingRecord, DrawingStyleMeta } from '@coderyo/drawings';\nimport type { IndicatorConfig } from '@coderyo/indicators';\n\nimport type {\n DataProvider,\n HistoryQuery,\n Interval,\n RealtimeStreamMode,\n SubscribeParams,\n SymbolResolver,\n} from '@coderyo/data';\nimport type { HistoryRequest } from '@coderyo/virtual-window';\nimport { parseInterval } from '@coderyo/data';\nimport { BarStore } from '@coderyo/series';\nimport { VirtualWindow, type FetchPolicy } from '@coderyo/virtual-window';\nimport { DrawingManager } from '@coderyo/drawings';\nimport { PaneOrchestrator } from '@coderyo/renderer-lite';\nimport {\n mergeChartFeatures,\n PENDING_SYMBOL,\n resolveChartFeatures,\n type ChartFeatures,\n type ResolvedChartFeatures,\n} from './chart-features.js';\n\nexport interface ChartOptions {\n width?: number;\n height?: number;\n theme?: 'dark' | 'light';\n interval?: Interval;\n /** Omit for empty chart until setSymbol(). */\n symbol?: string;\n chartId?: string;\n /** Host element below main chart for MACD/RSI/KDJ panes (from ui-shell layout). */\n indicatorHost?: HTMLElement;\n dataProvider: DataProvider;\n /** Integrator feature flags (minimal defaults). */\n features?: ChartFeatures;\n /** @deprecated Use features.fetchPolicy */\n fetchPolicy?: FetchPolicy;\n scaleMode?: 'linear' | 'log';\n /** Grid lines on chart panes (default false). */\n showGrid?: boolean;\n symbolResolver?: SymbolResolver;\n drawingDefaults?: { returnToCursorAfterDraw?: boolean };\n /** @deprecated Use features.indicators */\n indicatorConfig?: IndicatorConfig;\n}\n\nexport type ChartEvent =\n | 'connectionChange'\n | 'barUpdate'\n | 'error'\n | 'visibleRangeChange'\n | 'symbolChange'\n | 'intervalChange'\n | 'crosshairChange'\n | 'destroyed'\n | 'drawingSelectionChange'\n | 'drawingContextMenu'\n | 'requestCursorTool'\n | 'featuresChange';\n\ntype EventHandler = (payload?: unknown) => void;\n\nexport class ChartController {\n private readonly store: BarStore;\n private readonly virtualWindow: VirtualWindow;\n private readonly orchestrator: PaneOrchestrator;\n private readonly handlers = new Map<ChartEvent, Set<EventHandler>>();\n private subscriptionId: string | null = null;\n private destroyed = false;\n private readonly resizeObserver: ResizeObserver;\n private loadingMore = false;\n private visibleRangeInitialized = false;\n /** Bumped on symbol/interval change to drop stale bootstrap / loadMore / WS merges. */\n private loadGeneration = 0;\n private drawingManager: DrawingManager | null = null;\n private offCrosshair: (() => void) | null = null;\n private features: ResolvedChartFeatures;\n\n constructor(\n private readonly container: HTMLElement,\n private readonly options: ChartOptions,\n ) {\n this.features = resolveChartFeatures({\n ...options.features,\n fetchPolicy: options.features?.fetchPolicy ?? options.fetchPolicy,\n indicators:\n options.features?.indicators !== undefined\n ? options.features.indicators\n : options.indicatorConfig !== undefined\n ? options.indicatorConfig\n : undefined,\n });\n\n const symbol = options.symbol?.trim() || PENDING_SYMBOL;\n const interval = parseInterval(options.interval ?? '1h');\n const fetchPolicy = this.features.gaps.fillVisibleHoles\n ? 'fill-visible-holes'\n : this.features.fetchPolicy;\n\n this.store = new BarStore(symbol || PENDING_SYMBOL, interval);\n this.virtualWindow = new VirtualWindow(this.store, { fetchPolicy });\n this.orchestrator = new PaneOrchestrator({\n container,\n indicatorRoot: options.indicatorHost,\n theme: options.theme ?? 'dark',\n scaleMode: options.scaleMode ?? 'linear',\n showGrid: options.showGrid ?? false,\n indicatorConfig: this.features.indicators,\n });\n\n if (options.width) container.style.width = `${options.width}px`;\n if (options.height) container.style.height = `${options.height}px`;\n\n this.resizeObserver = new ResizeObserver(() => {\n if (!this.destroyed) this.resize();\n });\n this.resizeObserver.observe(container);\n\n this.orchestrator.bus.subscribeTransform(() => {\n const bus = this.orchestrator.bus;\n if (bus.visibleToMs > bus.visibleFromMs) {\n this.virtualWindow.setVisibleRange({\n fromMs: bus.visibleFromMs,\n toMs: bus.visibleToMs,\n });\n this.visibleRangeInitialized = true;\n }\n void this.maybeLoadMore();\n this.drawingManager?.redraw();\n });\n\n const overlay = this.orchestrator.getOverlayCanvas();\n if (overlay) {\n this.orchestrator.setOverlayPointerEvents('none');\n this.drawingManager = new DrawingManager({\n canvas: overlay,\n interactionHost: overlay.parentElement ?? undefined,\n chartId: options.chartId ?? 'default',\n symbol,\n interval,\n priceToY: (p) => this.orchestrator.priceToY(p),\n timeToX: (t) => this.orchestrator.timeToX(t),\n xToTime: (x) => this.orchestrator.xToTime(x),\n yToPrice: (y) => this.orchestrator.yToPrice(y),\n returnToCursorAfterDraw: options.drawingDefaults?.returnToCursorAfterDraw ?? false,\n onRequestCursorTool: () => this.emit('requestCursorTool'),\n onSelectionChange: (id, record) =>\n this.emit('drawingSelectionChange', { id, record }),\n onContextMenu: (payload) => this.emit('drawingContextMenu', payload),\n });\n this.drawingManager.setPersistence(this.features.drawings.persist);\n this.applyDrawingLayer();\n }\n\n this.offCrosshair = this.orchestrator.subscribeCrosshair((payload) => {\n this.emit('crosshairChange', payload);\n });\n\n if (this.hasActiveSymbol()) {\n void this.bootstrap(this.loadGeneration);\n } else {\n this.emit('connectionChange', 'disconnected');\n }\n }\n\n getFeatures(): ResolvedChartFeatures {\n return { ...this.features };\n }\n\n setFeatures(patch: ChartFeatures): this {\n this.features = mergeChartFeatures(this.features, patch);\n this.applyFeatures();\n this.emit('featuresChange', this.getFeatures());\n return this;\n }\n\n hasActiveSymbol(): boolean {\n const s = this.store.symbol;\n return s.length > 0 && s !== PENDING_SYMBOL;\n }\n\n private applyFeatures(): void {\n const fetchPolicy = this.features.gaps.fillVisibleHoles\n ? 'fill-visible-holes'\n : this.features.fetchPolicy;\n this.virtualWindow.setFetchPolicy(fetchPolicy);\n\n this.orchestrator.setIndicatorConfig(this.features.indicators);\n this.drawingManager?.setPersistence(this.features.drawings.persist);\n this.applyDrawingLayer();\n }\n\n private applyDrawingLayer(): void {\n if (!this.drawingManager) return;\n this.drawingManager.setLayerVisible(this.features.drawings.layer);\n this.syncOverlayPointerEvents();\n }\n\n private syncOverlayPointerEvents(): void {\n if (!this.drawingManager) return;\n const layer = this.features.drawings.layer;\n if (!layer) {\n this.orchestrator.setOverlayPointerEvents('none');\n return;\n }\n const tool = this.drawingManager.getTool();\n this.orchestrator.setOverlayPointerEvents(tool === 'cursor' ? 'none' : 'auto');\n }\n\n getContainer(): HTMLElement {\n return this.container;\n }\n\n getSymbol(): string {\n return this.store.symbol;\n }\n\n getInterval(): Interval {\n return this.store.interval;\n }\n\n async searchSymbols(query: string): Promise<import('@coderyo/data').SymbolSearchHit[]> {\n const resolver = this.options.symbolResolver;\n if (resolver?.search) return resolver.search(query);\n if (this.options.dataProvider.searchSymbols) {\n return this.options.dataProvider.searchSymbols(query);\n }\n return [];\n }\n\n async resolveSymbol(symbol: string): Promise<import('@coderyo/data').SymbolInfo | null> {\n if (this.options.symbolResolver) {\n return this.options.symbolResolver.resolve(symbol);\n }\n return { symbol };\n }\n\n on(event: ChartEvent, handler: EventHandler): this {\n if (!this.handlers.has(event)) this.handlers.set(event, new Set());\n this.handlers.get(event)!.add(handler);\n return this;\n }\n\n off(event: ChartEvent, handler: EventHandler): this {\n this.handlers.get(event)?.delete(handler);\n return this;\n }\n\n resize(size?: { width?: number; height?: number }): this {\n if (size?.width) this.container.style.width = `${size.width}px`;\n if (size?.height) this.container.style.height = `${size.height}px`;\n this.orchestrator.resize();\n return this;\n }\n\n setDrawingTool(tool: import('@coderyo/drawings').DrawingTool): this {\n this.drawingManager?.setTool(tool);\n this.syncOverlayPointerEvents();\n return this;\n }\n\n deleteSelectedDrawing(): boolean {\n return this.drawingManager?.deleteSelected() ?? false;\n }\n\n copySelectedDrawing(): DrawingRecord | null {\n return this.drawingManager?.copySelected() ?? null;\n }\n\n toggleLockSelectedDrawing(): boolean {\n return this.drawingManager?.toggleLockSelected() ?? false;\n }\n\n updateSelectedDrawingStyle(patch: DrawingStyleMeta): void {\n this.drawingManager?.updateSelectedStyle(patch);\n }\n\n deselectDrawing(): void {\n this.drawingManager?.deselect();\n }\n\n setIndicatorConfig(config: IndicatorConfig | null): void {\n this.features = mergeChartFeatures(this.features, { indicators: config });\n this.orchestrator.setIndicatorConfig(config);\n this.emit('featuresChange', this.getFeatures());\n }\n\n setReturnToCursorAfterDraw(v: boolean): void {\n this.drawingManager?.setReturnToCursorAfterDraw(v);\n }\n\n async setSymbol(symbol: string): Promise<void> {\n const trimmed = symbol.trim();\n if (!trimmed) return;\n const gen = this.beginDataContextChange();\n await this.teardownSubscription();\n await this.store.setSymbolInterval(trimmed, this.store.interval);\n this.drawingManager?.setContext(symbol, this.store.interval);\n const info = await this.resolveSymbol(symbol);\n await this.bootstrap(gen);\n this.emit('symbolChange', info ?? { symbol });\n }\n\n async setInterval(interval: Interval): Promise<void> {\n const gen = this.beginDataContextChange();\n await this.teardownSubscription();\n await this.store.setSymbolInterval(this.store.symbol, interval);\n this.drawingManager?.setContext(this.store.symbol, interval);\n if (this.hasActiveSymbol()) {\n await this.bootstrap(gen);\n }\n }\n\n setTheme(theme: 'dark' | 'light'): this {\n this.orchestrator.setTheme(theme);\n return this;\n }\n\n setShowGrid(show: boolean): this {\n this.orchestrator.setShowGrid(show);\n return this;\n }\n\n fitContent(): this {\n this.orchestrator.fitContent();\n return this;\n }\n\n scrollToRealtime(): this {\n this.orchestrator.scrollToRealtime();\n return this;\n }\n\n setLogScale(enabled: boolean): this {\n this.orchestrator.setLogScale(enabled);\n return this;\n }\n\n setFullscreen(_enabled: boolean): this {\n if (_enabled && this.container.requestFullscreen) {\n void this.container.requestFullscreen();\n } else if (document.fullscreenElement) {\n void document.exitFullscreen();\n }\n return this;\n }\n\n async exportImage(opts?: { pixelRatio?: number }): Promise<Blob> {\n const canvas = this.container.querySelector('canvas');\n if (!canvas) throw new Error('No canvas to export');\n const scale = opts?.pixelRatio ?? 2;\n const exportCanvas = document.createElement('canvas');\n exportCanvas.width = canvas.width * scale;\n exportCanvas.height = canvas.height * scale;\n const ctx = exportCanvas.getContext('2d')!;\n ctx.scale(scale, scale);\n ctx.drawImage(canvas, 0, 0);\n return new Promise((resolve, reject) => {\n exportCanvas.toBlob((b) => (b ? resolve(b) : reject(new Error('export failed'))), 'image/png');\n });\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.offCrosshair?.();\n this.offCrosshair = null;\n this.resizeObserver.disconnect();\n this.drawingManager?.destroy();\n void this.teardownSubscription();\n this.orchestrator.destroy();\n this.emit('destroyed', { chartId: this.options.chartId ?? 'default' });\n this.emit('connectionChange', 'disconnected');\n }\n\n private beginDataContextChange(): number {\n this.loadGeneration += 1;\n this.visibleRangeInitialized = false;\n this.virtualWindow.setVisibleRange({ fromMs: 0, toMs: 0 });\n this.orchestrator.resetViewState();\n this.orchestrator.clearBars();\n return this.loadGeneration;\n }\n\n private isLoadGenerationCurrent(gen: number): boolean {\n return !this.destroyed && gen === this.loadGeneration;\n }\n\n private async bootstrap(loadGen: number): Promise<void> {\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n\n const symbol = this.store.symbol;\n const interval = this.store.interval;\n const endTime = Date.now();\n const history = await this.options.dataProvider.getHistory({\n mode: 'loadMore',\n symbol,\n interval,\n endTime,\n limit: 500,\n });\n\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n if (this.store.symbol !== symbol || this.store.interval !== interval) return;\n\n await this.store.mergeBars(history.bars.map((bar) => ({ bar })));\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n this.refreshRender(loadGen);\n void this.resolveSymbol(symbol).then((info) => {\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n this.emit('symbolChange', info ?? { symbol });\n });\n this.emit('intervalChange', interval);\n\n const streamMode: RealtimeStreamMode = this.features.tickStream\n ? 'bar+tick'\n : this.features.streamMode;\n\n const params: SubscribeParams = {\n symbol,\n interval,\n channels: this.features.tickStream ? ['bar', 'tick'] : ['bar'],\n streamMode,\n };\n\n await this.options.dataProvider.connect?.();\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n\n const sub = await this.options.dataProvider.subscribe(params, {\n onBar: (bar, meta) => {\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n if (this.store.symbol !== symbol || this.store.interval !== interval) return;\n void this.store\n .mergeRealtime({\n bar,\n partial: meta.partial,\n })\n .then(() => this.refreshRender(loadGen));\n this.emit('barUpdate', bar);\n },\n onConnectionChange: (state) => this.emit('connectionChange', state),\n onError: (err) => this.emit('error', err),\n });\n if (!this.isLoadGenerationCurrent(loadGen)) {\n await this.options.dataProvider.unsubscribe(sub.id);\n return;\n }\n this.subscriptionId = sub.id;\n }\n\n private async teardownSubscription(): Promise<void> {\n if (this.subscriptionId) {\n await this.options.dataProvider.unsubscribe(this.subscriptionId);\n this.subscriptionId = null;\n }\n }\n\n private async maybeLoadMore(): Promise<void> {\n if (this.destroyed || this.loadingMore) return;\n const loadGen = this.loadGeneration;\n const reqs = this.virtualWindow.planFetches();\n if (reqs.length === 0) return;\n\n this.loadingMore = true;\n try {\n for (const req of reqs) {\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n const history = await this.options.dataProvider.getHistory(toHistoryQuery(req));\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n if (history.bars.length === 0) continue;\n await this.store.mergeBars(\n history.bars.map((bar) => ({ bar, source: 'rest' as const })),\n req.mode === 'loadMore',\n );\n }\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n this.refreshRender(loadGen);\n } catch (err) {\n this.emit('error', err);\n } finally {\n this.loadingMore = false;\n }\n }\n\n private refreshRender(loadGen = this.loadGeneration): void {\n if (!this.isLoadGenerationCurrent(loadGen)) return;\n\n const times = this.store.sortedTimes;\n if (times.length === 0) return;\n\n // Only seed visible range once; resetting to full series each tick triggers spurious loadMore.\n if (!this.visibleRangeInitialized) {\n this.virtualWindow.setVisibleRange({\n fromMs: times[0]!,\n toMs: times[times.length - 1]!,\n });\n this.visibleRangeInitialized = true;\n }\n\n const bars = this.virtualWindow.getBarsForRender();\n if (bars.length === 0) return;\n\n this.orchestrator.setBars(bars);\n this.drawingManager?.redraw();\n this.emit('visibleRangeChange', {\n from: bars[0]!.t,\n to: bars[bars.length - 1]!.t,\n });\n }\n\n private emit(event: ChartEvent, payload?: unknown): void {\n for (const h of this.handlers.get(event) ?? []) h(payload);\n }\n}\n\nfunction toHistoryQuery(req: HistoryRequest): HistoryQuery {\n if (req.mode === 'loadMore') {\n return {\n mode: 'loadMore',\n symbol: req.symbol,\n interval: req.interval,\n endTime: req.endTime ?? Date.now(),\n limit: req.limit,\n };\n }\n return {\n mode: 'range',\n symbol: req.symbol,\n interval: req.interval,\n from: req.fromMs ?? 0,\n to: req.toMs ?? Date.now(),\n };\n}","import type { RealtimeStreamMode } from '@coderyo/data';\nimport type { IndicatorConfig } from '@coderyo/indicators';\nimport type { FetchPolicy } from '@coderyo/virtual-window';\n\nexport interface ChartGapsFeatures {\n whitespace?: boolean;\n fillVisibleHoles?: boolean;\n}\n\nexport interface ChartDrawingsFeatures {\n /** Show interactive drawing overlay (default false). API remains available when false. */\n layer?: boolean;\n /** Persist drawings to localStorage (default true when layer/API used). */\n persist?: boolean;\n}\n\nexport interface ChartFeatures {\n fetchPolicy?: FetchPolicy;\n streamMode?: RealtimeStreamMode;\n gaps?: ChartGapsFeatures;\n drawings?: ChartDrawingsFeatures;\n /** Pass config to enable MA + indicator panes; omit/null = no indicators. */\n indicators?: IndicatorConfig | null;\n /** Save indicator params to storage (default false). */\n indicatorPersist?: boolean;\n /** Post-1.0 hooks — default false, no-op until implemented. */\n pineEnabled?: boolean;\n protobuf?: boolean;\n telemetry?: boolean;\n tickStream?: boolean;\n}\n\nexport interface ResolvedChartFeatures {\n fetchPolicy: FetchPolicy;\n streamMode: RealtimeStreamMode;\n gaps: Required<ChartGapsFeatures>;\n drawings: Required<ChartDrawingsFeatures>;\n indicators: IndicatorConfig | null;\n indicatorPersist: boolean;\n pineEnabled: boolean;\n protobuf: boolean;\n telemetry: boolean;\n tickStream: boolean;\n}\n\nexport const DEFAULT_CHART_FEATURES: ResolvedChartFeatures = {\n fetchPolicy: 'lazy-left-only',\n streamMode: 'bar',\n gaps: { whitespace: false, fillVisibleHoles: false },\n drawings: { layer: false, persist: true },\n indicators: null,\n indicatorPersist: false,\n pineEnabled: false,\n protobuf: false,\n telemetry: false,\n tickStream: false,\n};\n\nexport function resolveChartFeatures(partial?: ChartFeatures): ResolvedChartFeatures {\n const d = DEFAULT_CHART_FEATURES;\n return {\n fetchPolicy: partial?.fetchPolicy ?? d.fetchPolicy,\n streamMode: partial?.streamMode ?? d.streamMode,\n gaps: {\n whitespace: partial?.gaps?.whitespace ?? d.gaps.whitespace,\n fillVisibleHoles: partial?.gaps?.fillVisibleHoles ?? d.gaps.fillVisibleHoles,\n },\n drawings: {\n layer: partial?.drawings?.layer ?? d.drawings.layer,\n persist: partial?.drawings?.persist ?? d.drawings.persist,\n },\n indicators: partial?.indicators !== undefined ? partial.indicators : d.indicators,\n indicatorPersist: partial?.indicatorPersist ?? d.indicatorPersist,\n pineEnabled: partial?.pineEnabled ?? d.pineEnabled,\n protobuf: partial?.protobuf ?? d.protobuf,\n telemetry: partial?.telemetry ?? d.telemetry,\n tickStream: partial?.tickStream ?? d.tickStream,\n };\n}\n\nexport function mergeChartFeatures(\n current: ResolvedChartFeatures,\n patch: ChartFeatures,\n): ResolvedChartFeatures {\n return resolveChartFeatures({\n fetchPolicy: patch.fetchPolicy ?? current.fetchPolicy,\n streamMode: patch.streamMode ?? current.streamMode,\n gaps: { ...current.gaps, ...patch.gaps },\n drawings: { ...current.drawings, ...patch.drawings },\n indicators: patch.indicators !== undefined ? patch.indicators : current.indicators,\n indicatorPersist: patch.indicatorPersist ?? current.indicatorPersist,\n pineEnabled: patch.pineEnabled ?? current.pineEnabled,\n protobuf: patch.protobuf ?? current.protobuf,\n telemetry: patch.telemetry ?? current.telemetry,\n tickStream: patch.tickStream ?? current.tickStream,\n });\n}\n\n/** Empty chart until integrator calls setSymbol. */\nexport const PENDING_SYMBOL = '';","import type { IndicatorConfig } from '@coderyo/indicators';\nimport { DEFAULT_INDICATOR_CONFIG } from '@coderyo/indicators';\nimport type { Interval } from '@coderyo/data';\nimport type { ChartFeatures } from './chart-features.js';\nimport type { ChartOptions } from './chart-controller.js';\n\n/** Playground / docs: opt-in full TV-like chart features. */\nexport function createDemoChartFeatures(opts: {\n indicatorConfig?: IndicatorConfig;\n returnToCursorAfterDraw?: boolean;\n}): ChartFeatures {\n return {\n fetchPolicy: 'lazy-left-only',\n streamMode: 'bar',\n gaps: { whitespace: false, fillVisibleHoles: false },\n drawings: { layer: true, persist: true },\n indicators: opts.indicatorConfig ?? DEFAULT_INDICATOR_CONFIG,\n indicatorPersist: true,\n };\n}\n\nexport function createDemoChartOptions(\n base: Pick<ChartOptions, 'dataProvider' | 'indicatorHost' | 'symbolResolver' | 'chartId'> & {\n symbol: string;\n interval: Interval;\n theme?: 'dark' | 'light';\n showGrid?: boolean;\n indicatorConfig?: IndicatorConfig;\n returnToCursorAfterDraw?: boolean;\n },\n): ChartOptions {\n const indicatorConfig = base.indicatorConfig ?? DEFAULT_INDICATOR_CONFIG;\n return {\n ...base,\n features: createDemoChartFeatures({\n indicatorConfig,\n returnToCursorAfterDraw: base.returnToCursorAfterDraw,\n }),\n indicatorConfig,\n drawingDefaults: { returnToCursorAfterDraw: base.returnToCursorAfterDraw ?? false },\n };\n}","import type { BridgeAdapter } from '@coderyo/bridge';\nimport type { BridgeOutboundType } from '@coderyo/bridge';\nimport type { DrawingRecord, DrawingStyleMeta } from '@coderyo/drawings';\nimport type { IndicatorConfig } from '@coderyo/indicators';\nimport type { DataProvider } from '@coderyo/data';\nimport { wireChartBridge, TRADVIEW_API_VERSION } from './bridge-wire.js';\nimport { ChartController, type ChartOptions } from './chart-controller.js';\nimport type { ChartFeatures, ResolvedChartFeatures } from './chart-features.js';\nimport { TRADVIEW_VERSION } from './version.js';\n\nexport { TRADVIEW_API_VERSION, TRADVIEW_VERSION };\nexport type { ChartFeatures, ResolvedChartFeatures } from './chart-features.js';\nexport { resolveChartFeatures, DEFAULT_CHART_FEATURES, PENDING_SYMBOL } from './chart-features.js';\nexport { createDemoChartFeatures, createDemoChartOptions } from './demo-presets.js';\n\nexport interface CreateChartOptions extends Omit<ChartOptions, 'dataProvider'> {\n dataProvider: DataProvider;\n bridge?: BridgeAdapter;\n chartId?: string;\n /** If set, only these bridge outbound events are posted. */\n bridgeOutboundEvents?: BridgeOutboundType[];\n bridgeCrosshairThrottleMs?: number;\n}\n\nexport interface IChart {\n setSymbol(symbol: string): IChart;\n setInterval(interval: import('@coderyo/data').Interval): IChart;\n setTheme(theme: 'dark' | 'light'): IChart;\n setShowGrid(show: boolean): IChart;\n setLogScale(enabled: boolean): IChart;\n fitContent(): IChart;\n scrollToRealtime(): IChart;\n resize(size?: { width?: number; height?: number }): IChart;\n setFullscreen(enabled: boolean): IChart;\n exportImage(opts?: { pixelRatio?: number }): Promise<Blob>;\n on(event: import('./chart-controller.js').ChartEvent, handler: (p?: unknown) => void): IChart;\n off(event: import('./chart-controller.js').ChartEvent, handler: (p?: unknown) => void): IChart;\n searchSymbols(query: string): Promise<import('@coderyo/data').SymbolSearchHit[]>;\n setDrawingTool(tool: import('@coderyo/drawings').DrawingTool): IChart;\n deleteSelectedDrawing(): boolean;\n copySelectedDrawing(): DrawingRecord | null;\n toggleLockSelectedDrawing(): boolean;\n updateSelectedDrawingStyle(patch: DrawingStyleMeta): void;\n deselectDrawing(): void;\n setIndicatorConfig(config: IndicatorConfig | null): void;\n setReturnToCursorAfterDraw(v: boolean): void;\n setFeatures(patch: ChartFeatures): IChart;\n getFeatures(): ResolvedChartFeatures;\n hasActiveSymbol(): boolean;\n destroy(): void;\n}\n\nfunction wrap(controller: ChartController, beforeDestroy?: () => void): IChart {\n return {\n setSymbol: (s) => {\n void controller.setSymbol(s);\n return wrap(controller, beforeDestroy);\n },\n setInterval: (i) => {\n void controller.setInterval(i);\n return wrap(controller, beforeDestroy);\n },\n setTheme: (t) => {\n controller.setTheme(t);\n return wrap(controller, beforeDestroy);\n },\n setShowGrid: (show) => {\n controller.setShowGrid(show);\n return wrap(controller, beforeDestroy);\n },\n setLogScale: (enabled) => {\n controller.setLogScale(enabled);\n return wrap(controller, beforeDestroy);\n },\n fitContent: () => {\n controller.fitContent();\n return wrap(controller, beforeDestroy);\n },\n scrollToRealtime: () => {\n controller.scrollToRealtime();\n return wrap(controller, beforeDestroy);\n },\n resize: (s) => {\n controller.resize(s);\n return wrap(controller, beforeDestroy);\n },\n setFullscreen: (e) => {\n controller.setFullscreen(e);\n return wrap(controller, beforeDestroy);\n },\n exportImage: (o) => controller.exportImage(o),\n on: (e, h) => {\n controller.on(e, h);\n return wrap(controller, beforeDestroy);\n },\n off: (e, h) => {\n controller.off(e, h);\n return wrap(controller, beforeDestroy);\n },\n searchSymbols: (q) => controller.searchSymbols(q),\n setDrawingTool: (tool) => {\n controller.setDrawingTool(tool);\n return wrap(controller, beforeDestroy);\n },\n deleteSelectedDrawing: () => controller.deleteSelectedDrawing(),\n copySelectedDrawing: () => controller.copySelectedDrawing(),\n toggleLockSelectedDrawing: () => controller.toggleLockSelectedDrawing(),\n updateSelectedDrawingStyle: (p) => {\n controller.updateSelectedDrawingStyle(p);\n return wrap(controller, beforeDestroy);\n },\n deselectDrawing: () => {\n controller.deselectDrawing();\n return wrap(controller, beforeDestroy);\n },\n setIndicatorConfig: (c) => {\n controller.setIndicatorConfig(c);\n return wrap(controller, beforeDestroy);\n },\n setReturnToCursorAfterDraw: (v) => {\n controller.setReturnToCursorAfterDraw(v);\n return wrap(controller, beforeDestroy);\n },\n setFeatures: (patch) => {\n controller.setFeatures(patch);\n return wrap(controller, beforeDestroy);\n },\n getFeatures: () => controller.getFeatures(),\n hasActiveSymbol: () => controller.hasActiveSymbol(),\n destroy: () => {\n controller.destroy();\n beforeDestroy?.();\n },\n };\n}\n\nexport function createChart(\n target: HTMLElement | string,\n options: CreateChartOptions,\n): IChart {\n const el =\n typeof target === 'string'\n ? (document.querySelector(target) as HTMLElement | null)\n : target;\n if (!el) throw new Error('Chart container not found');\n const controller = new ChartController(el, options);\n let bridgeTeardown: (() => void) | undefined;\n const chart = wrap(controller, () => bridgeTeardown?.());\n if (options.bridge) {\n bridgeTeardown = wireChartBridge({\n controller,\n chart,\n bridge: options.bridge,\n chartId: options.chartId,\n outboundEvents: options.bridgeOutboundEvents,\n crosshairThrottleMs: options.bridgeCrosshairThrottleMs,\n });\n }\n return chart;\n}"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@coderyo/core",
|
|
3
|
+
"version": "1.0.0-rc.2",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@coderyo/data": "1.0.0-rc.2",
|
|
14
|
+
"@coderyo/virtual-window": "1.0.0-rc.2",
|
|
15
|
+
"@coderyo/renderer-lite": "1.0.0-rc.2",
|
|
16
|
+
"@coderyo/series": "1.0.0-rc.2",
|
|
17
|
+
"@coderyo/drawings": "1.0.0-rc.2",
|
|
18
|
+
"@coderyo/bridge": "1.0.0-rc.2",
|
|
19
|
+
"@coderyo/indicators": "1.0.0-rc.2"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"tsup": "^8.5.0",
|
|
23
|
+
"typescript": "^5.8.3",
|
|
24
|
+
"vitest": "^3.2.4",
|
|
25
|
+
"@coderyo/eslint-config": "0.0.0",
|
|
26
|
+
"@coderyo/tsconfig": "0.0.0"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/CodeRyoStudio/tradview.git",
|
|
34
|
+
"directory": "packages/core"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup",
|
|
41
|
+
"test": "vitest run --passWithNoTests",
|
|
42
|
+
"lint": "eslint src",
|
|
43
|
+
"typecheck": "tsc --noEmit"
|
|
44
|
+
}
|
|
45
|
+
}
|