@tradecanvas/chart 0.6.0 → 0.7.1

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.
@@ -1,7 +1,7 @@
1
1
  import { DARK_THEME as e, DEFAULT_PANEL_HEIGHT as t, LIGHT_THEME as n, LayerType as r, MIN_PANEL_HEIGHT as i, PRICE_AXIS_WIDTH as a, TIME_AXIS_HEIGHT as o, computePriceLimits as s, mergeBar as c, setLocale as l, timeframeToMs as u } from "@tradecanvas/commons";
2
- import { AlertManager as d, Animator as f, AreaRenderer as p, BarCountdown as m, BarRenderer as ee, BaselineRenderer as h, CandlestickRenderer as g, ChartLegend as te, ChartStateManager as _, CompareRenderer as v, CrosshairHandler as y, CrosshairTooltip as ne, CurrentPriceLine as re, DataExporter as b, DrawingManager as ie, DrawingRenderer as ae, EventBus as oe, GridRenderer as se, HollowCandleRenderer as ce, IndicatorEngine as x, InteractionManager as le, KagiRenderer as ue, KeyboardHandler as de, LineRenderer as S, PanHandler as C, PointAndFigureRenderer as w, PriceAxis as T, RenderEngine as E, RenkoRenderer as D, ReplayManager as O, Screenshot as k, SessionBreaks as A, StreamManager as j, TimeAxis as M, TradingManager as N, TradingRenderer as P, UndoRedoManager as F, Viewport as I, VolumeRenderer as L, Watermark as R, ZoomHandler as z, registerBuiltInDrawingTools as B, registerBuiltInIndicators as V, toHeikinAshi as H, toKagi as fe, toLineBreak as pe, toPointAndFigure as me, toRangeBars as he, toRenko as ge } from "@tradecanvas/core";
2
+ import { AlertManager as d, Animator as f, AreaRenderer as p, BarCountdown as m, BarRenderer as ee, BaselineRenderer as h, CandlestickRenderer as g, ChartLegend as te, ChartStateManager as _, CompareRenderer as v, CrosshairHandler as ne, CrosshairTooltip as re, CurrentPriceLine as ie, DataExporter as y, DrawingManager as ae, DrawingRenderer as oe, EventBus as se, GridRenderer as ce, HLCAreaRenderer as le, HollowCandleRenderer as ue, IndicatorEngine as b, InteractionManager as de, KagiRenderer as fe, KeyboardHandler as x, LineRenderer as S, LineWithMarkersRenderer as C, PanHandler as w, PointAndFigureRenderer as T, PriceAxis as E, RenderEngine as D, RenkoRenderer as O, ReplayManager as k, Screenshot as A, SessionBreaks as j, SignalMarkerManager as M, StepLineRenderer as N, StreamManager as P, TimeAxis as F, TradeZoneManager as I, TradingManager as L, TradingRenderer as R, UndoRedoManager as z, Viewport as B, VolumeCandleRenderer as V, VolumeRenderer as pe, Watermark as me, ZoomHandler as he, registerBuiltInDrawingTools as ge, registerBuiltInIndicators as H, toHeikinAshi as _e, toKagi as ve, toLineBreak as ye, toPointAndFigure as be, toRangeBars as xe, toRenko as Se } from "@tradecanvas/core";
3
3
  //#region src/charts/ChartTypeStrategy.ts
