@coderyo/renderer-lite 1.0.1 → 1.0.3
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 +39 -2
- package/dist/index.js +299 -76
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bar } from '@coderyo/data';
|
|
1
|
+
import { Interval, Bar } from '@coderyo/data';
|
|
2
2
|
import { IndicatorConfig } from '@coderyo/indicators';
|
|
3
3
|
import { IChartApi, LineData, UTCTimestamp } from 'lightweight-charts';
|
|
4
4
|
|
|
@@ -64,6 +64,10 @@ interface PaneOrchestratorOptions {
|
|
|
64
64
|
/** Animate last candle + price line toward new OHLC (~150ms). */
|
|
65
65
|
smoothPriceUpdate?: boolean;
|
|
66
66
|
smoothPriceDurationMs?: number;
|
|
67
|
+
onIndicatorConfigChange?: (config: IndicatorConfig) => void;
|
|
68
|
+
/** When true (default), set bar spacing on interval reload — does not change visible bar count. */
|
|
69
|
+
autoBarSpacingOnInterval?: boolean;
|
|
70
|
+
barSpacingByInterval?: Partial<Record<Interval, number>>;
|
|
67
71
|
}
|
|
68
72
|
declare class PaneOrchestrator {
|
|
69
73
|
readonly bus: TimeScaleBus;
|
|
@@ -90,6 +94,10 @@ declare class PaneOrchestrator {
|
|
|
90
94
|
private didInitialFit;
|
|
91
95
|
private skipNextInitialFit;
|
|
92
96
|
private indicatorConfig;
|
|
97
|
+
private onIndicatorConfigChange?;
|
|
98
|
+
private currentInterval;
|
|
99
|
+
private autoBarSpacingOnInterval;
|
|
100
|
+
private barSpacingByInterval?;
|
|
93
101
|
private priceLine;
|
|
94
102
|
private barAnimator;
|
|
95
103
|
private smoothPriceDurationMs;
|
|
@@ -102,9 +110,11 @@ declare class PaneOrchestrator {
|
|
|
102
110
|
}): void;
|
|
103
111
|
private applyLastBarToSeries;
|
|
104
112
|
private ensurePriceLine;
|
|
113
|
+
setIntervalContext(interval: Interval): void;
|
|
105
114
|
setTheme(theme: 'dark' | 'light'): void;
|
|
106
115
|
setIndicatorConfig(config: IndicatorConfig | null): void;
|
|
107
116
|
setPinePlots(plots: PinePlotLine[] | null): void;
|
|
117
|
+
private teardownIndicatorStack;
|
|
108
118
|
private applyMainOverlays;
|
|
109
119
|
private syncPinePlotSeries;
|
|
110
120
|
setShowGrid(show: boolean): void;
|
|
@@ -112,6 +122,14 @@ declare class PaneOrchestrator {
|
|
|
112
122
|
subscribeCrosshair(listener: (payload: CrosshairPayload | null) => void): () => void;
|
|
113
123
|
private findNearestBar;
|
|
114
124
|
private createIndicatorStack;
|
|
125
|
+
/** After symbol/interval reload: bar spacing for interval + show integrator-loaded span. */
|
|
126
|
+
applyIntervalBarSpacing(interval?: Interval): void;
|
|
127
|
+
setBarSpacingPolicy(opts: {
|
|
128
|
+
autoBarSpacingOnInterval?: boolean;
|
|
129
|
+
barSpacingByInterval?: Partial<Record<Interval, number>>;
|
|
130
|
+
}): void;
|
|
131
|
+
/** Sync time scale to loaded bars (integrator history); adjust bar spacing only, not bar count. */
|
|
132
|
+
private applyViewAfterDataReload;
|
|
115
133
|
resetViewState(): void;
|
|
116
134
|
/** Skip the next automatic fitContent after setBars (used by reloadHistory). */
|
|
117
135
|
preserveViewportOnNextSetBars(): void;
|
|
@@ -140,11 +158,15 @@ declare class PaneOrchestrator {
|
|
|
140
158
|
private layoutForTheme;
|
|
141
159
|
}
|
|
142
160
|
|
|
161
|
+
type IndicatorPaneId = 'macd' | 'rsi' | 'kdj';
|
|
143
162
|
interface IndicatorPaneStackOptions {
|
|
144
163
|
theme?: 'dark' | 'light';
|
|
145
164
|
showGrid?: boolean;
|
|
146
165
|
config?: IndicatorConfig;
|
|
166
|
+
onConfigChange?: (config: IndicatorConfig) => void;
|
|
147
167
|
}
|
|
168
|
+
/** PR-21: detect in-place tail updates vs full recompute. */
|
|
169
|
+
declare function detectIndicatorBarMutation(prevTimes: number[], bars: Bar[]): 'full' | 'tail-append' | 'tail-update';
|
|
148
170
|
declare class IndicatorPaneStack {
|
|
149
171
|
private readonly root;
|
|
150
172
|
private readonly macdChart;
|
|
@@ -163,10 +185,18 @@ declare class IndicatorPaneStack {
|
|
|
163
185
|
private readonly macdWrap;
|
|
164
186
|
private readonly rsiWrap;
|
|
165
187
|
private readonly kdjWrap;
|
|
188
|
+
private readonly detachResizers;
|
|
189
|
+
private lastBarTimes;
|
|
190
|
+
private onConfigChange?;
|
|
166
191
|
constructor(root: HTMLElement, bus: TimeScaleBus, opts?: IndicatorPaneStackOptions | 'dark' | 'light');
|
|
167
192
|
setConfig(config: IndicatorConfig): void;
|
|
193
|
+
private closePane;
|
|
168
194
|
private applyPaneVisibility;
|
|
169
195
|
clearBars(): void;
|
|
196
|
+
private warmupLookback;
|
|
197
|
+
private detectBarMutation;
|
|
198
|
+
private pushSeriesUpdates;
|
|
199
|
+
private pushHistUpdates;
|
|
170
200
|
setBars(bars: Bar[]): void;
|
|
171
201
|
setTheme(theme: 'dark' | 'light'): void;
|
|
172
202
|
setShowGrid(show: boolean): void;
|
|
@@ -186,4 +216,11 @@ declare function bollOverlayLines(bars: Bar[], period: number, mult: number, sou
|
|
|
186
216
|
lower: LineData<UTCTimestamp>[];
|
|
187
217
|
};
|
|
188
218
|
|
|
189
|
-
|
|
219
|
+
/**
|
|
220
|
+
* Default horizontal bar spacing (px) per interval so candle width feels consistent
|
|
221
|
+
* when the integrator controls how many bars are loaded / visible.
|
|
222
|
+
*/
|
|
223
|
+
declare function defaultBarSpacingForInterval(interval: Interval): number;
|
|
224
|
+
declare function resolveBarSpacingForInterval(interval: Interval, overrides?: Partial<Record<Interval, number>>): number;
|
|
225
|
+
|
|
226
|
+
export { type ChartVisibleRange, type CrosshairPayload, type IndicatorPaneId, IndicatorPaneStack, type IndicatorPaneStackOptions, PaneOrchestrator, type PaneOrchestratorOptions, type PinePlotLine, type ScaleMode, TimeScaleBus, type TransformState, bollOverlayLines, defaultBarSpacingForInterval, detectIndicatorBarMutation, emaOverlayLine, maOverlayLine, resolveBarSpacingForInterval, volMaOverlayLine };
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
HistogramSeries as HistogramSeries2,
|
|
7
7
|
LineSeries as LineSeries2
|
|
8
8
|
} from "lightweight-charts";
|
|
9
|
+
import { intervalMs as intervalMs2 } from "@coderyo/data";
|
|
9
10
|
import { lodDecimateBars } from "@coderyo/series";
|
|
10
11
|
|
|
11
12
|
// src/chart-grid.ts
|
|
@@ -17,6 +18,9 @@ function gridOptions(showGrid, dark) {
|
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
// src/pane-orchestrator.ts
|
|
22
|
+
import { hasVisibleIndicatorPanes as hasVisibleIndicatorPanes2 } from "@coderyo/indicators";
|
|
23
|
+
|
|
20
24
|
// src/indicator-panes.ts
|
|
21
25
|
import {
|
|
22
26
|
ColorType,
|
|
@@ -26,6 +30,7 @@ import {
|
|
|
26
30
|
} from "lightweight-charts";
|
|
27
31
|
import {
|
|
28
32
|
DEFAULT_INDICATOR_CONFIG,
|
|
33
|
+
hasVisibleIndicatorPanes,
|
|
29
34
|
boll,
|
|
30
35
|
kdj,
|
|
31
36
|
macd,
|
|
@@ -33,6 +38,55 @@ import {
|
|
|
33
38
|
sma,
|
|
34
39
|
ema
|
|
35
40
|
} from "@coderyo/indicators";
|
|
41
|
+
|
|
42
|
+
// src/pane-resize.ts
|
|
43
|
+
function attachPaneResizer(topPane, bottomPane, opts = {}) {
|
|
44
|
+
const minTop = opts.minTopPx ?? 120;
|
|
45
|
+
const minBottom = opts.minBottomPx ?? 60;
|
|
46
|
+
const parent = topPane.parentElement;
|
|
47
|
+
if (!parent) return () => {
|
|
48
|
+
};
|
|
49
|
+
const handle = document.createElement("div");
|
|
50
|
+
handle.style.cssText = "height:4px;cursor:row-resize;background:#30363d;flex-shrink:0;touch-action:none;";
|
|
51
|
+
bottomPane.insertAdjacentElement("beforebegin", handle);
|
|
52
|
+
const saved = opts.storageKey ? localStorage.getItem(opts.storageKey) : null;
|
|
53
|
+
if (saved) {
|
|
54
|
+
const ratio = Number(saved);
|
|
55
|
+
if (Number.isFinite(ratio) && ratio > 0 && ratio < 1) {
|
|
56
|
+
topPane.style.flex = `${ratio * 10}`;
|
|
57
|
+
bottomPane.style.flex = `${(1 - ratio) * 10}`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
let dragging = false;
|
|
61
|
+
const onMove = (clientY) => {
|
|
62
|
+
const rect = parent.getBoundingClientRect();
|
|
63
|
+
const y = clientY - rect.top;
|
|
64
|
+
const ratio = Math.min(0.85, Math.max(0.15, y / rect.height));
|
|
65
|
+
const topPx = ratio * rect.height;
|
|
66
|
+
const bottomPx = rect.height - topPx - handle.offsetHeight;
|
|
67
|
+
if (topPx < minTop || bottomPx < minBottom) return;
|
|
68
|
+
topPane.style.flex = `${ratio * 10}`;
|
|
69
|
+
bottomPane.style.flex = `${(1 - ratio) * 10}`;
|
|
70
|
+
if (opts.storageKey) localStorage.setItem(opts.storageKey, String(ratio));
|
|
71
|
+
};
|
|
72
|
+
const stop = () => {
|
|
73
|
+
dragging = false;
|
|
74
|
+
document.body.style.cursor = "";
|
|
75
|
+
};
|
|
76
|
+
handle.addEventListener("pointerdown", (e) => {
|
|
77
|
+
dragging = true;
|
|
78
|
+
handle.setPointerCapture(e.pointerId);
|
|
79
|
+
document.body.style.cursor = "row-resize";
|
|
80
|
+
});
|
|
81
|
+
handle.addEventListener("pointermove", (e) => {
|
|
82
|
+
if (dragging) onMove(e.clientY);
|
|
83
|
+
});
|
|
84
|
+
handle.addEventListener("pointerup", stop);
|
|
85
|
+
handle.addEventListener("pointercancel", stop);
|
|
86
|
+
return () => handle.remove();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/indicator-panes.ts
|
|
36
90
|
function barsForSource(bars, source) {
|
|
37
91
|
if (source === "close") return bars;
|
|
38
92
|
return bars.map((b) => ({ ...b, c: (b.h + b.l + b.c) / 3 }));
|
|
@@ -40,6 +94,21 @@ function barsForSource(bars, source) {
|
|
|
40
94
|
function toUtcSeconds(tMs) {
|
|
41
95
|
return Math.floor(tMs / 1e3);
|
|
42
96
|
}
|
|
97
|
+
function detectIndicatorBarMutation(prevTimes, bars) {
|
|
98
|
+
if (prevTimes.length === 0 || bars.length < prevTimes.length) return "full";
|
|
99
|
+
const prefixLen = Math.min(prevTimes.length, bars.length);
|
|
100
|
+
for (let i = 0; i < prefixLen - 1; i++) {
|
|
101
|
+
if (bars[i].t !== prevTimes[i]) return "full";
|
|
102
|
+
}
|
|
103
|
+
if (bars.length === prevTimes.length) {
|
|
104
|
+
return bars.length > 0 && bars[bars.length - 1].t === prevTimes[prevTimes.length - 1] ? "tail-update" : "full";
|
|
105
|
+
}
|
|
106
|
+
if (bars.length - prevTimes.length > 8) return "full";
|
|
107
|
+
for (let i = 0; i < prevTimes.length; i++) {
|
|
108
|
+
if (bars[i].t !== prevTimes[i]) return "full";
|
|
109
|
+
}
|
|
110
|
+
return "tail-append";
|
|
111
|
+
}
|
|
43
112
|
function lineData(bars, values) {
|
|
44
113
|
const out = [];
|
|
45
114
|
for (let i = 0; i < bars.length; i++) {
|
|
@@ -69,18 +138,31 @@ var IndicatorPaneStack = class {
|
|
|
69
138
|
this.dark = o.theme !== "light";
|
|
70
139
|
this.showGrid = o.showGrid ?? false;
|
|
71
140
|
this.config = o.config ?? DEFAULT_INDICATOR_CONFIG;
|
|
141
|
+
this.onConfigChange = o.onConfigChange;
|
|
72
142
|
this.root.style.display = "flex";
|
|
73
143
|
this.root.style.flexDirection = "column";
|
|
74
144
|
this.root.style.flex = "2";
|
|
75
145
|
this.root.style.minHeight = "0";
|
|
76
146
|
this.root.style.overflow = "hidden";
|
|
77
|
-
const macdPane = this.createPaneWrap("MACD");
|
|
78
|
-
const rsiPane = this.createPaneWrap("RSI");
|
|
79
|
-
const kdjPane = this.createPaneWrap("KDJ");
|
|
147
|
+
const macdPane = this.createPaneWrap("MACD", "macd");
|
|
148
|
+
const rsiPane = this.createPaneWrap("RSI", "rsi");
|
|
149
|
+
const kdjPane = this.createPaneWrap("KDJ", "kdj");
|
|
80
150
|
this.macdWrap = macdPane.wrap;
|
|
81
151
|
this.rsiWrap = rsiPane.wrap;
|
|
82
152
|
this.kdjWrap = kdjPane.wrap;
|
|
83
153
|
this.root.append(macdPane.wrap, rsiPane.wrap, kdjPane.wrap);
|
|
154
|
+
this.detachResizers.push(
|
|
155
|
+
attachPaneResizer(macdPane.wrap, rsiPane.wrap, {
|
|
156
|
+
storageKey: "tradview:pane:macd-rsi",
|
|
157
|
+
minTopPx: 72,
|
|
158
|
+
minBottomPx: 72
|
|
159
|
+
}),
|
|
160
|
+
attachPaneResizer(rsiPane.wrap, kdjPane.wrap, {
|
|
161
|
+
storageKey: "tradview:pane:rsi-kdj",
|
|
162
|
+
minTopPx: 72,
|
|
163
|
+
minBottomPx: 72
|
|
164
|
+
})
|
|
165
|
+
);
|
|
84
166
|
this.applyPaneVisibility();
|
|
85
167
|
const layout = this.layoutForTheme(this.dark);
|
|
86
168
|
const grid = gridOptions(this.showGrid, this.dark);
|
|
@@ -115,14 +197,29 @@ var IndicatorPaneStack = class {
|
|
|
115
197
|
macdWrap;
|
|
116
198
|
rsiWrap;
|
|
117
199
|
kdjWrap;
|
|
200
|
+
detachResizers = [];
|
|
201
|
+
lastBarTimes = [];
|
|
202
|
+
onConfigChange;
|
|
118
203
|
setConfig(config) {
|
|
119
204
|
this.config = config;
|
|
205
|
+
this.lastBarTimes = [];
|
|
206
|
+
this.applyPaneVisibility();
|
|
207
|
+
if (!this.config.showMacd && !this.config.showRsi && !this.config.showKdj) {
|
|
208
|
+
this.clearBars();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
closePane(id) {
|
|
212
|
+
const patch = id === "macd" ? { showMacd: false } : id === "rsi" ? { showRsi: false } : { showKdj: false };
|
|
213
|
+
this.config = { ...this.config, ...patch };
|
|
120
214
|
this.applyPaneVisibility();
|
|
215
|
+
this.onConfigChange?.(this.config);
|
|
121
216
|
}
|
|
122
217
|
applyPaneVisibility() {
|
|
123
218
|
this.macdWrap.style.display = this.config.showMacd ? "" : "none";
|
|
124
219
|
this.rsiWrap.style.display = this.config.showRsi ? "" : "none";
|
|
125
220
|
this.kdjWrap.style.display = this.config.showKdj ? "" : "none";
|
|
221
|
+
const anyVisible = this.config.showMacd || this.config.showRsi || this.config.showKdj;
|
|
222
|
+
this.root.style.display = anyVisible ? "flex" : "none";
|
|
126
223
|
}
|
|
127
224
|
clearBars() {
|
|
128
225
|
this.macdLine.setData([]);
|
|
@@ -132,22 +229,87 @@ var IndicatorPaneStack = class {
|
|
|
132
229
|
this.kdjK.setData([]);
|
|
133
230
|
this.kdjD.setData([]);
|
|
134
231
|
this.kdjJ.setData([]);
|
|
232
|
+
this.lastBarTimes = [];
|
|
233
|
+
}
|
|
234
|
+
warmupLookback() {
|
|
235
|
+
const c = this.config;
|
|
236
|
+
return Math.max(
|
|
237
|
+
c.macdSlow + c.macdSignal,
|
|
238
|
+
c.rsiPeriod,
|
|
239
|
+
c.kdjPeriod + c.kdjKSmooth + c.kdjDSmooth
|
|
240
|
+
) + 5;
|
|
241
|
+
}
|
|
242
|
+
detectBarMutation(bars) {
|
|
243
|
+
return detectIndicatorBarMutation(this.lastBarTimes, bars);
|
|
244
|
+
}
|
|
245
|
+
pushSeriesUpdates(series, bars, values, fromIndex) {
|
|
246
|
+
for (let i = fromIndex; i < bars.length; i++) {
|
|
247
|
+
const v = values[i];
|
|
248
|
+
if (v == null) continue;
|
|
249
|
+
series.update({ time: toUtcSeconds(bars[i].t), value: v });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
pushHistUpdates(series, bars, values, fromIndex) {
|
|
253
|
+
for (let i = fromIndex; i < bars.length; i++) {
|
|
254
|
+
const v = values[i];
|
|
255
|
+
if (v == null) continue;
|
|
256
|
+
series.update({
|
|
257
|
+
time: toUtcSeconds(bars[i].t),
|
|
258
|
+
value: v,
|
|
259
|
+
color: v >= 0 ? "#26a69a88" : "#ef535088"
|
|
260
|
+
});
|
|
261
|
+
}
|
|
135
262
|
}
|
|
136
263
|
setBars(bars) {
|
|
137
|
-
if (bars.length === 0)
|
|
264
|
+
if (bars.length === 0) {
|
|
265
|
+
this.clearBars();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const needMacd = this.config.showMacd;
|
|
269
|
+
const needRsi = this.config.showRsi;
|
|
270
|
+
const needKdj = this.config.showKdj;
|
|
271
|
+
if (!hasVisibleIndicatorPanes(this.config)) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const mutation = this.detectBarMutation(bars);
|
|
275
|
+
this.lastBarTimes = bars.map((b) => b.t);
|
|
138
276
|
const src = barsForSource(bars, this.config.source);
|
|
139
|
-
const m = macd(src, this.config.macdFast, this.config.macdSlow, this.config.macdSignal);
|
|
140
|
-
|
|
141
|
-
this.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
277
|
+
const m = needMacd ? macd(src, this.config.macdFast, this.config.macdSlow, this.config.macdSignal) : null;
|
|
278
|
+
const r = needRsi ? rsi(src, this.config.rsiPeriod) : null;
|
|
279
|
+
const k = needKdj ? kdj(src, this.config.kdjPeriod, this.config.kdjKSmooth, this.config.kdjDSmooth) : null;
|
|
280
|
+
if (mutation === "full") {
|
|
281
|
+
if (needMacd && m) {
|
|
282
|
+
this.macdLine.setData(lineData(bars, m.macd));
|
|
283
|
+
this.macdSignal.setData(lineData(bars, m.signal));
|
|
284
|
+
this.macdHist.setData(histData(bars, m.histogram));
|
|
285
|
+
this.macdChart.timeScale().fitContent();
|
|
286
|
+
}
|
|
287
|
+
if (needRsi && r) {
|
|
288
|
+
this.rsiLine.setData(lineData(bars, r));
|
|
289
|
+
this.rsiChart.timeScale().fitContent();
|
|
290
|
+
}
|
|
291
|
+
if (needKdj && k) {
|
|
292
|
+
this.kdjK.setData(lineData(bars, k.k));
|
|
293
|
+
this.kdjD.setData(lineData(bars, k.d));
|
|
294
|
+
this.kdjJ.setData(lineData(bars, k.j));
|
|
295
|
+
this.kdjChart.timeScale().fitContent();
|
|
296
|
+
}
|
|
297
|
+
} else {
|
|
298
|
+
const from = mutation === "tail-update" ? Math.max(0, bars.length - 1) : Math.max(0, bars.length - this.warmupLookback());
|
|
299
|
+
if (needMacd && m) {
|
|
300
|
+
this.pushSeriesUpdates(this.macdLine, bars, m.macd, from);
|
|
301
|
+
this.pushSeriesUpdates(this.macdSignal, bars, m.signal, from);
|
|
302
|
+
this.pushHistUpdates(this.macdHist, bars, m.histogram, from);
|
|
303
|
+
}
|
|
304
|
+
if (needRsi && r) {
|
|
305
|
+
this.pushSeriesUpdates(this.rsiLine, bars, r, from);
|
|
306
|
+
}
|
|
307
|
+
if (needKdj && k) {
|
|
308
|
+
this.pushSeriesUpdates(this.kdjK, bars, k.k, from);
|
|
309
|
+
this.pushSeriesUpdates(this.kdjD, bars, k.d, from);
|
|
310
|
+
this.pushSeriesUpdates(this.kdjJ, bars, k.j, from);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
151
313
|
this.resize();
|
|
152
314
|
}
|
|
153
315
|
setTheme(theme) {
|
|
@@ -188,20 +350,38 @@ var IndicatorPaneStack = class {
|
|
|
188
350
|
}
|
|
189
351
|
}
|
|
190
352
|
destroy() {
|
|
353
|
+
for (const detach of this.detachResizers) detach();
|
|
354
|
+
this.detachResizers.length = 0;
|
|
191
355
|
this.macdChart.remove();
|
|
192
356
|
this.rsiChart.remove();
|
|
193
357
|
this.kdjChart.remove();
|
|
194
358
|
this.root.replaceChildren();
|
|
195
359
|
}
|
|
196
|
-
createPaneWrap(label) {
|
|
360
|
+
createPaneWrap(label, paneId) {
|
|
197
361
|
const wrap = document.createElement("div");
|
|
362
|
+
wrap.className = `tv-indicator-pane tv-indicator-pane--${paneId}`;
|
|
198
363
|
wrap.style.cssText = "flex:1;min-height:72px;width:100%;position:relative;border-top:1px solid #30363d;";
|
|
199
364
|
const tag = document.createElement("span");
|
|
200
365
|
tag.textContent = label;
|
|
201
366
|
tag.style.cssText = "position:absolute;left:6px;top:4px;z-index:2;font-size:10px;color:#8b949e;pointer-events:none;";
|
|
367
|
+
const closeBtn = document.createElement("button");
|
|
368
|
+
closeBtn.type = "button";
|
|
369
|
+
closeBtn.textContent = "\xD7";
|
|
370
|
+
closeBtn.title = `\u95DC\u9589 ${label}`;
|
|
371
|
+
closeBtn.setAttribute("aria-label", `Close ${label}`);
|
|
372
|
+
closeBtn.style.cssText = "position:absolute;right:6px;top:4px;z-index:3;width:22px;height:22px;padding:0;border:1px solid #30363d;border-radius:4px;background:#21262d;color:#8b949e;cursor:pointer;font-size:14px;line-height:1;";
|
|
373
|
+
closeBtn.onmouseenter = () => {
|
|
374
|
+
closeBtn.style.color = "#e6edf3";
|
|
375
|
+
closeBtn.style.borderColor = "#484f58";
|
|
376
|
+
};
|
|
377
|
+
closeBtn.onmouseleave = () => {
|
|
378
|
+
closeBtn.style.color = "#8b949e";
|
|
379
|
+
closeBtn.style.borderColor = "#30363d";
|
|
380
|
+
};
|
|
381
|
+
closeBtn.onclick = () => this.closePane(paneId);
|
|
202
382
|
const el = document.createElement("div");
|
|
203
383
|
el.style.cssText = "width:100%;height:100%;";
|
|
204
|
-
wrap.append(tag, el);
|
|
384
|
+
wrap.append(tag, closeBtn, el);
|
|
205
385
|
return { wrap, el };
|
|
206
386
|
}
|
|
207
387
|
layoutForTheme(dark) {
|
|
@@ -233,53 +413,6 @@ function bollOverlayLines(bars, period, mult, source = "close") {
|
|
|
233
413
|
};
|
|
234
414
|
}
|
|
235
415
|
|
|
236
|
-
// src/pane-resize.ts
|
|
237
|
-
function attachPaneResizer(topPane, bottomPane, opts = {}) {
|
|
238
|
-
const minTop = opts.minTopPx ?? 120;
|
|
239
|
-
const minBottom = opts.minBottomPx ?? 60;
|
|
240
|
-
const parent = topPane.parentElement;
|
|
241
|
-
if (!parent) return () => {
|
|
242
|
-
};
|
|
243
|
-
const handle = document.createElement("div");
|
|
244
|
-
handle.style.cssText = "height:4px;cursor:row-resize;background:#30363d;flex-shrink:0;touch-action:none;";
|
|
245
|
-
bottomPane.insertAdjacentElement("beforebegin", handle);
|
|
246
|
-
const saved = opts.storageKey ? localStorage.getItem(opts.storageKey) : null;
|
|
247
|
-
if (saved) {
|
|
248
|
-
const ratio = Number(saved);
|
|
249
|
-
if (Number.isFinite(ratio) && ratio > 0 && ratio < 1) {
|
|
250
|
-
topPane.style.flex = `${ratio * 10}`;
|
|
251
|
-
bottomPane.style.flex = `${(1 - ratio) * 10}`;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
let dragging = false;
|
|
255
|
-
const onMove = (clientY) => {
|
|
256
|
-
const rect = parent.getBoundingClientRect();
|
|
257
|
-
const y = clientY - rect.top;
|
|
258
|
-
const ratio = Math.min(0.85, Math.max(0.15, y / rect.height));
|
|
259
|
-
const topPx = ratio * rect.height;
|
|
260
|
-
const bottomPx = rect.height - topPx - handle.offsetHeight;
|
|
261
|
-
if (topPx < minTop || bottomPx < minBottom) return;
|
|
262
|
-
topPane.style.flex = `${ratio * 10}`;
|
|
263
|
-
bottomPane.style.flex = `${(1 - ratio) * 10}`;
|
|
264
|
-
if (opts.storageKey) localStorage.setItem(opts.storageKey, String(ratio));
|
|
265
|
-
};
|
|
266
|
-
const stop = () => {
|
|
267
|
-
dragging = false;
|
|
268
|
-
document.body.style.cursor = "";
|
|
269
|
-
};
|
|
270
|
-
handle.addEventListener("pointerdown", (e) => {
|
|
271
|
-
dragging = true;
|
|
272
|
-
handle.setPointerCapture(e.pointerId);
|
|
273
|
-
document.body.style.cursor = "row-resize";
|
|
274
|
-
});
|
|
275
|
-
handle.addEventListener("pointermove", (e) => {
|
|
276
|
-
if (dragging) onMove(e.clientY);
|
|
277
|
-
});
|
|
278
|
-
handle.addEventListener("pointerup", stop);
|
|
279
|
-
handle.addEventListener("pointercancel", stop);
|
|
280
|
-
return () => handle.remove();
|
|
281
|
-
}
|
|
282
|
-
|
|
283
416
|
// src/time-scale-bus.ts
|
|
284
417
|
var TimeScaleBus = class {
|
|
285
418
|
charts = [];
|
|
@@ -368,6 +501,29 @@ var TimeScaleBus = class {
|
|
|
368
501
|
}
|
|
369
502
|
};
|
|
370
503
|
|
|
504
|
+
// src/viewport-fit.ts
|
|
505
|
+
import { intervalMs } from "@coderyo/data";
|
|
506
|
+
function defaultBarSpacingForInterval(interval) {
|
|
507
|
+
const ms = intervalMs(interval);
|
|
508
|
+
if (ms <= 1e3) return 3;
|
|
509
|
+
if (ms <= 5e3) return 4;
|
|
510
|
+
if (ms <= 15e3) return 5;
|
|
511
|
+
if (ms <= 3e4) return 6;
|
|
512
|
+
if (ms <= 6e4) return 7;
|
|
513
|
+
if (ms <= 3e5) return 8;
|
|
514
|
+
if (ms <= 9e5) return 9;
|
|
515
|
+
if (ms <= 36e5) return 10;
|
|
516
|
+
if (ms <= 144e5) return 11;
|
|
517
|
+
return 12;
|
|
518
|
+
}
|
|
519
|
+
function resolveBarSpacingForInterval(interval, overrides) {
|
|
520
|
+
const custom = overrides?.[interval];
|
|
521
|
+
if (custom != null && Number.isFinite(custom) && custom > 0) {
|
|
522
|
+
return Math.min(24, Math.max(2, custom));
|
|
523
|
+
}
|
|
524
|
+
return defaultBarSpacingForInterval(interval);
|
|
525
|
+
}
|
|
526
|
+
|
|
371
527
|
// src/bar-smooth-animator.ts
|
|
372
528
|
function lerp(a, b, t) {
|
|
373
529
|
return a + (b - a) * t;
|
|
@@ -459,6 +615,10 @@ var PaneOrchestrator = class {
|
|
|
459
615
|
didInitialFit = false;
|
|
460
616
|
skipNextInitialFit = false;
|
|
461
617
|
indicatorConfig = null;
|
|
618
|
+
onIndicatorConfigChange;
|
|
619
|
+
currentInterval = "1h";
|
|
620
|
+
autoBarSpacingOnInterval = true;
|
|
621
|
+
barSpacingByInterval;
|
|
462
622
|
priceLine = null;
|
|
463
623
|
barAnimator = null;
|
|
464
624
|
smoothPriceDurationMs = 150;
|
|
@@ -535,6 +695,9 @@ var PaneOrchestrator = class {
|
|
|
535
695
|
this.bus.register(this.volumeChart);
|
|
536
696
|
this.indicatorRoot = opts.indicatorRoot;
|
|
537
697
|
this.indicatorConfig = opts.indicatorConfig ?? null;
|
|
698
|
+
this.onIndicatorConfigChange = opts.onIndicatorConfigChange;
|
|
699
|
+
this.autoBarSpacingOnInterval = opts.autoBarSpacingOnInterval ?? true;
|
|
700
|
+
this.barSpacingByInterval = opts.barSpacingByInterval;
|
|
538
701
|
this.pinePlots = opts.pinePlots ?? null;
|
|
539
702
|
this.indicators = this.createIndicatorStack();
|
|
540
703
|
this.initOverlay(mainEl);
|
|
@@ -578,7 +741,9 @@ var PaneOrchestrator = class {
|
|
|
578
741
|
if (this.indicatorConfig) {
|
|
579
742
|
const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);
|
|
580
743
|
this.applyMainOverlays(bars);
|
|
581
|
-
this.
|
|
744
|
+
if (hasVisibleIndicatorPanes2(this.indicatorConfig)) {
|
|
745
|
+
this.indicators?.setBars(bars);
|
|
746
|
+
}
|
|
582
747
|
}
|
|
583
748
|
}
|
|
584
749
|
ensurePriceLine(price) {
|
|
@@ -595,6 +760,9 @@ var PaneOrchestrator = class {
|
|
|
595
760
|
this.priceLine.applyOptions({ price });
|
|
596
761
|
}
|
|
597
762
|
}
|
|
763
|
+
setIntervalContext(interval) {
|
|
764
|
+
this.currentInterval = interval;
|
|
765
|
+
}
|
|
598
766
|
setTheme(theme) {
|
|
599
767
|
this.dark = theme === "dark";
|
|
600
768
|
const layout = this.layoutForTheme(this.dark);
|
|
@@ -606,7 +774,7 @@ var PaneOrchestrator = class {
|
|
|
606
774
|
setIndicatorConfig(config) {
|
|
607
775
|
this.indicatorConfig = config;
|
|
608
776
|
if (!config) {
|
|
609
|
-
this.
|
|
777
|
+
this.teardownIndicatorStack();
|
|
610
778
|
this.maSeries.setData([]);
|
|
611
779
|
this.emaSeries.setData([]);
|
|
612
780
|
this.bollUpper.setData([]);
|
|
@@ -624,7 +792,9 @@ var PaneOrchestrator = class {
|
|
|
624
792
|
this.indicators?.setConfig(config);
|
|
625
793
|
if (bars.length > 0) {
|
|
626
794
|
this.applyMainOverlays(bars);
|
|
627
|
-
|
|
795
|
+
if (hasVisibleIndicatorPanes2(config)) {
|
|
796
|
+
this.indicators?.setBars(bars);
|
|
797
|
+
}
|
|
628
798
|
}
|
|
629
799
|
}
|
|
630
800
|
setPinePlots(plots) {
|
|
@@ -632,12 +802,27 @@ var PaneOrchestrator = class {
|
|
|
632
802
|
const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);
|
|
633
803
|
this.syncPinePlotSeries(bars);
|
|
634
804
|
}
|
|
805
|
+
teardownIndicatorStack() {
|
|
806
|
+
this.indicators?.destroy();
|
|
807
|
+
this.indicators = null;
|
|
808
|
+
}
|
|
635
809
|
applyMainOverlays(bars) {
|
|
636
810
|
const cfg = this.indicatorConfig;
|
|
637
811
|
if (!cfg) return;
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
812
|
+
if (cfg.showMa) {
|
|
813
|
+
this.maSeries.applyOptions({ visible: true, title: `MA${cfg.maPeriod}` });
|
|
814
|
+
this.maSeries.setData(maOverlayLine(bars, cfg.maPeriod, cfg.source));
|
|
815
|
+
} else {
|
|
816
|
+
this.maSeries.applyOptions({ visible: false });
|
|
817
|
+
this.maSeries.setData([]);
|
|
818
|
+
}
|
|
819
|
+
if (cfg.showVolMa) {
|
|
820
|
+
this.volMaSeries.applyOptions({ visible: true });
|
|
821
|
+
this.volMaSeries.setData(volMaOverlayLine(bars, cfg.volMaPeriod));
|
|
822
|
+
} else {
|
|
823
|
+
this.volMaSeries.applyOptions({ visible: false });
|
|
824
|
+
this.volMaSeries.setData([]);
|
|
825
|
+
}
|
|
641
826
|
if (cfg.showEma) {
|
|
642
827
|
this.emaSeries.applyOptions({ visible: true, title: `EMA${cfg.emaPeriod}` });
|
|
643
828
|
this.emaSeries.setData(emaOverlayLine(bars, cfg.emaPeriod, cfg.source));
|
|
@@ -715,7 +900,9 @@ var PaneOrchestrator = class {
|
|
|
715
900
|
this.volumeSeries.setData(vols);
|
|
716
901
|
if (this.indicatorConfig) {
|
|
717
902
|
this.applyMainOverlays(renderBars);
|
|
718
|
-
this.
|
|
903
|
+
if (hasVisibleIndicatorPanes2(this.indicatorConfig)) {
|
|
904
|
+
this.indicators?.setBars(renderBars);
|
|
905
|
+
}
|
|
719
906
|
} else {
|
|
720
907
|
this.maSeries.setData([]);
|
|
721
908
|
this.emaSeries.setData([]);
|
|
@@ -728,9 +915,7 @@ var PaneOrchestrator = class {
|
|
|
728
915
|
if (renderBars.length > 0) {
|
|
729
916
|
this.syncChartSize();
|
|
730
917
|
if (!this.didInitialFit && !this.skipNextInitialFit) {
|
|
731
|
-
this.
|
|
732
|
-
this.volumeChart.timeScale().fitContent();
|
|
733
|
-
this.indicators?.fitContent();
|
|
918
|
+
this.applyViewAfterDataReload(renderBars);
|
|
734
919
|
this.didInitialFit = true;
|
|
735
920
|
}
|
|
736
921
|
this.skipNextInitialFit = false;
|
|
@@ -775,9 +960,44 @@ var PaneOrchestrator = class {
|
|
|
775
960
|
return new IndicatorPaneStack(this.indicatorRoot, this.bus, {
|
|
776
961
|
theme: this.dark ? "dark" : "light",
|
|
777
962
|
showGrid: this.showGrid,
|
|
778
|
-
config: this.indicatorConfig
|
|
963
|
+
config: this.indicatorConfig,
|
|
964
|
+
onConfigChange: (config) => {
|
|
965
|
+
this.indicatorConfig = config;
|
|
966
|
+
this.onIndicatorConfigChange?.(config);
|
|
967
|
+
}
|
|
779
968
|
});
|
|
780
969
|
}
|
|
970
|
+
/** After symbol/interval reload: bar spacing for interval + show integrator-loaded span. */
|
|
971
|
+
applyIntervalBarSpacing(interval) {
|
|
972
|
+
if (!this.autoBarSpacingOnInterval) return;
|
|
973
|
+
const iv = interval ?? this.currentInterval;
|
|
974
|
+
const spacing = resolveBarSpacingForInterval(iv, this.barSpacingByInterval);
|
|
975
|
+
this.bus.setBarSpacing(spacing);
|
|
976
|
+
}
|
|
977
|
+
setBarSpacingPolicy(opts) {
|
|
978
|
+
if (opts.autoBarSpacingOnInterval !== void 0) {
|
|
979
|
+
this.autoBarSpacingOnInterval = opts.autoBarSpacingOnInterval;
|
|
980
|
+
}
|
|
981
|
+
if (opts.barSpacingByInterval !== void 0) {
|
|
982
|
+
this.barSpacingByInterval = opts.barSpacingByInterval;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
/** Sync time scale to loaded bars (integrator history); adjust bar spacing only, not bar count. */
|
|
986
|
+
applyViewAfterDataReload(renderBars) {
|
|
987
|
+
if (this.autoBarSpacingOnInterval) {
|
|
988
|
+
this.applyIntervalBarSpacing();
|
|
989
|
+
} else {
|
|
990
|
+
this.mainChart.timeScale().fitContent();
|
|
991
|
+
this.volumeChart.timeScale().fitContent();
|
|
992
|
+
this.indicators?.fitContent();
|
|
993
|
+
}
|
|
994
|
+
if (renderBars.length > 0) {
|
|
995
|
+
const fromMs = renderBars[0].t;
|
|
996
|
+
const toMs = renderBars[renderBars.length - 1].t + intervalMs2(this.currentInterval);
|
|
997
|
+
this.bus.setVisibleTimeRange({ fromMs, toMs });
|
|
998
|
+
}
|
|
999
|
+
this.scrollToRealtime();
|
|
1000
|
+
}
|
|
781
1001
|
resetViewState() {
|
|
782
1002
|
this.didInitialFit = false;
|
|
783
1003
|
this.skipNextInitialFit = false;
|
|
@@ -929,8 +1149,11 @@ export {
|
|
|
929
1149
|
PaneOrchestrator,
|
|
930
1150
|
TimeScaleBus,
|
|
931
1151
|
bollOverlayLines,
|
|
1152
|
+
defaultBarSpacingForInterval,
|
|
1153
|
+
detectIndicatorBarMutation,
|
|
932
1154
|
emaOverlayLine,
|
|
933
1155
|
maOverlayLine,
|
|
1156
|
+
resolveBarSpacingForInterval,
|
|
934
1157
|
volMaOverlayLine
|
|
935
1158
|
};
|
|
936
1159
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pane-orchestrator.ts","../src/chart-grid.ts","../src/indicator-panes.ts","../src/pane-resize.ts","../src/time-scale-bus.ts","../src/bar-smooth-animator.ts"],"sourcesContent":["import {\n CandlestickSeries,\n ColorType,\n createChart,\n HistogramSeries,\n LineSeries,\n type CandlestickData,\n type HistogramData,\n type WhitespaceData,\n type IChartApi,\n type ISeriesApi,\n type IPriceLine,\n type MouseEventParams,\n type Time,\n type UTCTimestamp,\n} from 'lightweight-charts';\nimport type { Bar } from '@coderyo/data';\nimport { lodDecimateBars } from '@coderyo/series';\nimport { gridOptions } from './chart-grid.js';\nimport type { IndicatorConfig } from '@coderyo/indicators';\n\nimport {\n IndicatorPaneStack,\n bollOverlayLines,\n emaOverlayLine,\n maOverlayLine,\n volMaOverlayLine,\n} from './indicator-panes.js';\nimport { attachPaneResizer } from './pane-resize.js';\nimport { TimeScaleBus, type ChartVisibleRange } from './time-scale-bus.js';\n\nexport type { ChartVisibleRange };\nimport { BarSmoothAnimator } from './bar-smooth-animator.js';\n\nexport type ScaleMode = 'linear' | 'log';\n\nexport interface CrosshairPayload {\n time: number;\n price: number | null;\n ohlcv: { o: number; h: number; l: number; c: number; v?: number } | null;\n}\n\nexport interface PinePlotLine {\n title: string;\n color?: string;\n values: (number | null)[];\n}\n\nexport interface PaneOrchestratorOptions {\n container: HTMLElement;\n indicatorRoot?: HTMLElement;\n theme?: 'dark' | 'light';\n scaleMode?: ScaleMode;\n maxRenderPoints?: number;\n /** Show chart grid lines (default false). */\n showGrid?: boolean;\n /** null = no MA overlays and no MACD/RSI/KDJ panes. */\n indicatorConfig?: IndicatorConfig | null;\n /** Pine-lite plot lines on main chart (when pineEnabled). */\n pinePlots?: PinePlotLine[] | null;\n /** Animate last candle + price line toward new OHLC (~150ms). */\n smoothPriceUpdate?: boolean;\n smoothPriceDurationMs?: number;\n}\n\nfunction toUtcSeconds(tMs: number): UTCTimestamp {\n return Math.floor(tMs / 1000) as UTCTimestamp;\n}\n\nfunction barToCandle(b: Bar): CandlestickData {\n return { time: toUtcSeconds(b.t), open: b.o, high: b.h, low: b.l, close: b.c };\n}\n\nfunction barToVolume(b: Bar): HistogramData<UTCTimestamp> {\n return { time: toUtcSeconds(b.t), value: b.v ?? 0 };\n}\n\nexport class PaneOrchestrator {\n readonly bus = new TimeScaleBus();\n private readonly mainChart: IChartApi;\n private readonly volumeChart: IChartApi;\n private readonly mainSeries: ISeriesApi<'Candlestick'>;\n private readonly volumeSeries: ISeriesApi<'Histogram'>;\n private readonly maSeries: ISeriesApi<'Line'>;\n private readonly emaSeries: ISeriesApi<'Line'>;\n private readonly bollUpper: ISeriesApi<'Line'>;\n private readonly bollMiddle: ISeriesApi<'Line'>;\n private readonly bollLower: ISeriesApi<'Line'>;\n private readonly volMaSeries: ISeriesApi<'Line'>;\n private readonly indicatorRoot?: HTMLElement;\n private indicators: IndicatorPaneStack | null;\n private pinePlotSeries: ISeriesApi<'Line'>[] = [];\n private pinePlots: PinePlotLine[] | null = null;\n private overlayCanvas: HTMLCanvasElement | null = null;\n private dark = true;\n private showGrid = false;\n private readonly maxRenderPoints: number;\n private barByTime = new Map<number, Bar>();\n private barTimesOrdered: number[] = [];\n private didInitialFit = false;\n private skipNextInitialFit = false;\n private indicatorConfig: IndicatorConfig | null = null;\n private priceLine: IPriceLine | null = null;\n private barAnimator: BarSmoothAnimator | null = null;\n private smoothPriceDurationMs = 150;\n\n constructor(opts: PaneOrchestratorOptions) {\n this.maxRenderPoints = opts.maxRenderPoints ?? 4000;\n this.dark = opts.theme !== 'light';\n this.showGrid = opts.showGrid ?? false;\n const layout = this.layoutForTheme(this.dark);\n const grid = gridOptions(this.showGrid, this.dark);\n\n const mainEl = document.createElement('div');\n mainEl.style.cssText = 'flex:7;min-height:120px;width:100%;position:relative;';\n const volEl = document.createElement('div');\n volEl.style.cssText = 'flex:2;min-height:64px;width:100%;position:relative;';\n\n opts.container.style.cssText =\n 'display:flex;flex-direction:column;height:100%;width:100%;min-height:240px;overflow:hidden;';\n opts.container.append(mainEl, volEl);\n attachPaneResizer(mainEl, volEl, { storageKey: 'tradview:pane:main-volume' });\n\n this.mainChart = createChart(mainEl, { layout, grid, autoSize: true });\n this.volumeChart = createChart(volEl, {\n layout,\n grid,\n autoSize: true,\n rightPriceScale: { scaleMargins: { top: 0.8, bottom: 0 } },\n });\n\n if (opts.scaleMode === 'log') {\n this.mainChart.priceScale('right').applyOptions({ mode: 1 });\n }\n\n this.mainSeries = this.mainChart.addSeries(CandlestickSeries, {\n upColor: '#26a69a',\n downColor: '#ef5350',\n borderVisible: false,\n wickUpColor: '#26a69a',\n wickDownColor: '#ef5350',\n });\n this.maSeries = this.mainChart.addSeries(LineSeries, {\n color: '#f0b429',\n lineWidth: 1,\n title: 'MA',\n });\n this.emaSeries = this.mainChart.addSeries(LineSeries, {\n color: '#7ee787',\n lineWidth: 1,\n title: 'EMA',\n visible: false,\n });\n this.bollUpper = this.mainChart.addSeries(LineSeries, {\n color: '#8b949e',\n lineWidth: 1,\n title: 'BOLL↑',\n visible: false,\n });\n this.bollMiddle = this.mainChart.addSeries(LineSeries, {\n color: '#8b949e88',\n lineWidth: 1,\n lineStyle: 2,\n title: 'BOLL',\n visible: false,\n });\n this.bollLower = this.mainChart.addSeries(LineSeries, {\n color: '#8b949e',\n lineWidth: 1,\n title: 'BOLL↓',\n visible: false,\n });\n this.volumeSeries = this.volumeChart.addSeries(HistogramSeries, {\n color: '#26a69a55',\n priceFormat: { type: 'volume' },\n });\n this.volMaSeries = this.volumeChart.addSeries(LineSeries, {\n color: '#58a6ff',\n lineWidth: 1,\n title: 'VolMA5',\n });\n\n this.bus.register(this.mainChart);\n this.bus.register(this.volumeChart);\n\n this.indicatorRoot = opts.indicatorRoot;\n this.indicatorConfig = opts.indicatorConfig ?? null;\n this.pinePlots = opts.pinePlots ?? null;\n this.indicators = this.createIndicatorStack();\n\n this.initOverlay(mainEl);\n this.setSmoothPriceUpdate(opts.smoothPriceUpdate ?? false, opts.smoothPriceDurationMs);\n }\n\n setSmoothPriceUpdate(enabled: boolean, durationMs = 150): void {\n this.smoothPriceDurationMs = durationMs;\n if (enabled) {\n if (!this.barAnimator) {\n this.barAnimator = new BarSmoothAnimator(durationMs, (bar) => this.applyLastBarToSeries(bar));\n } else {\n this.barAnimator.setDuration(durationMs);\n }\n return;\n }\n this.barAnimator?.cancel();\n this.barAnimator = null;\n if (this.priceLine) {\n this.mainSeries.removePriceLine(this.priceLine);\n this.priceLine = null;\n }\n }\n\n /** Update the last candle (and price line); optional smooth interpolation. */\n updateLastBar(target: Bar, opts?: { smooth?: boolean; durationMs?: number }): void {\n const prev = this.barByTime.get(target.t);\n const smooth = opts?.smooth ?? !!this.barAnimator;\n const duration = opts?.durationMs ?? this.smoothPriceDurationMs;\n if (smooth && this.barAnimator) {\n this.barAnimator.setDuration(duration);\n this.barAnimator.animateTo(target, prev ?? target);\n return;\n }\n this.barAnimator?.cancel();\n this.applyLastBarToSeries(target);\n }\n\n private applyLastBarToSeries(bar: Bar): void {\n this.barByTime.set(bar.t, bar);\n this.mainSeries.update(barToCandle(bar));\n this.volumeSeries.update(barToVolume(bar));\n this.ensurePriceLine(bar.c);\n if (this.indicatorConfig) {\n const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);\n this.applyMainOverlays(bars);\n this.indicators?.setBars(bars);\n }\n }\n\n private ensurePriceLine(price: number): void {\n if (!this.priceLine) {\n this.priceLine = this.mainSeries.createPriceLine({\n price,\n color: '#58a6ff',\n lineWidth: 1,\n lineStyle: 2,\n axisLabelVisible: true,\n title: '',\n });\n } else {\n this.priceLine.applyOptions({ price });\n }\n }\n\n setTheme(theme: 'dark' | 'light'): void {\n this.dark = theme === 'dark';\n const layout = this.layoutForTheme(this.dark);\n const grid = gridOptions(this.showGrid, this.dark);\n this.mainChart.applyOptions({ layout, grid });\n this.volumeChart.applyOptions({ layout, grid });\n this.indicators?.setTheme(theme);\n }\n\n setIndicatorConfig(config: IndicatorConfig | null): void {\n this.indicatorConfig = config;\n if (!config) {\n this.indicators = null;\n this.maSeries.setData([]);\n this.emaSeries.setData([]);\n this.bollUpper.setData([]);\n this.bollMiddle.setData([]);\n this.bollLower.setData([]);\n this.volMaSeries.setData([]);\n this.emaSeries.applyOptions({ visible: false });\n this.bollUpper.applyOptions({ visible: false });\n this.bollMiddle.applyOptions({ visible: false });\n this.bollLower.applyOptions({ visible: false });\n return;\n }\n if (!this.indicators) this.indicators = this.createIndicatorStack();\n const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);\n this.indicators?.setConfig(config);\n if (bars.length > 0) {\n this.applyMainOverlays(bars);\n this.indicators?.setBars(bars);\n }\n }\n\n setPinePlots(plots: PinePlotLine[] | null): void {\n this.pinePlots = plots;\n const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);\n this.syncPinePlotSeries(bars);\n }\n\n private applyMainOverlays(bars: Bar[]): void {\n const cfg = this.indicatorConfig;\n if (!cfg) return;\n this.maSeries.applyOptions({ title: `MA${cfg.maPeriod}` });\n this.maSeries.setData(maOverlayLine(bars, cfg.maPeriod, cfg.source));\n this.volMaSeries.setData(volMaOverlayLine(bars, cfg.volMaPeriod));\n\n if (cfg.showEma) {\n this.emaSeries.applyOptions({ visible: true, title: `EMA${cfg.emaPeriod}` });\n this.emaSeries.setData(emaOverlayLine(bars, cfg.emaPeriod, cfg.source));\n } else {\n this.emaSeries.applyOptions({ visible: false });\n this.emaSeries.setData([]);\n }\n\n if (cfg.showBoll) {\n const bands = bollOverlayLines(bars, cfg.bollPeriod, cfg.bollMult, cfg.source);\n this.bollUpper.applyOptions({ visible: true });\n this.bollMiddle.applyOptions({ visible: true });\n this.bollLower.applyOptions({ visible: true });\n this.bollUpper.setData(bands.upper);\n this.bollMiddle.setData(bands.middle);\n this.bollLower.setData(bands.lower);\n } else {\n this.bollUpper.applyOptions({ visible: false });\n this.bollMiddle.applyOptions({ visible: false });\n this.bollLower.applyOptions({ visible: false });\n this.bollUpper.setData([]);\n this.bollMiddle.setData([]);\n this.bollLower.setData([]);\n }\n this.syncPinePlotSeries(bars);\n }\n\n private syncPinePlotSeries(bars: Bar[]): void {\n for (const s of this.pinePlotSeries) this.mainChart.removeSeries(s);\n this.pinePlotSeries = [];\n if (!this.pinePlots?.length || bars.length === 0) return;\n\n const palette = ['#58a6ff', '#d2a8ff', '#ff7b72', '#ffa657'];\n for (let i = 0; i < this.pinePlots.length; i++) {\n const plot = this.pinePlots[i]!;\n const series = this.mainChart.addSeries(LineSeries, {\n color: plot.color ?? palette[i % palette.length]!,\n lineWidth: 1,\n title: plot.title,\n });\n const out: { time: UTCTimestamp; value: number }[] = [];\n for (let j = 0; j < bars.length; j++) {\n const v = plot.values[j];\n if (v == null) continue;\n out.push({ time: toUtcSeconds(bars[j]!.t), value: v });\n }\n series.setData(out);\n this.pinePlotSeries.push(series);\n }\n }\n\n setShowGrid(show: boolean): void {\n this.showGrid = show;\n const grid = gridOptions(show, this.dark);\n this.mainChart.applyOptions({ grid });\n this.volumeChart.applyOptions({ grid });\n this.indicators?.setShowGrid(show);\n }\n\n setBars(bars: Bar[], gaps?: number[]): void {\n const renderBars = lodDecimateBars(bars, this.maxRenderPoints);\n this.barByTime = new Map(renderBars.map((b) => [b.t, b]));\n this.barTimesOrdered = renderBars.map((b) => b.t);\n\n const gapSet = new Set(gaps ?? []);\n const seenTimes = new Set<number>();\n type CandlePoint = CandlestickData | WhitespaceData<UTCTimestamp>;\n const candles: CandlePoint[] = [];\n const vols: HistogramData<UTCTimestamp>[] = [];\n\n for (let i = 0; i < renderBars.length; i++) {\n const b = renderBars[i]!;\n const time = toUtcSeconds(b.t);\n if (seenTimes.has(time)) continue;\n seenTimes.add(time);\n if (gapSet.has(b.t)) {\n candles.push({ time });\n }\n candles.push(barToCandle(b));\n vols.push(barToVolume(b));\n }\n\n this.mainSeries.setData(candles);\n this.volumeSeries.setData(vols);\n if (this.indicatorConfig) {\n this.applyMainOverlays(renderBars);\n this.indicators?.setBars(renderBars);\n } else {\n this.maSeries.setData([]);\n this.emaSeries.setData([]);\n this.bollUpper.setData([]);\n this.bollMiddle.setData([]);\n this.bollLower.setData([]);\n this.volMaSeries.setData([]);\n this.syncPinePlotSeries(renderBars);\n }\n\n if (renderBars.length > 0) {\n this.syncChartSize();\n if (!this.didInitialFit && !this.skipNextInitialFit) {\n this.mainChart.timeScale().fitContent();\n this.volumeChart.timeScale().fitContent();\n this.indicators?.fitContent();\n this.didInitialFit = true;\n }\n this.skipNextInitialFit = false;\n }\n }\n\n subscribeCrosshair(listener: (payload: CrosshairPayload | null) => void): () => void {\n const handler = (param: MouseEventParams<Time>) => {\n if (param.time == null || !param.point) {\n listener(null);\n return;\n }\n const tMs = typeof param.time === 'number' ? param.time * 1000 : null;\n if (tMs == null) {\n listener(null);\n return;\n }\n const price = this.mainSeries.coordinateToPrice(param.point.y) ?? null;\n const bar = this.barByTime.get(tMs) ?? this.findNearestBar(tMs);\n listener({\n time: tMs,\n price,\n ohlcv: bar\n ? { o: bar.o, h: bar.h, l: bar.l, c: bar.c, v: bar.v }\n : null,\n });\n };\n this.mainChart.subscribeCrosshairMove(handler);\n return () => this.mainChart.unsubscribeCrosshairMove(handler);\n }\n\n private findNearestBar(tMs: number): Bar | null {\n let best: Bar | null = null;\n let bestDt = Infinity;\n for (const b of this.barByTime.values()) {\n const dt = Math.abs(b.t - tMs);\n if (dt < bestDt) {\n bestDt = dt;\n best = b;\n }\n }\n return bestDt < 120_000 ? best : null;\n }\n\n private createIndicatorStack(): IndicatorPaneStack | null {\n if (!this.indicatorRoot || !this.indicatorConfig) return null;\n return new IndicatorPaneStack(this.indicatorRoot, this.bus, {\n theme: this.dark ? 'dark' : 'light',\n showGrid: this.showGrid,\n config: this.indicatorConfig,\n });\n }\n\n resetViewState(): void {\n this.didInitialFit = false;\n this.skipNextInitialFit = false;\n this.bus.visibleFromMs = 0;\n this.bus.visibleToMs = 0;\n }\n\n /** Skip the next automatic fitContent after setBars (used by reloadHistory). */\n preserveViewportOnNextSetBars(): void {\n this.skipNextInitialFit = true;\n this.didInitialFit = true;\n }\n\n getVisibleRange(): ChartVisibleRange | null {\n return this.bus.getVisibleRange();\n }\n\n getBarSpace(): number {\n return this.bus.getBarSpacing();\n }\n\n setBarSpace(px: number): void {\n this.bus.setBarSpacing(px);\n }\n\n setVisibleRange(range: ChartVisibleRange): void {\n this.bus.setVisibleTimeRange(range);\n this.didInitialFit = true;\n }\n\n scrollToTimestamp(tsMs: number, animationMs?: number): void {\n const time = toUtcSeconds(tsMs);\n const idx = this.mainChart.timeScale().timeToIndex(time, true);\n if (idx == null) {\n const nearest = this.findNearestBar(tsMs);\n if (nearest == null) return;\n const i = this.barTimesOrdered.indexOf(nearest.t);\n if (i < 0) return;\n this.bus.scrollToLogicalPosition(i, (animationMs ?? 0) > 0);\n return;\n }\n this.bus.scrollToLogicalPosition(idx as number, (animationMs ?? 0) > 0);\n }\n\n /** Clear series while symbol/interval data reloads (avoids overlapping candles). */\n clearBars(): void {\n this.barAnimator?.cancel();\n this.barByTime = new Map();\n this.barTimesOrdered = [];\n this.mainSeries.setData([]);\n this.maSeries.setData([]);\n this.volumeSeries.setData([]);\n this.volMaSeries.setData([]);\n this.indicators?.clearBars();\n }\n\n fitContent(): void {\n this.mainChart.timeScale().fitContent();\n this.volumeChart.timeScale().fitContent();\n this.indicators?.fitContent();\n this.didInitialFit = true;\n }\n\n scrollToRealtime(): void {\n this.mainChart.timeScale().scrollToRealTime();\n this.volumeChart.timeScale().scrollToRealTime();\n this.indicators?.scrollToRealtime();\n }\n\n setLogScale(enabled: boolean): void {\n this.mainChart.priceScale('right').applyOptions({ mode: enabled ? 1 : 0 });\n }\n\n resize(): void {\n this.syncChartSize();\n this.syncOverlaySize();\n this.indicators?.resize();\n }\n\n getOverlayCanvas(): HTMLCanvasElement | null {\n return this.overlayCanvas;\n }\n\n timeToX(tMs: number): number | null {\n const coord = this.mainChart.timeScale().timeToCoordinate(toUtcSeconds(tMs));\n if (coord == null) return null;\n return coord * devicePixelRatio;\n }\n\n priceToY(price: number): number | null {\n const coord = this.mainSeries.priceToCoordinate(price);\n if (coord == null) return null;\n return coord * devicePixelRatio;\n }\n\n xToTime(x: number): number | null {\n const t = this.mainChart.timeScale().coordinateToTime(x / devicePixelRatio);\n if (t == null) return null;\n return Number(t) * 1000;\n }\n\n yToPrice(y: number): number | null {\n const p = this.mainSeries.coordinateToPrice(y / devicePixelRatio);\n return p ?? null;\n }\n\n destroy(): void {\n this.barAnimator?.cancel();\n if (this.priceLine) {\n this.mainSeries.removePriceLine(this.priceLine);\n this.priceLine = null;\n }\n this.mainChart.remove();\n this.volumeChart.remove();\n this.indicators?.destroy();\n this.overlayCanvas?.remove();\n }\n\n private initOverlay(parent: HTMLElement) {\n const canvas = document.createElement('canvas');\n canvas.style.cssText =\n 'position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:10;';\n parent.style.position = 'relative';\n parent.appendChild(canvas);\n this.overlayCanvas = canvas;\n this.syncOverlaySize();\n this.bus.subscribeTransform(() => {\n this.syncOverlaySize();\n });\n }\n\n /** Let drawing overlay receive clicks; cursor mode keeps pan/zoom on LWC. */\n setOverlayPointerEvents(mode: 'auto' | 'none'): void {\n if (this.overlayCanvas) this.overlayCanvas.style.pointerEvents = mode;\n }\n\n private syncOverlaySize() {\n if (!this.overlayCanvas?.parentElement) return;\n const parent = this.overlayCanvas.parentElement;\n if (parent.lastElementChild !== this.overlayCanvas) {\n parent.appendChild(this.overlayCanvas);\n }\n const rect = parent.getBoundingClientRect();\n this.overlayCanvas.width = rect.width * devicePixelRatio;\n this.overlayCanvas.height = rect.height * devicePixelRatio;\n }\n\n private syncChartSize(): void {\n const mainEl = this.mainChart.chartElement().parentElement;\n const volEl = this.volumeChart.chartElement().parentElement;\n if (mainEl) {\n const w = mainEl.clientWidth;\n const h = mainEl.clientHeight;\n if (w > 0 && h > 0) this.mainChart.resize(w, h);\n }\n if (volEl) {\n const w = volEl.clientWidth;\n const h = volEl.clientHeight;\n if (w > 0 && h > 0) this.volumeChart.resize(w, h);\n }\n }\n\n private layoutForTheme(dark: boolean) {\n return {\n background: { type: ColorType.Solid, color: dark ? '#0d1117' : '#ffffff' },\n textColor: dark ? '#e6edf3' : '#24292f',\n };\n }\n}","/** LWC grid line options — default off per product spec. */\nexport function gridOptions(showGrid: boolean, dark: boolean) {\n const color = dark ? '#21262d' : '#d0d7de';\n return {\n vertLines: { visible: showGrid, color },\n horzLines: { visible: showGrid, color },\n };\n}","import {\n ColorType,\n createChart,\n HistogramSeries,\n LineSeries,\n type HistogramData,\n type IChartApi,\n type ISeriesApi,\n type LineData,\n type UTCTimestamp,\n} from 'lightweight-charts';\nimport type { Bar } from '@coderyo/data';\nimport {\n type IndicatorConfig,\n DEFAULT_INDICATOR_CONFIG,\n boll,\n kdj,\n macd,\n rsi,\n sma,\n ema,\n} from '@coderyo/indicators';\nimport { gridOptions } from './chart-grid.js';\nimport type { TimeScaleBus } from './time-scale-bus.js';\n\nexport interface IndicatorPaneStackOptions {\n theme?: 'dark' | 'light';\n showGrid?: boolean;\n config?: IndicatorConfig;\n}\n\nfunction barsForSource(bars: Bar[], source: IndicatorConfig['source']): Bar[] {\n if (source === 'close') return bars;\n return bars.map((b) => ({ ...b, c: (b.h + b.l + b.c) / 3 }));\n}\n\nfunction toUtcSeconds(tMs: number): UTCTimestamp {\n return Math.floor(tMs / 1000) as UTCTimestamp;\n}\n\nfunction lineData(bars: Bar[], values: (number | null)[]): LineData<UTCTimestamp>[] {\n const out: LineData<UTCTimestamp>[] = [];\n for (let i = 0; i < bars.length; i++) {\n const v = values[i];\n if (v == null) continue;\n out.push({ time: toUtcSeconds(bars[i]!.t), value: v });\n }\n return out;\n}\n\nfunction histData(bars: Bar[], values: (number | null)[]): HistogramData<UTCTimestamp>[] {\n const out: HistogramData<UTCTimestamp>[] = [];\n for (let i = 0; i < bars.length; i++) {\n const v = values[i];\n if (v == null) continue;\n out.push({\n time: toUtcSeconds(bars[i]!.t),\n value: v,\n color: v >= 0 ? '#26a69a88' : '#ef535088',\n });\n }\n return out;\n}\n\nexport class IndicatorPaneStack {\n private readonly macdChart: IChartApi;\n private readonly rsiChart: IChartApi;\n private readonly kdjChart: IChartApi;\n private readonly macdLine: ISeriesApi<'Line'>;\n private readonly macdSignal: ISeriesApi<'Line'>;\n private readonly macdHist: ISeriesApi<'Histogram'>;\n private readonly rsiLine: ISeriesApi<'Line'>;\n private readonly kdjK: ISeriesApi<'Line'>;\n private readonly kdjD: ISeriesApi<'Line'>;\n private readonly kdjJ: ISeriesApi<'Line'>;\n private dark = true;\n private showGrid = false;\n private config: IndicatorConfig = DEFAULT_INDICATOR_CONFIG;\n private readonly macdWrap: HTMLElement;\n private readonly rsiWrap: HTMLElement;\n private readonly kdjWrap: HTMLElement;\n\n constructor(\n private readonly root: HTMLElement,\n bus: TimeScaleBus,\n opts: IndicatorPaneStackOptions | 'dark' | 'light' = 'dark',\n ) {\n const o = typeof opts === 'string' ? { theme: opts, showGrid: false } : opts;\n this.dark = o.theme !== 'light';\n this.showGrid = o.showGrid ?? false;\n this.config = o.config ?? DEFAULT_INDICATOR_CONFIG;\n this.root.style.display = 'flex';\n this.root.style.flexDirection = 'column';\n this.root.style.flex = '2';\n this.root.style.minHeight = '0';\n this.root.style.overflow = 'hidden';\n\n const macdPane = this.createPaneWrap('MACD');\n const rsiPane = this.createPaneWrap('RSI');\n const kdjPane = this.createPaneWrap('KDJ');\n this.macdWrap = macdPane.wrap;\n this.rsiWrap = rsiPane.wrap;\n this.kdjWrap = kdjPane.wrap;\n this.root.append(macdPane.wrap, rsiPane.wrap, kdjPane.wrap);\n this.applyPaneVisibility();\n\n const layout = this.layoutForTheme(this.dark);\n const grid = gridOptions(this.showGrid, this.dark);\n this.macdChart = createChart(macdPane.el, { layout, grid, autoSize: true });\n this.rsiChart = createChart(rsiPane.el, { layout, grid, autoSize: true });\n this.kdjChart = createChart(kdjPane.el, { layout, grid, autoSize: true });\n\n for (const c of [this.macdChart, this.rsiChart, this.kdjChart]) bus.register(c);\n\n this.macdLine = this.macdChart.addSeries(LineSeries, { color: '#2962ff', lineWidth: 1 });\n this.macdSignal = this.macdChart.addSeries(LineSeries, { color: '#ff9800', lineWidth: 1 });\n this.macdHist = this.macdChart.addSeries(HistogramSeries, {\n priceFormat: { type: 'price', precision: 4, minMove: 0.0001 },\n });\n this.rsiLine = this.rsiChart.addSeries(LineSeries, { color: '#ab47bc', lineWidth: 1 });\n this.kdjK = this.kdjChart.addSeries(LineSeries, { color: '#42a5f5', lineWidth: 1 });\n this.kdjD = this.kdjChart.addSeries(LineSeries, { color: '#ffa726', lineWidth: 1 });\n this.kdjJ = this.kdjChart.addSeries(LineSeries, { color: '#ef5350', lineWidth: 1 });\n }\n\n setConfig(config: IndicatorConfig): void {\n this.config = config;\n this.applyPaneVisibility();\n }\n\n private applyPaneVisibility(): void {\n this.macdWrap.style.display = this.config.showMacd ? '' : 'none';\n this.rsiWrap.style.display = this.config.showRsi ? '' : 'none';\n this.kdjWrap.style.display = this.config.showKdj ? '' : 'none';\n }\n\n clearBars(): void {\n this.macdLine.setData([]);\n this.macdSignal.setData([]);\n this.macdHist.setData([]);\n this.rsiLine.setData([]);\n this.kdjK.setData([]);\n this.kdjD.setData([]);\n this.kdjJ.setData([]);\n }\n\n setBars(bars: Bar[]): void {\n if (bars.length === 0) return;\n const src = barsForSource(bars, this.config.source);\n const m = macd(src, this.config.macdFast, this.config.macdSlow, this.config.macdSignal);\n this.macdLine.setData(lineData(bars, m.macd));\n this.macdSignal.setData(lineData(bars, m.signal));\n this.macdHist.setData(histData(bars, m.histogram));\n\n this.rsiLine.setData(lineData(bars, rsi(src, this.config.rsiPeriod)));\n\n const k = kdj(src, this.config.kdjPeriod, this.config.kdjKSmooth, this.config.kdjDSmooth);\n this.kdjK.setData(lineData(bars, k.k));\n this.kdjD.setData(lineData(bars, k.d));\n this.kdjJ.setData(lineData(bars, k.j));\n\n this.macdChart.timeScale().fitContent();\n this.rsiChart.timeScale().fitContent();\n this.kdjChart.timeScale().fitContent();\n this.resize();\n }\n\n setTheme(theme: 'dark' | 'light'): void {\n this.dark = theme === 'dark';\n const layout = this.layoutForTheme(this.dark);\n const grid = gridOptions(this.showGrid, this.dark);\n this.macdChart.applyOptions({ layout, grid });\n this.rsiChart.applyOptions({ layout, grid });\n this.kdjChart.applyOptions({ layout, grid });\n }\n\n setShowGrid(show: boolean): void {\n this.showGrid = show;\n const grid = gridOptions(show, this.dark);\n this.macdChart.applyOptions({ grid });\n this.rsiChart.applyOptions({ grid });\n this.kdjChart.applyOptions({ grid });\n }\n\n fitContent(): void {\n this.macdChart.timeScale().fitContent();\n this.rsiChart.timeScale().fitContent();\n this.kdjChart.timeScale().fitContent();\n }\n\n scrollToRealtime(): void {\n this.macdChart.timeScale().scrollToRealTime();\n this.rsiChart.timeScale().scrollToRealTime();\n this.kdjChart.timeScale().scrollToRealTime();\n }\n\n resize(): void {\n for (const { chart, el } of [\n { chart: this.macdChart, el: this.macdChart.chartElement().parentElement },\n { chart: this.rsiChart, el: this.rsiChart.chartElement().parentElement },\n { chart: this.kdjChart, el: this.kdjChart.chartElement().parentElement },\n ]) {\n if (!el) continue;\n const w = el.clientWidth;\n const h = el.clientHeight;\n if (w > 0 && h > 0) chart.resize(w, h);\n }\n }\n\n destroy(): void {\n this.macdChart.remove();\n this.rsiChart.remove();\n this.kdjChart.remove();\n this.root.replaceChildren();\n }\n\n private createPaneWrap(label: string): { wrap: HTMLElement; el: HTMLElement } {\n const wrap = document.createElement('div');\n wrap.style.cssText =\n 'flex:1;min-height:72px;width:100%;position:relative;border-top:1px solid #30363d;';\n const tag = document.createElement('span');\n tag.textContent = label;\n tag.style.cssText =\n 'position:absolute;left:6px;top:4px;z-index:2;font-size:10px;color:#8b949e;pointer-events:none;';\n const el = document.createElement('div');\n el.style.cssText = 'width:100%;height:100%;';\n wrap.append(tag, el);\n return { wrap, el };\n }\n\n private layoutForTheme(dark: boolean) {\n return {\n background: { type: ColorType.Solid, color: dark ? '#0d1117' : '#ffffff' },\n textColor: dark ? '#e6edf3' : '#24292f',\n };\n }\n}\n\nexport function maOverlayLine(\n bars: Bar[],\n period = 20,\n source: IndicatorConfig['source'] = 'close',\n): LineData<UTCTimestamp>[] {\n const src = barsForSource(bars, source);\n return lineData(bars, sma(src, period));\n}\n\nexport function volMaOverlayLine(bars: Bar[], period = 5): LineData<UTCTimestamp>[] {\n const volBars = bars.map((b) => ({ ...b, c: b.v ?? 0 }));\n return lineData(bars, sma(volBars, period, 'close'));\n}\n\nexport function emaOverlayLine(\n bars: Bar[],\n period: number,\n source: IndicatorConfig['source'] = 'close',\n): LineData<UTCTimestamp>[] {\n const src = barsForSource(bars, source);\n return lineData(bars, ema(src, period));\n}\n\nexport function bollOverlayLines(\n bars: Bar[],\n period: number,\n mult: number,\n source: IndicatorConfig['source'] = 'close',\n): {\n upper: LineData<UTCTimestamp>[];\n middle: LineData<UTCTimestamp>[];\n lower: LineData<UTCTimestamp>[];\n} {\n const src = barsForSource(bars, source);\n const bands = boll(src, period, mult);\n return {\n upper: lineData(bars, bands.upper),\n middle: lineData(bars, bands.middle),\n lower: lineData(bars, bands.lower),\n };\n}","export function attachPaneResizer(\n topPane: HTMLElement,\n bottomPane: HTMLElement,\n opts: { minTopPx?: number; minBottomPx?: number; storageKey?: string } = {},\n): () => void {\n const minTop = opts.minTopPx ?? 120;\n const minBottom = opts.minBottomPx ?? 60;\n const parent = topPane.parentElement;\n if (!parent) return () => {};\n\n const handle = document.createElement('div');\n handle.style.cssText =\n 'height:4px;cursor:row-resize;background:#30363d;flex-shrink:0;touch-action:none;';\n bottomPane.insertAdjacentElement('beforebegin', handle);\n\n const saved = opts.storageKey ? localStorage.getItem(opts.storageKey) : null;\n if (saved) {\n const ratio = Number(saved);\n if (Number.isFinite(ratio) && ratio > 0 && ratio < 1) {\n topPane.style.flex = `${ratio * 10}`;\n bottomPane.style.flex = `${(1 - ratio) * 10}`;\n }\n }\n\n let dragging = false;\n\n const onMove = (clientY: number) => {\n const rect = parent.getBoundingClientRect();\n const y = clientY - rect.top;\n const ratio = Math.min(0.85, Math.max(0.15, y / rect.height));\n const topPx = ratio * rect.height;\n const bottomPx = rect.height - topPx - handle.offsetHeight;\n if (topPx < minTop || bottomPx < minBottom) return;\n topPane.style.flex = `${ratio * 10}`;\n bottomPane.style.flex = `${(1 - ratio) * 10}`;\n if (opts.storageKey) localStorage.setItem(opts.storageKey, String(ratio));\n };\n\n const stop = () => {\n dragging = false;\n document.body.style.cursor = '';\n };\n\n handle.addEventListener('pointerdown', (e) => {\n dragging = true;\n handle.setPointerCapture(e.pointerId);\n document.body.style.cursor = 'row-resize';\n });\n handle.addEventListener('pointermove', (e) => {\n if (dragging) onMove(e.clientY);\n });\n handle.addEventListener('pointerup', stop);\n handle.addEventListener('pointercancel', stop);\n\n return () => handle.remove();\n}","import type { IChartApi, LogicalRange, UTCTimestamp } from 'lightweight-charts';\n\nexport interface ChartVisibleRange {\n fromMs: number;\n toMs: number;\n}\n\nexport interface TransformState {\n visibleFromMs: number;\n visibleToMs: number;\n width: number;\n height: number;\n}\n\ntype TransformListener = (state: TransformState) => void;\n\n/** Sync visible logical range across multiple LWC panes (§10.4.1). */\nexport class TimeScaleBus {\n private charts: IChartApi[] = [];\n private listeners = new Set<TransformListener>();\n private syncing = false;\n visibleFromMs = 0;\n visibleToMs = 0;\n\n register(chart: IChartApi): void {\n if (this.charts.includes(chart)) return;\n this.charts.push(chart);\n chart.timeScale().subscribeVisibleLogicalRangeChange((range) => {\n if (this.syncing || !range) return;\n const tr = chart.timeScale().getVisibleRange();\n if (tr && typeof tr.from === 'number' && typeof tr.to === 'number') {\n this.visibleFromMs = tr.from * 1000;\n this.visibleToMs = tr.to * 1000;\n }\n this.syncFrom(chart, range);\n });\n }\n\n subscribeTransform(listener: TransformListener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n setBarsTimeRange(fromMs: number, toMs: number): void {\n this.visibleFromMs = fromMs;\n this.visibleToMs = toMs;\n this.emit();\n }\n\n getVisibleRange(): ChartVisibleRange | null {\n if (this.visibleToMs <= this.visibleFromMs) return null;\n return { fromMs: this.visibleFromMs, toMs: this.visibleToMs };\n }\n\n getBarSpacing(): number {\n const chart = this.charts[0];\n return chart ? chart.timeScale().options().barSpacing : 6;\n }\n\n setBarSpacing(spacing: number): void {\n if (!Number.isFinite(spacing) || spacing <= 0) return;\n this.syncing = true;\n for (const chart of this.charts) {\n chart.timeScale().applyOptions({ barSpacing: spacing });\n }\n this.syncing = false;\n this.emit();\n }\n\n setVisibleTimeRange(range: ChartVisibleRange): void {\n const from = Math.floor(range.fromMs / 1000) as UTCTimestamp;\n const to = Math.floor(range.toMs / 1000) as UTCTimestamp;\n if (to <= from) return;\n this.visibleFromMs = range.fromMs;\n this.visibleToMs = range.toMs;\n this.syncing = true;\n for (const chart of this.charts) {\n chart.timeScale().setVisibleRange({ from, to });\n }\n this.syncing = false;\n this.emit();\n }\n\n scrollToLogicalPosition(position: number, animated = false): void {\n this.syncing = true;\n for (const chart of this.charts) {\n chart.timeScale().scrollToPosition(position, animated);\n }\n this.syncing = false;\n this.emit();\n }\n\n private syncFrom(source: IChartApi, range: LogicalRange) {\n this.syncing = true;\n for (const chart of this.charts) {\n if (chart !== source) {\n chart.timeScale().setVisibleLogicalRange(range);\n }\n }\n this.syncing = false;\n this.emit();\n }\n\n private emit(): void {\n const state: TransformState = {\n visibleFromMs: this.visibleFromMs,\n visibleToMs: this.visibleToMs,\n width: 0,\n height: 0,\n };\n for (const l of this.listeners) l(state);\n }\n}","import type { Bar } from '@coderyo/data';\n\nfunction lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nfunction easeOutCubic(t: number): number {\n return 1 - Math.pow(1 - t, 3);\n}\n\n/** Interpolate last candle OHLC toward target over `durationMs` (interrupts on new target). */\nexport class BarSmoothAnimator {\n private raf = 0;\n private start = 0;\n private from: Bar | null = null;\n private to: Bar | null = null;\n\n constructor(\n private durationMs: number,\n private readonly onFrame: (bar: Bar) => void,\n ) {}\n\n setDuration(ms: number): void {\n this.durationMs = ms;\n }\n\n animateTo(target: Bar, from?: Bar): void {\n if (this.raf) cancelAnimationFrame(this.raf);\n const base = from ?? this.to ?? target;\n this.from = { ...base, t: target.t };\n this.to = { ...target };\n this.start = performance.now();\n\n const step = (now: number) => {\n const raw = Math.min(1, (now - this.start) / this.durationMs);\n const p = easeOutCubic(raw);\n const f = this.from!;\n const t = this.to!;\n const frame: Bar = {\n t: t.t,\n o: lerp(f.o, t.o, p),\n h: lerp(f.h, t.h, p),\n l: lerp(f.l, t.l, p),\n c: lerp(f.c, t.c, p),\n v: t.v,\n };\n this.onFrame(frame);\n if (raw < 1) {\n this.raf = requestAnimationFrame(step);\n } else {\n this.raf = 0;\n this.onFrame(t);\n }\n };\n this.raf = requestAnimationFrame(step);\n }\n\n cancel(): void {\n if (this.raf) cancelAnimationFrame(this.raf);\n this.raf = 0;\n }\n}"],"mappings":"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","names":["ColorType","createChart","HistogramSeries","LineSeries","toUtcSeconds","createChart","LineSeries","HistogramSeries","ColorType"]}
|
|
1
|
+
{"version":3,"sources":["../src/pane-orchestrator.ts","../src/chart-grid.ts","../src/indicator-panes.ts","../src/pane-resize.ts","../src/time-scale-bus.ts","../src/viewport-fit.ts","../src/bar-smooth-animator.ts"],"sourcesContent":["import {\n CandlestickSeries,\n ColorType,\n createChart,\n HistogramSeries,\n LineSeries,\n type CandlestickData,\n type HistogramData,\n type WhitespaceData,\n type IChartApi,\n type ISeriesApi,\n type IPriceLine,\n type MouseEventParams,\n type Time,\n type UTCTimestamp,\n} from 'lightweight-charts';\nimport { intervalMs, type Bar, type Interval } from '@coderyo/data';\nimport { lodDecimateBars } from '@coderyo/series';\nimport { gridOptions } from './chart-grid.js';\nimport { hasVisibleIndicatorPanes, type IndicatorConfig } from '@coderyo/indicators';\n\nimport {\n IndicatorPaneStack,\n bollOverlayLines,\n emaOverlayLine,\n maOverlayLine,\n volMaOverlayLine,\n} from './indicator-panes.js';\nimport { attachPaneResizer } from './pane-resize.js';\nimport { TimeScaleBus, type ChartVisibleRange } from './time-scale-bus.js';\nimport { resolveBarSpacingForInterval } from './viewport-fit.js';\n\nexport type { ChartVisibleRange };\nimport { BarSmoothAnimator } from './bar-smooth-animator.js';\n\nexport type ScaleMode = 'linear' | 'log';\n\nexport interface CrosshairPayload {\n time: number;\n price: number | null;\n ohlcv: { o: number; h: number; l: number; c: number; v?: number } | null;\n}\n\nexport interface PinePlotLine {\n title: string;\n color?: string;\n values: (number | null)[];\n}\n\nexport interface PaneOrchestratorOptions {\n container: HTMLElement;\n indicatorRoot?: HTMLElement;\n theme?: 'dark' | 'light';\n scaleMode?: ScaleMode;\n maxRenderPoints?: number;\n /** Show chart grid lines (default false). */\n showGrid?: boolean;\n /** null = no MA overlays and no MACD/RSI/KDJ panes. */\n indicatorConfig?: IndicatorConfig | null;\n /** Pine-lite plot lines on main chart (when pineEnabled). */\n pinePlots?: PinePlotLine[] | null;\n /** Animate last candle + price line toward new OHLC (~150ms). */\n smoothPriceUpdate?: boolean;\n smoothPriceDurationMs?: number;\n onIndicatorConfigChange?: (config: IndicatorConfig) => void;\n /** When true (default), set bar spacing on interval reload — does not change visible bar count. */\n autoBarSpacingOnInterval?: boolean;\n barSpacingByInterval?: Partial<Record<Interval, number>>;\n}\n\nfunction toUtcSeconds(tMs: number): UTCTimestamp {\n return Math.floor(tMs / 1000) as UTCTimestamp;\n}\n\nfunction barToCandle(b: Bar): CandlestickData {\n return { time: toUtcSeconds(b.t), open: b.o, high: b.h, low: b.l, close: b.c };\n}\n\nfunction barToVolume(b: Bar): HistogramData<UTCTimestamp> {\n return { time: toUtcSeconds(b.t), value: b.v ?? 0 };\n}\n\nexport class PaneOrchestrator {\n readonly bus = new TimeScaleBus();\n private readonly mainChart: IChartApi;\n private readonly volumeChart: IChartApi;\n private readonly mainSeries: ISeriesApi<'Candlestick'>;\n private readonly volumeSeries: ISeriesApi<'Histogram'>;\n private readonly maSeries: ISeriesApi<'Line'>;\n private readonly emaSeries: ISeriesApi<'Line'>;\n private readonly bollUpper: ISeriesApi<'Line'>;\n private readonly bollMiddle: ISeriesApi<'Line'>;\n private readonly bollLower: ISeriesApi<'Line'>;\n private readonly volMaSeries: ISeriesApi<'Line'>;\n private readonly indicatorRoot?: HTMLElement;\n private indicators: IndicatorPaneStack | null;\n private pinePlotSeries: ISeriesApi<'Line'>[] = [];\n private pinePlots: PinePlotLine[] | null = null;\n private overlayCanvas: HTMLCanvasElement | null = null;\n private dark = true;\n private showGrid = false;\n private readonly maxRenderPoints: number;\n private barByTime = new Map<number, Bar>();\n private barTimesOrdered: number[] = [];\n private didInitialFit = false;\n private skipNextInitialFit = false;\n private indicatorConfig: IndicatorConfig | null = null;\n private onIndicatorConfigChange?: (config: IndicatorConfig) => void;\n private currentInterval: Interval = '1h';\n private autoBarSpacingOnInterval = true;\n private barSpacingByInterval?: Partial<Record<Interval, number>>;\n private priceLine: IPriceLine | null = null;\n private barAnimator: BarSmoothAnimator | null = null;\n private smoothPriceDurationMs = 150;\n\n constructor(opts: PaneOrchestratorOptions) {\n this.maxRenderPoints = opts.maxRenderPoints ?? 4000;\n this.dark = opts.theme !== 'light';\n this.showGrid = opts.showGrid ?? false;\n const layout = this.layoutForTheme(this.dark);\n const grid = gridOptions(this.showGrid, this.dark);\n\n const mainEl = document.createElement('div');\n mainEl.style.cssText = 'flex:7;min-height:120px;width:100%;position:relative;';\n const volEl = document.createElement('div');\n volEl.style.cssText = 'flex:2;min-height:64px;width:100%;position:relative;';\n\n opts.container.style.cssText =\n 'display:flex;flex-direction:column;height:100%;width:100%;min-height:240px;overflow:hidden;';\n opts.container.append(mainEl, volEl);\n attachPaneResizer(mainEl, volEl, { storageKey: 'tradview:pane:main-volume' });\n\n this.mainChart = createChart(mainEl, { layout, grid, autoSize: true });\n this.volumeChart = createChart(volEl, {\n layout,\n grid,\n autoSize: true,\n rightPriceScale: { scaleMargins: { top: 0.8, bottom: 0 } },\n });\n\n if (opts.scaleMode === 'log') {\n this.mainChart.priceScale('right').applyOptions({ mode: 1 });\n }\n\n this.mainSeries = this.mainChart.addSeries(CandlestickSeries, {\n upColor: '#26a69a',\n downColor: '#ef5350',\n borderVisible: false,\n wickUpColor: '#26a69a',\n wickDownColor: '#ef5350',\n });\n this.maSeries = this.mainChart.addSeries(LineSeries, {\n color: '#f0b429',\n lineWidth: 1,\n title: 'MA',\n });\n this.emaSeries = this.mainChart.addSeries(LineSeries, {\n color: '#7ee787',\n lineWidth: 1,\n title: 'EMA',\n visible: false,\n });\n this.bollUpper = this.mainChart.addSeries(LineSeries, {\n color: '#8b949e',\n lineWidth: 1,\n title: 'BOLL↑',\n visible: false,\n });\n this.bollMiddle = this.mainChart.addSeries(LineSeries, {\n color: '#8b949e88',\n lineWidth: 1,\n lineStyle: 2,\n title: 'BOLL',\n visible: false,\n });\n this.bollLower = this.mainChart.addSeries(LineSeries, {\n color: '#8b949e',\n lineWidth: 1,\n title: 'BOLL↓',\n visible: false,\n });\n this.volumeSeries = this.volumeChart.addSeries(HistogramSeries, {\n color: '#26a69a55',\n priceFormat: { type: 'volume' },\n });\n this.volMaSeries = this.volumeChart.addSeries(LineSeries, {\n color: '#58a6ff',\n lineWidth: 1,\n title: 'VolMA5',\n });\n\n this.bus.register(this.mainChart);\n this.bus.register(this.volumeChart);\n\n this.indicatorRoot = opts.indicatorRoot;\n this.indicatorConfig = opts.indicatorConfig ?? null;\n this.onIndicatorConfigChange = opts.onIndicatorConfigChange;\n this.autoBarSpacingOnInterval = opts.autoBarSpacingOnInterval ?? true;\n this.barSpacingByInterval = opts.barSpacingByInterval;\n this.pinePlots = opts.pinePlots ?? null;\n this.indicators = this.createIndicatorStack();\n\n this.initOverlay(mainEl);\n this.setSmoothPriceUpdate(opts.smoothPriceUpdate ?? false, opts.smoothPriceDurationMs);\n }\n\n setSmoothPriceUpdate(enabled: boolean, durationMs = 150): void {\n this.smoothPriceDurationMs = durationMs;\n if (enabled) {\n if (!this.barAnimator) {\n this.barAnimator = new BarSmoothAnimator(durationMs, (bar) => this.applyLastBarToSeries(bar));\n } else {\n this.barAnimator.setDuration(durationMs);\n }\n return;\n }\n this.barAnimator?.cancel();\n this.barAnimator = null;\n if (this.priceLine) {\n this.mainSeries.removePriceLine(this.priceLine);\n this.priceLine = null;\n }\n }\n\n /** Update the last candle (and price line); optional smooth interpolation. */\n updateLastBar(target: Bar, opts?: { smooth?: boolean; durationMs?: number }): void {\n const prev = this.barByTime.get(target.t);\n const smooth = opts?.smooth ?? !!this.barAnimator;\n const duration = opts?.durationMs ?? this.smoothPriceDurationMs;\n if (smooth && this.barAnimator) {\n this.barAnimator.setDuration(duration);\n this.barAnimator.animateTo(target, prev ?? target);\n return;\n }\n this.barAnimator?.cancel();\n this.applyLastBarToSeries(target);\n }\n\n private applyLastBarToSeries(bar: Bar): void {\n this.barByTime.set(bar.t, bar);\n this.mainSeries.update(barToCandle(bar));\n this.volumeSeries.update(barToVolume(bar));\n this.ensurePriceLine(bar.c);\n if (this.indicatorConfig) {\n const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);\n this.applyMainOverlays(bars);\n if (hasVisibleIndicatorPanes(this.indicatorConfig)) {\n this.indicators?.setBars(bars);\n }\n }\n }\n\n private ensurePriceLine(price: number): void {\n if (!this.priceLine) {\n this.priceLine = this.mainSeries.createPriceLine({\n price,\n color: '#58a6ff',\n lineWidth: 1,\n lineStyle: 2,\n axisLabelVisible: true,\n title: '',\n });\n } else {\n this.priceLine.applyOptions({ price });\n }\n }\n\n setIntervalContext(interval: Interval): void {\n this.currentInterval = interval;\n }\n\n setTheme(theme: 'dark' | 'light'): void {\n this.dark = theme === 'dark';\n const layout = this.layoutForTheme(this.dark);\n const grid = gridOptions(this.showGrid, this.dark);\n this.mainChart.applyOptions({ layout, grid });\n this.volumeChart.applyOptions({ layout, grid });\n this.indicators?.setTheme(theme);\n }\n\n setIndicatorConfig(config: IndicatorConfig | null): void {\n this.indicatorConfig = config;\n if (!config) {\n this.teardownIndicatorStack();\n this.maSeries.setData([]);\n this.emaSeries.setData([]);\n this.bollUpper.setData([]);\n this.bollMiddle.setData([]);\n this.bollLower.setData([]);\n this.volMaSeries.setData([]);\n this.emaSeries.applyOptions({ visible: false });\n this.bollUpper.applyOptions({ visible: false });\n this.bollMiddle.applyOptions({ visible: false });\n this.bollLower.applyOptions({ visible: false });\n return;\n }\n if (!this.indicators) this.indicators = this.createIndicatorStack();\n const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);\n this.indicators?.setConfig(config);\n if (bars.length > 0) {\n this.applyMainOverlays(bars);\n if (hasVisibleIndicatorPanes(config)) {\n this.indicators?.setBars(bars);\n }\n }\n }\n\n setPinePlots(plots: PinePlotLine[] | null): void {\n this.pinePlots = plots;\n const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);\n this.syncPinePlotSeries(bars);\n }\n\n private teardownIndicatorStack(): void {\n this.indicators?.destroy();\n this.indicators = null;\n }\n\n private applyMainOverlays(bars: Bar[]): void {\n const cfg = this.indicatorConfig;\n if (!cfg) return;\n if (cfg.showMa) {\n this.maSeries.applyOptions({ visible: true, title: `MA${cfg.maPeriod}` });\n this.maSeries.setData(maOverlayLine(bars, cfg.maPeriod, cfg.source));\n } else {\n this.maSeries.applyOptions({ visible: false });\n this.maSeries.setData([]);\n }\n if (cfg.showVolMa) {\n this.volMaSeries.applyOptions({ visible: true });\n this.volMaSeries.setData(volMaOverlayLine(bars, cfg.volMaPeriod));\n } else {\n this.volMaSeries.applyOptions({ visible: false });\n this.volMaSeries.setData([]);\n }\n\n if (cfg.showEma) {\n this.emaSeries.applyOptions({ visible: true, title: `EMA${cfg.emaPeriod}` });\n this.emaSeries.setData(emaOverlayLine(bars, cfg.emaPeriod, cfg.source));\n } else {\n this.emaSeries.applyOptions({ visible: false });\n this.emaSeries.setData([]);\n }\n\n if (cfg.showBoll) {\n const bands = bollOverlayLines(bars, cfg.bollPeriod, cfg.bollMult, cfg.source);\n this.bollUpper.applyOptions({ visible: true });\n this.bollMiddle.applyOptions({ visible: true });\n this.bollLower.applyOptions({ visible: true });\n this.bollUpper.setData(bands.upper);\n this.bollMiddle.setData(bands.middle);\n this.bollLower.setData(bands.lower);\n } else {\n this.bollUpper.applyOptions({ visible: false });\n this.bollMiddle.applyOptions({ visible: false });\n this.bollLower.applyOptions({ visible: false });\n this.bollUpper.setData([]);\n this.bollMiddle.setData([]);\n this.bollLower.setData([]);\n }\n this.syncPinePlotSeries(bars);\n }\n\n private syncPinePlotSeries(bars: Bar[]): void {\n for (const s of this.pinePlotSeries) this.mainChart.removeSeries(s);\n this.pinePlotSeries = [];\n if (!this.pinePlots?.length || bars.length === 0) return;\n\n const palette = ['#58a6ff', '#d2a8ff', '#ff7b72', '#ffa657'];\n for (let i = 0; i < this.pinePlots.length; i++) {\n const plot = this.pinePlots[i]!;\n const series = this.mainChart.addSeries(LineSeries, {\n color: plot.color ?? palette[i % palette.length]!,\n lineWidth: 1,\n title: plot.title,\n });\n const out: { time: UTCTimestamp; value: number }[] = [];\n for (let j = 0; j < bars.length; j++) {\n const v = plot.values[j];\n if (v == null) continue;\n out.push({ time: toUtcSeconds(bars[j]!.t), value: v });\n }\n series.setData(out);\n this.pinePlotSeries.push(series);\n }\n }\n\n setShowGrid(show: boolean): void {\n this.showGrid = show;\n const grid = gridOptions(show, this.dark);\n this.mainChart.applyOptions({ grid });\n this.volumeChart.applyOptions({ grid });\n this.indicators?.setShowGrid(show);\n }\n\n setBars(bars: Bar[], gaps?: number[]): void {\n const renderBars = lodDecimateBars(bars, this.maxRenderPoints);\n this.barByTime = new Map(renderBars.map((b) => [b.t, b]));\n this.barTimesOrdered = renderBars.map((b) => b.t);\n\n const gapSet = new Set(gaps ?? []);\n const seenTimes = new Set<number>();\n type CandlePoint = CandlestickData | WhitespaceData<UTCTimestamp>;\n const candles: CandlePoint[] = [];\n const vols: HistogramData<UTCTimestamp>[] = [];\n\n for (let i = 0; i < renderBars.length; i++) {\n const b = renderBars[i]!;\n const time = toUtcSeconds(b.t);\n if (seenTimes.has(time)) continue;\n seenTimes.add(time);\n if (gapSet.has(b.t)) {\n candles.push({ time });\n }\n candles.push(barToCandle(b));\n vols.push(barToVolume(b));\n }\n\n this.mainSeries.setData(candles);\n this.volumeSeries.setData(vols);\n if (this.indicatorConfig) {\n this.applyMainOverlays(renderBars);\n if (hasVisibleIndicatorPanes(this.indicatorConfig)) {\n this.indicators?.setBars(renderBars);\n }\n } else {\n this.maSeries.setData([]);\n this.emaSeries.setData([]);\n this.bollUpper.setData([]);\n this.bollMiddle.setData([]);\n this.bollLower.setData([]);\n this.volMaSeries.setData([]);\n this.syncPinePlotSeries(renderBars);\n }\n\n if (renderBars.length > 0) {\n this.syncChartSize();\n if (!this.didInitialFit && !this.skipNextInitialFit) {\n this.applyViewAfterDataReload(renderBars);\n this.didInitialFit = true;\n }\n this.skipNextInitialFit = false;\n }\n }\n\n subscribeCrosshair(listener: (payload: CrosshairPayload | null) => void): () => void {\n const handler = (param: MouseEventParams<Time>) => {\n if (param.time == null || !param.point) {\n listener(null);\n return;\n }\n const tMs = typeof param.time === 'number' ? param.time * 1000 : null;\n if (tMs == null) {\n listener(null);\n return;\n }\n const price = this.mainSeries.coordinateToPrice(param.point.y) ?? null;\n const bar = this.barByTime.get(tMs) ?? this.findNearestBar(tMs);\n listener({\n time: tMs,\n price,\n ohlcv: bar\n ? { o: bar.o, h: bar.h, l: bar.l, c: bar.c, v: bar.v }\n : null,\n });\n };\n this.mainChart.subscribeCrosshairMove(handler);\n return () => this.mainChart.unsubscribeCrosshairMove(handler);\n }\n\n private findNearestBar(tMs: number): Bar | null {\n let best: Bar | null = null;\n let bestDt = Infinity;\n for (const b of this.barByTime.values()) {\n const dt = Math.abs(b.t - tMs);\n if (dt < bestDt) {\n bestDt = dt;\n best = b;\n }\n }\n return bestDt < 120_000 ? best : null;\n }\n\n private createIndicatorStack(): IndicatorPaneStack | null {\n if (!this.indicatorRoot || !this.indicatorConfig) return null;\n return new IndicatorPaneStack(this.indicatorRoot, this.bus, {\n theme: this.dark ? 'dark' : 'light',\n showGrid: this.showGrid,\n config: this.indicatorConfig,\n onConfigChange: (config) => {\n this.indicatorConfig = config;\n this.onIndicatorConfigChange?.(config);\n },\n });\n }\n\n /** After symbol/interval reload: bar spacing for interval + show integrator-loaded span. */\n applyIntervalBarSpacing(interval?: Interval): void {\n if (!this.autoBarSpacingOnInterval) return;\n const iv = interval ?? this.currentInterval;\n const spacing = resolveBarSpacingForInterval(iv, this.barSpacingByInterval);\n this.bus.setBarSpacing(spacing);\n }\n\n setBarSpacingPolicy(opts: {\n autoBarSpacingOnInterval?: boolean;\n barSpacingByInterval?: Partial<Record<Interval, number>>;\n }): void {\n if (opts.autoBarSpacingOnInterval !== undefined) {\n this.autoBarSpacingOnInterval = opts.autoBarSpacingOnInterval;\n }\n if (opts.barSpacingByInterval !== undefined) {\n this.barSpacingByInterval = opts.barSpacingByInterval;\n }\n }\n\n /** Sync time scale to loaded bars (integrator history); adjust bar spacing only, not bar count. */\n private applyViewAfterDataReload(renderBars: Bar[]): void {\n if (this.autoBarSpacingOnInterval) {\n this.applyIntervalBarSpacing();\n } else {\n this.mainChart.timeScale().fitContent();\n this.volumeChart.timeScale().fitContent();\n this.indicators?.fitContent();\n }\n\n if (renderBars.length > 0) {\n const fromMs = renderBars[0]!.t;\n const toMs = renderBars[renderBars.length - 1]!.t + intervalMs(this.currentInterval);\n this.bus.setVisibleTimeRange({ fromMs, toMs });\n }\n this.scrollToRealtime();\n }\n\n resetViewState(): void {\n this.didInitialFit = false;\n this.skipNextInitialFit = false;\n this.bus.visibleFromMs = 0;\n this.bus.visibleToMs = 0;\n }\n\n /** Skip the next automatic fitContent after setBars (used by reloadHistory). */\n preserveViewportOnNextSetBars(): void {\n this.skipNextInitialFit = true;\n this.didInitialFit = true;\n }\n\n getVisibleRange(): ChartVisibleRange | null {\n return this.bus.getVisibleRange();\n }\n\n getBarSpace(): number {\n return this.bus.getBarSpacing();\n }\n\n setBarSpace(px: number): void {\n this.bus.setBarSpacing(px);\n }\n\n setVisibleRange(range: ChartVisibleRange): void {\n this.bus.setVisibleTimeRange(range);\n this.didInitialFit = true;\n }\n\n scrollToTimestamp(tsMs: number, animationMs?: number): void {\n const time = toUtcSeconds(tsMs);\n const idx = this.mainChart.timeScale().timeToIndex(time, true);\n if (idx == null) {\n const nearest = this.findNearestBar(tsMs);\n if (nearest == null) return;\n const i = this.barTimesOrdered.indexOf(nearest.t);\n if (i < 0) return;\n this.bus.scrollToLogicalPosition(i, (animationMs ?? 0) > 0);\n return;\n }\n this.bus.scrollToLogicalPosition(idx as number, (animationMs ?? 0) > 0);\n }\n\n /** Clear series while symbol/interval data reloads (avoids overlapping candles). */\n clearBars(): void {\n this.barAnimator?.cancel();\n this.barByTime = new Map();\n this.barTimesOrdered = [];\n this.mainSeries.setData([]);\n this.maSeries.setData([]);\n this.volumeSeries.setData([]);\n this.volMaSeries.setData([]);\n this.indicators?.clearBars();\n }\n\n fitContent(): void {\n this.mainChart.timeScale().fitContent();\n this.volumeChart.timeScale().fitContent();\n this.indicators?.fitContent();\n this.didInitialFit = true;\n }\n\n scrollToRealtime(): void {\n this.mainChart.timeScale().scrollToRealTime();\n this.volumeChart.timeScale().scrollToRealTime();\n this.indicators?.scrollToRealtime();\n }\n\n setLogScale(enabled: boolean): void {\n this.mainChart.priceScale('right').applyOptions({ mode: enabled ? 1 : 0 });\n }\n\n resize(): void {\n this.syncChartSize();\n this.syncOverlaySize();\n this.indicators?.resize();\n }\n\n getOverlayCanvas(): HTMLCanvasElement | null {\n return this.overlayCanvas;\n }\n\n timeToX(tMs: number): number | null {\n const coord = this.mainChart.timeScale().timeToCoordinate(toUtcSeconds(tMs));\n if (coord == null) return null;\n return coord * devicePixelRatio;\n }\n\n priceToY(price: number): number | null {\n const coord = this.mainSeries.priceToCoordinate(price);\n if (coord == null) return null;\n return coord * devicePixelRatio;\n }\n\n xToTime(x: number): number | null {\n const t = this.mainChart.timeScale().coordinateToTime(x / devicePixelRatio);\n if (t == null) return null;\n return Number(t) * 1000;\n }\n\n yToPrice(y: number): number | null {\n const p = this.mainSeries.coordinateToPrice(y / devicePixelRatio);\n return p ?? null;\n }\n\n destroy(): void {\n this.barAnimator?.cancel();\n if (this.priceLine) {\n this.mainSeries.removePriceLine(this.priceLine);\n this.priceLine = null;\n }\n this.mainChart.remove();\n this.volumeChart.remove();\n this.indicators?.destroy();\n this.overlayCanvas?.remove();\n }\n\n private initOverlay(parent: HTMLElement) {\n const canvas = document.createElement('canvas');\n canvas.style.cssText =\n 'position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:10;';\n parent.style.position = 'relative';\n parent.appendChild(canvas);\n this.overlayCanvas = canvas;\n this.syncOverlaySize();\n this.bus.subscribeTransform(() => {\n this.syncOverlaySize();\n });\n }\n\n /** Let drawing overlay receive clicks; cursor mode keeps pan/zoom on LWC. */\n setOverlayPointerEvents(mode: 'auto' | 'none'): void {\n if (this.overlayCanvas) this.overlayCanvas.style.pointerEvents = mode;\n }\n\n private syncOverlaySize() {\n if (!this.overlayCanvas?.parentElement) return;\n const parent = this.overlayCanvas.parentElement;\n if (parent.lastElementChild !== this.overlayCanvas) {\n parent.appendChild(this.overlayCanvas);\n }\n const rect = parent.getBoundingClientRect();\n this.overlayCanvas.width = rect.width * devicePixelRatio;\n this.overlayCanvas.height = rect.height * devicePixelRatio;\n }\n\n private syncChartSize(): void {\n const mainEl = this.mainChart.chartElement().parentElement;\n const volEl = this.volumeChart.chartElement().parentElement;\n if (mainEl) {\n const w = mainEl.clientWidth;\n const h = mainEl.clientHeight;\n if (w > 0 && h > 0) this.mainChart.resize(w, h);\n }\n if (volEl) {\n const w = volEl.clientWidth;\n const h = volEl.clientHeight;\n if (w > 0 && h > 0) this.volumeChart.resize(w, h);\n }\n }\n\n private layoutForTheme(dark: boolean) {\n return {\n background: { type: ColorType.Solid, color: dark ? '#0d1117' : '#ffffff' },\n textColor: dark ? '#e6edf3' : '#24292f',\n };\n }\n}","/** LWC grid line options — default off per product spec. */\nexport function gridOptions(showGrid: boolean, dark: boolean) {\n const color = dark ? '#21262d' : '#d0d7de';\n return {\n vertLines: { visible: showGrid, color },\n horzLines: { visible: showGrid, color },\n };\n}","import {\n ColorType,\n createChart,\n HistogramSeries,\n LineSeries,\n type HistogramData,\n type IChartApi,\n type ISeriesApi,\n type LineData,\n type UTCTimestamp,\n} from 'lightweight-charts';\nimport type { Bar } from '@coderyo/data';\nimport {\n type IndicatorConfig,\n DEFAULT_INDICATOR_CONFIG,\n hasVisibleIndicatorPanes,\n boll,\n kdj,\n macd,\n rsi,\n sma,\n ema,\n} from '@coderyo/indicators';\nimport { gridOptions } from './chart-grid.js';\nimport { attachPaneResizer } from './pane-resize.js';\nimport type { TimeScaleBus } from './time-scale-bus.js';\n\nexport type IndicatorPaneId = 'macd' | 'rsi' | 'kdj';\n\nexport interface IndicatorPaneStackOptions {\n theme?: 'dark' | 'light';\n showGrid?: boolean;\n config?: IndicatorConfig;\n onConfigChange?: (config: IndicatorConfig) => void;\n}\n\nfunction barsForSource(bars: Bar[], source: IndicatorConfig['source']): Bar[] {\n if (source === 'close') return bars;\n return bars.map((b) => ({ ...b, c: (b.h + b.l + b.c) / 3 }));\n}\n\nfunction toUtcSeconds(tMs: number): UTCTimestamp {\n return Math.floor(tMs / 1000) as UTCTimestamp;\n}\n\n/** PR-21: detect in-place tail updates vs full recompute. */\nexport function detectIndicatorBarMutation(\n prevTimes: number[],\n bars: Bar[],\n): 'full' | 'tail-append' | 'tail-update' {\n if (prevTimes.length === 0 || bars.length < prevTimes.length) return 'full';\n const prefixLen = Math.min(prevTimes.length, bars.length);\n for (let i = 0; i < prefixLen - 1; i++) {\n if (bars[i]!.t !== prevTimes[i]) return 'full';\n }\n if (bars.length === prevTimes.length) {\n return bars.length > 0 && bars[bars.length - 1]!.t === prevTimes[prevTimes.length - 1]\n ? 'tail-update'\n : 'full';\n }\n if (bars.length - prevTimes.length > 8) return 'full';\n for (let i = 0; i < prevTimes.length; i++) {\n if (bars[i]!.t !== prevTimes[i]) return 'full';\n }\n return 'tail-append';\n}\n\nfunction lineData(bars: Bar[], values: (number | null)[]): LineData<UTCTimestamp>[] {\n const out: LineData<UTCTimestamp>[] = [];\n for (let i = 0; i < bars.length; i++) {\n const v = values[i];\n if (v == null) continue;\n out.push({ time: toUtcSeconds(bars[i]!.t), value: v });\n }\n return out;\n}\n\nfunction histData(bars: Bar[], values: (number | null)[]): HistogramData<UTCTimestamp>[] {\n const out: HistogramData<UTCTimestamp>[] = [];\n for (let i = 0; i < bars.length; i++) {\n const v = values[i];\n if (v == null) continue;\n out.push({\n time: toUtcSeconds(bars[i]!.t),\n value: v,\n color: v >= 0 ? '#26a69a88' : '#ef535088',\n });\n }\n return out;\n}\n\nexport class IndicatorPaneStack {\n private readonly macdChart: IChartApi;\n private readonly rsiChart: IChartApi;\n private readonly kdjChart: IChartApi;\n private readonly macdLine: ISeriesApi<'Line'>;\n private readonly macdSignal: ISeriesApi<'Line'>;\n private readonly macdHist: ISeriesApi<'Histogram'>;\n private readonly rsiLine: ISeriesApi<'Line'>;\n private readonly kdjK: ISeriesApi<'Line'>;\n private readonly kdjD: ISeriesApi<'Line'>;\n private readonly kdjJ: ISeriesApi<'Line'>;\n private dark = true;\n private showGrid = false;\n private config: IndicatorConfig = DEFAULT_INDICATOR_CONFIG;\n private readonly macdWrap: HTMLElement;\n private readonly rsiWrap: HTMLElement;\n private readonly kdjWrap: HTMLElement;\n private readonly detachResizers: Array<() => void> = [];\n private lastBarTimes: number[] = [];\n private onConfigChange?: (config: IndicatorConfig) => void;\n\n constructor(\n private readonly root: HTMLElement,\n bus: TimeScaleBus,\n opts: IndicatorPaneStackOptions | 'dark' | 'light' = 'dark',\n ) {\n const o = typeof opts === 'string' ? { theme: opts, showGrid: false } : opts;\n this.dark = o.theme !== 'light';\n this.showGrid = o.showGrid ?? false;\n this.config = o.config ?? DEFAULT_INDICATOR_CONFIG;\n this.onConfigChange = o.onConfigChange;\n this.root.style.display = 'flex';\n this.root.style.flexDirection = 'column';\n this.root.style.flex = '2';\n this.root.style.minHeight = '0';\n this.root.style.overflow = 'hidden';\n\n const macdPane = this.createPaneWrap('MACD', 'macd');\n const rsiPane = this.createPaneWrap('RSI', 'rsi');\n const kdjPane = this.createPaneWrap('KDJ', 'kdj');\n this.macdWrap = macdPane.wrap;\n this.rsiWrap = rsiPane.wrap;\n this.kdjWrap = kdjPane.wrap;\n this.root.append(macdPane.wrap, rsiPane.wrap, kdjPane.wrap);\n this.detachResizers.push(\n attachPaneResizer(macdPane.wrap, rsiPane.wrap, {\n storageKey: 'tradview:pane:macd-rsi',\n minTopPx: 72,\n minBottomPx: 72,\n }),\n attachPaneResizer(rsiPane.wrap, kdjPane.wrap, {\n storageKey: 'tradview:pane:rsi-kdj',\n minTopPx: 72,\n minBottomPx: 72,\n }),\n );\n this.applyPaneVisibility();\n\n const layout = this.layoutForTheme(this.dark);\n const grid = gridOptions(this.showGrid, this.dark);\n this.macdChart = createChart(macdPane.el, { layout, grid, autoSize: true });\n this.rsiChart = createChart(rsiPane.el, { layout, grid, autoSize: true });\n this.kdjChart = createChart(kdjPane.el, { layout, grid, autoSize: true });\n\n for (const c of [this.macdChart, this.rsiChart, this.kdjChart]) bus.register(c);\n\n this.macdLine = this.macdChart.addSeries(LineSeries, { color: '#2962ff', lineWidth: 1 });\n this.macdSignal = this.macdChart.addSeries(LineSeries, { color: '#ff9800', lineWidth: 1 });\n this.macdHist = this.macdChart.addSeries(HistogramSeries, {\n priceFormat: { type: 'price', precision: 4, minMove: 0.0001 },\n });\n this.rsiLine = this.rsiChart.addSeries(LineSeries, { color: '#ab47bc', lineWidth: 1 });\n this.kdjK = this.kdjChart.addSeries(LineSeries, { color: '#42a5f5', lineWidth: 1 });\n this.kdjD = this.kdjChart.addSeries(LineSeries, { color: '#ffa726', lineWidth: 1 });\n this.kdjJ = this.kdjChart.addSeries(LineSeries, { color: '#ef5350', lineWidth: 1 });\n }\n\n setConfig(config: IndicatorConfig): void {\n this.config = config;\n this.lastBarTimes = [];\n this.applyPaneVisibility();\n if (!this.config.showMacd && !this.config.showRsi && !this.config.showKdj) {\n this.clearBars();\n }\n }\n\n private closePane(id: IndicatorPaneId): void {\n const patch: Partial<IndicatorConfig> =\n id === 'macd' ? { showMacd: false } : id === 'rsi' ? { showRsi: false } : { showKdj: false };\n this.config = { ...this.config, ...patch };\n this.applyPaneVisibility();\n this.onConfigChange?.(this.config);\n }\n\n private applyPaneVisibility(): void {\n this.macdWrap.style.display = this.config.showMacd ? '' : 'none';\n this.rsiWrap.style.display = this.config.showRsi ? '' : 'none';\n this.kdjWrap.style.display = this.config.showKdj ? '' : 'none';\n const anyVisible = this.config.showMacd || this.config.showRsi || this.config.showKdj;\n this.root.style.display = anyVisible ? 'flex' : 'none';\n }\n\n clearBars(): void {\n this.macdLine.setData([]);\n this.macdSignal.setData([]);\n this.macdHist.setData([]);\n this.rsiLine.setData([]);\n this.kdjK.setData([]);\n this.kdjD.setData([]);\n this.kdjJ.setData([]);\n this.lastBarTimes = [];\n }\n\n private warmupLookback(): number {\n const c = this.config;\n return (\n Math.max(\n c.macdSlow + c.macdSignal,\n c.rsiPeriod,\n c.kdjPeriod + c.kdjKSmooth + c.kdjDSmooth,\n ) + 5\n );\n }\n\n private detectBarMutation(bars: Bar[]): 'full' | 'tail-append' | 'tail-update' {\n return detectIndicatorBarMutation(this.lastBarTimes, bars);\n }\n\n private pushSeriesUpdates(\n series: ISeriesApi<'Line'>,\n bars: Bar[],\n values: (number | null)[],\n fromIndex: number,\n ): void {\n for (let i = fromIndex; i < bars.length; i++) {\n const v = values[i];\n if (v == null) continue;\n series.update({ time: toUtcSeconds(bars[i]!.t), value: v });\n }\n }\n\n private pushHistUpdates(\n series: ISeriesApi<'Histogram'>,\n bars: Bar[],\n values: (number | null)[],\n fromIndex: number,\n ): void {\n for (let i = fromIndex; i < bars.length; i++) {\n const v = values[i];\n if (v == null) continue;\n series.update({\n time: toUtcSeconds(bars[i]!.t),\n value: v,\n color: v >= 0 ? '#26a69a88' : '#ef535088',\n });\n }\n }\n\n setBars(bars: Bar[]): void {\n if (bars.length === 0) {\n this.clearBars();\n return;\n }\n\n const needMacd = this.config.showMacd;\n const needRsi = this.config.showRsi;\n const needKdj = this.config.showKdj;\n if (!hasVisibleIndicatorPanes(this.config)) {\n return;\n }\n\n const mutation = this.detectBarMutation(bars);\n this.lastBarTimes = bars.map((b) => b.t);\n const src = barsForSource(bars, this.config.source);\n const m = needMacd\n ? macd(src, this.config.macdFast, this.config.macdSlow, this.config.macdSignal)\n : null;\n const r = needRsi ? rsi(src, this.config.rsiPeriod) : null;\n const k = needKdj\n ? kdj(src, this.config.kdjPeriod, this.config.kdjKSmooth, this.config.kdjDSmooth)\n : null;\n\n if (mutation === 'full') {\n if (needMacd && m) {\n this.macdLine.setData(lineData(bars, m.macd));\n this.macdSignal.setData(lineData(bars, m.signal));\n this.macdHist.setData(histData(bars, m.histogram));\n this.macdChart.timeScale().fitContent();\n }\n if (needRsi && r) {\n this.rsiLine.setData(lineData(bars, r));\n this.rsiChart.timeScale().fitContent();\n }\n if (needKdj && k) {\n this.kdjK.setData(lineData(bars, k.k));\n this.kdjD.setData(lineData(bars, k.d));\n this.kdjJ.setData(lineData(bars, k.j));\n this.kdjChart.timeScale().fitContent();\n }\n } else {\n const from =\n mutation === 'tail-update' ? Math.max(0, bars.length - 1) : Math.max(0, bars.length - this.warmupLookback());\n if (needMacd && m) {\n this.pushSeriesUpdates(this.macdLine, bars, m.macd, from);\n this.pushSeriesUpdates(this.macdSignal, bars, m.signal, from);\n this.pushHistUpdates(this.macdHist, bars, m.histogram, from);\n }\n if (needRsi && r) {\n this.pushSeriesUpdates(this.rsiLine, bars, r, from);\n }\n if (needKdj && k) {\n this.pushSeriesUpdates(this.kdjK, bars, k.k, from);\n this.pushSeriesUpdates(this.kdjD, bars, k.d, from);\n this.pushSeriesUpdates(this.kdjJ, bars, k.j, from);\n }\n }\n\n this.resize();\n }\n\n setTheme(theme: 'dark' | 'light'): void {\n this.dark = theme === 'dark';\n const layout = this.layoutForTheme(this.dark);\n const grid = gridOptions(this.showGrid, this.dark);\n this.macdChart.applyOptions({ layout, grid });\n this.rsiChart.applyOptions({ layout, grid });\n this.kdjChart.applyOptions({ layout, grid });\n }\n\n setShowGrid(show: boolean): void {\n this.showGrid = show;\n const grid = gridOptions(show, this.dark);\n this.macdChart.applyOptions({ grid });\n this.rsiChart.applyOptions({ grid });\n this.kdjChart.applyOptions({ grid });\n }\n\n fitContent(): void {\n this.macdChart.timeScale().fitContent();\n this.rsiChart.timeScale().fitContent();\n this.kdjChart.timeScale().fitContent();\n }\n\n scrollToRealtime(): void {\n this.macdChart.timeScale().scrollToRealTime();\n this.rsiChart.timeScale().scrollToRealTime();\n this.kdjChart.timeScale().scrollToRealTime();\n }\n\n resize(): void {\n for (const { chart, el } of [\n { chart: this.macdChart, el: this.macdChart.chartElement().parentElement },\n { chart: this.rsiChart, el: this.rsiChart.chartElement().parentElement },\n { chart: this.kdjChart, el: this.kdjChart.chartElement().parentElement },\n ]) {\n if (!el) continue;\n const w = el.clientWidth;\n const h = el.clientHeight;\n if (w > 0 && h > 0) chart.resize(w, h);\n }\n }\n\n destroy(): void {\n for (const detach of this.detachResizers) detach();\n this.detachResizers.length = 0;\n this.macdChart.remove();\n this.rsiChart.remove();\n this.kdjChart.remove();\n this.root.replaceChildren();\n }\n\n private createPaneWrap(\n label: string,\n paneId: IndicatorPaneId,\n ): { wrap: HTMLElement; el: HTMLElement } {\n const wrap = document.createElement('div');\n wrap.className = `tv-indicator-pane tv-indicator-pane--${paneId}`;\n wrap.style.cssText =\n 'flex:1;min-height:72px;width:100%;position:relative;border-top:1px solid #30363d;';\n const tag = document.createElement('span');\n tag.textContent = label;\n tag.style.cssText =\n 'position:absolute;left:6px;top:4px;z-index:2;font-size:10px;color:#8b949e;pointer-events:none;';\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.textContent = '×';\n closeBtn.title = `關閉 ${label}`;\n closeBtn.setAttribute('aria-label', `Close ${label}`);\n closeBtn.style.cssText =\n 'position:absolute;right:6px;top:4px;z-index:3;width:22px;height:22px;padding:0;border:1px solid #30363d;border-radius:4px;background:#21262d;color:#8b949e;cursor:pointer;font-size:14px;line-height:1;';\n closeBtn.onmouseenter = () => {\n closeBtn.style.color = '#e6edf3';\n closeBtn.style.borderColor = '#484f58';\n };\n closeBtn.onmouseleave = () => {\n closeBtn.style.color = '#8b949e';\n closeBtn.style.borderColor = '#30363d';\n };\n closeBtn.onclick = () => this.closePane(paneId);\n const el = document.createElement('div');\n el.style.cssText = 'width:100%;height:100%;';\n wrap.append(tag, closeBtn, el);\n return { wrap, el };\n }\n\n private layoutForTheme(dark: boolean) {\n return {\n background: { type: ColorType.Solid, color: dark ? '#0d1117' : '#ffffff' },\n textColor: dark ? '#e6edf3' : '#24292f',\n };\n }\n}\n\nexport function maOverlayLine(\n bars: Bar[],\n period = 20,\n source: IndicatorConfig['source'] = 'close',\n): LineData<UTCTimestamp>[] {\n const src = barsForSource(bars, source);\n return lineData(bars, sma(src, period));\n}\n\nexport function volMaOverlayLine(bars: Bar[], period = 5): LineData<UTCTimestamp>[] {\n const volBars = bars.map((b) => ({ ...b, c: b.v ?? 0 }));\n return lineData(bars, sma(volBars, period, 'close'));\n}\n\nexport function emaOverlayLine(\n bars: Bar[],\n period: number,\n source: IndicatorConfig['source'] = 'close',\n): LineData<UTCTimestamp>[] {\n const src = barsForSource(bars, source);\n return lineData(bars, ema(src, period));\n}\n\nexport function bollOverlayLines(\n bars: Bar[],\n period: number,\n mult: number,\n source: IndicatorConfig['source'] = 'close',\n): {\n upper: LineData<UTCTimestamp>[];\n middle: LineData<UTCTimestamp>[];\n lower: LineData<UTCTimestamp>[];\n} {\n const src = barsForSource(bars, source);\n const bands = boll(src, period, mult);\n return {\n upper: lineData(bars, bands.upper),\n middle: lineData(bars, bands.middle),\n lower: lineData(bars, bands.lower),\n };\n}","export function attachPaneResizer(\n topPane: HTMLElement,\n bottomPane: HTMLElement,\n opts: { minTopPx?: number; minBottomPx?: number; storageKey?: string } = {},\n): () => void {\n const minTop = opts.minTopPx ?? 120;\n const minBottom = opts.minBottomPx ?? 60;\n const parent = topPane.parentElement;\n if (!parent) return () => {};\n\n const handle = document.createElement('div');\n handle.style.cssText =\n 'height:4px;cursor:row-resize;background:#30363d;flex-shrink:0;touch-action:none;';\n bottomPane.insertAdjacentElement('beforebegin', handle);\n\n const saved = opts.storageKey ? localStorage.getItem(opts.storageKey) : null;\n if (saved) {\n const ratio = Number(saved);\n if (Number.isFinite(ratio) && ratio > 0 && ratio < 1) {\n topPane.style.flex = `${ratio * 10}`;\n bottomPane.style.flex = `${(1 - ratio) * 10}`;\n }\n }\n\n let dragging = false;\n\n const onMove = (clientY: number) => {\n const rect = parent.getBoundingClientRect();\n const y = clientY - rect.top;\n const ratio = Math.min(0.85, Math.max(0.15, y / rect.height));\n const topPx = ratio * rect.height;\n const bottomPx = rect.height - topPx - handle.offsetHeight;\n if (topPx < minTop || bottomPx < minBottom) return;\n topPane.style.flex = `${ratio * 10}`;\n bottomPane.style.flex = `${(1 - ratio) * 10}`;\n if (opts.storageKey) localStorage.setItem(opts.storageKey, String(ratio));\n };\n\n const stop = () => {\n dragging = false;\n document.body.style.cursor = '';\n };\n\n handle.addEventListener('pointerdown', (e) => {\n dragging = true;\n handle.setPointerCapture(e.pointerId);\n document.body.style.cursor = 'row-resize';\n });\n handle.addEventListener('pointermove', (e) => {\n if (dragging) onMove(e.clientY);\n });\n handle.addEventListener('pointerup', stop);\n handle.addEventListener('pointercancel', stop);\n\n return () => handle.remove();\n}","import type { IChartApi, LogicalRange, UTCTimestamp } from 'lightweight-charts';\n\nexport interface ChartVisibleRange {\n fromMs: number;\n toMs: number;\n}\n\nexport interface TransformState {\n visibleFromMs: number;\n visibleToMs: number;\n width: number;\n height: number;\n}\n\ntype TransformListener = (state: TransformState) => void;\n\n/** Sync visible logical range across multiple LWC panes (§10.4.1). */\nexport class TimeScaleBus {\n private charts: IChartApi[] = [];\n private listeners = new Set<TransformListener>();\n private syncing = false;\n visibleFromMs = 0;\n visibleToMs = 0;\n\n register(chart: IChartApi): void {\n if (this.charts.includes(chart)) return;\n this.charts.push(chart);\n chart.timeScale().subscribeVisibleLogicalRangeChange((range) => {\n if (this.syncing || !range) return;\n const tr = chart.timeScale().getVisibleRange();\n if (tr && typeof tr.from === 'number' && typeof tr.to === 'number') {\n this.visibleFromMs = tr.from * 1000;\n this.visibleToMs = tr.to * 1000;\n }\n this.syncFrom(chart, range);\n });\n }\n\n subscribeTransform(listener: TransformListener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n setBarsTimeRange(fromMs: number, toMs: number): void {\n this.visibleFromMs = fromMs;\n this.visibleToMs = toMs;\n this.emit();\n }\n\n getVisibleRange(): ChartVisibleRange | null {\n if (this.visibleToMs <= this.visibleFromMs) return null;\n return { fromMs: this.visibleFromMs, toMs: this.visibleToMs };\n }\n\n getBarSpacing(): number {\n const chart = this.charts[0];\n return chart ? chart.timeScale().options().barSpacing : 6;\n }\n\n setBarSpacing(spacing: number): void {\n if (!Number.isFinite(spacing) || spacing <= 0) return;\n this.syncing = true;\n for (const chart of this.charts) {\n chart.timeScale().applyOptions({ barSpacing: spacing });\n }\n this.syncing = false;\n this.emit();\n }\n\n setVisibleTimeRange(range: ChartVisibleRange): void {\n const from = Math.floor(range.fromMs / 1000) as UTCTimestamp;\n const to = Math.floor(range.toMs / 1000) as UTCTimestamp;\n if (to <= from) return;\n this.visibleFromMs = range.fromMs;\n this.visibleToMs = range.toMs;\n this.syncing = true;\n for (const chart of this.charts) {\n chart.timeScale().setVisibleRange({ from, to });\n }\n this.syncing = false;\n this.emit();\n }\n\n scrollToLogicalPosition(position: number, animated = false): void {\n this.syncing = true;\n for (const chart of this.charts) {\n chart.timeScale().scrollToPosition(position, animated);\n }\n this.syncing = false;\n this.emit();\n }\n\n private syncFrom(source: IChartApi, range: LogicalRange) {\n this.syncing = true;\n for (const chart of this.charts) {\n if (chart !== source) {\n chart.timeScale().setVisibleLogicalRange(range);\n }\n }\n this.syncing = false;\n this.emit();\n }\n\n private emit(): void {\n const state: TransformState = {\n visibleFromMs: this.visibleFromMs,\n visibleToMs: this.visibleToMs,\n width: 0,\n height: 0,\n };\n for (const l of this.listeners) l(state);\n }\n}","import { intervalMs, type Interval } from '@coderyo/data';\n\n/**\n * Default horizontal bar spacing (px) per interval so candle width feels consistent\n * when the integrator controls how many bars are loaded / visible.\n */\nexport function defaultBarSpacingForInterval(interval: Interval): number {\n const ms = intervalMs(interval);\n if (ms <= 1_000) return 3;\n if (ms <= 5_000) return 4;\n if (ms <= 15_000) return 5;\n if (ms <= 30_000) return 6;\n if (ms <= 60_000) return 7;\n if (ms <= 300_000) return 8;\n if (ms <= 900_000) return 9;\n if (ms <= 3_600_000) return 10;\n if (ms <= 14_400_000) return 11;\n return 12;\n}\n\nexport function resolveBarSpacingForInterval(\n interval: Interval,\n overrides?: Partial<Record<Interval, number>>,\n): number {\n const custom = overrides?.[interval];\n if (custom != null && Number.isFinite(custom) && custom > 0) {\n return Math.min(24, Math.max(2, custom));\n }\n return defaultBarSpacingForInterval(interval);\n}","import type { Bar } from '@coderyo/data';\n\nfunction lerp(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\nfunction easeOutCubic(t: number): number {\n return 1 - Math.pow(1 - t, 3);\n}\n\n/** Interpolate last candle OHLC toward target over `durationMs` (interrupts on new target). */\nexport class BarSmoothAnimator {\n private raf = 0;\n private start = 0;\n private from: Bar | null = null;\n private to: Bar | null = null;\n\n constructor(\n private durationMs: number,\n private readonly onFrame: (bar: Bar) => void,\n ) {}\n\n setDuration(ms: number): void {\n this.durationMs = ms;\n }\n\n animateTo(target: Bar, from?: Bar): void {\n if (this.raf) cancelAnimationFrame(this.raf);\n const base = from ?? this.to ?? target;\n this.from = { ...base, t: target.t };\n this.to = { ...target };\n this.start = performance.now();\n\n const step = (now: number) => {\n const raw = Math.min(1, (now - this.start) / this.durationMs);\n const p = easeOutCubic(raw);\n const f = this.from!;\n const t = this.to!;\n const frame: Bar = {\n t: t.t,\n o: lerp(f.o, t.o, p),\n h: lerp(f.h, t.h, p),\n l: lerp(f.l, t.l, p),\n c: lerp(f.c, t.c, p),\n v: t.v,\n };\n this.onFrame(frame);\n if (raw < 1) {\n this.raf = requestAnimationFrame(step);\n } else {\n this.raf = 0;\n this.onFrame(t);\n }\n };\n this.raf = requestAnimationFrame(step);\n }\n\n cancel(): void {\n if (this.raf) cancelAnimationFrame(this.raf);\n this.raf = 0;\n }\n}"],"mappings":"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","names":["ColorType","createChart","HistogramSeries","LineSeries","intervalMs","hasVisibleIndicatorPanes","toUtcSeconds","createChart","LineSeries","HistogramSeries","hasVisibleIndicatorPanes","intervalMs","ColorType"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coderyo/renderer-lite",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"lightweight-charts": "^5.0.7",
|
|
14
|
-
"@coderyo/data": "1.0.
|
|
15
|
-
"@coderyo/
|
|
16
|
-
"@coderyo/
|
|
14
|
+
"@coderyo/data": "1.0.3",
|
|
15
|
+
"@coderyo/indicators": "1.0.3",
|
|
16
|
+
"@coderyo/series": "1.0.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"tsup": "^8.5.0",
|