@coderyo/renderer-lite 1.0.0-rc.2 → 1.0.0-rc.4
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 +37 -1
- package/dist/index.js +245 -8
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,11 @@ interface CrosshairPayload {
|
|
|
35
35
|
v?: number;
|
|
36
36
|
} | null;
|
|
37
37
|
}
|
|
38
|
+
interface PinePlotLine {
|
|
39
|
+
title: string;
|
|
40
|
+
color?: string;
|
|
41
|
+
values: (number | null)[];
|
|
42
|
+
}
|
|
38
43
|
interface PaneOrchestratorOptions {
|
|
39
44
|
container: HTMLElement;
|
|
40
45
|
indicatorRoot?: HTMLElement;
|
|
@@ -45,6 +50,11 @@ interface PaneOrchestratorOptions {
|
|
|
45
50
|
showGrid?: boolean;
|
|
46
51
|
/** null = no MA overlays and no MACD/RSI/KDJ panes. */
|
|
47
52
|
indicatorConfig?: IndicatorConfig | null;
|
|
53
|
+
/** Pine-lite plot lines on main chart (when pineEnabled). */
|
|
54
|
+
pinePlots?: PinePlotLine[] | null;
|
|
55
|
+
/** Animate last candle + price line toward new OHLC (~150ms). */
|
|
56
|
+
smoothPriceUpdate?: boolean;
|
|
57
|
+
smoothPriceDurationMs?: number;
|
|
48
58
|
}
|
|
49
59
|
declare class PaneOrchestrator {
|
|
50
60
|
readonly bus: TimeScaleBus;
|
|
@@ -53,9 +63,15 @@ declare class PaneOrchestrator {
|
|
|
53
63
|
private readonly mainSeries;
|
|
54
64
|
private readonly volumeSeries;
|
|
55
65
|
private readonly maSeries;
|
|
66
|
+
private readonly emaSeries;
|
|
67
|
+
private readonly bollUpper;
|
|
68
|
+
private readonly bollMiddle;
|
|
69
|
+
private readonly bollLower;
|
|
56
70
|
private readonly volMaSeries;
|
|
57
71
|
private readonly indicatorRoot?;
|
|
58
72
|
private indicators;
|
|
73
|
+
private pinePlotSeries;
|
|
74
|
+
private pinePlots;
|
|
59
75
|
private overlayCanvas;
|
|
60
76
|
private dark;
|
|
61
77
|
private showGrid;
|
|
@@ -63,9 +79,23 @@ declare class PaneOrchestrator {
|
|
|
63
79
|
private barByTime;
|
|
64
80
|
private didInitialFit;
|
|
65
81
|
private indicatorConfig;
|
|
82
|
+
private priceLine;
|
|
83
|
+
private barAnimator;
|
|
84
|
+
private smoothPriceDurationMs;
|
|
66
85
|
constructor(opts: PaneOrchestratorOptions);
|
|
86
|
+
setSmoothPriceUpdate(enabled: boolean, durationMs?: number): void;
|
|
87
|
+
/** Update the last candle (and price line); optional smooth interpolation. */
|
|
88
|
+
updateLastBar(target: Bar, opts?: {
|
|
89
|
+
smooth?: boolean;
|
|
90
|
+
durationMs?: number;
|
|
91
|
+
}): void;
|
|
92
|
+
private applyLastBarToSeries;
|
|
93
|
+
private ensurePriceLine;
|
|
67
94
|
setTheme(theme: 'dark' | 'light'): void;
|
|
68
95
|
setIndicatorConfig(config: IndicatorConfig | null): void;
|
|
96
|
+
setPinePlots(plots: PinePlotLine[] | null): void;
|
|
97
|
+
private applyMainOverlays;
|
|
98
|
+
private syncPinePlotSeries;
|
|
69
99
|
setShowGrid(show: boolean): void;
|
|
70
100
|
setBars(bars: Bar[], gaps?: number[]): void;
|
|
71
101
|
subscribeCrosshair(listener: (payload: CrosshairPayload | null) => void): () => void;
|
|
@@ -131,5 +161,11 @@ declare class IndicatorPaneStack {
|
|
|
131
161
|
}
|
|
132
162
|
declare function maOverlayLine(bars: Bar[], period?: number, source?: IndicatorConfig['source']): LineData<UTCTimestamp>[];
|
|
133
163
|
declare function volMaOverlayLine(bars: Bar[], period?: number): LineData<UTCTimestamp>[];
|
|
164
|
+
declare function emaOverlayLine(bars: Bar[], period: number, source?: IndicatorConfig['source']): LineData<UTCTimestamp>[];
|
|
165
|
+
declare function bollOverlayLines(bars: Bar[], period: number, mult: number, source?: IndicatorConfig['source']): {
|
|
166
|
+
upper: LineData<UTCTimestamp>[];
|
|
167
|
+
middle: LineData<UTCTimestamp>[];
|
|
168
|
+
lower: LineData<UTCTimestamp>[];
|
|
169
|
+
};
|
|
134
170
|
|
|
135
|
-
export { type CrosshairPayload, IndicatorPaneStack, type IndicatorPaneStackOptions, PaneOrchestrator, type PaneOrchestratorOptions, type ScaleMode, TimeScaleBus, type TransformState, maOverlayLine, volMaOverlayLine };
|
|
171
|
+
export { type CrosshairPayload, IndicatorPaneStack, type IndicatorPaneStackOptions, PaneOrchestrator, type PaneOrchestratorOptions, type PinePlotLine, type ScaleMode, TimeScaleBus, type TransformState, bollOverlayLines, emaOverlayLine, maOverlayLine, volMaOverlayLine };
|
package/dist/index.js
CHANGED
|
@@ -26,10 +26,12 @@ import {
|
|
|
26
26
|
} from "lightweight-charts";
|
|
27
27
|
import {
|
|
28
28
|
DEFAULT_INDICATOR_CONFIG,
|
|
29
|
+
boll,
|
|
29
30
|
kdj,
|
|
30
31
|
macd,
|
|
31
32
|
rsi,
|
|
32
|
-
sma
|
|
33
|
+
sma,
|
|
34
|
+
ema
|
|
33
35
|
} from "@coderyo/indicators";
|
|
34
36
|
function barsForSource(bars, source) {
|
|
35
37
|
if (source === "close") return bars;
|
|
@@ -217,6 +219,19 @@ function volMaOverlayLine(bars, period = 5) {
|
|
|
217
219
|
const volBars = bars.map((b) => ({ ...b, c: b.v ?? 0 }));
|
|
218
220
|
return lineData(bars, sma(volBars, period, "close"));
|
|
219
221
|
}
|
|
222
|
+
function emaOverlayLine(bars, period, source = "close") {
|
|
223
|
+
const src = barsForSource(bars, source);
|
|
224
|
+
return lineData(bars, ema(src, period));
|
|
225
|
+
}
|
|
226
|
+
function bollOverlayLines(bars, period, mult, source = "close") {
|
|
227
|
+
const src = barsForSource(bars, source);
|
|
228
|
+
const bands = boll(src, period, mult);
|
|
229
|
+
return {
|
|
230
|
+
upper: lineData(bars, bands.upper),
|
|
231
|
+
middle: lineData(bars, bands.middle),
|
|
232
|
+
lower: lineData(bars, bands.lower)
|
|
233
|
+
};
|
|
234
|
+
}
|
|
220
235
|
|
|
221
236
|
// src/pane-resize.ts
|
|
222
237
|
function attachPaneResizer(topPane, bottomPane, opts = {}) {
|
|
@@ -315,6 +330,62 @@ var TimeScaleBus = class {
|
|
|
315
330
|
}
|
|
316
331
|
};
|
|
317
332
|
|
|
333
|
+
// src/bar-smooth-animator.ts
|
|
334
|
+
function lerp(a, b, t) {
|
|
335
|
+
return a + (b - a) * t;
|
|
336
|
+
}
|
|
337
|
+
function easeOutCubic(t) {
|
|
338
|
+
return 1 - Math.pow(1 - t, 3);
|
|
339
|
+
}
|
|
340
|
+
var BarSmoothAnimator = class {
|
|
341
|
+
constructor(durationMs, onFrame) {
|
|
342
|
+
this.durationMs = durationMs;
|
|
343
|
+
this.onFrame = onFrame;
|
|
344
|
+
}
|
|
345
|
+
durationMs;
|
|
346
|
+
onFrame;
|
|
347
|
+
raf = 0;
|
|
348
|
+
start = 0;
|
|
349
|
+
from = null;
|
|
350
|
+
to = null;
|
|
351
|
+
setDuration(ms) {
|
|
352
|
+
this.durationMs = ms;
|
|
353
|
+
}
|
|
354
|
+
animateTo(target, from) {
|
|
355
|
+
if (this.raf) cancelAnimationFrame(this.raf);
|
|
356
|
+
const base = from ?? this.to ?? target;
|
|
357
|
+
this.from = { ...base, t: target.t };
|
|
358
|
+
this.to = { ...target };
|
|
359
|
+
this.start = performance.now();
|
|
360
|
+
const step = (now) => {
|
|
361
|
+
const raw = Math.min(1, (now - this.start) / this.durationMs);
|
|
362
|
+
const p = easeOutCubic(raw);
|
|
363
|
+
const f = this.from;
|
|
364
|
+
const t = this.to;
|
|
365
|
+
const frame = {
|
|
366
|
+
t: t.t,
|
|
367
|
+
o: lerp(f.o, t.o, p),
|
|
368
|
+
h: lerp(f.h, t.h, p),
|
|
369
|
+
l: lerp(f.l, t.l, p),
|
|
370
|
+
c: lerp(f.c, t.c, p),
|
|
371
|
+
v: t.v
|
|
372
|
+
};
|
|
373
|
+
this.onFrame(frame);
|
|
374
|
+
if (raw < 1) {
|
|
375
|
+
this.raf = requestAnimationFrame(step);
|
|
376
|
+
} else {
|
|
377
|
+
this.raf = 0;
|
|
378
|
+
this.onFrame(t);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
this.raf = requestAnimationFrame(step);
|
|
382
|
+
}
|
|
383
|
+
cancel() {
|
|
384
|
+
if (this.raf) cancelAnimationFrame(this.raf);
|
|
385
|
+
this.raf = 0;
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
|
|
318
389
|
// src/pane-orchestrator.ts
|
|
319
390
|
function toUtcSeconds2(tMs) {
|
|
320
391
|
return Math.floor(tMs / 1e3);
|
|
@@ -332,9 +403,15 @@ var PaneOrchestrator = class {
|
|
|
332
403
|
mainSeries;
|
|
333
404
|
volumeSeries;
|
|
334
405
|
maSeries;
|
|
406
|
+
emaSeries;
|
|
407
|
+
bollUpper;
|
|
408
|
+
bollMiddle;
|
|
409
|
+
bollLower;
|
|
335
410
|
volMaSeries;
|
|
336
411
|
indicatorRoot;
|
|
337
412
|
indicators;
|
|
413
|
+
pinePlotSeries = [];
|
|
414
|
+
pinePlots = null;
|
|
338
415
|
overlayCanvas = null;
|
|
339
416
|
dark = true;
|
|
340
417
|
showGrid = false;
|
|
@@ -342,6 +419,9 @@ var PaneOrchestrator = class {
|
|
|
342
419
|
barByTime = /* @__PURE__ */ new Map();
|
|
343
420
|
didInitialFit = false;
|
|
344
421
|
indicatorConfig = null;
|
|
422
|
+
priceLine = null;
|
|
423
|
+
barAnimator = null;
|
|
424
|
+
smoothPriceDurationMs = 150;
|
|
345
425
|
constructor(opts) {
|
|
346
426
|
this.maxRenderPoints = opts.maxRenderPoints ?? 4e3;
|
|
347
427
|
this.dark = opts.theme !== "light";
|
|
@@ -375,7 +455,32 @@ var PaneOrchestrator = class {
|
|
|
375
455
|
this.maSeries = this.mainChart.addSeries(LineSeries2, {
|
|
376
456
|
color: "#f0b429",
|
|
377
457
|
lineWidth: 1,
|
|
378
|
-
title: "
|
|
458
|
+
title: "MA"
|
|
459
|
+
});
|
|
460
|
+
this.emaSeries = this.mainChart.addSeries(LineSeries2, {
|
|
461
|
+
color: "#7ee787",
|
|
462
|
+
lineWidth: 1,
|
|
463
|
+
title: "EMA",
|
|
464
|
+
visible: false
|
|
465
|
+
});
|
|
466
|
+
this.bollUpper = this.mainChart.addSeries(LineSeries2, {
|
|
467
|
+
color: "#8b949e",
|
|
468
|
+
lineWidth: 1,
|
|
469
|
+
title: "BOLL\u2191",
|
|
470
|
+
visible: false
|
|
471
|
+
});
|
|
472
|
+
this.bollMiddle = this.mainChart.addSeries(LineSeries2, {
|
|
473
|
+
color: "#8b949e88",
|
|
474
|
+
lineWidth: 1,
|
|
475
|
+
lineStyle: 2,
|
|
476
|
+
title: "BOLL",
|
|
477
|
+
visible: false
|
|
478
|
+
});
|
|
479
|
+
this.bollLower = this.mainChart.addSeries(LineSeries2, {
|
|
480
|
+
color: "#8b949e",
|
|
481
|
+
lineWidth: 1,
|
|
482
|
+
title: "BOLL\u2193",
|
|
483
|
+
visible: false
|
|
379
484
|
});
|
|
380
485
|
this.volumeSeries = this.volumeChart.addSeries(HistogramSeries2, {
|
|
381
486
|
color: "#26a69a55",
|
|
@@ -390,8 +495,65 @@ var PaneOrchestrator = class {
|
|
|
390
495
|
this.bus.register(this.volumeChart);
|
|
391
496
|
this.indicatorRoot = opts.indicatorRoot;
|
|
392
497
|
this.indicatorConfig = opts.indicatorConfig ?? null;
|
|
498
|
+
this.pinePlots = opts.pinePlots ?? null;
|
|
393
499
|
this.indicators = this.createIndicatorStack();
|
|
394
500
|
this.initOverlay(mainEl);
|
|
501
|
+
this.setSmoothPriceUpdate(opts.smoothPriceUpdate ?? false, opts.smoothPriceDurationMs);
|
|
502
|
+
}
|
|
503
|
+
setSmoothPriceUpdate(enabled, durationMs = 150) {
|
|
504
|
+
this.smoothPriceDurationMs = durationMs;
|
|
505
|
+
if (enabled) {
|
|
506
|
+
if (!this.barAnimator) {
|
|
507
|
+
this.barAnimator = new BarSmoothAnimator(durationMs, (bar) => this.applyLastBarToSeries(bar));
|
|
508
|
+
} else {
|
|
509
|
+
this.barAnimator.setDuration(durationMs);
|
|
510
|
+
}
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
this.barAnimator?.cancel();
|
|
514
|
+
this.barAnimator = null;
|
|
515
|
+
if (this.priceLine) {
|
|
516
|
+
this.mainSeries.removePriceLine(this.priceLine);
|
|
517
|
+
this.priceLine = null;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
/** Update the last candle (and price line); optional smooth interpolation. */
|
|
521
|
+
updateLastBar(target, opts) {
|
|
522
|
+
const prev = this.barByTime.get(target.t);
|
|
523
|
+
const smooth = opts?.smooth ?? !!this.barAnimator;
|
|
524
|
+
const duration = opts?.durationMs ?? this.smoothPriceDurationMs;
|
|
525
|
+
if (smooth && this.barAnimator) {
|
|
526
|
+
this.barAnimator.setDuration(duration);
|
|
527
|
+
this.barAnimator.animateTo(target, prev ?? target);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
this.barAnimator?.cancel();
|
|
531
|
+
this.applyLastBarToSeries(target);
|
|
532
|
+
}
|
|
533
|
+
applyLastBarToSeries(bar) {
|
|
534
|
+
this.barByTime.set(bar.t, bar);
|
|
535
|
+
this.mainSeries.update(barToCandle(bar));
|
|
536
|
+
this.volumeSeries.update(barToVolume(bar));
|
|
537
|
+
this.ensurePriceLine(bar.c);
|
|
538
|
+
if (this.indicatorConfig) {
|
|
539
|
+
const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);
|
|
540
|
+
this.applyMainOverlays(bars);
|
|
541
|
+
this.indicators?.setBars(bars);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
ensurePriceLine(price) {
|
|
545
|
+
if (!this.priceLine) {
|
|
546
|
+
this.priceLine = this.mainSeries.createPriceLine({
|
|
547
|
+
price,
|
|
548
|
+
color: "#58a6ff",
|
|
549
|
+
lineWidth: 1,
|
|
550
|
+
lineStyle: 2,
|
|
551
|
+
axisLabelVisible: true,
|
|
552
|
+
title: ""
|
|
553
|
+
});
|
|
554
|
+
} else {
|
|
555
|
+
this.priceLine.applyOptions({ price });
|
|
556
|
+
}
|
|
395
557
|
}
|
|
396
558
|
setTheme(theme) {
|
|
397
559
|
this.dark = theme === "dark";
|
|
@@ -406,18 +568,83 @@ var PaneOrchestrator = class {
|
|
|
406
568
|
if (!config) {
|
|
407
569
|
this.indicators = null;
|
|
408
570
|
this.maSeries.setData([]);
|
|
571
|
+
this.emaSeries.setData([]);
|
|
572
|
+
this.bollUpper.setData([]);
|
|
573
|
+
this.bollMiddle.setData([]);
|
|
574
|
+
this.bollLower.setData([]);
|
|
409
575
|
this.volMaSeries.setData([]);
|
|
576
|
+
this.emaSeries.applyOptions({ visible: false });
|
|
577
|
+
this.bollUpper.applyOptions({ visible: false });
|
|
578
|
+
this.bollMiddle.applyOptions({ visible: false });
|
|
579
|
+
this.bollLower.applyOptions({ visible: false });
|
|
410
580
|
return;
|
|
411
581
|
}
|
|
412
582
|
if (!this.indicators) this.indicators = this.createIndicatorStack();
|
|
413
583
|
const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);
|
|
414
584
|
this.indicators?.setConfig(config);
|
|
415
585
|
if (bars.length > 0) {
|
|
416
|
-
this.
|
|
417
|
-
this.volMaSeries.setData(volMaOverlayLine(bars, config.volMaPeriod));
|
|
586
|
+
this.applyMainOverlays(bars);
|
|
418
587
|
this.indicators?.setBars(bars);
|
|
419
588
|
}
|
|
420
589
|
}
|
|
590
|
+
setPinePlots(plots) {
|
|
591
|
+
this.pinePlots = plots;
|
|
592
|
+
const bars = [...this.barByTime.values()].sort((a, b) => a.t - b.t);
|
|
593
|
+
this.syncPinePlotSeries(bars);
|
|
594
|
+
}
|
|
595
|
+
applyMainOverlays(bars) {
|
|
596
|
+
const cfg = this.indicatorConfig;
|
|
597
|
+
if (!cfg) return;
|
|
598
|
+
this.maSeries.applyOptions({ title: `MA${cfg.maPeriod}` });
|
|
599
|
+
this.maSeries.setData(maOverlayLine(bars, cfg.maPeriod, cfg.source));
|
|
600
|
+
this.volMaSeries.setData(volMaOverlayLine(bars, cfg.volMaPeriod));
|
|
601
|
+
if (cfg.showEma) {
|
|
602
|
+
this.emaSeries.applyOptions({ visible: true, title: `EMA${cfg.emaPeriod}` });
|
|
603
|
+
this.emaSeries.setData(emaOverlayLine(bars, cfg.emaPeriod, cfg.source));
|
|
604
|
+
} else {
|
|
605
|
+
this.emaSeries.applyOptions({ visible: false });
|
|
606
|
+
this.emaSeries.setData([]);
|
|
607
|
+
}
|
|
608
|
+
if (cfg.showBoll) {
|
|
609
|
+
const bands = bollOverlayLines(bars, cfg.bollPeriod, cfg.bollMult, cfg.source);
|
|
610
|
+
this.bollUpper.applyOptions({ visible: true });
|
|
611
|
+
this.bollMiddle.applyOptions({ visible: true });
|
|
612
|
+
this.bollLower.applyOptions({ visible: true });
|
|
613
|
+
this.bollUpper.setData(bands.upper);
|
|
614
|
+
this.bollMiddle.setData(bands.middle);
|
|
615
|
+
this.bollLower.setData(bands.lower);
|
|
616
|
+
} else {
|
|
617
|
+
this.bollUpper.applyOptions({ visible: false });
|
|
618
|
+
this.bollMiddle.applyOptions({ visible: false });
|
|
619
|
+
this.bollLower.applyOptions({ visible: false });
|
|
620
|
+
this.bollUpper.setData([]);
|
|
621
|
+
this.bollMiddle.setData([]);
|
|
622
|
+
this.bollLower.setData([]);
|
|
623
|
+
}
|
|
624
|
+
this.syncPinePlotSeries(bars);
|
|
625
|
+
}
|
|
626
|
+
syncPinePlotSeries(bars) {
|
|
627
|
+
for (const s of this.pinePlotSeries) this.mainChart.removeSeries(s);
|
|
628
|
+
this.pinePlotSeries = [];
|
|
629
|
+
if (!this.pinePlots?.length || bars.length === 0) return;
|
|
630
|
+
const palette = ["#58a6ff", "#d2a8ff", "#ff7b72", "#ffa657"];
|
|
631
|
+
for (let i = 0; i < this.pinePlots.length; i++) {
|
|
632
|
+
const plot = this.pinePlots[i];
|
|
633
|
+
const series = this.mainChart.addSeries(LineSeries2, {
|
|
634
|
+
color: plot.color ?? palette[i % palette.length],
|
|
635
|
+
lineWidth: 1,
|
|
636
|
+
title: plot.title
|
|
637
|
+
});
|
|
638
|
+
const out = [];
|
|
639
|
+
for (let j = 0; j < bars.length; j++) {
|
|
640
|
+
const v = plot.values[j];
|
|
641
|
+
if (v == null) continue;
|
|
642
|
+
out.push({ time: toUtcSeconds2(bars[j].t), value: v });
|
|
643
|
+
}
|
|
644
|
+
series.setData(out);
|
|
645
|
+
this.pinePlotSeries.push(series);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
421
648
|
setShowGrid(show) {
|
|
422
649
|
this.showGrid = show;
|
|
423
650
|
const grid = gridOptions(show, this.dark);
|
|
@@ -445,14 +672,16 @@ var PaneOrchestrator = class {
|
|
|
445
672
|
this.mainSeries.setData(candles);
|
|
446
673
|
this.volumeSeries.setData(vols);
|
|
447
674
|
if (this.indicatorConfig) {
|
|
448
|
-
this.
|
|
449
|
-
maOverlayLine(renderBars, this.indicatorConfig.maPeriod, this.indicatorConfig.source)
|
|
450
|
-
);
|
|
451
|
-
this.volMaSeries.setData(volMaOverlayLine(renderBars, this.indicatorConfig.volMaPeriod));
|
|
675
|
+
this.applyMainOverlays(renderBars);
|
|
452
676
|
this.indicators?.setBars(renderBars);
|
|
453
677
|
} else {
|
|
454
678
|
this.maSeries.setData([]);
|
|
679
|
+
this.emaSeries.setData([]);
|
|
680
|
+
this.bollUpper.setData([]);
|
|
681
|
+
this.bollMiddle.setData([]);
|
|
682
|
+
this.bollLower.setData([]);
|
|
455
683
|
this.volMaSeries.setData([]);
|
|
684
|
+
this.syncPinePlotSeries(renderBars);
|
|
456
685
|
}
|
|
457
686
|
if (renderBars.length > 0) {
|
|
458
687
|
this.syncChartSize();
|
|
@@ -513,6 +742,7 @@ var PaneOrchestrator = class {
|
|
|
513
742
|
}
|
|
514
743
|
/** Clear series while symbol/interval data reloads (avoids overlapping candles). */
|
|
515
744
|
clearBars() {
|
|
745
|
+
this.barAnimator?.cancel();
|
|
516
746
|
this.barByTime = /* @__PURE__ */ new Map();
|
|
517
747
|
this.mainSeries.setData([]);
|
|
518
748
|
this.maSeries.setData([]);
|
|
@@ -562,6 +792,11 @@ var PaneOrchestrator = class {
|
|
|
562
792
|
return p ?? null;
|
|
563
793
|
}
|
|
564
794
|
destroy() {
|
|
795
|
+
this.barAnimator?.cancel();
|
|
796
|
+
if (this.priceLine) {
|
|
797
|
+
this.mainSeries.removePriceLine(this.priceLine);
|
|
798
|
+
this.priceLine = null;
|
|
799
|
+
}
|
|
565
800
|
this.mainChart.remove();
|
|
566
801
|
this.volumeChart.remove();
|
|
567
802
|
this.indicators?.destroy();
|
|
@@ -617,6 +852,8 @@ export {
|
|
|
617
852
|
IndicatorPaneStack,
|
|
618
853
|
PaneOrchestrator,
|
|
619
854
|
TimeScaleBus,
|
|
855
|
+
bollOverlayLines,
|
|
856
|
+
emaOverlayLine,
|
|
620
857
|
maOverlayLine,
|
|
621
858
|
volMaOverlayLine
|
|
622
859
|
};
|
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"],"sourcesContent":["import {\n CandlestickSeries,\n ColorType,\n createChart,\n HistogramSeries,\n LineSeries,\n type CandlestickData,\n type HistogramData,\n type IChartApi,\n type ISeriesApi,\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 { IndicatorPaneStack, maOverlayLine, volMaOverlayLine } from './indicator-panes.js';\nimport { attachPaneResizer } from './pane-resize.js';\nimport { TimeScaleBus } from './time-scale-bus.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 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}\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 volMaSeries: ISeriesApi<'Line'>;\n private readonly indicatorRoot?: HTMLElement;\n private indicators: IndicatorPaneStack | 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 didInitialFit = false;\n private indicatorConfig: IndicatorConfig | null = null;\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: 'MA20',\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.indicators = this.createIndicatorStack();\n\n this.initOverlay(mainEl);\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.volMaSeries.setData([]);\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.maSeries.setData(maOverlayLine(bars, config.maPeriod, config.source));\n this.volMaSeries.setData(volMaOverlayLine(bars, config.volMaPeriod));\n this.indicators?.setBars(bars);\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\n const candles: CandlestickData[] = [];\n const vols: HistogramData<UTCTimestamp>[] = [];\n const gapSet = new Set(gaps ?? []);\n const seenTimes = new Set<number>();\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 (i > 0 && gapSet.has(b.t)) {\n // whitespace: skip connecting — LWC uses sparse times\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.maSeries.setData(\n maOverlayLine(renderBars, this.indicatorConfig.maPeriod, this.indicatorConfig.source),\n );\n this.volMaSeries.setData(volMaOverlayLine(renderBars, this.indicatorConfig.volMaPeriod));\n this.indicators?.setBars(renderBars);\n } else {\n this.maSeries.setData([]);\n this.volMaSeries.setData([]);\n }\n\n if (renderBars.length > 0) {\n this.syncChartSize();\n if (!this.didInitialFit) {\n this.mainChart.timeScale().fitContent();\n this.volumeChart.timeScale().fitContent();\n this.indicators?.fitContent();\n this.didInitialFit = true;\n }\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.bus.visibleFromMs = 0;\n this.bus.visibleToMs = 0;\n }\n\n /** Clear series while symbol/interval data reloads (avoids overlapping candles). */\n clearBars(): void {\n this.barByTime = new Map();\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.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 kdj,\n macd,\n rsi,\n sma,\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}","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 } from 'lightweight-charts';\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 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}"],"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/bar-smooth-animator.ts"],"sourcesContent":["import {\n CandlestickSeries,\n ColorType,\n createChart,\n HistogramSeries,\n LineSeries,\n type CandlestickData,\n type HistogramData,\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 } from './time-scale-bus.js';\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 didInitialFit = 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\n const candles: CandlestickData[] = [];\n const vols: HistogramData<UTCTimestamp>[] = [];\n const gapSet = new Set(gaps ?? []);\n const seenTimes = new Set<number>();\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 (i > 0 && gapSet.has(b.t)) {\n // whitespace: skip connecting — LWC uses sparse times\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) {\n this.mainChart.timeScale().fitContent();\n this.volumeChart.timeScale().fitContent();\n this.indicators?.fitContent();\n this.didInitialFit = true;\n }\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.bus.visibleFromMs = 0;\n this.bus.visibleToMs = 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.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 } from 'lightweight-charts';\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 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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coderyo/renderer-lite",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"lightweight-charts": "^5.0.7",
|
|
14
|
-
"@coderyo/data": "1.0.0-rc.
|
|
15
|
-
"@coderyo/indicators": "1.0.0-rc.
|
|
16
|
-
"@coderyo/series": "1.0.0-rc.
|
|
14
|
+
"@coderyo/data": "1.0.0-rc.4",
|
|
15
|
+
"@coderyo/indicators": "1.0.0-rc.4",
|
|
16
|
+
"@coderyo/series": "1.0.0-rc.4"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"tsup": "^8.5.0",
|
|
20
20
|
"typescript": "^5.8.3",
|
|
21
21
|
"vitest": "^3.2.4",
|
|
22
|
-
"@coderyo/
|
|
23
|
-
"@coderyo/
|
|
22
|
+
"@coderyo/eslint-config": "0.0.0",
|
|
23
|
+
"@coderyo/tsconfig": "0.0.0"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"dist"
|