4
- function _e(e) {
4
+ function Ce(e) {
5
5
  switch (e) {
6
6
  case "candlestick":
7
7
  case "heikinAshi":
@@ -10,27 +10,31 @@ function _e(e) {
10
10
  case "line": return new S();
11
11
  case "area": return new p();
12
12
  case "bar": return new ee();
13
- case "hollowCandle": return new ce();
13
+ case "hollowCandle": return new ue();
14
14
  case "baseline": return new h();
15
- case "renko": return new D();
16
- case "kagi": return new ue();
17
- case "pointAndFigure": return new w();
15
+ case "renko": return new O();
16
+ case "kagi": return new fe();
17
+ case "pointAndFigure": return new T();
18
+ case "volumeCandles": return new V();
19
+ case "hlcArea": return new le();
20
+ case "stepLine": return new N();
21
+ case "lineWithMarkers": return new C();
18
22
  default: return new g();
19
23
  }
20
24
  }
21
- function ve(e, t) {
25
+ function we(e, t) {
22
26
  if (t.length === 0) return t;
23
27
  switch (e) {
24
- case "heikinAshi": return H(t);
25
- case "renko": return ge(t, {
28
+ case "heikinAshi": return _e(t);
29
+ case "renko": return Se(t, {
26
30
  brickSize: 0,
27
31
  useATR: !0,
28
32
  atrPeriod: 14
29
33
  });
30
- case "lineBreak": return pe(t, 3);
31
- case "kagi": return fe(t, 4);
32
- case "pointAndFigure": return me(t, U(t) * .01, 3);
33
- case "rangeBars": return he(t, { rangeSize: U(t) * .005 });
34
+ case "lineBreak": return ye(t, 3);
35
+ case "kagi": return ve(t, 4);
36
+ case "pointAndFigure": return be(t, U(t) * .01, 3);
37
+ case "rangeBars": return xe(t, { rangeSize: U(t) * .005 });
34
38
  default: return t;
35
39
  }
36
40
  }
@@ -45,7 +49,7 @@ var W = {
45
49
  min: 0,
46
50
  max: 100
47
51
  }, G = .1;
48
- function ye(e, t, n) {
52
+ function Te(e, t, n) {
49
53
  if (!e) return { ...W };
50
54
  let r = Infinity, i = -Infinity, a = 0;
51
55
  for (let [, o] of e.values) {
@@ -64,7 +68,7 @@ function ye(e, t, n) {
64
68
  }
65
69
  //#endregion
66
70
  //#region src/state/AutoSaveScheduler.ts
67
- var be = class {
71
+ var Ee = class {
68
72
  timer = null;
69
73
  delayMs = 0;
70
74
  key = null;
@@ -282,8 +286,8 @@ var J = class {
282
286
  registerIndicator(e) {
283
287
  this.indicatorEngine.register(e);
284
288
  }
285
- }, xe = class {
286
- static version = "0.3.0";
289
+ }, De = class {
290
+ static version = "0.7.0";
287
291
  engine;
288
292
  viewport;
289
293
  dataManager;
@@ -312,9 +316,11 @@ var J = class {
312
316
  countdownInterval = null;
313
317
  volumeRenderer;
314
318
  alertManager;
319
+ signalMarkerManager;
320
+ tradeZoneManager;
315
321
  replayManager;
316
322
  undoRedoManager;
317
- autoSaveScheduler = new be((e) => this.saveState(e));
323
+ autoSaveScheduler = new Ee((e) => this.saveState(e));
318
324
  animator;
319
325
  crosshairTooltip;
320
326
  interactionManager;
@@ -365,19 +371,19 @@ var J = class {
365
371
  logScale: n.logScale ?? !0,
366
372
  timeframes: n.timeframes ?? [],
367
373
  defaultTimeframeFavorites: n.defaultTimeframeFavorites ?? []
368
- }, e.style.position = "relative", e.style.overflow = "hidden", e.tabIndex = 0, e.style.outline = "none", this.dataManager = new J(), this.themeManager = new Y(t.theme), this.layoutManager = new Q(), this.indicatorEngine = new x(), this.pluginManager = new $(this.indicatorEngine), this.eventBus = new oe(), V(this.indicatorEngine), this.drawingManager = new ie(), B(this.drawingManager), this.drawingRenderer = new ae(this.drawingManager), this.drawingManager.setRequestRender(() => {
374
+ }, e.style.position = "relative", e.style.overflow = "hidden", e.tabIndex = 0, e.style.outline = "none", this.dataManager = new J(), this.themeManager = new Y(t.theme), this.layoutManager = new Q(), this.indicatorEngine = new b(), this.pluginManager = new $(this.indicatorEngine), this.eventBus = new se(), H(this.indicatorEngine), this.drawingManager = new ae(), ge(this.drawingManager), this.drawingRenderer = new oe(this.drawingManager), this.drawingManager.setRequestRender(() => {
369
375
  this.syncRenderContext(), this.engine.requestRender(r.Overlay), this.scheduleAutoSave();
370
376
  }), this.drawingManager.setEventCallback((e, t) => {
371
377
  this.eventBus.emit(e, t);
372
- }), this.undoRedoManager = new F(), this.drawingManager.setUndoRedoManager(this.undoRedoManager), this.drawingManager.setDataGetter(() => this.dataManager.getData()), this.drawingManager.setDisplayDataGetter(() => this.getDisplayData()), t.crosshair?.mode === "magnet" && this.drawingManager.setMagnetMode("magnet"), this.tradingManager = new N(), this.tradingRenderer = new P(this.tradingManager), this.tradingManager.setContainer(e), this.tradingManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradingManager.setEventCallback((e, t) => {
378
+ }), this.undoRedoManager = new z(), this.drawingManager.setUndoRedoManager(this.undoRedoManager), this.drawingManager.setDataGetter(() => this.dataManager.getData()), this.drawingManager.setDisplayDataGetter(() => this.getDisplayData()), t.crosshair?.mode === "magnet" && this.drawingManager.setMagnetMode("magnet"), this.tradingManager = new L(), this.tradingRenderer = new R(this.tradingManager), this.tradingManager.setContainer(e), this.tradingManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradingManager.setEventCallback((e, t) => {
373
379
  this.eventBus.emit(e, t);
374
- }), this.engine = new E(e);
380
+ }), this.engine = new D(e);
375
381
  let i = this.engine.dprManager.getContainerSize();
376
- this.viewport = new I(i.width, i.height, t.minBarSpacing ?? 2, t.maxBarSpacing ?? 30, t.rightMargin ?? 5), this.layoutManager.resize(i.width, i.height), this.engine.onContainerResize = (e) => {
382
+ this.viewport = new B(i.width, i.height, t.minBarSpacing ?? 2, t.maxBarSpacing ?? 30, t.rightMargin ?? 5), this.layoutManager.resize(i.width, i.height), this.engine.onContainerResize = (e) => {
377
383
  if (e.width <= 0 || e.height <= 0) return;
378
384
  let t = this.viewport.isAtEnd();
379
385
  this.viewport.resize(e.width, e.height), this.layoutManager.resize(e.width, e.height), this.updateViewportAndRender(t);
380
- }, this.chartRenderer = this.createChartRenderer(t.chartType), this.gridRenderer = new se(), t.grid?.visible === !1 && this.gridRenderer.setVisible(!1), this.priceAxis = new T(), this.priceAxis.setLocale(this.numberLocale), this.timeAxis = new M(), this.crosshairHandler = new y(), this.crosshairHandler.setLocale(this.numberLocale), t.crosshair?.mode && this.crosshairHandler.setMode(t.crosshair.mode), this.crosshairHandler.setCallback((e, t) => {
386
+ }, this.chartRenderer = this.createChartRenderer(t.chartType), this.gridRenderer = new ce(), t.grid?.visible === !1 && this.gridRenderer.setVisible(!1), this.priceAxis = new E(), this.priceAxis.setLocale(this.numberLocale), this.timeAxis = new F(), this.crosshairHandler = new ne(), this.crosshairHandler.setLocale(this.numberLocale), t.crosshair?.mode && this.crosshairHandler.setMode(t.crosshair.mode), this.crosshairHandler.setCallback((e, t) => {
381
387
  if (e !== null && t) {
382
388
  let n = this.dataManager.getData(), r = e < n.length ? n[e] : void 0;
383
389
  this.chartLegend.setHoverBar(r ?? null), r && this.crosshairTooltip.show(t, r, this.themeManager.getTheme(), this.cachedContainerSize()), this.eventBus.emit("crosshairMove", {
@@ -386,12 +392,12 @@ var J = class {
386
392
  barIndex: e
387
393
  });
388
394
  } else this.crosshairTooltip.hide(), this.chartLegend.setHoverBar(null);
389
- }), this.chartLegend = new te(), this.chartLegend.setChartType(t.chartType), this.watermark = new R(), t.watermark && this.watermark.setConfig(t.watermark), this.volumeRenderer = new L(), this.barCountdown = new m(), this.sessionBreaks = new A(), this.compareRenderer = new v(), t.sessionBreaks ? this.sessionBreaks.setConfig({
395
+ }), this.chartLegend = new te(), this.chartLegend.setChartType(t.chartType), this.watermark = new me(), t.watermark && this.watermark.setConfig(t.watermark), this.volumeRenderer = new pe(), this.barCountdown = new m(), this.sessionBreaks = new j(), this.compareRenderer = new v(), t.sessionBreaks ? this.sessionBreaks.setConfig({
390
396
  visible: t.sessionBreaks.visible ?? !0,
391
397
  color: t.sessionBreaks.color,
392
398
  lineStyle: t.sessionBreaks.lineStyle,
393
399
  lineWidth: t.sessionBreaks.lineWidth
394
- }) : t.features?.sessionBreaks !== !1 && this.sessionBreaks.setVisible(!0), t.logScale && this.viewport.setLogScale(!0), this.animator = new f(), this.crosshairTooltip = new ne(), this.crosshairTooltip.create(e), this.keyboardHandler = new de({
400
+ }) : t.features?.sessionBreaks !== !1 && this.sessionBreaks.setVisible(!0), t.logScale && this.viewport.setLogScale(!0), this.animator = new f(), this.crosshairTooltip = new re(), this.crosshairTooltip.create(e), this.keyboardHandler = new x({
395
401
  scrollBars: (e) => {
396
402
  let t = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;
397
403
  this.viewport.scrollBy(e * t), this.updateViewportAndRender();
@@ -411,18 +417,39 @@ var J = class {
411
417
  if (!this.keyboardHandler) return;
412
418
  let t = document.activeElement;
413
419
  t && t !== this.container && !this.container.contains(t) || t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable) || this.keyboardHandler.handleKey(e) && e.preventDefault();
414
- }, window.addEventListener("keydown", this.onWindowKeyDown), this.currentPriceLine = new re(), this.alertManager = new d(), this.alertManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.alertManager.on("triggered", (e) => {
420
+ }, window.addEventListener("keydown", this.onWindowKeyDown), this.currentPriceLine = new ie(), this.alertManager = new d(), this.alertManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.alertManager.on("triggered", (e) => {
415
421
  this.eventBus.emit("dataUpdate", {
416
422
  alert: "triggered",
417
423
  alertId: e.id,
418
424
  price: e.price,
419
425
  message: e.message
420
426
  });
421
- }), this.replayManager = new O(), this.interactionManager = new le(e), this.features.panning && this.interactionManager.setPanHandler(new C((e) => {
427
+ }), this.signalMarkerManager = new M(), this.signalMarkerManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.signalMarkerManager.setDataGetter(() => this.dataManager.getData()), this.signalMarkerManager.on("added", (e) => {
428
+ this.eventBus.emit("signalMarkerAdd", {
429
+ id: e.id,
430
+ source: e.source,
431
+ direction: e.direction
432
+ });
433
+ }), this.signalMarkerManager.on("removed", (e) => {
434
+ this.eventBus.emit("signalMarkerRemove", { id: e });
435
+ }), this.tradeZoneManager = new I(), this.tradeZoneManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradeZoneManager.setDataGetter(() => this.dataManager.getData()), this.tradeZoneManager.on("added", (e) => {
436
+ this.eventBus.emit("tradeZoneAdd", {
437
+ id: e.id,
438
+ direction: e.direction
439
+ });
440
+ }), this.tradeZoneManager.on("removed", (e) => {
441
+ this.eventBus.emit("tradeZoneRemove", { id: e });
442
+ }), this.replayManager = new k(), this.interactionManager = new de(e), this.features.panning && this.interactionManager.setPanHandler(new w((e) => {
422
443
  this.viewport.scrollBy(e), this.updateViewportAndRender();
423
- })), this.features.zooming && this.interactionManager.setZoomHandler(new z((e, t) => {
444
+ })), this.features.zooming && this.interactionManager.setZoomHandler(new he((e, t) => {
424
445
  this.viewport.zoom(e, t), this.updateViewportAndRender();
425
- })), this.features.crosshair && this.interactionManager.setCrosshairHandler(this.crosshairHandler), this.features.drawings && this.interactionManager.setDrawingManager(this.drawingManager, () => this.viewport.getState()), this.features.trading && this.interactionManager.setTradingManager(this.tradingManager, () => this.viewport.getState()), this.interactionManager.setOverlayDirtyCallback(() => {
446
+ })), this.features.crosshair && this.interactionManager.setCrosshairHandler(this.crosshairHandler), this.features.drawings && this.interactionManager.setDrawingManager(this.drawingManager, () => ({
447
+ ...this.viewport.getState(),
448
+ data: this.getDisplayData()
449
+ })), this.features.trading && this.interactionManager.setTradingManager(this.tradingManager, () => ({
450
+ ...this.viewport.getState(),
451
+ data: this.getDisplayData()
452
+ })), this.interactionManager.setOverlayDirtyCallback(() => {
426
453
  this.engine.requestRender(r.Overlay), this.layoutManager.getPanels().length > 0 && this.engine.requestRender(r.UI);
427
454
  }), this.interactionManager.attach(), this.syncRenderContext(), this.engine.start();
428
455
  }
@@ -469,8 +496,8 @@ var J = class {
469
496
  this.pluginManager.registerIndicator(e);
470
497
  }
471
498
  static indicators() {
472
- let e = new x();
473
- return V(e), e.getAvailableIndicators();
499
+ let e = new b();
500
+ return H(e), e.getAvailableIndicators();
474
501
  }
475
502
  setPanelPosition(e, t) {
476
503
  this.layoutManager.setPanelPosition(e, t), this.engine.requestRender();
@@ -536,21 +563,21 @@ var J = class {
536
563
  exportVisibleData(e = "csv", t) {
537
564
  let n = this.viewport.getState(), r = this.dataManager.getData(), i = Math.max(0, n.visibleRange.from), a = Math.min(r.length - 1, n.visibleRange.to), o = r.slice(i, a + 1);
538
565
  if (e === "json") {
539
- let e = b.toJSON(o);
540
- b.download(e, t ?? "chart-data.json", "application/json");
566
+ let e = y.toJSON(o);
567
+ y.download(e, t ?? "chart-data.json", "application/json");
541
568
  } else {
542
- let e = b.toCSV(o);
543
- b.download(e, t ?? "chart-data.csv", "text/csv");
569
+ let e = y.toCSV(o);
570
+ y.download(e, t ?? "chart-data.csv", "text/csv");
544
571
  }
545
572
  }
546
573
  exportAllData(e = "csv", t) {
547
574
  let n = this.dataManager.getData();
548
575
  if (e === "json") {
549
- let e = b.toJSON(n);
550
- b.download(e, t ?? "chart-data.json", "application/json");
576
+ let e = y.toJSON(n);
577
+ y.download(e, t ?? "chart-data.json", "application/json");
551
578
  } else {
552
- let e = b.toCSV(n);
553
- b.download(e, t ?? "chart-data.csv", "text/csv");
579
+ let e = y.toCSV(n);
580
+ y.download(e, t ?? "chart-data.csv", "text/csv");
554
581
  }
555
582
  }
556
583
  setAutoSave(e, t = 5e3) {
@@ -601,7 +628,7 @@ var J = class {
601
628
  this.features.trading && this.tradingManager.setConfig(e);
602
629
  }
603
630
  async connect(e) {
604
- this.disconnectStream(), this.streamManager = new j(), this.streamManager.on("snapshot", (e) => {
631
+ this.disconnectStream(), this.streamManager = new P(), this.streamManager.on("snapshot", (e) => {
605
632
  this.setData(e);
606
633
  }), this.streamManager.on("barClose", (e) => {
607
634
  this.dataManager.appendBar(e), this.crosshairHandler.setData(this.dataManager.getData()), this.autoScrollOnNewBar && this.viewport.scrollToEnd(), this.indicatorEngine.recalculateAll(this.dataManager.getData()), this.updateViewportAndRender();
@@ -753,6 +780,12 @@ var J = class {
753
780
  getCrosshairMode() {
754
781
  return this.crosshairHandler.getMode();
755
782
  }
783
+ setCrosshairPosition(e) {
784
+ e && this.crosshairHandler.onPointerMove(e), this.engine.requestRender(r.Overlay);
785
+ }
786
+ getData() {
787
+ return this.dataManager.getData();
788
+ }
756
789
  setGridVisible(e) {
757
790
  this.gridRenderer.setVisible(e), this.engine.requestRender(r.Background);
758
791
  }
@@ -775,13 +808,13 @@ var J = class {
775
808
  this.chartLegend.setStatusText(e), this.engine.requestRender(r.UI);
776
809
  }
777
810
  screenshot(e) {
778
- this.features.screenshot && k.download(this.container, e, this.themeManager.getTheme().background);
811
+ this.features.screenshot && A.download(this.container, e, this.themeManager.getTheme().background);
779
812
  }
780
813
  screenshotDataURL() {
781
- return this.features.screenshot ? k.toDataURL(this.container, this.themeManager.getTheme().background) : null;
814
+ return this.features.screenshot ? A.toDataURL(this.container, this.themeManager.getTheme().background) : null;
782
815
  }
783
816
  async screenshotBlob() {
784
- return this.features.screenshot ? k.toBlob(this.container, this.themeManager.getTheme().background) : null;
817
+ return this.features.screenshot ? A.toBlob(this.container, this.themeManager.getTheme().background) : null;
785
818
  }
786
819
  addAlert(e, t = "crossing", n) {
787
820
  if (!this.features.alerts) return null;
@@ -803,6 +836,45 @@ var J = class {
803
836
  loadAlerts(e) {
804
837
  this.alertManager.loadFromStorage(e), this.engine.requestRender(r.Overlay);
805
838
  }
839
+ addSignalMarker(e) {
840
+ return this.signalMarkerManager.addMarker(e);
841
+ }
842
+ removeSignalMarker(e) {
843
+ this.signalMarkerManager.removeMarker(e);
844
+ }
845
+ getSignalMarkers() {
846
+ return this.signalMarkerManager.getMarkers();
847
+ }
848
+ setSignalMarkers(e) {
849
+ this.signalMarkerManager.setMarkers(e);
850
+ }
851
+ clearSignalMarkers() {
852
+ this.signalMarkerManager.clearMarkers();
853
+ }
854
+ setSignalMarkerStyle(e) {
855
+ this.signalMarkerManager.setStyle(e);
856
+ }
857
+ addTradeZone(e) {
858
+ return this.tradeZoneManager.addZone(e);
859
+ }
860
+ updateTradeZone(e, t) {
861
+ this.tradeZoneManager.updateZone(e, t);
862
+ }
863
+ removeTradeZone(e) {
864
+ this.tradeZoneManager.removeZone(e);
865
+ }
866
+ getTradeZones() {
867
+ return this.tradeZoneManager.getZones();
868
+ }
869
+ setTradeZones(e) {
870
+ this.tradeZoneManager.setZones(e);
871
+ }
872
+ clearTradeZones() {
873
+ this.tradeZoneManager.clearZones();
874
+ }
875
+ setTradeZoneStyle(e) {
876
+ this.tradeZoneManager.setStyle(e);
877
+ }
806
878
  replay(e) {
807
879
  if (!this.features.replay) return;
808
880
  let t = this.dataManager.getData();
@@ -920,13 +992,13 @@ var J = class {
920
992
  this.countdownInterval && clearInterval(this.countdownInterval), this.disableAutoSave(), this.disconnectStream(), this.onWindowKeyDown &&= (window.removeEventListener("keydown", this.onWindowKeyDown), null), this.keyboardHandler = null, this.interactionManager.detach(), this.tradingManager.destroy(), this.animator.dispose(), this.crosshairTooltip.destroy(), this.replayManager.dispose(), this.undoRedoManager.clear(), this.engine.destroy(), this.eventBus.destroy(), this.container.innerHTML = "";
921
993
  }
922
994
  createChartRenderer(e) {
923
- return _e(e);
995
+ return Ce(e);
924
996
  }
925
997
  getDisplayData() {
926
998
  if (this.displayDataCache) return this.displayDataCache;
927
999
  let e = this.dataManager.getData();
928
1000
  if (e.length === 0) return e;
929
- let t = ve(this.options.chartType, e);
1001
+ let t = we(this.options.chartType, e);
930
1002
  return this.displayDataCache = t, t;
931
1003
  }
932
1004
  scheduleRender() {
@@ -963,7 +1035,7 @@ var J = class {
963
1035
  buildPanelRenderInfos() {
964
1036
  if (this.panelInfoCache) return this.panelInfoCache;
965
1037
  let e = this.getResolvedLayout(), t = this.viewport.getState(), { from: n, to: r } = t.visibleRange, i = e.panels.map((e) => {
966
- let i = ye(this.indicatorEngine.getOutput(e.config.id), n, r), a = {
1038
+ let i = Te(this.indicatorEngine.getOutput(e.config.id), n, r), a = {
967
1039
  x: e.rect.x,
968
1040
  y: e.rect.y + 20,
969
1041
  width: e.rect.width,
@@ -982,7 +1054,7 @@ var J = class {
982
1054
  return this.panelInfoCache = i, i;
983
1055
  }
984
1056
  syncRenderContext() {
985
- let e = this.getResolvedLayout(), t = this.features.indicators ? this.buildPanelRenderInfos() : [], n = e.panels.filter((e) => e.config.position === "bottom").reduce((e, t) => e + t.rect.height, 0), r = e.mainChartRect.y + e.mainChartRect.height + n;
1057
+ let e = this.getResolvedLayout(), t = this.features.indicators ? this.buildPanelRenderInfos() : [], n = e.panels.filter((e) => e.config.position === "bottom").reduce((e, t) => e + t.rect.height, 0), r = e.mainChartRect.y + e.mainChartRect.height + n, i = this.getDisplayData();
986
1058
  this.engine.setRenderContext({
987
1059
  chartRenderer: this.chartRenderer,
988
1060
  gridRenderer: this.features.grid ? this.gridRenderer : null,
@@ -999,12 +1071,18 @@ var J = class {
999
1071
  barCountdown: this.barCountdown,
1000
1072
  sessionBreaks: this.sessionBreaks,
1001
1073
  compareRenderer: this.compareRenderer,
1074
+ alertManager: this.features.alerts ? this.alertManager : null,
1075
+ signalMarkerManager: this.signalMarkerManager,
1076
+ tradeZoneManager: this.tradeZoneManager,
1002
1077
  panels: t,
1003
1078
  priceLimits: this.buildPriceLimits(),
1004
1079
  timeAxisY: r,
1005
- viewport: this.viewport.getState(),
1080
+ viewport: {
1081
+ ...this.viewport.getState(),
1082
+ data: i
1083
+ },
1006
1084
  theme: this.themeManager.getTheme(),
1007
- data: this.getDisplayData(),
1085
+ data: i,
1008
1086
  numberLocale: this.numberLocale
1009
1087
  });
1010
1088
  }
@@ -1022,6 +1100,6 @@ var J = class {
1022
1100
  }
1023
1101
  };
1024
1102
  //#endregion
1025
- export { J as a, Y as i, $ as n, Q as r, xe as t };
1103
+ export { J as a, Y as i, $ as n, Q as r, De as t };
1026
1104
 
1027
- //# sourceMappingURL=Chart-CrrTKx3r.js.map
1105
+ //# sourceMappingURL=Chart-Cy8K3wHS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Chart-Cy8K3wHS.js","names":[],"sources":["../src/charts/ChartTypeStrategy.ts","../src/charts/IndicatorPriceRange.ts","../src/state/AutoSaveScheduler.ts","../src/DataManager.ts","../src/ThemeManager.ts","../src/layout/LayoutManager.ts","../src/plugins/PluginManager.ts","../src/Chart.ts"],"sourcesContent":["import type { ChartType, DataSeries } from '@tradecanvas/commons';\r\nimport {\r\n AreaRenderer,\r\n BarRenderer,\r\n BaselineRenderer,\r\n CandlestickRenderer,\r\n HLCAreaRenderer,\r\n HollowCandleRenderer,\r\n KagiRenderer,\r\n LineRenderer,\r\n LineWithMarkersRenderer,\r\n PointAndFigureRenderer,\r\n RenkoRenderer,\r\n StepLineRenderer,\r\n VolumeCandleRenderer,\r\n toHeikinAshi,\r\n toKagi,\r\n toLineBreak,\r\n toPointAndFigure,\r\n toRangeBars,\r\n toRenko,\r\n} from '@tradecanvas/core';\r\nimport type { ChartRendererInterface } from '@tradecanvas/core';\r\n\r\n/**\r\n * Pure mapping from `ChartType` to the renderer class that draws it. Several\r\n * chart types reuse `CandlestickRenderer` against transformed data\r\n * (heikinAshi, lineBreak, rangeBars).\r\n */\r\nexport function createRendererFor(type: ChartType): ChartRendererInterface {\r\n switch (type) {\r\n case 'candlestick':\r\n case 'heikinAshi':\r\n case 'lineBreak':\r\n case 'rangeBars':\r\n return new CandlestickRenderer();\r\n case 'line':\r\n return new LineRenderer();\r\n case 'area':\r\n return new AreaRenderer();\r\n case 'bar':\r\n return new BarRenderer();\r\n case 'hollowCandle':\r\n return new HollowCandleRenderer();\r\n case 'baseline':\r\n return new BaselineRenderer();\r\n case 'renko':\r\n return new RenkoRenderer();\r\n case 'kagi':\r\n return new KagiRenderer();\r\n case 'pointAndFigure':\r\n return new PointAndFigureRenderer();\r\n case 'volumeCandles':\r\n return new VolumeCandleRenderer();\r\n case 'hlcArea':\r\n return new HLCAreaRenderer();\r\n case 'stepLine':\r\n return new StepLineRenderer();\r\n case 'lineWithMarkers':\r\n return new LineWithMarkersRenderer();\r\n default:\r\n return new CandlestickRenderer();\r\n }\r\n}\r\n\r\n/**\r\n * Transform raw OHLC bars into the display series for a given chart type.\r\n * Returns the input unchanged for chart types that render raw OHLC directly.\r\n *\r\n * Centralized so adding a new chart type only requires editing one file.\r\n */\r\nexport function transformDisplayData(type: ChartType, raw: DataSeries): DataSeries {\r\n if (raw.length === 0) return raw;\r\n\r\n switch (type) {\r\n case 'heikinAshi':\r\n return toHeikinAshi(raw);\r\n case 'renko':\r\n return toRenko(raw, { brickSize: 0, useATR: true, atrPeriod: 14 });\r\n case 'lineBreak':\r\n return toLineBreak(raw, 3);\r\n case 'kagi':\r\n return toKagi(raw, 4);\r\n case 'pointAndFigure': {\r\n const avgPrice = averageClose(raw);\r\n return toPointAndFigure(raw, avgPrice * 0.01, 3);\r\n }\r\n case 'rangeBars': {\r\n const avgPrice = averageClose(raw);\r\n return toRangeBars(raw, { rangeSize: avgPrice * 0.005 });\r\n }\r\n default:\r\n return raw;\r\n }\r\n}\r\n\r\n/** Chart types that materially transform raw OHLC into a different series. */\r\nexport function isTransformedChartType(type: ChartType): boolean {\r\n switch (type) {\r\n case 'heikinAshi':\r\n case 'renko':\r\n case 'lineBreak':\r\n case 'kagi':\r\n case 'pointAndFigure':\r\n case 'rangeBars':\r\n return true;\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\nfunction averageClose(raw: DataSeries): number {\r\n let sum = 0;\r\n for (const b of raw) sum += b.close;\r\n return sum / raw.length;\r\n}\r\n","import type { IndicatorOutput } from '@tradecanvas/commons';\r\n\r\nexport interface PriceRange {\r\n min: number;\r\n max: number;\r\n}\r\n\r\nconst DEFAULT_RANGE: PriceRange = { min: 0, max: 100 };\r\nconst PADDING = 0.1;\r\n\r\n/**\r\n * Compute a padded {min, max} price range for an indicator panel from the\r\n * visible slice of its output. Returns a sensible default range when the\r\n * output is empty or has no values inside [from, to].\r\n *\r\n * Pure — no canvas, no viewport object, just the values map and bar bounds.\r\n * Iterates the output's `values` map in insertion order; we treat its index\r\n * (0…N-1) as the bar index, matching how the engine inserts values.\r\n */\r\nexport function computeIndicatorPriceRange(\r\n output: IndicatorOutput | null,\r\n from: number,\r\n to: number,\r\n): PriceRange {\r\n if (!output) return { ...DEFAULT_RANGE };\r\n\r\n let vMin = Infinity;\r\n let vMax = -Infinity;\r\n let idx = 0;\r\n for (const [, val] of output.values) {\r\n if (idx >= from && idx <= to) {\r\n for (const key in val) {\r\n const v = val[key];\r\n if (v !== undefined && Number.isFinite(v)) {\r\n if (v < vMin) vMin = v;\r\n if (v > vMax) vMax = v;\r\n }\r\n }\r\n }\r\n idx++;\r\n }\r\n\r\n if (vMin === Infinity) return { ...DEFAULT_RANGE };\r\n\r\n const range = vMax - vMin || 1;\r\n return {\r\n min: vMin - range * PADDING,\r\n max: vMax + range * PADDING,\r\n };\r\n}\r\n","/**\r\n * Debounced auto-save scheduler. Coalesces a burst of `schedule()` calls into\r\n * a single `save(key)` invocation after `delayMs` of quiet time. Pure state\r\n * machine — owner injects the actual save callback so this stays testable.\r\n */\r\nexport class AutoSaveScheduler {\r\n private timer: ReturnType<typeof setTimeout> | null = null;\r\n private delayMs = 0;\r\n private key: string | null = null;\r\n\r\n constructor(private save: (key: string) => void) {}\r\n\r\n /** Enable auto-save with the given storage key and quiet-time debounce. */\r\n enable(key: string, delayMs: number): void {\r\n this.key = key;\r\n this.delayMs = delayMs;\r\n }\r\n\r\n /** Disable auto-save and cancel any pending fire. */\r\n disable(): void {\r\n this.key = null;\r\n this.delayMs = 0;\r\n this.cancel();\r\n }\r\n\r\n /**\r\n * Reset the quiet-time window. If currently disabled (no key or delay ≤ 0),\r\n * this is a no-op. Subsequent calls within the window restart the timer.\r\n */\r\n schedule(): void {\r\n if (this.delayMs <= 0 || !this.key) return;\r\n if (this.timer) clearTimeout(this.timer);\r\n this.timer = setTimeout(() => {\r\n this.timer = null;\r\n if (this.key) this.save(this.key);\r\n }, this.delayMs);\r\n }\r\n\r\n /** Cancel any pending fire without changing enabled state. */\r\n cancel(): void {\r\n if (this.timer) {\r\n clearTimeout(this.timer);\r\n this.timer = null;\r\n }\r\n }\r\n\r\n isEnabled(): boolean {\r\n return this.delayMs > 0 && this.key !== null;\r\n }\r\n\r\n hasPending(): boolean {\r\n return this.timer !== null;\r\n }\r\n}\r\n","import type { OHLCBar, DataSeries } from '@tradecanvas/commons';\nimport { mergeBar } from '@tradecanvas/commons';\n\n/** Validate a single OHLC bar. Returns true if bar is usable. */\nfunction isValidBar(bar: OHLCBar): boolean {\n if (!bar || typeof bar.time !== 'number') return false;\n const { open, high, low, close } = bar;\n // Reject NaN / Infinity\n if (!isFinite(open) || !isFinite(high) || !isFinite(low) || !isFinite(close)) return false;\n // Reject negative prices\n if (open < 0 || high < 0 || low < 0 || close < 0) return false;\n // High must be >= low\n if (high < low) return false;\n // Volume (optional) must be non-negative if present\n if (bar.volume !== undefined && (!isFinite(bar.volume) || bar.volume < 0)) return false;\n return true;\n}\n\n/** Sanitize a bar: clamp high/low to envelope OHLC values. */\nfunction sanitizeBar(bar: OHLCBar): OHLCBar {\n return {\n ...bar,\n high: Math.max(bar.open, bar.high, bar.low, bar.close),\n low: Math.min(bar.open, bar.high, bar.low, bar.close),\n volume: bar.volume !== undefined ? Math.max(0, bar.volume) : 0,\n };\n}\n\nexport class DataManager {\n private data: DataSeries = [];\n\n getData(): DataSeries {\n return this.data;\n }\n\n setData(data: DataSeries): void {\n // Filter out completely invalid bars, sanitize the rest\n this.data = data\n .filter(isValidBar)\n .map(sanitizeBar);\n }\n\n appendBar(bar: OHLCBar): void {\n if (!isValidBar(bar)) return;\n this.data.push(sanitizeBar(bar));\n }\n\n updateLastBar(bar: OHLCBar): void {\n if (!isValidBar(bar)) return;\n const sanitized = sanitizeBar(bar);\n if (this.data.length === 0) {\n this.data.push(sanitized);\n return;\n }\n this.data[this.data.length - 1] = sanitized;\n }\n\n updateLastBarFromTick(tick: { price: number; volume?: number; time: number }): void {\n if (this.data.length === 0) return;\n if (!isFinite(tick.price) || tick.price < 0) return;\n if (tick.volume !== undefined && (!isFinite(tick.volume) || tick.volume < 0)) return;\n this.data[this.data.length - 1] = mergeBar(this.data[this.data.length - 1], tick);\n }\n\n getLength(): number {\n return this.data.length;\n }\n\n clear(): void {\n this.data = [];\n }\n}\n","import type { Theme, ThemeName } from '@tradecanvas/commons';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\n\nexport class ThemeManager {\n private theme: Theme;\n\n constructor(themeOrName?: ThemeName | Theme) {\n if (!themeOrName || themeOrName === 'dark') {\n this.theme = { ...DARK_THEME };\n } else if (themeOrName === 'light') {\n this.theme = { ...LIGHT_THEME };\n } else {\n this.theme = { ...themeOrName };\n }\n }\n\n getTheme(): Theme {\n return this.theme;\n }\n\n setTheme(themeOrName: ThemeName | Theme): void {\n if (themeOrName === 'dark') {\n this.theme = { ...DARK_THEME };\n } else if (themeOrName === 'light') {\n this.theme = { ...LIGHT_THEME };\n } else {\n this.theme = { ...themeOrName };\n }\n }\n}\n","import type { PanelPosition, PanelConfig, ResolvedLayout, ResolvedPanel, DividerRect, Rect } from '@tradecanvas/commons';\nimport { DEFAULT_PANEL_HEIGHT, MIN_PANEL_HEIGHT, PRICE_AXIS_WIDTH, TIME_AXIS_HEIGHT } from '@tradecanvas/commons';\n\nconst DEFAULT_PANEL_WIDTH = 200;\nconst MIN_PANEL_WIDTH = 80;\n\nexport class LayoutManager {\n private panels: PanelConfig[] = [];\n private containerWidth = 0;\n private containerHeight = 0;\n\n resize(width: number, height: number): void {\n this.containerWidth = width;\n this.containerHeight = height;\n }\n\n addPanel(instanceId: string, position: PanelPosition = 'bottom', size?: number): void {\n const isVertical = position === 'left' || position === 'right';\n this.panels.push({\n id: instanceId,\n position,\n size: size ?? (isVertical ? DEFAULT_PANEL_WIDTH : DEFAULT_PANEL_HEIGHT),\n minSize: isVertical ? MIN_PANEL_WIDTH : MIN_PANEL_HEIGHT,\n content: { type: 'indicator', indicatorInstanceId: instanceId },\n });\n }\n\n removePanel(instanceId: string): void {\n this.panels = this.panels.filter((p) => p.id !== instanceId);\n }\n\n setPanelPosition(instanceId: string, position: PanelPosition): void {\n const panel = this.panels.find((p) => p.id === instanceId);\n if (panel) {\n const wasVertical = panel.position === 'left' || panel.position === 'right';\n const isVertical = position === 'left' || position === 'right';\n panel.position = position;\n if (wasVertical !== isVertical) {\n panel.size = isVertical ? DEFAULT_PANEL_WIDTH : DEFAULT_PANEL_HEIGHT;\n panel.minSize = isVertical ? MIN_PANEL_WIDTH : MIN_PANEL_HEIGHT;\n }\n }\n }\n\n setPanelSize(instanceId: string, size: number): void {\n const panel = this.panels.find((p) => p.id === instanceId);\n if (panel) {\n panel.size = Math.max(panel.minSize, size);\n }\n }\n\n getPanels(): PanelConfig[] {\n return this.panels;\n }\n\n resolve(): ResolvedLayout {\n const leftPanels = this.panels.filter((p) => p.position === 'left');\n const rightPanels = this.panels.filter((p) => p.position === 'right');\n const topPanels = this.panels.filter((p) => p.position === 'top');\n const bottomPanels = this.panels.filter((p) => p.position === 'bottom');\n\n const leftWidth = leftPanels.reduce((s, p) => s + p.size, 0);\n const rightWidth = rightPanels.reduce((s, p) => s + p.size, 0);\n const topHeight = topPanels.reduce((s, p) => s + p.size, 0);\n const bottomHeight = bottomPanels.reduce((s, p) => s + p.size, 0);\n\n const mainChartRect: Rect = {\n x: leftWidth,\n y: topHeight,\n width: Math.max(0, this.containerWidth - leftWidth - rightWidth - PRICE_AXIS_WIDTH),\n height: Math.max(0, this.containerHeight - topHeight - bottomHeight - TIME_AXIS_HEIGHT),\n };\n\n const resolvedPanels: ResolvedPanel[] = [];\n const dividers: DividerRect[] = [];\n\n // Left panels (stacked vertically)\n let x = 0;\n for (const panel of leftPanels) {\n resolvedPanels.push({\n config: panel,\n rect: { x, y: 0, width: panel.size, height: this.containerHeight - TIME_AXIS_HEIGHT },\n });\n dividers.push({\n panelId: panel.id,\n rect: { x: x + panel.size - 2, y: 0, width: 4, height: this.containerHeight },\n orientation: 'vertical',\n });\n x += panel.size;\n }\n\n // Top panels (stacked horizontally, full width minus left/right)\n let y = 0;\n for (const panel of topPanels) {\n resolvedPanels.push({\n config: panel,\n rect: { x: leftWidth, y, width: mainChartRect.width, height: panel.size },\n });\n dividers.push({\n panelId: panel.id,\n rect: { x: leftWidth, y: y + panel.size - 2, width: mainChartRect.width, height: 4 },\n orientation: 'horizontal',\n });\n y += panel.size;\n }\n\n // Bottom panels\n y = mainChartRect.y + mainChartRect.height;\n for (const panel of bottomPanels) {\n resolvedPanels.push({\n config: panel,\n rect: { x: leftWidth, y, width: mainChartRect.width, height: panel.size },\n });\n dividers.push({\n panelId: panel.id,\n rect: { x: leftWidth, y: y - 2, width: mainChartRect.width, height: 4 },\n orientation: 'horizontal',\n });\n y += panel.size;\n }\n\n // Right panels\n x = leftWidth + mainChartRect.width + PRICE_AXIS_WIDTH;\n for (const panel of rightPanels) {\n resolvedPanels.push({\n config: panel,\n rect: { x, y: 0, width: panel.size, height: this.containerHeight - TIME_AXIS_HEIGHT },\n });\n dividers.push({\n panelId: panel.id,\n rect: { x: x - 2, y: 0, width: 4, height: this.containerHeight },\n orientation: 'vertical',\n });\n x += panel.size;\n }\n\n return { mainChartRect, panels: resolvedPanels, dividers };\n }\n\n getMainChartRect(): Rect {\n return this.resolve().mainChartRect;\n }\n}\n","import type { IndicatorPlugin } from '@tradecanvas/commons';\nimport type { IndicatorEngine } from '@tradecanvas/core';\n\nexport class PluginManager {\n constructor(private indicatorEngine: IndicatorEngine) {}\n\n registerIndicator(plugin: IndicatorPlugin): void {\n this.indicatorEngine.register(plugin);\n }\n}\n","import type {\r\n ChartOptions,\r\n ChartType,\r\n OHLCBar,\r\n DataSeries,\r\n Theme,\r\n ThemeName,\r\n ChartEventType,\r\n ChartEvent,\r\n ChartEventMap,\r\n TauriBridgeOptions,\r\n IndicatorPlugin,\r\n IndicatorDescriptor,\r\n IndicatorOutput,\r\n DrawingToolType,\r\n DrawingState,\r\n DrawingStyle,\r\n DrawingPlugin,\r\n PanelPosition,\r\n TradingOrder,\r\n TradingPosition,\r\n DepthData,\r\n TradingConfig,\r\n MarketConfig,\r\n Locale,\r\n StreamConfig,\r\n ConnectionState,\r\n ConnectionInfo,\r\n TimeFrame,\r\n FeaturesConfig,\r\n} from '@tradecanvas/commons';\r\nimport { LayerType, setLocale as setGlobalLocale, computePriceLimits } from '@tradecanvas/commons';\r\nimport {\r\n RenderEngine,\r\n Viewport,\r\n GridRenderer,\r\n PriceAxis,\r\n TimeAxis,\r\n InteractionManager,\r\n PanHandler,\r\n ZoomHandler,\r\n CrosshairHandler,\r\n IndicatorEngine,\r\n registerBuiltInIndicators,\r\n EventBus,\r\n DrawingManager,\r\n DrawingRenderer,\r\n registerBuiltInDrawingTools,\r\n TradingManager,\r\n TradingRenderer,\r\n StreamManager,\r\n ChartLegend,\r\n Screenshot,\r\n Watermark,\r\n BarCountdown,\r\n VolumeRenderer,\r\n AlertManager,\r\n SignalMarkerManager,\r\n TradeZoneManager,\r\n ReplayManager,\r\n ChartStateManager,\r\n UndoRedoManager,\r\n Animator,\r\n KeyboardHandler,\r\n CrosshairTooltip,\r\n DataExporter,\r\n SessionBreaks,\r\n CompareRenderer,\r\n CurrentPriceLine,\r\n} from '@tradecanvas/core';\r\nimport type { ChartRendererInterface } from '@tradecanvas/core';\r\nimport { timeframeToMs } from '@tradecanvas/commons';\r\nimport { createRendererFor, transformDisplayData } from './charts/ChartTypeStrategy.js';\r\nimport { computeIndicatorPriceRange } from './charts/IndicatorPriceRange.js';\r\nimport { AutoSaveScheduler } from './state/AutoSaveScheduler.js';\r\nimport { DataManager } from './DataManager.js';\r\nimport { ThemeManager } from './ThemeManager.js';\r\nimport { LayoutManager } from './layout/LayoutManager.js';\r\nimport { PluginManager } from './plugins/PluginManager.js';\r\n\r\nexport class Chart {\r\n static version = '0.7.0';\r\n\r\n private engine: RenderEngine;\r\n private viewport: Viewport;\r\n private dataManager: DataManager;\r\n private themeManager: ThemeManager;\r\n private layoutManager: LayoutManager;\r\n private pluginManager: PluginManager;\r\n private indicatorEngine: IndicatorEngine;\r\n private drawingManager: DrawingManager;\r\n private drawingRenderer: DrawingRenderer;\r\n private tradingManager: TradingManager;\r\n private tradingRenderer: TradingRenderer;\r\n private eventBus: EventBus;\r\n private streamManager: StreamManager | null = null;\r\n private autoScrollOnNewBar = true;\r\n private displayDataCache: DataSeries | null = null;\r\n private resolvedLayoutCache: import('@tradecanvas/commons').ResolvedLayout | null = null;\r\n private panelInfoCache: import('@tradecanvas/core').PanelRenderInfo[] | null = null;\r\n private renderScheduled = false;\r\n private containerSizeCache: { width: number; height: number } | null = null;\r\n private containerSizeCacheTime = 0;\r\n private chartLegend: ChartLegend;\r\n private watermark: Watermark;\r\n private barCountdown: BarCountdown;\r\n private sessionBreaks: SessionBreaks;\r\n private compareRenderer: CompareRenderer;\r\n private countdownInterval: ReturnType<typeof setInterval> | null = null;\r\n private volumeRenderer: VolumeRenderer;\r\n private alertManager: AlertManager;\r\n private signalMarkerManager: SignalMarkerManager;\r\n private tradeZoneManager: TradeZoneManager;\r\n private replayManager: ReplayManager;\r\n private undoRedoManager: UndoRedoManager;\r\n private autoSaveScheduler = new AutoSaveScheduler((key) => this.saveState(key));\r\n private animator: Animator;\r\n private crosshairTooltip: CrosshairTooltip;\r\n private interactionManager: InteractionManager;\r\n private crosshairHandler: CrosshairHandler;\r\n private chartRenderer: ChartRendererInterface;\r\n private gridRenderer: GridRenderer;\r\n private priceAxis: PriceAxis;\r\n private timeAxis: TimeAxis;\r\n private options: ChartOptions;\r\n private features: Required<FeaturesConfig>;\r\n private marketConfig: MarketConfig | null = null;\r\n private container: HTMLElement;\r\n private currentPriceLine: import('@tradecanvas/core').CurrentPriceLine;\r\n private numberLocale: string;\r\n private keyboardHandler: KeyboardHandler | null = null;\r\n private onWindowKeyDown: ((e: KeyboardEvent) => void) | null = null;\r\n private currentSymbol: string = '';\r\n\r\n\r\n constructor(container: HTMLElement, options: ChartOptions) {\r\n this.container = container;\r\n this.options = options;\r\n this.numberLocale = options.numberLocale ?? 'en-US';\r\n\r\n // Resolve feature flags (all default to true)\r\n const f = options.features ?? {};\r\n this.features = {\r\n drawings: f.drawings ?? true,\r\n drawingTools: f.drawingTools ?? [],\r\n drawingMagnet: f.drawingMagnet ?? true,\r\n drawingUndoRedo: f.drawingUndoRedo ?? true,\r\n trading: f.trading ?? true,\r\n tradingContextMenu: f.tradingContextMenu ?? true,\r\n indicators: f.indicators ?? true,\r\n indicatorIds: f.indicatorIds ?? [],\r\n panning: f.panning ?? true,\r\n zooming: f.zooming ?? true,\r\n crosshair: f.crosshair ?? true,\r\n keyboard: f.keyboard ?? true,\r\n priceAxis: f.priceAxis ?? true,\r\n timeAxis: f.timeAxis ?? true,\r\n grid: f.grid ?? (options.grid?.visible ?? true),\r\n legend: f.legend ?? true,\r\n volume: f.volume ?? true,\r\n watermark: f.watermark ?? true,\r\n saveLoad: f.saveLoad ?? true,\r\n screenshot: f.screenshot ?? true,\r\n alerts: f.alerts ?? true,\r\n replay: f.replay ?? true,\r\n sessionBreaks: f.sessionBreaks ?? true,\r\n barCountdown: f.barCountdown ?? true,\r\n compareSymbols: f.compareSymbols ?? true,\r\n dataExport: f.dataExport ?? true,\r\n logScale: f.logScale ?? true,\r\n timeframes: f.timeframes ?? [],\r\n defaultTimeframeFavorites: f.defaultTimeframeFavorites ?? [],\r\n };\r\n\r\n container.style.position = 'relative';\r\n container.style.overflow = 'hidden';\r\n container.tabIndex = 0; // Allow keyboard events\r\n container.style.outline = 'none';\r\n\r\n // Initialize managers\r\n this.dataManager = new DataManager();\r\n this.themeManager = new ThemeManager(options.theme);\r\n this.layoutManager = new LayoutManager();\r\n this.indicatorEngine = new IndicatorEngine();\r\n this.pluginManager = new PluginManager(this.indicatorEngine);\r\n this.eventBus = new EventBus();\r\n\r\n registerBuiltInIndicators(this.indicatorEngine);\r\n\r\n // Drawing tools\r\n this.drawingManager = new DrawingManager();\r\n registerBuiltInDrawingTools(this.drawingManager);\r\n this.drawingRenderer = new DrawingRenderer(this.drawingManager);\r\n this.drawingManager.setRequestRender(() => {\r\n // Sync entire render context so drawings render with same viewport as candles\r\n this.syncRenderContext();\r\n this.engine.requestRender(LayerType.Overlay);\r\n this.scheduleAutoSave();\r\n });\r\n this.drawingManager.setEventCallback((event, data) => {\r\n this.eventBus.emit(event as ChartEventType, data);\r\n });\r\n // Undo/redo\r\n this.undoRedoManager = new UndoRedoManager();\r\n this.drawingManager.setUndoRedoManager(this.undoRedoManager);\r\n this.drawingManager.setDataGetter(() => this.dataManager.getData());\r\n this.drawingManager.setDisplayDataGetter(() => this.getDisplayData());\r\n // Magnet mode\r\n if (options.crosshair?.mode === 'magnet') {\r\n this.drawingManager.setMagnetMode('magnet');\r\n }\r\n\r\n // Trading\r\n this.tradingManager = new TradingManager();\r\n this.tradingRenderer = new TradingRenderer(this.tradingManager);\r\n this.tradingManager.setContainer(container);\r\n this.tradingManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\r\n this.tradingManager.setEventCallback((event, data) => {\r\n this.eventBus.emit(event as ChartEventType, data);\r\n });\r\n\r\n // Rendering\r\n this.engine = new RenderEngine(container);\r\n const size = this.engine.dprManager.getContainerSize();\r\n this.viewport = new Viewport(\r\n size.width,\r\n size.height,\r\n options.minBarSpacing ?? 2,\r\n options.maxBarSpacing ?? 30,\r\n options.rightMargin ?? 5,\r\n );\r\n this.layoutManager.resize(size.width, size.height);\r\n\r\n // Sync viewport + layout when the container resizes. Without this hook\r\n // the chart's viewport keeps its construction-time chartRect forever\r\n // (which is wrong if the container started at 0 or got resized since),\r\n // and `scrollToEnd` / clampOffset compute against stale dimensions —\r\n // chart sticks at the wrong offset and the user can't scroll to the\r\n // latest bar.\r\n this.engine.onContainerResize = (newSize) => {\r\n if (newSize.width <= 0 || newSize.height <= 0) return;\r\n const wasAtEnd = this.viewport.isAtEnd();\r\n this.viewport.resize(newSize.width, newSize.height);\r\n this.layoutManager.resize(newSize.width, newSize.height);\r\n // wasAtEnd carries the user's intent: if they were tracking the live\r\n // edge before the resize, keep them there afterwards. Otherwise leave\r\n // their scroll position alone.\r\n this.updateViewportAndRender(wasAtEnd);\r\n };\r\n\r\n // Chart renderer\r\n this.chartRenderer = this.createChartRenderer(options.chartType);\r\n this.gridRenderer = new GridRenderer();\r\n if (options.grid?.visible === false) this.gridRenderer.setVisible(false);\r\n this.priceAxis = new PriceAxis();\r\n this.priceAxis.setLocale(this.numberLocale);\r\n this.timeAxis = new TimeAxis();\r\n\r\n // Crosshair\r\n this.crosshairHandler = new CrosshairHandler();\r\n this.crosshairHandler.setLocale(this.numberLocale);\r\n if (options.crosshair?.mode) {\r\n this.crosshairHandler.setMode(options.crosshair.mode);\r\n }\r\n // Crosshair callback — fired via microtask AFTER render, only when bar changes.\r\n // No DOM writes, no layout reads, no extra render requests.\r\n this.crosshairHandler.setCallback((barIndex, point) => {\r\n if (barIndex !== null && point) {\r\n const data = this.dataManager.getData();\r\n const bar = barIndex < data.length ? data[barIndex] : undefined;\r\n\r\n // Update legend (canvas-rendered, will show on next UI paint)\r\n this.chartLegend.setHoverBar(bar ?? null);\r\n\r\n // Update tooltip (DOM, lightweight update only when bar changes)\r\n if (bar) {\r\n this.crosshairTooltip.show(point, bar, this.themeManager.getTheme(), this.cachedContainerSize());\r\n }\r\n\r\n // Emit for external consumers\r\n this.eventBus.emit('crosshairMove', { point, bar, barIndex });\r\n } else {\r\n this.crosshairTooltip.hide();\r\n this.chartLegend.setHoverBar(null);\r\n }\r\n });\r\n\r\n // Chart legend (OHLCV overlay)\r\n this.chartLegend = new ChartLegend();\r\n this.chartLegend.setChartType(options.chartType);\r\n\r\n // Watermark + Volume\r\n this.watermark = new Watermark();\r\n if (options.watermark) this.watermark.setConfig(options.watermark);\r\n this.volumeRenderer = new VolumeRenderer();\r\n\r\n // Bar countdown timer\r\n this.barCountdown = new BarCountdown();\r\n this.sessionBreaks = new SessionBreaks();\r\n this.compareRenderer = new CompareRenderer();\r\n\r\n // Apply session break config from options\r\n if (options.sessionBreaks) {\r\n this.sessionBreaks.setConfig({\r\n visible: options.sessionBreaks.visible ?? true,\r\n color: options.sessionBreaks.color,\r\n lineStyle: options.sessionBreaks.lineStyle,\r\n lineWidth: options.sessionBreaks.lineWidth,\r\n });\r\n } else if (options.features?.sessionBreaks !== false) {\r\n this.sessionBreaks.setVisible(true);\r\n }\r\n\r\n // Apply log scale from options\r\n if (options.logScale) {\r\n this.viewport.setLogScale(true);\r\n }\r\n\r\n // Animation\r\n this.animator = new Animator();\r\n\r\n // Crosshair tooltip (DOM)\r\n this.crosshairTooltip = new CrosshairTooltip();\r\n this.crosshairTooltip.create(container);\r\n\r\n // Keyboard navigation\r\n this.keyboardHandler = new KeyboardHandler({\r\n scrollBars: (count) => {\r\n const barUnit = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;\r\n this.viewport.scrollBy(count * barUnit);\r\n this.updateViewportAndRender();\r\n },\r\n zoom: (delta) => {\r\n const chartWidth = this.viewport.getState().chartRect.width;\r\n this.viewport.zoom(delta, chartWidth / 2);\r\n this.updateViewportAndRender();\r\n },\r\n goToStart: () => {\r\n this.viewport.scrollBy(-Infinity);\r\n this.updateViewportAndRender();\r\n },\r\n goToEnd: () => {\r\n this.viewport.scrollToEnd();\r\n this.updateViewportAndRender();\r\n },\r\n fitContent: () => this.fitContent(),\r\n });\r\n this.keyboardHandler.setEnabled(this.features.keyboard);\r\n\r\n // Attach keyboard listener to window. Only consume the event when the\r\n // chart actually handles the key AND the container is the focused element\r\n // (or an ancestor) — this prevents the chart from swallowing keystrokes\r\n // intended for inputs elsewhere on the page.\r\n this.onWindowKeyDown = (e: KeyboardEvent) => {\r\n if (!this.keyboardHandler) return;\r\n const active = document.activeElement as HTMLElement | null;\r\n if (active && active !== this.container && !this.container.contains(active)) {\r\n return;\r\n }\r\n // Ignore when typing in a form field that happens to live inside the chart.\r\n if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable)) {\r\n return;\r\n }\r\n if (this.keyboardHandler.handleKey(e)) {\r\n e.preventDefault();\r\n }\r\n };\r\n window.addEventListener('keydown', this.onWindowKeyDown);\r\n\r\n // Current price line (standalone, works without StreamManager)\r\n this.currentPriceLine = new CurrentPriceLine();\r\n\r\n // Alerts\r\n this.alertManager = new AlertManager();\r\n this.alertManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\r\n this.alertManager.on('triggered', (alert) => {\r\n this.eventBus.emit('dataUpdate', { alert: 'triggered', alertId: alert.id, price: alert.price, message: alert.message });\r\n });\r\n\r\n // Signal markers\r\n this.signalMarkerManager = new SignalMarkerManager();\r\n this.signalMarkerManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\r\n this.signalMarkerManager.setDataGetter(() => this.dataManager.getData());\r\n this.signalMarkerManager.on('added', (m) => {\r\n this.eventBus.emit('signalMarkerAdd' as ChartEventType, { id: m.id, source: m.source, direction: m.direction });\r\n });\r\n this.signalMarkerManager.on('removed', (id) => {\r\n this.eventBus.emit('signalMarkerRemove' as ChartEventType, { id });\r\n });\r\n\r\n // Trade zones\r\n this.tradeZoneManager = new TradeZoneManager();\r\n this.tradeZoneManager.setRequestRender(() => this.engine.requestRender(LayerType.Overlay));\r\n this.tradeZoneManager.setDataGetter(() => this.dataManager.getData());\r\n this.tradeZoneManager.on('added', (z) => {\r\n this.eventBus.emit('tradeZoneAdd' as ChartEventType, { id: z.id, direction: z.direction });\r\n });\r\n this.tradeZoneManager.on('removed', (id) => {\r\n this.eventBus.emit('tradeZoneRemove' as ChartEventType, { id });\r\n });\r\n\r\n // Replay\r\n this.replayManager = new ReplayManager();\r\n\r\n // Interaction\r\n this.interactionManager = new InteractionManager(container);\r\n if (this.features.panning) {\r\n this.interactionManager.setPanHandler(\r\n new PanHandler((deltaX) => {\r\n this.viewport.scrollBy(deltaX);\r\n this.updateViewportAndRender();\r\n }),\r\n );\r\n }\r\n if (this.features.zooming) {\r\n this.interactionManager.setZoomHandler(\r\n new ZoomHandler((delta, centerX) => {\r\n this.viewport.zoom(delta, centerX);\r\n this.updateViewportAndRender();\r\n }),\r\n );\r\n }\r\n if (this.features.crosshair) {\r\n this.interactionManager.setCrosshairHandler(this.crosshairHandler);\r\n }\r\n if (this.features.drawings) {\r\n this.interactionManager.setDrawingManager(\r\n this.drawingManager,\r\n // Inject current data so drawing anchors are stored/resolved as real\r\n // timestamps (survives timeframe/symbol switches).\r\n () => ({ ...this.viewport.getState(), data: this.getDisplayData() }),\r\n );\r\n }\r\n if (this.features.trading) {\r\n this.interactionManager.setTradingManager(\r\n this.tradingManager,\r\n () => ({ ...this.viewport.getState(), data: this.getDisplayData() }),\r\n );\r\n }\r\n this.interactionManager.setOverlayDirtyCallback(() => {\r\n this.engine.requestRender(LayerType.Overlay);\r\n // Also refresh UI layer for panel crosshair value labels\r\n if (this.layoutManager.getPanels().length > 0) {\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n });\r\n this.interactionManager.attach();\r\n\r\n // Set render context\r\n this.syncRenderContext();\r\n this.engine.start();\r\n }\r\n\r\n // --- Data ---\r\n\r\n setData(data: DataSeries): void {\r\n this.dataManager.setData(data);\r\n this.crosshairHandler.setData(this.dataManager.getData());\r\n this.displayDataCache = null;\r\n this.sessionBreaks.invalidateCache();\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n // Auto-set current price line from last bar's close\r\n if (data.length > 0) {\r\n this.currentPriceLine.setPrice(data[data.length - 1].close);\r\n }\r\n this.updateViewportAndRender(true);\r\n this.eventBus.emit('dataUpdate', { length: data.length });\r\n }\r\n\r\n appendBar(bar: OHLCBar): void {\r\n this.dataManager.appendBar(bar);\r\n this.crosshairHandler.setData(this.dataManager.getData());\r\n this.displayDataCache = null;\r\n if (this.autoScrollOnNewBar) this.viewport.scrollToEnd();\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.updateViewportAndRender();\r\n }\r\n\r\n /**\r\n * Append multiple bars at once (e.g., catch-up after reconnect).\r\n * More efficient than calling appendBar() in a loop — recalculates\r\n * indicators only once at the end.\r\n */\r\n appendBars(bars: OHLCBar[]): void {\r\n if (bars.length === 0) return;\r\n for (const bar of bars) {\r\n this.dataManager.appendBar(bar);\r\n }\r\n this.displayDataCache = null;\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.crosshairHandler.setData(this.dataManager.getData());\r\n this.updateViewportAndRender(this.viewport.isAtEnd());\r\n }\r\n\r\n updateLastBar(bar: OHLCBar): void {\r\n this.dataManager.updateLastBar(bar);\r\n this.currentPriceLine.setPrice(bar.close);\r\n // For non-transform chart types, the displayDataCache still points to the\r\n // same raw array (mutated in place), so no need to invalidate.\r\n // Only invalidate for transform types that produce derived arrays.\r\n if (this.options.chartType !== 'candlestick' && this.options.chartType !== 'line'\r\n && this.options.chartType !== 'area' && this.options.chartType !== 'bar'\r\n && this.options.chartType !== 'hollowCandle') {\r\n this.displayDataCache = null;\r\n }\r\n // Keep indicator lines in sync with the forming bar. Without this, panel\r\n // + overlay indicators freeze until bar close.\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.scheduleRender();\r\n }\r\n\r\n /** Merge a price tick into the current last bar (convenience for live feeds) */\r\n updateLastBarFromTick(tick: { price: number; volume?: number; time: number }): void {\r\n this.dataManager.updateLastBarFromTick(tick);\r\n this.currentPriceLine.setPrice(tick.price);\r\n if (this.options.chartType !== 'candlestick' && this.options.chartType !== 'line'\r\n && this.options.chartType !== 'area' && this.options.chartType !== 'bar'\r\n && this.options.chartType !== 'hollowCandle') {\r\n this.displayDataCache = null;\r\n }\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.scheduleRender();\r\n }\r\n\r\n // --- Chart type ---\r\n\r\n setChartType(type: ChartType): void {\r\n this.options.chartType = type;\r\n this.chartRenderer = this.createChartRenderer(type);\r\n this.chartLegend.setChartType(type);\r\n this.displayDataCache = null;\r\n this.updateViewportAndRender(true);\r\n }\r\n\r\n // --- Indicators ---\r\n\r\n addIndicator(id: string, params: Record<string, number | string | boolean> = {}, position: PanelPosition = 'bottom'): string | null {\r\n if (!this.features.indicators) return null;\r\n if (this.features.indicatorIds.length > 0 && !this.features.indicatorIds.includes(id)) return null;\r\n const instanceId = this.indicatorEngine.addIndicator(id, params, this.dataManager.getData());\r\n const descriptor = this.indicatorEngine.getAvailableIndicators().find((d) => d.id === id);\r\n if (descriptor?.placement === 'panel') {\r\n this.layoutManager.addPanel(instanceId, position);\r\n // Panel layout changed — must re-resolve layout, update viewport, and sync render context\r\n this.updateViewportAndRender();\r\n } else {\r\n this.engine.requestRender();\r\n }\r\n this.eventBus.emit('indicatorAdd', { instanceId, id });\r\n return instanceId;\r\n }\r\n\r\n updateIndicator(instanceId: string, params: Record<string, number | string | boolean>): void {\r\n this.indicatorEngine.updateIndicator(instanceId, params, this.dataManager.getData());\r\n this.engine.requestRender();\r\n }\r\n\r\n removeIndicator(instanceId: string): void {\r\n const hadPanel = this.layoutManager.getPanels().some(p => p.id === instanceId);\r\n this.indicatorEngine.removeIndicator(instanceId);\r\n this.layoutManager.removePanel(instanceId);\r\n this.eventBus.emit('indicatorRemove', { instanceId });\r\n if (hadPanel) {\r\n this.updateViewportAndRender();\r\n } else {\r\n this.engine.requestRender();\r\n }\r\n }\r\n\r\n getIndicatorOutput(instanceId: string): IndicatorOutput | null {\r\n return this.indicatorEngine.getOutput(instanceId);\r\n }\r\n\r\n registerIndicator(plugin: IndicatorPlugin): void {\r\n this.pluginManager.registerIndicator(plugin);\r\n }\r\n\r\n static indicators(): IndicatorDescriptor[] {\r\n const engine = new IndicatorEngine();\r\n registerBuiltInIndicators(engine);\r\n return engine.getAvailableIndicators();\r\n }\r\n\r\n // --- Panel layout ---\r\n\r\n setPanelPosition(instanceId: string, position: PanelPosition): void {\r\n this.layoutManager.setPanelPosition(instanceId, position);\r\n this.engine.requestRender();\r\n }\r\n\r\n setPanelSize(instanceId: string, size: number): void {\r\n this.layoutManager.setPanelSize(instanceId, size);\r\n this.engine.requestRender();\r\n }\r\n\r\n // --- Drawing tools ---\r\n\r\n setDrawingTool(type: DrawingToolType | null): void {\r\n if (!this.features.drawings) return;\r\n // If whitelist is set, check it\r\n if (type && this.features.drawingTools.length > 0 && !this.features.drawingTools.includes(type)) return;\r\n this.drawingManager.setActiveTool(type);\r\n }\r\n\r\n getDrawingTool(): DrawingToolType | null {\r\n return this.drawingManager.getActiveTool();\r\n }\r\n\r\n setDrawingStyle(style: Partial<DrawingStyle>): void {\r\n this.drawingManager.setStyle(style);\r\n }\r\n\r\n getDrawings(): DrawingState[] {\r\n return this.drawingManager.getDrawings();\r\n }\r\n\r\n setDrawings(drawings: DrawingState[]): void {\r\n this.drawingManager.setDrawings(drawings);\r\n }\r\n\r\n removeDrawing(id: string): void {\r\n this.drawingManager.removeDrawing(id);\r\n }\r\n\r\n clearDrawings(): void {\r\n this.drawingManager.clearDrawings();\r\n }\r\n\r\n registerDrawingTool(plugin: DrawingPlugin): void {\r\n this.drawingManager.register(plugin);\r\n }\r\n\r\n // --- Undo/Redo ---\r\n\r\n undo(): boolean {\r\n if (!this.features.drawingUndoRedo) return false;\r\n return this.drawingManager.undo();\r\n }\r\n\r\n redo(): boolean {\r\n if (!this.features.drawingUndoRedo) return false;\r\n return this.drawingManager.redo();\r\n }\r\n\r\n getUndoRedoState(): { canUndo: boolean; canRedo: boolean } {\r\n return this.undoRedoManager.getState();\r\n }\r\n\r\n // --- Drawing magnet ---\r\n\r\n setDrawingMagnet(enabled: boolean): void {\r\n this.drawingManager.setMagnetMode(enabled ? 'magnet' : 'none');\r\n }\r\n\r\n getDrawingMagnet(): boolean {\r\n return this.drawingManager.getMagnetMode() === 'magnet';\r\n }\r\n\r\n // --- Bulk drawing operations ---\r\n\r\n lockAllDrawings(): void {\r\n this.drawingManager.lockAllDrawings();\r\n }\r\n\r\n unlockAllDrawings(): void {\r\n this.drawingManager.unlockAllDrawings();\r\n }\r\n\r\n hideAllDrawings(): void {\r\n this.drawingManager.hideAllDrawings();\r\n }\r\n\r\n showAllDrawings(): void {\r\n this.drawingManager.showAllDrawings();\r\n }\r\n\r\n // --- Drawing duplication ---\r\n\r\n duplicateDrawing(id?: string): string | null {\r\n const targetId = id ?? this.drawingManager.getSelectedDrawingId();\r\n if (!targetId) return null;\r\n return this.drawingManager.duplicateDrawing(targetId);\r\n }\r\n\r\n // --- Data export ---\r\n\r\n exportVisibleData(format: 'csv' | 'json' = 'csv', filename?: string): void {\r\n const vp = this.viewport.getState();\r\n const data = this.dataManager.getData();\r\n const from = Math.max(0, vp.visibleRange.from);\r\n const to = Math.min(data.length - 1, vp.visibleRange.to);\r\n const slice = data.slice(from, to + 1);\r\n\r\n if (format === 'json') {\r\n const content = DataExporter.toJSON(slice);\r\n DataExporter.download(content, filename ?? 'chart-data.json', 'application/json');\r\n } else {\r\n const content = DataExporter.toCSV(slice);\r\n DataExporter.download(content, filename ?? 'chart-data.csv', 'text/csv');\r\n }\r\n }\r\n\r\n exportAllData(format: 'csv' | 'json' = 'csv', filename?: string): void {\r\n const data = this.dataManager.getData();\r\n if (format === 'json') {\r\n const content = DataExporter.toJSON(data);\r\n DataExporter.download(content, filename ?? 'chart-data.json', 'application/json');\r\n } else {\r\n const content = DataExporter.toCSV(data);\r\n DataExporter.download(content, filename ?? 'chart-data.csv', 'text/csv');\r\n }\r\n }\r\n\r\n // --- Auto-save ---\r\n\r\n setAutoSave(key: string, delayMs = 5000): void {\r\n this.autoSaveScheduler.enable(key, delayMs);\r\n }\r\n\r\n disableAutoSave(): void {\r\n this.autoSaveScheduler.disable();\r\n }\r\n\r\n private scheduleAutoSave(): void {\r\n this.autoSaveScheduler.schedule();\r\n }\r\n\r\n // --- Indicator introspection ---\r\n\r\n getAvailableIndicators(): IndicatorDescriptor[] {\r\n return this.indicatorEngine.getAvailableIndicators();\r\n }\r\n\r\n getIndicatorInputs(id: string): { id: string; params: Record<string, unknown> } | null {\r\n const indicators = this.indicatorEngine.getAvailableIndicators();\r\n const desc = indicators.find(i => i.id === id);\r\n if (!desc) return null;\r\n return { id: desc.id, params: desc.defaultConfig };\r\n }\r\n\r\n /** Get all active indicator instances with their current params */\r\n getActiveIndicators(): { instanceId: string; id: string; params: Record<string, unknown>; descriptor: IndicatorDescriptor }[] {\r\n return this.indicatorEngine.getActiveIndicators();\r\n }\r\n\r\n /** Get current config for a specific indicator instance */\r\n getIndicatorConfig(instanceId: string): { id: string; params: Record<string, unknown> } | null {\r\n const config = this.indicatorEngine.getIndicatorConfig(instanceId);\r\n if (!config) return null;\r\n return { id: config.id, params: { ...config.params } };\r\n }\r\n\r\n /** Update indicator colors/line widths at runtime */\r\n updateIndicatorStyle(instanceId: string, style: { colors?: string[]; lineWidths?: number[]; opacity?: number }): void {\r\n this.indicatorEngine.updateIndicatorStyle(instanceId, style);\r\n this.engine.requestRender();\r\n }\r\n\r\n // --- Trading ---\r\n\r\n setOrders(orders: TradingOrder[]): void {\r\n if (!this.features.trading) return;\r\n this.tradingManager.setOrders(orders);\r\n }\r\n\r\n setPositions(positions: TradingPosition[]): void {\r\n if (!this.features.trading) return;\r\n this.tradingManager.setPositions(positions);\r\n }\r\n\r\n setDepthData(depth: DepthData | null): void {\r\n if (!this.features.trading) return;\r\n this.tradingManager.setDepthData(depth);\r\n }\r\n\r\n setCurrentPrice(price: number, _pulseColor?: string): void {\r\n this.tradingManager.setCurrentPrice(price);\r\n // Also update standalone price line (visible even without trading feature)\r\n this.currentPriceLine.setPrice(price);\r\n this.scheduleRender();\r\n if (this.features.alerts) this.alertManager.checkPrice(price);\r\n }\r\n\r\n setTradingConfig(config: Partial<TradingConfig>): void {\r\n if (!this.features.trading) return;\r\n this.tradingManager.setConfig(config);\r\n }\r\n\r\n // --- Real-time Streaming ---\r\n\r\n /**\r\n * Connect to a real-time data source.\r\n * Loads history, starts streaming, manages reconnection automatically.\r\n *\r\n * @example\r\n * import { BinanceAdapter } from '@tradecanvas/core';\r\n * chart.connect({\r\n * adapter: new BinanceAdapter(),\r\n * symbol: 'BTCUSDT',\r\n * timeframe: '1m',\r\n * });\r\n */\r\n async connect(config: StreamConfig): Promise<void> {\r\n this.disconnectStream();\r\n\r\n this.streamManager = new StreamManager();\r\n\r\n this.streamManager.on('snapshot', (bars) => {\r\n this.setData(bars);\r\n });\r\n\r\n this.streamManager.on('barClose', (bar) => {\r\n this.dataManager.appendBar(bar);\r\n this.crosshairHandler.setData(this.dataManager.getData());\r\n if (this.autoScrollOnNewBar) this.viewport.scrollToEnd();\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.updateViewportAndRender();\r\n });\r\n\r\n this.streamManager.on('barUpdate', (bar) => {\r\n this.dataManager.updateLastBar(bar);\r\n this.currentPriceLine.setPrice(bar.close);\r\n // Recalculate indicators so panel/overlay series track the forming bar\r\n // instead of freezing until bar close.\r\n this.indicatorEngine.recalculateAll(this.dataManager.getData());\r\n this.scheduleRender();\r\n });\r\n\r\n this.streamManager.on('priceChange', ({ price }) => {\r\n this.tradingManager.setCurrentPrice(price);\r\n this.currentPriceLine.setPrice(price);\r\n this.engine.requestRender(LayerType.Overlay);\r\n this.engine.requestRender(LayerType.UI);\r\n });\r\n\r\n this.streamManager.on('connectionChange', (info) => {\r\n this.eventBus.emit('dataUpdate', { connection: info });\r\n });\r\n\r\n this.streamManager.on('error', (err) => {\r\n this.eventBus.emit('dataUpdate', { error: err.message });\r\n });\r\n\r\n this.autoScrollOnNewBar = config.autoScroll !== false;\r\n this.currentSymbol = config.symbol;\r\n\r\n await this.streamManager.connect(config);\r\n\r\n // Set up bar countdown timer based on timeframe\r\n const tfMs = timeframeToMs(config.timeframe);\r\n this.barCountdown.setTimeframeMs(tfMs);\r\n\r\n // Start countdown refresh interval\r\n if (this.countdownInterval) clearInterval(this.countdownInterval);\r\n this.countdownInterval = setInterval(() => {\r\n if (this.barCountdown.isVisible()) {\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n }, 1000);\r\n }\r\n\r\n /**\r\n * Switch symbol or timeframe on an active stream without full reconnect.\r\n */\r\n async switchStream(symbol: string, timeframe: TimeFrame): Promise<void> {\r\n if (!this.streamManager) return;\r\n this.currentSymbol = symbol;\r\n await this.streamManager.switchTo(symbol, timeframe);\r\n }\r\n\r\n /**\r\n * Switch to a new timeframe. Requires an active stream connection.\r\n * Internally calls switchStream with the current symbol.\r\n */\r\n async setTimeframe(timeframe: TimeFrame): Promise<void> {\r\n if (!this.streamManager) throw new Error('No active stream. Call connect() first.');\r\n await this.switchStream(this.currentSymbol, timeframe);\r\n }\r\n\r\n /**\r\n * Disconnect the real-time stream.\r\n */\r\n disconnectStream(): void {\r\n if (this.streamManager) {\r\n this.streamManager.dispose();\r\n this.streamManager = null;\r\n }\r\n }\r\n\r\n setBarCountdownVisible(visible: boolean): void {\r\n this.barCountdown.setVisible(visible);\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n\r\n setSessionBreaksVisible(visible: boolean): void {\r\n this.sessionBreaks.setVisible(visible);\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n\r\n // --- Compare symbols ---\r\n\r\n addCompareSymbol(id: string, label: string, data: DataSeries, color: string): void {\r\n this.compareRenderer.addSymbol({ id, label, data, color, visible: true });\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n removeCompareSymbol(id: string): void {\r\n this.compareRenderer.removeSymbol(id);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n updateCompareData(id: string, data: DataSeries): void {\r\n this.compareRenderer.setSymbolData(id, data);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n setCompareMode(mode: 'percent' | 'absolute'): void {\r\n this.compareRenderer.setMode(mode);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n clearCompareSymbols(): void {\r\n this.compareRenderer.clear();\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n // --- Log scale ---\r\n\r\n setLogScale(enabled: boolean): void {\r\n this.viewport.setLogScale(enabled);\r\n this.updateViewportAndRender();\r\n }\r\n\r\n isLogScale(): boolean {\r\n return this.viewport.isLogScale();\r\n }\r\n\r\n setSessionBreaksConfig(config: { color?: string; lineStyle?: 'solid' | 'dashed' | 'dotted'; lineWidth?: number }): void {\r\n this.sessionBreaks.setConfig(config);\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n\r\n getConnectionState(): ConnectionState {\r\n return this.streamManager?.getConnectionState() ?? 'disconnected';\r\n }\r\n\r\n getConnectionInfo(): ConnectionInfo {\r\n return this.streamManager?.getConnectionInfo() ?? { state: 'disconnected' };\r\n }\r\n\r\n setAutoScroll(enabled: boolean): void {\r\n this.autoScrollOnNewBar = enabled;\r\n }\r\n\r\n // --- Viewport ---\r\n\r\n scrollTo(timestamp: number): void {\r\n const data = this.dataManager.getData();\r\n for (let i = 0; i < data.length; i++) {\r\n if (data[i].time >= timestamp) {\r\n const barUnit = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;\r\n this.viewport.scrollBy(i * barUnit - this.viewport.getState().offset);\r\n this.updateViewportAndRender();\r\n return;\r\n }\r\n }\r\n }\r\n\r\n scrollToEnd(): void {\r\n this.viewport.scrollToEnd();\r\n this.updateViewportAndRender();\r\n }\r\n\r\n setVisibleRange(fromTimestamp: number, toTimestamp: number): void {\r\n const data = this.dataManager.getData();\r\n let fromIdx = 0;\r\n let toIdx = data.length - 1;\r\n for (let i = 0; i < data.length; i++) {\r\n if (data[i].time >= fromTimestamp) { fromIdx = i; break; }\r\n }\r\n for (let i = data.length - 1; i >= 0; i--) {\r\n if (data[i].time <= toTimestamp) { toIdx = i; break; }\r\n }\r\n const barCount = toIdx - fromIdx + 1;\r\n if (barCount > 0) {\r\n const chartWidth = this.viewport.getState().chartRect.width;\r\n const targetBarUnit = chartWidth / barCount;\r\n const newBarWidth = Math.max(2, targetBarUnit - this.viewport.getState().barSpacing);\r\n this.viewport.zoom(\r\n (newBarWidth - this.viewport.getState().barWidth) / this.viewport.getState().barWidth,\r\n chartWidth / 2,\r\n );\r\n }\r\n this.updateViewportAndRender();\r\n }\r\n\r\n zoomIn(): void {\r\n const chartWidth = this.viewport.getState().chartRect.width;\r\n this.viewport.zoom(0.2, chartWidth / 2);\r\n this.updateViewportAndRender();\r\n }\r\n\r\n zoomOut(): void {\r\n const chartWidth = this.viewport.getState().chartRect.width;\r\n this.viewport.zoom(-0.2, chartWidth / 2);\r\n this.updateViewportAndRender();\r\n }\r\n\r\n fitContent(): void {\r\n const data = this.dataManager.getData();\r\n if (data.length === 0) return;\r\n this.setVisibleRange(data[0].time, data[data.length - 1].time);\r\n }\r\n\r\n // --- Events ---\r\n\r\n on<K extends ChartEventType>(type: K, handler: (event: ChartEvent<K extends keyof ChartEventMap ? ChartEventMap[K] : unknown>) => void): void {\r\n this.eventBus.on(type, handler as (event: ChartEvent) => void);\r\n }\r\n\r\n off<K extends ChartEventType>(type: K, handler: (event: ChartEvent<K extends keyof ChartEventMap ? ChartEventMap[K] : unknown>) => void): void {\r\n this.eventBus.off(type, handler as (event: ChartEvent) => void);\r\n }\r\n\r\n enableTauriBridge(options?: Partial<TauriBridgeOptions>): void {\r\n this.eventBus.enableTauriBridge({ enabled: true, ...options });\r\n }\r\n\r\n disableTauriBridge(): void {\r\n this.eventBus.disableTauriBridge();\r\n }\r\n\r\n // --- Theme ---\r\n\r\n setTheme(themeOrName: ThemeName | Theme): void {\r\n this.themeManager.setTheme(themeOrName);\r\n this.syncRenderContext();\r\n this.container.style.backgroundColor = this.themeManager.getTheme().background;\r\n this.engine.requestRender();\r\n this.eventBus.emit('themeChange', { theme: themeOrName });\r\n }\r\n\r\n getTheme(): Theme {\r\n return this.themeManager.getTheme();\r\n }\r\n\r\n // --- Watermark ---\r\n\r\n setWatermark(text: string, opts?: { color?: string; fontSize?: number }): void {\r\n this.watermark.setConfig({ text, ...opts });\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n\r\n // --- Auto Scale ---\r\n\r\n setAutoScale(enabled: boolean): void {\r\n this.options.autoScale = enabled;\r\n this.updateViewportAndRender();\r\n }\r\n\r\n isAutoScale(): boolean {\r\n return this.options.autoScale !== false;\r\n }\r\n\r\n // --- Crosshair ---\r\n\r\n setCrosshairMode(mode: 'normal' | 'magnet' | 'hidden'): void {\r\n this.crosshairHandler.setMode(mode);\r\n this.engine.requestRender(LayerType.Overlay);\r\n }\r\n\r\n getCrosshairMode(): string {\r\n return this.crosshairHandler.getMode();\r\n }\r\n\r\n setCrosshairPosition(point: { x: number; y: number } | null): void {\r\n if (point) {\r\n this.crosshairHandler.onPointerMove(point);\r\n }\r\n this.engine.requestRender(LayerType.Overlay);\r\n }\r\n\r\n getData(): DataSeries {\r\n return this.dataManager.getData();\r\n }\r\n\r\n // --- Grid ---\r\n\r\n setGridVisible(visible: boolean): void {\r\n this.gridRenderer.setVisible(visible);\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n\r\n isGridVisible(): boolean {\r\n return this.gridRenderer.isVisible();\r\n }\r\n\r\n // --- Volume ---\r\n\r\n setVolumeVisible(visible: boolean): void {\r\n this.volumeRenderer.setVisible(visible);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n\r\n // --- Tooltip ---\r\n\r\n setTooltipVisible(visible: boolean): void {\r\n if (!visible) this.crosshairTooltip.hide();\r\n }\r\n\r\n // --- Legend ---\r\n\r\n setLegend(config: Partial<import('@tradecanvas/core').LegendConfig>): void {\r\n this.chartLegend.setConfig(config);\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n\r\n setSymbolName(symbol: string): void {\r\n this.chartLegend.setSymbol(symbol);\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n\r\n /**\r\n * Set a status text displayed in the chart legend area (e.g., \"LIVE . 8ms\").\r\n * Pass null to clear.\r\n */\r\n setStatusText(text: string | null): void {\r\n this.chartLegend.setStatusText(text);\r\n this.engine.requestRender(LayerType.UI);\r\n }\r\n\r\n // --- Screenshot ---\r\n\r\n screenshot(filename?: string): void {\r\n if (!this.features.screenshot) return;\r\n Screenshot.download(this.container, filename, this.themeManager.getTheme().background);\r\n }\r\n\r\n screenshotDataURL(): string | null {\r\n if (!this.features.screenshot) return null;\r\n return Screenshot.toDataURL(this.container, this.themeManager.getTheme().background);\r\n }\r\n\r\n async screenshotBlob(): Promise<Blob | null> {\r\n if (!this.features.screenshot) return null;\r\n return Screenshot.toBlob(this.container, this.themeManager.getTheme().background);\r\n }\r\n\r\n // --- Alerts ---\r\n\r\n addAlert(price: number, condition: import('@tradecanvas/core').AlertCondition = 'crossing', message?: string): string | null {\r\n if (!this.features.alerts) return null;\r\n const id = this.alertManager.addAlert(price, condition, message);\r\n this.scheduleAutoSave();\r\n return id;\r\n }\r\n\r\n removeAlert(id: string): void {\r\n this.alertManager.removeAlert(id);\r\n this.scheduleAutoSave();\r\n }\r\n\r\n getAlerts(): import('@tradecanvas/core').PriceAlert[] {\r\n return this.alertManager.getAlerts();\r\n }\r\n\r\n clearAlerts(): void {\r\n this.alertManager.clearAlerts();\r\n this.scheduleAutoSave();\r\n }\r\n\r\n saveAlerts(key: string): void {\r\n this.alertManager.saveToStorage(key);\r\n }\r\n\r\n loadAlerts(key: string): void {\r\n this.alertManager.loadFromStorage(key);\r\n this.engine.requestRender(LayerType.Overlay);\r\n }\r\n\r\n // --- Signal Markers ---\r\n\r\n addSignalMarker(marker: Omit<import('@tradecanvas/commons').SignalMarker, 'id'> & { id?: string }): string {\r\n return this.signalMarkerManager.addMarker(marker);\r\n }\r\n\r\n removeSignalMarker(id: string): void {\r\n this.signalMarkerManager.removeMarker(id);\r\n }\r\n\r\n getSignalMarkers(): import('@tradecanvas/commons').SignalMarker[] {\r\n return this.signalMarkerManager.getMarkers();\r\n }\r\n\r\n setSignalMarkers(markers: import('@tradecanvas/commons').SignalMarker[]): void {\r\n this.signalMarkerManager.setMarkers(markers);\r\n }\r\n\r\n clearSignalMarkers(): void {\r\n this.signalMarkerManager.clearMarkers();\r\n }\r\n\r\n setSignalMarkerStyle(style: Partial<import('@tradecanvas/commons').SignalMarkerStyle>): void {\r\n this.signalMarkerManager.setStyle(style);\r\n }\r\n\r\n // --- Trade Zones ---\r\n\r\n addTradeZone(zone: Omit<import('@tradecanvas/commons').TradeZone, 'id'> & { id?: string }): string {\r\n return this.tradeZoneManager.addZone(zone);\r\n }\r\n\r\n updateTradeZone(id: string, updates: Partial<Omit<import('@tradecanvas/commons').TradeZone, 'id'>>): void {\r\n this.tradeZoneManager.updateZone(id, updates);\r\n }\r\n\r\n removeTradeZone(id: string): void {\r\n this.tradeZoneManager.removeZone(id);\r\n }\r\n\r\n getTradeZones(): import('@tradecanvas/commons').TradeZone[] {\r\n return this.tradeZoneManager.getZones();\r\n }\r\n\r\n setTradeZones(zones: import('@tradecanvas/commons').TradeZone[]): void {\r\n this.tradeZoneManager.setZones(zones);\r\n }\r\n\r\n clearTradeZones(): void {\r\n this.tradeZoneManager.clearZones();\r\n }\r\n\r\n setTradeZoneStyle(style: Partial<import('@tradecanvas/commons').TradeZoneStyle>): void {\r\n this.tradeZoneManager.setStyle(style);\r\n }\r\n\r\n // --- Replay ---\r\n\r\n replay(config?: Partial<import('@tradecanvas/core').ReplayConfig>): void {\r\n if (!this.features.replay) return;\r\n const data = this.dataManager.getData();\r\n this.replayManager.load(data);\r\n this.replayManager.on('bar', ({ bar: _bar, index }) => {\r\n const slice = data.slice(0, index + 1);\r\n this.dataManager.setData(slice);\r\n this.crosshairHandler.setData(slice);\r\n this.indicatorEngine.recalculateAll(slice);\r\n this.updateViewportAndRender();\r\n });\r\n this.replayManager.play(config);\r\n }\r\n\r\n replayPause(): void { this.replayManager.pause(); }\r\n replayResume(): void { this.replayManager.resume(); }\r\n replayStop(): void { this.replayManager.stop(); }\r\n replaySeek(index: number): void { this.replayManager.seekTo(index); }\r\n setReplaySpeed(speed: number): void { this.replayManager.setSpeed(speed); }\r\n getReplayState(): 'playing' | 'paused' | 'stopped' { return this.replayManager.getState(); }\r\n getReplayProgress(): { current: number; total: number; percent: number } { return this.replayManager.getProgress(); }\r\n\r\n // --- Save / Load ---\r\n\r\n saveState(key?: string): string | null {\r\n if (!this.features.saveLoad) return null;\r\n const snapshot = ChartStateManager.capture(\r\n {\r\n getDrawings: () => this.getDrawings(),\r\n getTheme: () => this.getTheme(),\r\n getAlerts: () => this.getAlerts(),\r\n },\r\n { chartType: this.options.chartType },\r\n );\r\n const json = ChartStateManager.serialize(snapshot);\r\n if (key) ChartStateManager.saveToStorage(key, snapshot);\r\n return json;\r\n }\r\n\r\n loadState(json: string): void {\r\n if (!this.features.saveLoad) return;\r\n const snapshot = ChartStateManager.deserialize(json);\r\n if (snapshot.chartType) this.setChartType(snapshot.chartType);\r\n if (snapshot.drawings) this.setDrawings(snapshot.drawings);\r\n if (snapshot.theme) this.setTheme(snapshot.theme as any);\r\n if (snapshot.alerts) {\r\n this.clearAlerts();\r\n for (const a of snapshot.alerts) {\r\n this.addAlert(a.price, a.condition, a.message);\r\n }\r\n }\r\n }\r\n\r\n loadStateFromStorage(key: string): boolean {\r\n if (!this.features.saveLoad) return false;\r\n const snapshot = ChartStateManager.loadFromStorage(key);\r\n if (!snapshot) return false;\r\n this.loadState(ChartStateManager.serialize(snapshot));\r\n return true;\r\n }\r\n\r\n downloadState(filename?: string): void {\r\n if (!this.features.saveLoad) return;\r\n const snapshot = ChartStateManager.capture(\r\n { getDrawings: () => this.getDrawings(), getTheme: () => this.getTheme(), getAlerts: () => this.getAlerts() },\r\n { chartType: this.options.chartType },\r\n );\r\n ChartStateManager.downloadFile(snapshot, filename);\r\n }\r\n\r\n async loadStateFromFile(): Promise<void> {\r\n if (!this.features.saveLoad) return;\r\n const snapshot = await ChartStateManager.loadFromFile();\r\n this.loadState(ChartStateManager.serialize(snapshot));\r\n }\r\n\r\n // --- Locale ---\r\n\r\n setLocale(locale: Locale): void {\r\n setGlobalLocale(locale);\r\n this.engine.requestRender();\r\n }\r\n\r\n /**\r\n * Update the BCP 47 locale used for number formatting\r\n * (e.g. price axis labels, crosshair value badges).\r\n * Defaults to 'en-US'. Example values: 'de-DE', 'vi-VN', 'fr-FR'.\r\n */\r\n setNumberLocale(locale: string): void {\r\n this.numberLocale = locale;\r\n this.priceAxis.setLocale(locale);\r\n this.crosshairHandler.setLocale(locale);\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n }\r\n\r\n getNumberLocale(): string {\r\n return this.numberLocale;\r\n }\r\n\r\n // --- Market ---\r\n\r\n setMarket(config: MarketConfig): void {\r\n this.marketConfig = config;\r\n\r\n // Apply market color scheme to theme\r\n if (config.colorScheme) {\r\n const base = this.themeManager.getTheme();\r\n const marketTheme: Theme = {\r\n ...base,\r\n candleUp: config.colorScheme.up,\r\n candleDown: config.colorScheme.down,\r\n candleUpWick: config.colorScheme.up,\r\n candleDownWick: config.colorScheme.down,\r\n volumeUp: config.colorScheme.up.replace(')', ', 0.3)').replace('rgb(', 'rgba(') || `${config.colorScheme.up}4D`,\r\n volumeDown: config.colorScheme.down.replace(')', ', 0.3)').replace('rgb(', 'rgba(') || `${config.colorScheme.down}4D`,\r\n };\r\n this.themeManager.setTheme(marketTheme);\r\n }\r\n\r\n // Apply price precision to trading, alerts, and price line\r\n if (config.pricePrecision !== undefined) {\r\n this.tradingManager.setConfig({ pricePrecision: config.pricePrecision });\r\n this.alertManager.setPricePrecision(config.pricePrecision);\r\n this.streamManager?.priceLine.setPricePrecision(config.pricePrecision);\r\n this.crosshairHandler.setPricePrecision(config.pricePrecision);\r\n }\r\n\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n }\r\n\r\n getMarket(): MarketConfig | null {\r\n return this.marketConfig;\r\n }\r\n\r\n setPriceLimits(referencePrice: number): void {\r\n if (!this.marketConfig) return;\r\n const limits = computePriceLimits(referencePrice, this.marketConfig);\r\n if (limits) {\r\n this.marketConfig.priceLimits = {\r\n ...this.marketConfig.priceLimits!,\r\n referencePrice,\r\n };\r\n }\r\n this.engine.requestRender();\r\n }\r\n\r\n // --- Features ---\r\n\r\n /** Get the resolved feature configuration */\r\n getFeatures(): Readonly<Required<FeaturesConfig>> {\r\n return this.features;\r\n }\r\n\r\n /** Update feature flags at runtime. Only provided keys are changed. */\r\n setFeatures(patch: Partial<FeaturesConfig>): void {\r\n Object.assign(this.features, patch);\r\n\r\n // Apply immediate side-effects\r\n if (patch.crosshair === false) {\r\n this.crosshairTooltip.hide();\r\n }\r\n if (patch.grid !== undefined) {\r\n this.engine.requestRender(LayerType.Background);\r\n }\r\n if (patch.volume !== undefined) {\r\n this.volumeRenderer.setVisible(patch.volume);\r\n this.engine.requestRender(LayerType.Main);\r\n }\r\n if (patch.drawings === false) {\r\n this.drawingManager.setActiveTool(null);\r\n }\r\n if (patch.trading === false) {\r\n this.tradingManager.setOrders([]);\r\n this.tradingManager.setPositions([]);\r\n }\r\n if (patch.keyboard !== undefined) {\r\n this.keyboardHandler?.setEnabled(patch.keyboard);\r\n }\r\n\r\n this.engine.requestRender();\r\n }\r\n\r\n // --- Lifecycle ---\r\n\r\n resize(): void {\r\n const size = this.engine.dprManager.readContainerSize();\r\n if (size.width <= 0 || size.height <= 0) return;\r\n this.containerSizeCache = size;\r\n this.containerSizeCacheTime = Date.now();\r\n // Resize canvas layers immediately (don't wait for DPRManager's debounced callback)\r\n const dpr = this.engine.dprManager.getDpr();\r\n this.engine.layerManager.resize(size, dpr);\r\n // Check if viewport was at the end before resize\r\n const wasAtEnd = this.viewport.isAtEnd();\r\n this.viewport.resize(size.width, size.height);\r\n this.layoutManager.resize(size.width, size.height);\r\n this.updateViewportAndRender(wasAtEnd);\r\n this.eventBus.emit('resize', size);\r\n }\r\n\r\n destroy(): void {\r\n if (this.countdownInterval) clearInterval(this.countdownInterval);\r\n this.disableAutoSave();\r\n this.disconnectStream();\r\n if (this.onWindowKeyDown) {\r\n window.removeEventListener('keydown', this.onWindowKeyDown);\r\n this.onWindowKeyDown = null;\r\n }\r\n this.keyboardHandler = null;\r\n this.interactionManager.detach();\r\n this.tradingManager.destroy();\r\n this.animator.dispose();\r\n this.crosshairTooltip.destroy();\r\n this.replayManager.dispose();\r\n this.undoRedoManager.clear();\r\n this.engine.destroy();\r\n this.eventBus.destroy();\r\n this.container.innerHTML = '';\r\n }\r\n\r\n // --- Internal ---\r\n\r\n private createChartRenderer(type: ChartType): ChartRendererInterface {\r\n return createRendererFor(type);\r\n }\r\n\r\n /** Cached display data. Invalidated when raw data or chart type changes. */\r\n private getDisplayData(): DataSeries {\r\n if (this.displayDataCache) return this.displayDataCache;\r\n const raw = this.dataManager.getData();\r\n if (raw.length === 0) return raw;\r\n const result = transformDisplayData(this.options.chartType, raw);\r\n this.displayDataCache = result;\r\n return result;\r\n }\r\n\r\n /** Lightweight render for streaming updates. No layout resolve, no indicator recalc. */\r\n private scheduleRender(): void {\r\n if (this.renderScheduled) return;\r\n this.renderScheduled = true;\r\n requestAnimationFrame(() => {\r\n this.renderScheduled = false;\r\n const displayData = this.getDisplayData();\r\n this.viewport.updateData(displayData, this.options.autoScale !== false);\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n });\r\n }\r\n\r\n /** Full update: resolve layout, update viewport, sync context, request render. */\r\n private updateViewportAndRender(scrollToEnd = false): void {\r\n // Invalidate layout cache\r\n this.resolvedLayoutCache = null;\r\n this.panelInfoCache = null;\r\n\r\n const resolved = this.getResolvedLayout();\r\n this.viewport.setChartRect(resolved.mainChartRect);\r\n\r\n const displayData = this.getDisplayData();\r\n this.viewport.updateData(displayData, this.options.autoScale !== false);\r\n\r\n // Expand price range to include overlay indicator values (BB, Ichimoku, etc.)\r\n if (this.options.autoScale !== false) {\r\n const vs = this.viewport.getState();\r\n const overlayRange = this.indicatorEngine.getOverlayPriceRange(\r\n vs.visibleRange.from,\r\n Math.min(vs.visibleRange.to, displayData.length - 1),\r\n );\r\n if (overlayRange) {\r\n const current = vs.priceRange;\r\n const expandedMin = Math.min(current.min, overlayRange.min);\r\n const expandedMax = Math.max(current.max, overlayRange.max);\r\n if (expandedMin < current.min || expandedMax > current.max) {\r\n const range = expandedMax - expandedMin || 1;\r\n this.viewport.setPriceRange(\r\n expandedMin - range * 0.02,\r\n expandedMax + range * 0.02,\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Scroll to end AFTER updateData so dataLength is current\r\n if (scrollToEnd) this.viewport.scrollToEnd();\r\n\r\n this.syncRenderContext();\r\n this.engine.requestRender();\r\n }\r\n\r\n private getResolvedLayout() {\r\n if (!this.resolvedLayoutCache) {\r\n this.resolvedLayoutCache = this.layoutManager.resolve();\r\n }\r\n return this.resolvedLayoutCache;\r\n }\r\n\r\n /** Cache container size for 500ms to avoid layout thrashing on rapid calls */\r\n private cachedContainerSize(): { width: number; height: number } {\r\n const now = Date.now();\r\n if (!this.containerSizeCache || now - this.containerSizeCacheTime > 500) {\r\n this.containerSizeCache = this.engine.dprManager.getContainerSize();\r\n this.containerSizeCacheTime = now;\r\n }\r\n return this.containerSizeCache;\r\n }\r\n\r\n private buildPanelRenderInfos(): import('@tradecanvas/core').PanelRenderInfo[] {\r\n if (this.panelInfoCache) return this.panelInfoCache;\r\n\r\n const resolved = this.getResolvedLayout();\r\n const mainVP = this.viewport.getState();\r\n\r\n const { from, to } = mainVP.visibleRange;\r\n const panels = resolved.panels.map((panel) => {\r\n const output = this.indicatorEngine.getOutput(panel.config.id);\r\n const priceRange = computeIndicatorPriceRange(output, from, to);\r\n\r\n // Inset the indicator drawing area below the panel header (title + divider)\r\n const PANEL_HEADER_HEIGHT = 20;\r\n const insetRect = {\r\n x: panel.rect.x,\r\n y: panel.rect.y + PANEL_HEADER_HEIGHT,\r\n width: panel.rect.width,\r\n height: Math.max(0, panel.rect.height - PANEL_HEADER_HEIGHT),\r\n };\r\n\r\n return {\r\n instanceId: panel.config.id,\r\n rect: panel.rect,\r\n viewport: {\r\n ...mainVP,\r\n chartRect: insetRect,\r\n priceRange,\r\n },\r\n };\r\n });\r\n\r\n this.panelInfoCache = panels;\r\n return panels;\r\n }\r\n\r\n private syncRenderContext(): void {\r\n const resolved = this.getResolvedLayout();\r\n const panels = this.features.indicators ? this.buildPanelRenderInfos() : [];\r\n\r\n // Compute where the time axis should render: below main chart + all bottom panels\r\n const bottomPanelHeight = resolved.panels\r\n .filter(p => p.config.position === 'bottom')\r\n .reduce((sum, p) => sum + p.rect.height, 0);\r\n const timeAxisY = resolved.mainChartRect.y + resolved.mainChartRect.height + bottomPanelHeight;\r\n\r\n const displayData = this.getDisplayData();\r\n this.engine.setRenderContext({\r\n chartRenderer: this.chartRenderer,\r\n gridRenderer: this.features.grid ? this.gridRenderer : null,\r\n priceAxis: this.features.priceAxis ? this.priceAxis : null,\r\n timeAxis: this.features.timeAxis ? this.timeAxis : null,\r\n crosshairHandler: this.features.crosshair ? this.crosshairHandler : null,\r\n indicatorEngine: this.features.indicators ? this.indicatorEngine : null,\r\n drawingRenderer: this.features.drawings ? this.drawingRenderer : null,\r\n tradingRenderer: this.features.trading ? this.tradingRenderer : null,\r\n currentPriceLine: this.streamManager?.priceLine ?? this.currentPriceLine,\r\n chartLegend: this.features.legend ? this.chartLegend : null,\r\n volumeRenderer: this.features.volume ? this.volumeRenderer : null,\r\n watermark: this.features.watermark ? this.watermark : null,\r\n barCountdown: this.barCountdown,\r\n sessionBreaks: this.sessionBreaks,\r\n compareRenderer: this.compareRenderer,\r\n alertManager: this.features.alerts ? this.alertManager : null,\r\n signalMarkerManager: this.signalMarkerManager,\r\n tradeZoneManager: this.tradeZoneManager,\r\n panels,\r\n priceLimits: this.buildPriceLimits(),\r\n timeAxisY,\r\n // Attach data to the viewport so drawings/indicators can treat\r\n // `anchor.time` as a real timestamp and convert via timestampToBarIndex.\r\n viewport: { ...this.viewport.getState(), data: displayData },\r\n theme: this.themeManager.getTheme(),\r\n data: displayData,\r\n numberLocale: this.numberLocale,\r\n });\r\n }\r\n\r\n private buildPriceLimits() {\r\n if (!this.marketConfig?.priceLimits?.enabled || !this.marketConfig.priceLimits.referencePrice) return null;\r\n const limits = computePriceLimits(this.marketConfig.priceLimits.referencePrice, this.marketConfig);\r\n if (!limits) return null;\r\n return {\r\n ...limits,\r\n colors: this.marketConfig.colorScheme ? {\r\n ceiling: this.marketConfig.colorScheme.ceiling,\r\n floor: this.marketConfig.colorScheme.floor,\r\n reference: this.marketConfig.colorScheme.reference,\r\n } : undefined,\r\n };\r\n }\r\n}\r\n"],"mappings":"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"}