@tradecanvas/chart 0.7.1 → 0.8.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.
- package/dist/Chart-Br_N-BCL.cjs +2 -0
- package/dist/Chart-Br_N-BCL.cjs.map +1 -0
- package/dist/{Chart-Cy8K3wHS.js → Chart-Cn_TSMO7.js} +46 -42
- package/dist/Chart-Cn_TSMO7.js.map +1 -0
- package/dist/Chart.d.ts.map +1 -1
- package/dist/charts/ChartTypeStrategy.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/widget/index.cjs +1 -1
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +5 -1
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/widgetConfig.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/Chart-BVaoFQh0.cjs +0 -2
- package/dist/Chart-BVaoFQh0.cjs.map +0 -1
- package/dist/Chart-Cy8K3wHS.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require(`@tradecanvas/commons`),t=require(`@tradecanvas/core`);function n(e){switch(e){case`candlestick`:case`heikinAshi`:case`lineBreak`:case`rangeBars`:return new t.CandlestickRenderer;case`line`:return new t.LineRenderer;case`area`:return new t.AreaRenderer;case`bar`:return new t.BarRenderer;case`hollowCandle`:return new t.HollowCandleRenderer;case`baseline`:return new t.BaselineRenderer;case`renko`:return new t.RenkoRenderer;case`kagi`:return new t.KagiRenderer;case`pointAndFigure`:return new t.PointAndFigureRenderer;case`volumeCandles`:return new t.VolumeCandleRenderer;case`equivolume`:return new t.EquivolumeRenderer;case`hlcArea`:return new t.HLCAreaRenderer;case`stepLine`:return new t.StepLineRenderer;case`lineWithMarkers`:return new t.LineWithMarkersRenderer;default:return new t.CandlestickRenderer}}function r(e,n){if(n.length===0)return n;switch(e){case`heikinAshi`:return(0,t.toHeikinAshi)(n);case`renko`:return(0,t.toRenko)(n,{brickSize:0,useATR:!0,atrPeriod:14});case`lineBreak`:return(0,t.toLineBreak)(n,3);case`kagi`:return(0,t.toKagi)(n,4);case`pointAndFigure`:return(0,t.toPointAndFigure)(n,i(n)*.01,3);case`rangeBars`:return(0,t.toRangeBars)(n,{rangeSize:i(n)*.005});default:return n}}function i(e){let t=0;for(let n of e)t+=n.close;return t/e.length}var a={min:0,max:100},o=.1;function s(e,t,n){if(!e)return{...a};let r=1/0,i=-1/0,s=0;for(let[,a]of e.values){if(s>=t&&s<=n)for(let e in a){let t=a[e];t!==void 0&&Number.isFinite(t)&&(t<r&&(r=t),t>i&&(i=t))}s++}if(r===1/0)return{...a};let c=i-r||1;return{min:r-c*o,max:i+c*o}}var c=class{timer=null;delayMs=0;key=null;constructor(e){this.save=e}enable(e,t){this.key=e,this.delayMs=t}disable(){this.key=null,this.delayMs=0,this.cancel()}schedule(){this.delayMs<=0||!this.key||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>{this.timer=null,this.key&&this.save(this.key)},this.delayMs))}cancel(){this.timer&&=(clearTimeout(this.timer),null)}isEnabled(){return this.delayMs>0&&this.key!==null}hasPending(){return this.timer!==null}};function l(e){if(!e||typeof e.time!=`number`)return!1;let{open:t,high:n,low:r,close:i}=e;return!(!isFinite(t)||!isFinite(n)||!isFinite(r)||!isFinite(i)||t<0||n<0||r<0||i<0||n<r||e.volume!==void 0&&(!isFinite(e.volume)||e.volume<0))}function u(e){return{...e,high:Math.max(e.open,e.high,e.low,e.close),low:Math.min(e.open,e.high,e.low,e.close),volume:e.volume===void 0?0:Math.max(0,e.volume)}}var d=class{data=[];getData(){return this.data}setData(e){this.data=e.filter(l).map(u)}appendBar(e){l(e)&&this.data.push(u(e))}updateLastBar(e){if(!l(e))return;let t=u(e);if(this.data.length===0){this.data.push(t);return}this.data[this.data.length-1]=t}updateLastBarFromTick(t){this.data.length!==0&&(!isFinite(t.price)||t.price<0||t.volume!==void 0&&(!isFinite(t.volume)||t.volume<0)||(this.data[this.data.length-1]=(0,e.mergeBar)(this.data[this.data.length-1],t)))}getLength(){return this.data.length}clear(){this.data=[]}},f=class{theme;constructor(t){!t||t===`dark`?this.theme={...e.DARK_THEME}:t===`light`?this.theme={...e.LIGHT_THEME}:this.theme={...t}}getTheme(){return this.theme}setTheme(t){t===`dark`?this.theme={...e.DARK_THEME}:t===`light`?this.theme={...e.LIGHT_THEME}:this.theme={...t}}},p=200,m=80,h=class{panels=[];containerWidth=0;containerHeight=0;resize(e,t){this.containerWidth=e,this.containerHeight=t}addPanel(t,n=`bottom`,r){let i=n===`left`||n===`right`;this.panels.push({id:t,position:n,size:r??(i?p:e.DEFAULT_PANEL_HEIGHT),minSize:i?m:e.MIN_PANEL_HEIGHT,content:{type:`indicator`,indicatorInstanceId:t}})}removePanel(e){this.panels=this.panels.filter(t=>t.id!==e)}setPanelPosition(t,n){let r=this.panels.find(e=>e.id===t);if(r){let t=r.position===`left`||r.position===`right`,i=n===`left`||n===`right`;r.position=n,t!==i&&(r.size=i?p:e.DEFAULT_PANEL_HEIGHT,r.minSize=i?m:e.MIN_PANEL_HEIGHT)}}setPanelSize(e,t){let n=this.panels.find(t=>t.id===e);n&&(n.size=Math.max(n.minSize,t))}getPanels(){return this.panels}resolve(){let t=this.panels.filter(e=>e.position===`left`),n=this.panels.filter(e=>e.position===`right`),r=this.panels.filter(e=>e.position===`top`),i=this.panels.filter(e=>e.position===`bottom`),a=t.reduce((e,t)=>e+t.size,0),o=n.reduce((e,t)=>e+t.size,0),s=r.reduce((e,t)=>e+t.size,0),c=i.reduce((e,t)=>e+t.size,0),l={x:a,y:s,width:Math.max(0,this.containerWidth-a-o-e.PRICE_AXIS_WIDTH),height:Math.max(0,this.containerHeight-s-c-e.TIME_AXIS_HEIGHT)},u=[],d=[],f=0;for(let n of t)u.push({config:n,rect:{x:f,y:0,width:n.size,height:this.containerHeight-e.TIME_AXIS_HEIGHT}}),d.push({panelId:n.id,rect:{x:f+n.size-2,y:0,width:4,height:this.containerHeight},orientation:`vertical`}),f+=n.size;let p=0;for(let e of r)u.push({config:e,rect:{x:a,y:p,width:l.width,height:e.size}}),d.push({panelId:e.id,rect:{x:a,y:p+e.size-2,width:l.width,height:4},orientation:`horizontal`}),p+=e.size;p=l.y+l.height;for(let e of i)u.push({config:e,rect:{x:a,y:p,width:l.width,height:e.size}}),d.push({panelId:e.id,rect:{x:a,y:p-2,width:l.width,height:4},orientation:`horizontal`}),p+=e.size;f=a+l.width+e.PRICE_AXIS_WIDTH;for(let t of n)u.push({config:t,rect:{x:f,y:0,width:t.size,height:this.containerHeight-e.TIME_AXIS_HEIGHT}}),d.push({panelId:t.id,rect:{x:f-2,y:0,width:4,height:this.containerHeight},orientation:`vertical`}),f+=t.size;return{mainChartRect:l,panels:u,dividers:d}}getMainChartRect(){return this.resolve().mainChartRect}},g=class{constructor(e){this.indicatorEngine=e}registerIndicator(e){this.indicatorEngine.register(e)}},_=class{static version=`0.7.0`;engine;viewport;dataManager;themeManager;layoutManager;pluginManager;indicatorEngine;drawingManager;drawingRenderer;tradingManager;tradingRenderer;eventBus;streamManager=null;autoScrollOnNewBar=!0;displayDataCache=null;resolvedLayoutCache=null;panelInfoCache=null;renderScheduled=!1;containerSizeCache=null;containerSizeCacheTime=0;chartLegend;watermark;barCountdown;sessionBreaks;compareRenderer;countdownInterval=null;volumeRenderer;alertManager;signalMarkerManager;tradeZoneManager;replayManager;undoRedoManager;autoSaveScheduler=new c(e=>this.saveState(e));animator;crosshairTooltip;interactionManager;crosshairHandler;chartRenderer;gridRenderer;priceAxis;timeAxis;options;features;marketConfig=null;container;currentPriceLine;numberLocale;keyboardHandler=null;onWindowKeyDown=null;currentSymbol=``;constructor(n,r){this.container=n,this.options=r,this.numberLocale=r.numberLocale??`en-US`;let i=r.features??{};this.features={drawings:i.drawings??!0,drawingTools:i.drawingTools??[],drawingMagnet:i.drawingMagnet??!0,drawingUndoRedo:i.drawingUndoRedo??!0,trading:i.trading??!0,tradingContextMenu:i.tradingContextMenu??!0,indicators:i.indicators??!0,indicatorIds:i.indicatorIds??[],panning:i.panning??!0,zooming:i.zooming??!0,crosshair:i.crosshair??!0,keyboard:i.keyboard??!0,priceAxis:i.priceAxis??!0,timeAxis:i.timeAxis??!0,grid:i.grid??r.grid?.visible??!0,legend:i.legend??!0,volume:i.volume??!0,watermark:i.watermark??!0,saveLoad:i.saveLoad??!0,screenshot:i.screenshot??!0,alerts:i.alerts??!0,replay:i.replay??!0,sessionBreaks:i.sessionBreaks??!0,barCountdown:i.barCountdown??!0,compareSymbols:i.compareSymbols??!0,dataExport:i.dataExport??!0,logScale:i.logScale??!0,timeframes:i.timeframes??[],defaultTimeframeFavorites:i.defaultTimeframeFavorites??[]},n.style.position=`relative`,n.style.overflow=`hidden`,n.tabIndex=0,n.style.outline=`none`,this.dataManager=new d,this.themeManager=new f(r.theme),this.layoutManager=new h,this.indicatorEngine=new t.IndicatorEngine,this.pluginManager=new g(this.indicatorEngine),this.eventBus=new t.EventBus,(0,t.registerBuiltInIndicators)(this.indicatorEngine),this.drawingManager=new t.DrawingManager,(0,t.registerBuiltInDrawingTools)(this.drawingManager),this.drawingRenderer=new t.DrawingRenderer(this.drawingManager),this.drawingManager.setRequestRender(()=>{this.syncRenderContext(),this.engine.requestRender(e.LayerType.Overlay),this.scheduleAutoSave()}),this.drawingManager.setEventCallback((e,t)=>{this.eventBus.emit(e,t)}),this.undoRedoManager=new t.UndoRedoManager,this.drawingManager.setUndoRedoManager(this.undoRedoManager),this.drawingManager.setDataGetter(()=>this.dataManager.getData()),this.drawingManager.setDisplayDataGetter(()=>this.getDisplayData()),r.crosshair?.mode===`magnet`&&this.drawingManager.setMagnetMode(`magnet`),this.tradingManager=new t.TradingManager({enabled:this.features.trading,contextMenu:{enabled:this.features.tradingContextMenu}}),this.tradingRenderer=new t.TradingRenderer(this.tradingManager),this.tradingManager.setContainer(n),this.tradingManager.setRequestRender(()=>this.engine.requestRender(e.LayerType.Overlay)),this.tradingManager.setEventCallback((e,t)=>{this.eventBus.emit(e,t)}),this.engine=new t.RenderEngine(n);let a=this.engine.dprManager.getContainerSize();this.viewport=new t.Viewport(a.width,a.height,r.minBarSpacing??2,r.maxBarSpacing??30,r.rightMargin??5),this.layoutManager.resize(a.width,a.height),this.engine.onContainerResize=e=>{if(e.width<=0||e.height<=0)return;let t=this.viewport.isAtEnd();this.viewport.resize(e.width,e.height),this.layoutManager.resize(e.width,e.height),this.updateViewportAndRender(t)},this.chartRenderer=this.createChartRenderer(r.chartType),this.gridRenderer=new t.GridRenderer,r.grid?.visible===!1&&this.gridRenderer.setVisible(!1),this.priceAxis=new t.PriceAxis,this.priceAxis.setLocale(this.numberLocale),this.timeAxis=new t.TimeAxis,this.crosshairHandler=new t.CrosshairHandler,this.crosshairHandler.setLocale(this.numberLocale),r.crosshair?.mode&&this.crosshairHandler.setMode(r.crosshair.mode),this.crosshairHandler.setCallback((e,t)=>{if(e!==null&&t){let n=this.dataManager.getData(),r=e<n.length?n[e]:void 0;this.chartLegend.setHoverBar(r??null),r&&this.crosshairTooltip.show(t,r,this.themeManager.getTheme(),this.cachedContainerSize()),this.eventBus.emit(`crosshairMove`,{point:t,bar:r,barIndex:e})}else this.crosshairTooltip.hide(),this.chartLegend.setHoverBar(null)}),this.chartLegend=new t.ChartLegend,this.chartLegend.setChartType(r.chartType),this.watermark=new t.Watermark,r.watermark&&this.watermark.setConfig(r.watermark),this.volumeRenderer=new t.VolumeRenderer,this.barCountdown=new t.BarCountdown,this.sessionBreaks=new t.SessionBreaks,this.compareRenderer=new t.CompareRenderer,r.sessionBreaks?this.sessionBreaks.setConfig({visible:r.sessionBreaks.visible??!0,color:r.sessionBreaks.color,lineStyle:r.sessionBreaks.lineStyle,lineWidth:r.sessionBreaks.lineWidth}):r.features?.sessionBreaks!==!1&&this.sessionBreaks.setVisible(!0),r.logScale&&this.viewport.setLogScale(!0),this.animator=new t.Animator,this.crosshairTooltip=new t.CrosshairTooltip,this.crosshairTooltip.create(n),this.keyboardHandler=new t.KeyboardHandler({scrollBars:e=>{let t=this.viewport.getState().barWidth+this.viewport.getState().barSpacing;this.viewport.scrollBy(e*t),this.updateViewportAndRender()},zoom:e=>{let t=this.viewport.getState().chartRect.width;this.viewport.zoom(e,t/2),this.updateViewportAndRender()},goToStart:()=>{this.viewport.scrollBy(-1/0),this.updateViewportAndRender()},goToEnd:()=>{this.viewport.scrollToEnd(),this.updateViewportAndRender()},fitContent:()=>this.fitContent()}),this.keyboardHandler.setEnabled(this.features.keyboard),this.onWindowKeyDown=e=>{if(!this.keyboardHandler)return;let t=document.activeElement;t&&t!==this.container&&!this.container.contains(t)||t&&(t.tagName===`INPUT`||t.tagName===`TEXTAREA`||t.isContentEditable)||this.keyboardHandler.handleKey(e)&&e.preventDefault()},window.addEventListener(`keydown`,this.onWindowKeyDown),this.currentPriceLine=new t.CurrentPriceLine,this.alertManager=new t.AlertManager,this.alertManager.setRequestRender(()=>this.engine.requestRender(e.LayerType.Overlay)),this.alertManager.on(`triggered`,e=>{this.eventBus.emit(`dataUpdate`,{alert:`triggered`,alertId:e.id,price:e.price,message:e.message})}),this.signalMarkerManager=new t.SignalMarkerManager,this.signalMarkerManager.setRequestRender(()=>this.engine.requestRender(e.LayerType.Overlay)),this.signalMarkerManager.setDataGetter(()=>this.dataManager.getData()),this.signalMarkerManager.on(`added`,e=>{this.eventBus.emit(`signalMarkerAdd`,{id:e.id,source:e.source,direction:e.direction})}),this.signalMarkerManager.on(`removed`,e=>{this.eventBus.emit(`signalMarkerRemove`,{id:e})}),this.tradeZoneManager=new t.TradeZoneManager,this.tradeZoneManager.setRequestRender(()=>this.engine.requestRender(e.LayerType.Overlay)),this.tradeZoneManager.setDataGetter(()=>this.dataManager.getData()),this.tradeZoneManager.on(`added`,e=>{this.eventBus.emit(`tradeZoneAdd`,{id:e.id,direction:e.direction})}),this.tradeZoneManager.on(`removed`,e=>{this.eventBus.emit(`tradeZoneRemove`,{id:e})}),this.replayManager=new t.ReplayManager,this.interactionManager=new t.InteractionManager(n),this.features.panning&&this.interactionManager.setPanHandler(new t.PanHandler(e=>{this.viewport.scrollBy(e),this.updateViewportAndRender()})),this.features.zooming&&this.interactionManager.setZoomHandler(new t.ZoomHandler((e,t)=>{this.viewport.zoom(e,t),this.updateViewportAndRender()})),this.features.crosshair&&this.interactionManager.setCrosshairHandler(this.crosshairHandler),this.features.drawings&&this.interactionManager.setDrawingManager(this.drawingManager,()=>({...this.viewport.getState(),data:this.getDisplayData()})),this.features.trading&&this.interactionManager.setTradingManager(this.tradingManager,()=>({...this.viewport.getState(),data:this.getDisplayData()})),this.interactionManager.setOverlayDirtyCallback(()=>{this.engine.requestRender(e.LayerType.Overlay),this.layoutManager.getPanels().length>0&&this.engine.requestRender(e.LayerType.UI)}),this.interactionManager.attach(),this.syncRenderContext(),this.engine.start()}setData(e){this.dataManager.setData(e),this.crosshairHandler.setData(this.dataManager.getData()),this.displayDataCache=null,this.sessionBreaks.invalidateCache(),this.indicatorEngine.recalculateAll(this.dataManager.getData()),e.length>0&&this.currentPriceLine.setPrice(e[e.length-1].close),this.updateViewportAndRender(!0),this.eventBus.emit(`dataUpdate`,{length:e.length})}appendBar(e){this.dataManager.appendBar(e),this.crosshairHandler.setData(this.dataManager.getData()),this.displayDataCache=null,this.autoScrollOnNewBar&&this.viewport.scrollToEnd(),this.indicatorEngine.recalculateAll(this.dataManager.getData()),this.updateViewportAndRender()}appendBars(e){if(e.length!==0){for(let t of e)this.dataManager.appendBar(t);this.displayDataCache=null,this.indicatorEngine.recalculateAll(this.dataManager.getData()),this.crosshairHandler.setData(this.dataManager.getData()),this.updateViewportAndRender(this.viewport.isAtEnd())}}updateLastBar(e){this.dataManager.updateLastBar(e),this.currentPriceLine.setPrice(e.close),this.options.chartType!==`candlestick`&&this.options.chartType!==`line`&&this.options.chartType!==`area`&&this.options.chartType!==`bar`&&this.options.chartType!==`hollowCandle`&&(this.displayDataCache=null),this.indicatorEngine.recalculateAll(this.dataManager.getData()),this.scheduleRender()}updateLastBarFromTick(e){this.dataManager.updateLastBarFromTick(e),this.currentPriceLine.setPrice(e.price),this.options.chartType!==`candlestick`&&this.options.chartType!==`line`&&this.options.chartType!==`area`&&this.options.chartType!==`bar`&&this.options.chartType!==`hollowCandle`&&(this.displayDataCache=null),this.indicatorEngine.recalculateAll(this.dataManager.getData()),this.scheduleRender()}setChartType(e){this.options.chartType=e,this.chartRenderer=this.createChartRenderer(e),this.chartLegend.setChartType(e),this.displayDataCache=null,this.updateViewportAndRender(!0)}addIndicator(e,t={},n=`bottom`){if(!this.features.indicators||this.features.indicatorIds.length>0&&!this.features.indicatorIds.includes(e))return null;let r=this.indicatorEngine.addIndicator(e,t,this.dataManager.getData());return this.indicatorEngine.getAvailableIndicators().find(t=>t.id===e)?.placement===`panel`?(this.layoutManager.addPanel(r,n),this.updateViewportAndRender()):this.engine.requestRender(),this.eventBus.emit(`indicatorAdd`,{instanceId:r,id:e}),r}updateIndicator(e,t){this.indicatorEngine.updateIndicator(e,t,this.dataManager.getData()),this.engine.requestRender()}removeIndicator(e){let t=this.layoutManager.getPanels().some(t=>t.id===e);this.indicatorEngine.removeIndicator(e),this.layoutManager.removePanel(e),this.eventBus.emit(`indicatorRemove`,{instanceId:e}),t?this.updateViewportAndRender():this.engine.requestRender()}getIndicatorOutput(e){return this.indicatorEngine.getOutput(e)}registerIndicator(e){this.pluginManager.registerIndicator(e)}static indicators(){let e=new t.IndicatorEngine;return(0,t.registerBuiltInIndicators)(e),e.getAvailableIndicators()}setPanelPosition(e,t){this.layoutManager.setPanelPosition(e,t),this.engine.requestRender()}setPanelSize(e,t){this.layoutManager.setPanelSize(e,t),this.engine.requestRender()}setDrawingTool(e){this.features.drawings&&(e&&this.features.drawingTools.length>0&&!this.features.drawingTools.includes(e)||this.drawingManager.setActiveTool(e))}getDrawingTool(){return this.drawingManager.getActiveTool()}setDrawingStyle(e){this.drawingManager.setStyle(e)}getDrawings(){return this.drawingManager.getDrawings()}setDrawings(e){this.drawingManager.setDrawings(e)}removeDrawing(e){this.drawingManager.removeDrawing(e)}clearDrawings(){this.drawingManager.clearDrawings()}registerDrawingTool(e){this.drawingManager.register(e)}undo(){return this.features.drawingUndoRedo?this.drawingManager.undo():!1}redo(){return this.features.drawingUndoRedo?this.drawingManager.redo():!1}getUndoRedoState(){return this.undoRedoManager.getState()}setDrawingMagnet(e){this.drawingManager.setMagnetMode(e?`magnet`:`none`)}getDrawingMagnet(){return this.drawingManager.getMagnetMode()===`magnet`}lockAllDrawings(){this.drawingManager.lockAllDrawings()}unlockAllDrawings(){this.drawingManager.unlockAllDrawings()}hideAllDrawings(){this.drawingManager.hideAllDrawings()}showAllDrawings(){this.drawingManager.showAllDrawings()}duplicateDrawing(e){let t=e??this.drawingManager.getSelectedDrawingId();return t?this.drawingManager.duplicateDrawing(t):null}exportVisibleData(e=`csv`,n){let r=this.viewport.getState(),i=this.dataManager.getData(),a=Math.max(0,r.visibleRange.from),o=Math.min(i.length-1,r.visibleRange.to),s=i.slice(a,o+1);if(e===`json`){let e=t.DataExporter.toJSON(s);t.DataExporter.download(e,n??`chart-data.json`,`application/json`)}else{let e=t.DataExporter.toCSV(s);t.DataExporter.download(e,n??`chart-data.csv`,`text/csv`)}}exportAllData(e=`csv`,n){let r=this.dataManager.getData();if(e===`json`){let e=t.DataExporter.toJSON(r);t.DataExporter.download(e,n??`chart-data.json`,`application/json`)}else{let e=t.DataExporter.toCSV(r);t.DataExporter.download(e,n??`chart-data.csv`,`text/csv`)}}setAutoSave(e,t=5e3){this.autoSaveScheduler.enable(e,t)}disableAutoSave(){this.autoSaveScheduler.disable()}scheduleAutoSave(){this.autoSaveScheduler.schedule()}getAvailableIndicators(){return this.indicatorEngine.getAvailableIndicators()}getIndicatorInputs(e){let t=this.indicatorEngine.getAvailableIndicators().find(t=>t.id===e);return t?{id:t.id,params:t.defaultConfig}:null}getActiveIndicators(){return this.indicatorEngine.getActiveIndicators()}getIndicatorConfig(e){let t=this.indicatorEngine.getIndicatorConfig(e);return t?{id:t.id,params:{...t.params}}:null}updateIndicatorStyle(e,t){this.indicatorEngine.updateIndicatorStyle(e,t),this.engine.requestRender()}setOrders(e){this.features.trading&&this.tradingManager.setOrders(e)}setPositions(e){this.features.trading&&this.tradingManager.setPositions(e)}setDepthData(e){this.features.trading&&this.tradingManager.setDepthData(e)}setCurrentPrice(e,t){this.tradingManager.setCurrentPrice(e),this.currentPriceLine.setPrice(e),this.scheduleRender(),this.features.alerts&&this.alertManager.checkPrice(e)}setTradingConfig(e){this.features.trading&&this.tradingManager.setConfig(e)}async connect(n){this.disconnectStream(),this.streamManager=new t.StreamManager,this.streamManager.on(`snapshot`,e=>{this.setData(e)}),this.streamManager.on(`barClose`,e=>{this.dataManager.appendBar(e),this.crosshairHandler.setData(this.dataManager.getData()),this.autoScrollOnNewBar&&this.viewport.scrollToEnd(),this.indicatorEngine.recalculateAll(this.dataManager.getData()),this.updateViewportAndRender()}),this.streamManager.on(`barUpdate`,e=>{this.dataManager.updateLastBar(e),this.currentPriceLine.setPrice(e.close),this.indicatorEngine.recalculateAll(this.dataManager.getData()),this.scheduleRender()}),this.streamManager.on(`priceChange`,({price:t})=>{this.tradingManager.setCurrentPrice(t),this.currentPriceLine.setPrice(t),this.engine.requestRender(e.LayerType.Overlay),this.engine.requestRender(e.LayerType.UI)}),this.streamManager.on(`connectionChange`,e=>{this.eventBus.emit(`dataUpdate`,{connection:e})}),this.streamManager.on(`error`,e=>{this.eventBus.emit(`dataUpdate`,{error:e.message})}),this.autoScrollOnNewBar=n.autoScroll!==!1,this.currentSymbol=n.symbol,await this.streamManager.connect(n);let r=(0,e.timeframeToMs)(n.timeframe);this.barCountdown.setTimeframeMs(r),this.countdownInterval&&clearInterval(this.countdownInterval),this.countdownInterval=setInterval(()=>{this.barCountdown.isVisible()&&this.engine.requestRender(e.LayerType.UI)},1e3)}async switchStream(e,t){this.streamManager&&(this.currentSymbol=e,await this.streamManager.switchTo(e,t))}async setTimeframe(e){if(!this.streamManager)throw Error(`No active stream. Call connect() first.`);await this.switchStream(this.currentSymbol,e)}disconnectStream(){this.streamManager&&=(this.streamManager.dispose(),null)}setBarCountdownVisible(t){this.barCountdown.setVisible(t),this.engine.requestRender(e.LayerType.UI)}setSessionBreaksVisible(t){this.sessionBreaks.setVisible(t),this.engine.requestRender(e.LayerType.Background)}addCompareSymbol(t,n,r,i){this.compareRenderer.addSymbol({id:t,label:n,data:r,color:i,visible:!0}),this.engine.requestRender(e.LayerType.Main)}removeCompareSymbol(t){this.compareRenderer.removeSymbol(t),this.engine.requestRender(e.LayerType.Main)}updateCompareData(t,n){this.compareRenderer.setSymbolData(t,n),this.engine.requestRender(e.LayerType.Main)}setCompareMode(t){this.compareRenderer.setMode(t),this.engine.requestRender(e.LayerType.Main)}clearCompareSymbols(){this.compareRenderer.clear(),this.engine.requestRender(e.LayerType.Main)}setLogScale(e){this.viewport.setLogScale(e),this.updateViewportAndRender()}isLogScale(){return this.viewport.isLogScale()}setSessionBreaksConfig(t){this.sessionBreaks.setConfig(t),this.engine.requestRender(e.LayerType.Background)}getConnectionState(){return this.streamManager?.getConnectionState()??`disconnected`}getConnectionInfo(){return this.streamManager?.getConnectionInfo()??{state:`disconnected`}}setAutoScroll(e){this.autoScrollOnNewBar=e}scrollTo(e){let t=this.dataManager.getData();for(let n=0;n<t.length;n++)if(t[n].time>=e){let e=this.viewport.getState().barWidth+this.viewport.getState().barSpacing;this.viewport.scrollBy(n*e-this.viewport.getState().offset),this.updateViewportAndRender();return}}scrollToEnd(){this.viewport.scrollToEnd(),this.updateViewportAndRender()}setVisibleRange(e,t){let n=this.dataManager.getData(),r=0,i=n.length-1;for(let t=0;t<n.length;t++)if(n[t].time>=e){r=t;break}for(let e=n.length-1;e>=0;e--)if(n[e].time<=t){i=e;break}let a=i-r+1;if(a>0){let e=this.viewport.getState().chartRect.width,t=e/a,n=Math.max(2,t-this.viewport.getState().barSpacing);this.viewport.zoom((n-this.viewport.getState().barWidth)/this.viewport.getState().barWidth,e/2)}this.updateViewportAndRender()}zoomIn(){let e=this.viewport.getState().chartRect.width;this.viewport.zoom(.2,e/2),this.updateViewportAndRender()}zoomOut(){let e=this.viewport.getState().chartRect.width;this.viewport.zoom(-.2,e/2),this.updateViewportAndRender()}fitContent(){let e=this.dataManager.getData();e.length!==0&&this.setVisibleRange(e[0].time,e[e.length-1].time)}on(e,t){this.eventBus.on(e,t)}off(e,t){this.eventBus.off(e,t)}enableTauriBridge(e){this.eventBus.enableTauriBridge({enabled:!0,...e})}disableTauriBridge(){this.eventBus.disableTauriBridge()}setTheme(e){this.themeManager.setTheme(e),this.syncRenderContext(),this.container.style.backgroundColor=this.themeManager.getTheme().background,this.engine.requestRender(),this.eventBus.emit(`themeChange`,{theme:e})}getTheme(){return this.themeManager.getTheme()}setWatermark(t,n){this.watermark.setConfig({text:t,...n}),this.engine.requestRender(e.LayerType.Background)}setAutoScale(e){this.options.autoScale=e,this.updateViewportAndRender()}isAutoScale(){return this.options.autoScale!==!1}setCrosshairMode(t){this.crosshairHandler.setMode(t),this.engine.requestRender(e.LayerType.Overlay)}getCrosshairMode(){return this.crosshairHandler.getMode()}setCrosshairPosition(t){t&&this.crosshairHandler.onPointerMove(t),this.engine.requestRender(e.LayerType.Overlay)}getData(){return this.dataManager.getData()}setGridVisible(t){this.gridRenderer.setVisible(t),this.engine.requestRender(e.LayerType.Background)}isGridVisible(){return this.gridRenderer.isVisible()}setVolumeVisible(t){this.volumeRenderer.setVisible(t),this.engine.requestRender(e.LayerType.Main)}setTooltipVisible(e){e||this.crosshairTooltip.hide()}setLegend(t){this.chartLegend.setConfig(t),this.engine.requestRender(e.LayerType.UI)}setSymbolName(t){this.chartLegend.setSymbol(t),this.engine.requestRender(e.LayerType.UI)}setStatusText(t){this.chartLegend.setStatusText(t),this.engine.requestRender(e.LayerType.UI)}screenshot(e){this.features.screenshot&&t.Screenshot.download(this.container,e,this.themeManager.getTheme().background)}screenshotDataURL(){return this.features.screenshot?t.Screenshot.toDataURL(this.container,this.themeManager.getTheme().background):null}async screenshotBlob(){return this.features.screenshot?t.Screenshot.toBlob(this.container,this.themeManager.getTheme().background):null}addAlert(e,t=`crossing`,n){if(!this.features.alerts)return null;let r=this.alertManager.addAlert(e,t,n);return this.scheduleAutoSave(),r}removeAlert(e){this.alertManager.removeAlert(e),this.scheduleAutoSave()}getAlerts(){return this.alertManager.getAlerts()}clearAlerts(){this.alertManager.clearAlerts(),this.scheduleAutoSave()}saveAlerts(e){this.alertManager.saveToStorage(e)}loadAlerts(t){this.alertManager.loadFromStorage(t),this.engine.requestRender(e.LayerType.Overlay)}addSignalMarker(e){return this.signalMarkerManager.addMarker(e)}removeSignalMarker(e){this.signalMarkerManager.removeMarker(e)}getSignalMarkers(){return this.signalMarkerManager.getMarkers()}setSignalMarkers(e){this.signalMarkerManager.setMarkers(e)}clearSignalMarkers(){this.signalMarkerManager.clearMarkers()}setSignalMarkerStyle(e){this.signalMarkerManager.setStyle(e)}addTradeZone(e){return this.tradeZoneManager.addZone(e)}updateTradeZone(e,t){this.tradeZoneManager.updateZone(e,t)}removeTradeZone(e){this.tradeZoneManager.removeZone(e)}getTradeZones(){return this.tradeZoneManager.getZones()}setTradeZones(e){this.tradeZoneManager.setZones(e)}clearTradeZones(){this.tradeZoneManager.clearZones()}setTradeZoneStyle(e){this.tradeZoneManager.setStyle(e)}replay(e){if(!this.features.replay)return;let t=this.dataManager.getData();this.replayManager.load(t),this.replayManager.on(`bar`,({bar:e,index:n})=>{let r=t.slice(0,n+1);this.dataManager.setData(r),this.crosshairHandler.setData(r),this.indicatorEngine.recalculateAll(r),this.updateViewportAndRender()}),this.replayManager.play(e)}replayPause(){this.replayManager.pause()}replayResume(){this.replayManager.resume()}replayStop(){this.replayManager.stop()}replaySeek(e){this.replayManager.seekTo(e)}setReplaySpeed(e){this.replayManager.setSpeed(e)}getReplayState(){return this.replayManager.getState()}getReplayProgress(){return this.replayManager.getProgress()}saveState(e){if(!this.features.saveLoad)return null;let n=t.ChartStateManager.capture({getDrawings:()=>this.getDrawings(),getTheme:()=>this.getTheme(),getAlerts:()=>this.getAlerts()},{chartType:this.options.chartType}),r=t.ChartStateManager.serialize(n);return e&&t.ChartStateManager.saveToStorage(e,n),r}loadState(e){if(!this.features.saveLoad)return;let n=t.ChartStateManager.deserialize(e);if(n.chartType&&this.setChartType(n.chartType),n.drawings&&this.setDrawings(n.drawings),n.theme&&this.setTheme(n.theme),n.alerts){this.clearAlerts();for(let e of n.alerts)this.addAlert(e.price,e.condition,e.message)}}loadStateFromStorage(e){if(!this.features.saveLoad)return!1;let n=t.ChartStateManager.loadFromStorage(e);return n?(this.loadState(t.ChartStateManager.serialize(n)),!0):!1}downloadState(e){if(!this.features.saveLoad)return;let n=t.ChartStateManager.capture({getDrawings:()=>this.getDrawings(),getTheme:()=>this.getTheme(),getAlerts:()=>this.getAlerts()},{chartType:this.options.chartType});t.ChartStateManager.downloadFile(n,e)}async loadStateFromFile(){if(!this.features.saveLoad)return;let e=await t.ChartStateManager.loadFromFile();this.loadState(t.ChartStateManager.serialize(e))}setLocale(t){(0,e.setLocale)(t),this.engine.requestRender()}setNumberLocale(e){this.numberLocale=e,this.priceAxis.setLocale(e),this.crosshairHandler.setLocale(e),this.syncRenderContext(),this.engine.requestRender()}getNumberLocale(){return this.numberLocale}setMarket(e){if(this.marketConfig=e,e.colorScheme){let t={...this.themeManager.getTheme(),candleUp:e.colorScheme.up,candleDown:e.colorScheme.down,candleUpWick:e.colorScheme.up,candleDownWick:e.colorScheme.down,volumeUp:e.colorScheme.up.replace(`)`,`, 0.3)`).replace(`rgb(`,`rgba(`)||`${e.colorScheme.up}4D`,volumeDown:e.colorScheme.down.replace(`)`,`, 0.3)`).replace(`rgb(`,`rgba(`)||`${e.colorScheme.down}4D`};this.themeManager.setTheme(t)}e.pricePrecision!==void 0&&(this.tradingManager.setConfig({pricePrecision:e.pricePrecision}),this.alertManager.setPricePrecision(e.pricePrecision),this.streamManager?.priceLine.setPricePrecision(e.pricePrecision),this.crosshairHandler.setPricePrecision(e.pricePrecision)),this.syncRenderContext(),this.engine.requestRender()}getMarket(){return this.marketConfig}setPriceLimits(t){this.marketConfig&&((0,e.computePriceLimits)(t,this.marketConfig)&&(this.marketConfig.priceLimits={...this.marketConfig.priceLimits,referencePrice:t}),this.engine.requestRender())}getFeatures(){return this.features}setFeatures(t){Object.assign(this.features,t),t.crosshair===!1&&this.crosshairTooltip.hide(),t.grid!==void 0&&this.engine.requestRender(e.LayerType.Background),t.volume!==void 0&&(this.volumeRenderer.setVisible(t.volume),this.engine.requestRender(e.LayerType.Main)),t.drawings===!1&&this.drawingManager.setActiveTool(null),t.trading===!1&&(this.tradingManager.setOrders([]),this.tradingManager.setPositions([])),t.keyboard!==void 0&&this.keyboardHandler?.setEnabled(t.keyboard),this.engine.requestRender()}resize(){let e=this.engine.dprManager.readContainerSize();if(e.width<=0||e.height<=0)return;this.containerSizeCache=e,this.containerSizeCacheTime=Date.now();let t=this.engine.dprManager.getDpr();this.engine.layerManager.resize(e,t);let n=this.viewport.isAtEnd();this.viewport.resize(e.width,e.height),this.layoutManager.resize(e.width,e.height),this.updateViewportAndRender(n),this.eventBus.emit(`resize`,e)}destroy(){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=``}createChartRenderer(e){return n(e)}getDisplayData(){if(this.displayDataCache)return this.displayDataCache;let e=this.dataManager.getData();if(e.length===0)return e;let t=r(this.options.chartType,e);return this.displayDataCache=t,t}scheduleRender(){this.renderScheduled||(this.renderScheduled=!0,requestAnimationFrame(()=>{this.renderScheduled=!1;let e=this.getDisplayData();this.viewport.updateData(e,this.options.autoScale!==!1),this.syncRenderContext(),this.engine.requestRender()}))}updateViewportAndRender(e=!1){this.resolvedLayoutCache=null,this.panelInfoCache=null;let t=this.getResolvedLayout();this.viewport.setChartRect(t.mainChartRect);let n=this.getDisplayData();if(this.viewport.updateData(n,this.options.autoScale!==!1),this.options.autoScale!==!1){let e=this.viewport.getState(),t=this.indicatorEngine.getOverlayPriceRange(e.visibleRange.from,Math.min(e.visibleRange.to,n.length-1));if(t){let n=e.priceRange,r=Math.min(n.min,t.min),i=Math.max(n.max,t.max);if(r<n.min||i>n.max){let e=i-r||1;this.viewport.setPriceRange(r-e*.02,i+e*.02)}}}e&&this.viewport.scrollToEnd(),this.syncRenderContext(),this.engine.requestRender()}getResolvedLayout(){return this.resolvedLayoutCache||=this.layoutManager.resolve(),this.resolvedLayoutCache}cachedContainerSize(){let e=Date.now();return(!this.containerSizeCache||e-this.containerSizeCacheTime>500)&&(this.containerSizeCache=this.engine.dprManager.getContainerSize(),this.containerSizeCacheTime=e),this.containerSizeCache}buildPanelRenderInfos(){if(this.panelInfoCache)return this.panelInfoCache;let e=this.getResolvedLayout(),t=this.viewport.getState(),{from:n,to:r}=t.visibleRange,i=e.panels.map(e=>{let i=s(this.indicatorEngine.getOutput(e.config.id),n,r),a={x:e.rect.x,y:e.rect.y+20,width:e.rect.width,height:Math.max(0,e.rect.height-20)};return{instanceId:e.config.id,rect:e.rect,viewport:{...t,chartRect:a,priceRange:i}}});return this.panelInfoCache=i,i}syncRenderContext(){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();this.engine.setRenderContext({chartRenderer:this.chartRenderer,gridRenderer:this.features.grid?this.gridRenderer:null,priceAxis:this.features.priceAxis?this.priceAxis:null,timeAxis:this.features.timeAxis?this.timeAxis:null,crosshairHandler:this.features.crosshair?this.crosshairHandler:null,indicatorEngine:this.features.indicators?this.indicatorEngine:null,drawingRenderer:this.features.drawings?this.drawingRenderer:null,tradingRenderer:this.features.trading?this.tradingRenderer:null,currentPriceLine:this.streamManager?.priceLine??this.currentPriceLine,chartLegend:this.features.legend?this.chartLegend:null,volumeRenderer:this.features.volume?this.volumeRenderer:null,watermark:this.features.watermark?this.watermark:null,barCountdown:this.barCountdown,sessionBreaks:this.sessionBreaks,compareRenderer:this.compareRenderer,alertManager:this.features.alerts?this.alertManager:null,signalMarkerManager:this.signalMarkerManager,tradeZoneManager:this.tradeZoneManager,panels:t,priceLimits:this.buildPriceLimits(),timeAxisY:r,viewport:{...this.viewport.getState(),data:i},theme:this.themeManager.getTheme(),data:i,numberLocale:this.numberLocale})}buildPriceLimits(){if(!this.marketConfig?.priceLimits?.enabled||!this.marketConfig.priceLimits.referencePrice)return null;let t=(0,e.computePriceLimits)(this.marketConfig.priceLimits.referencePrice,this.marketConfig);return t?{...t,colors:this.marketConfig.colorScheme?{ceiling:this.marketConfig.colorScheme.ceiling,floor:this.marketConfig.colorScheme.floor,reference:this.marketConfig.colorScheme.reference}:void 0}:null}};Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return _}});
|
|
2
|
+
//# sourceMappingURL=Chart-Br_N-BCL.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Chart-Br_N-BCL.cjs","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 EquivolumeRenderer,\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 'equivolume':\r\n return new EquivolumeRenderer();\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 enabled: this.features.trading,\r\n contextMenu: { enabled: this.features.tradingContextMenu },\r\n });\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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"}
|
|
@@ -1,40 +1,41 @@
|
|
|
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 ne, CrosshairTooltip as re, CurrentPriceLine as ie, DataExporter as y, DrawingManager as ae, DrawingRenderer as oe,
|
|
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, EquivolumeRenderer as se, EventBus as ce, GridRenderer as le, HLCAreaRenderer as ue, HollowCandleRenderer as de, IndicatorEngine as b, InteractionManager as fe, KagiRenderer as x, KeyboardHandler as S, LineRenderer as C, LineWithMarkersRenderer as w, PanHandler as T, PointAndFigureRenderer as E, PriceAxis as D, RenderEngine as O, RenkoRenderer as k, ReplayManager as A, Screenshot as j, SessionBreaks as M, SignalMarkerManager as N, StepLineRenderer as P, StreamManager as F, TimeAxis as I, TradeZoneManager as L, TradingManager as R, TradingRenderer as z, UndoRedoManager as B, Viewport as V, VolumeCandleRenderer as pe, VolumeRenderer as me, Watermark as he, ZoomHandler as ge, registerBuiltInDrawingTools as _e, registerBuiltInIndicators as H, toHeikinAshi as ve, toKagi as ye, toLineBreak as be, toPointAndFigure as xe, toRangeBars as Se, toRenko as Ce } from "@tradecanvas/core";
|
|
3
3
|
//#region src/charts/ChartTypeStrategy.ts
|
|
4
|
-
function
|
|
4
|
+
function we(e) {
|
|
5
5
|
switch (e) {
|
|
6
6
|
case "candlestick":
|
|
7
7
|
case "heikinAshi":
|
|
8
8
|
case "lineBreak":
|
|
9
9
|
case "rangeBars": return new g();
|
|
10
|
-
case "line": return new
|
|
10
|
+
case "line": return new C();
|
|
11
11
|
case "area": return new p();
|
|
12
12
|
case "bar": return new ee();
|
|
13
|
-
case "hollowCandle": return new
|
|
13
|
+
case "hollowCandle": return new de();
|
|
14
14
|
case "baseline": return new h();
|
|
15
|
-
case "renko": return new
|
|
16
|
-
case "kagi": return new
|
|
17
|
-
case "pointAndFigure": return new
|
|
18
|
-
case "volumeCandles": return new
|
|
19
|
-
case "
|
|
20
|
-
case "
|
|
21
|
-
case "
|
|
15
|
+
case "renko": return new k();
|
|
16
|
+
case "kagi": return new x();
|
|
17
|
+
case "pointAndFigure": return new E();
|
|
18
|
+
case "volumeCandles": return new pe();
|
|
19
|
+
case "equivolume": return new se();
|
|
20
|
+
case "hlcArea": return new ue();
|
|
21
|
+
case "stepLine": return new P();
|
|
22
|
+
case "lineWithMarkers": return new w();
|
|
22
23
|
default: return new g();
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
|
-
function
|
|
26
|
+
function Te(e, t) {
|
|
26
27
|
if (t.length === 0) return t;
|
|
27
28
|
switch (e) {
|
|
28
|
-
case "heikinAshi": return
|
|
29
|
-
case "renko": return
|
|
29
|
+
case "heikinAshi": return ve(t);
|
|
30
|
+
case "renko": return Ce(t, {
|
|
30
31
|
brickSize: 0,
|
|
31
32
|
useATR: !0,
|
|
32
33
|
atrPeriod: 14
|
|
33
34
|
});
|
|
34
|
-
case "lineBreak": return
|
|
35
|
-
case "kagi": return
|
|
36
|
-
case "pointAndFigure": return
|
|
37
|
-
case "rangeBars": return
|
|
35
|
+
case "lineBreak": return be(t, 3);
|
|
36
|
+
case "kagi": return ye(t, 4);
|
|
37
|
+
case "pointAndFigure": return xe(t, U(t) * .01, 3);
|
|
38
|
+
case "rangeBars": return Se(t, { rangeSize: U(t) * .005 });
|
|
38
39
|
default: return t;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
@@ -49,7 +50,7 @@ var W = {
|
|
|
49
50
|
min: 0,
|
|
50
51
|
max: 100
|
|
51
52
|
}, G = .1;
|
|
52
|
-
function
|
|
53
|
+
function Ee(e, t, n) {
|
|
53
54
|
if (!e) return { ...W };
|
|
54
55
|
let r = Infinity, i = -Infinity, a = 0;
|
|
55
56
|
for (let [, o] of e.values) {
|
|
@@ -68,7 +69,7 @@ function Te(e, t, n) {
|
|
|
68
69
|
}
|
|
69
70
|
//#endregion
|
|
70
71
|
//#region src/state/AutoSaveScheduler.ts
|
|
71
|
-
var
|
|
72
|
+
var De = class {
|
|
72
73
|
timer = null;
|
|
73
74
|
delayMs = 0;
|
|
74
75
|
key = null;
|
|
@@ -286,7 +287,7 @@ var J = class {
|
|
|
286
287
|
registerIndicator(e) {
|
|
287
288
|
this.indicatorEngine.register(e);
|
|
288
289
|
}
|
|
289
|
-
},
|
|
290
|
+
}, Oe = class {
|
|
290
291
|
static version = "0.7.0";
|
|
291
292
|
engine;
|
|
292
293
|
viewport;
|
|
@@ -320,7 +321,7 @@ var J = class {
|
|
|
320
321
|
tradeZoneManager;
|
|
321
322
|
replayManager;
|
|
322
323
|
undoRedoManager;
|
|
323
|
-
autoSaveScheduler = new
|
|
324
|
+
autoSaveScheduler = new De((e) => this.saveState(e));
|
|
324
325
|
animator;
|
|
325
326
|
crosshairTooltip;
|
|
326
327
|
interactionManager;
|
|
@@ -371,19 +372,22 @@ var J = class {
|
|
|
371
372
|
logScale: n.logScale ?? !0,
|
|
372
373
|
timeframes: n.timeframes ?? [],
|
|
373
374
|
defaultTimeframeFavorites: n.defaultTimeframeFavorites ?? []
|
|
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
|
|
375
|
+
}, 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 ce(), H(this.indicatorEngine), this.drawingManager = new ae(), _e(this.drawingManager), this.drawingRenderer = new oe(this.drawingManager), this.drawingManager.setRequestRender(() => {
|
|
375
376
|
this.syncRenderContext(), this.engine.requestRender(r.Overlay), this.scheduleAutoSave();
|
|
376
377
|
}), this.drawingManager.setEventCallback((e, t) => {
|
|
377
378
|
this.eventBus.emit(e, t);
|
|
378
|
-
}), this.undoRedoManager = new
|
|
379
|
+
}), this.undoRedoManager = new B(), 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 R({
|
|
380
|
+
enabled: this.features.trading,
|
|
381
|
+
contextMenu: { enabled: this.features.tradingContextMenu }
|
|
382
|
+
}), this.tradingRenderer = new z(this.tradingManager), this.tradingManager.setContainer(e), this.tradingManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradingManager.setEventCallback((e, t) => {
|
|
379
383
|
this.eventBus.emit(e, t);
|
|
380
|
-
}), this.engine = new
|
|
384
|
+
}), this.engine = new O(e);
|
|
381
385
|
let i = this.engine.dprManager.getContainerSize();
|
|
382
|
-
this.viewport = new
|
|
386
|
+
this.viewport = new V(i.width, i.height, t.minBarSpacing ?? 2, t.maxBarSpacing ?? 30, t.rightMargin ?? 5), this.layoutManager.resize(i.width, i.height), this.engine.onContainerResize = (e) => {
|
|
383
387
|
if (e.width <= 0 || e.height <= 0) return;
|
|
384
388
|
let t = this.viewport.isAtEnd();
|
|
385
389
|
this.viewport.resize(e.width, e.height), this.layoutManager.resize(e.width, e.height), this.updateViewportAndRender(t);
|
|
386
|
-
}, this.chartRenderer = this.createChartRenderer(t.chartType), this.gridRenderer = new
|
|
390
|
+
}, this.chartRenderer = this.createChartRenderer(t.chartType), this.gridRenderer = new le(), t.grid?.visible === !1 && this.gridRenderer.setVisible(!1), this.priceAxis = new D(), this.priceAxis.setLocale(this.numberLocale), this.timeAxis = new I(), this.crosshairHandler = new ne(), this.crosshairHandler.setLocale(this.numberLocale), t.crosshair?.mode && this.crosshairHandler.setMode(t.crosshair.mode), this.crosshairHandler.setCallback((e, t) => {
|
|
387
391
|
if (e !== null && t) {
|
|
388
392
|
let n = this.dataManager.getData(), r = e < n.length ? n[e] : void 0;
|
|
389
393
|
this.chartLegend.setHoverBar(r ?? null), r && this.crosshairTooltip.show(t, r, this.themeManager.getTheme(), this.cachedContainerSize()), this.eventBus.emit("crosshairMove", {
|
|
@@ -392,12 +396,12 @@ var J = class {
|
|
|
392
396
|
barIndex: e
|
|
393
397
|
});
|
|
394
398
|
} else this.crosshairTooltip.hide(), this.chartLegend.setHoverBar(null);
|
|
395
|
-
}), this.chartLegend = new te(), this.chartLegend.setChartType(t.chartType), this.watermark = new
|
|
399
|
+
}), this.chartLegend = new te(), this.chartLegend.setChartType(t.chartType), this.watermark = new he(), t.watermark && this.watermark.setConfig(t.watermark), this.volumeRenderer = new me(), this.barCountdown = new m(), this.sessionBreaks = new M(), this.compareRenderer = new v(), t.sessionBreaks ? this.sessionBreaks.setConfig({
|
|
396
400
|
visible: t.sessionBreaks.visible ?? !0,
|
|
397
401
|
color: t.sessionBreaks.color,
|
|
398
402
|
lineStyle: t.sessionBreaks.lineStyle,
|
|
399
403
|
lineWidth: t.sessionBreaks.lineWidth
|
|
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
|
|
404
|
+
}) : 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 S({
|
|
401
405
|
scrollBars: (e) => {
|
|
402
406
|
let t = this.viewport.getState().barWidth + this.viewport.getState().barSpacing;
|
|
403
407
|
this.viewport.scrollBy(e * t), this.updateViewportAndRender();
|
|
@@ -424,7 +428,7 @@ var J = class {
|
|
|
424
428
|
price: e.price,
|
|
425
429
|
message: e.message
|
|
426
430
|
});
|
|
427
|
-
}), this.signalMarkerManager = new
|
|
431
|
+
}), this.signalMarkerManager = new N(), this.signalMarkerManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.signalMarkerManager.setDataGetter(() => this.dataManager.getData()), this.signalMarkerManager.on("added", (e) => {
|
|
428
432
|
this.eventBus.emit("signalMarkerAdd", {
|
|
429
433
|
id: e.id,
|
|
430
434
|
source: e.source,
|
|
@@ -432,16 +436,16 @@ var J = class {
|
|
|
432
436
|
});
|
|
433
437
|
}), this.signalMarkerManager.on("removed", (e) => {
|
|
434
438
|
this.eventBus.emit("signalMarkerRemove", { id: e });
|
|
435
|
-
}), this.tradeZoneManager = new
|
|
439
|
+
}), this.tradeZoneManager = new L(), this.tradeZoneManager.setRequestRender(() => this.engine.requestRender(r.Overlay)), this.tradeZoneManager.setDataGetter(() => this.dataManager.getData()), this.tradeZoneManager.on("added", (e) => {
|
|
436
440
|
this.eventBus.emit("tradeZoneAdd", {
|
|
437
441
|
id: e.id,
|
|
438
442
|
direction: e.direction
|
|
439
443
|
});
|
|
440
444
|
}), this.tradeZoneManager.on("removed", (e) => {
|
|
441
445
|
this.eventBus.emit("tradeZoneRemove", { id: e });
|
|
442
|
-
}), this.replayManager = new
|
|
446
|
+
}), this.replayManager = new A(), this.interactionManager = new fe(e), this.features.panning && this.interactionManager.setPanHandler(new T((e) => {
|
|
443
447
|
this.viewport.scrollBy(e), this.updateViewportAndRender();
|
|
444
|
-
})), this.features.zooming && this.interactionManager.setZoomHandler(new
|
|
448
|
+
})), this.features.zooming && this.interactionManager.setZoomHandler(new ge((e, t) => {
|
|
445
449
|
this.viewport.zoom(e, t), this.updateViewportAndRender();
|
|
446
450
|
})), this.features.crosshair && this.interactionManager.setCrosshairHandler(this.crosshairHandler), this.features.drawings && this.interactionManager.setDrawingManager(this.drawingManager, () => ({
|
|
447
451
|
...this.viewport.getState(),
|
|
@@ -628,7 +632,7 @@ var J = class {
|
|
|
628
632
|
this.features.trading && this.tradingManager.setConfig(e);
|
|
629
633
|
}
|
|
630
634
|
async connect(e) {
|
|
631
|
-
this.disconnectStream(), this.streamManager = new
|
|
635
|
+
this.disconnectStream(), this.streamManager = new F(), this.streamManager.on("snapshot", (e) => {
|
|
632
636
|
this.setData(e);
|
|
633
637
|
}), this.streamManager.on("barClose", (e) => {
|
|
634
638
|
this.dataManager.appendBar(e), this.crosshairHandler.setData(this.dataManager.getData()), this.autoScrollOnNewBar && this.viewport.scrollToEnd(), this.indicatorEngine.recalculateAll(this.dataManager.getData()), this.updateViewportAndRender();
|
|
@@ -808,13 +812,13 @@ var J = class {
|
|
|
808
812
|
this.chartLegend.setStatusText(e), this.engine.requestRender(r.UI);
|
|
809
813
|
}
|
|
810
814
|
screenshot(e) {
|
|
811
|
-
this.features.screenshot &&
|
|
815
|
+
this.features.screenshot && j.download(this.container, e, this.themeManager.getTheme().background);
|
|
812
816
|
}
|
|
813
817
|
screenshotDataURL() {
|
|
814
|
-
return this.features.screenshot ?
|
|
818
|
+
return this.features.screenshot ? j.toDataURL(this.container, this.themeManager.getTheme().background) : null;
|
|
815
819
|
}
|
|
816
820
|
async screenshotBlob() {
|
|
817
|
-
return this.features.screenshot ?
|
|
821
|
+
return this.features.screenshot ? j.toBlob(this.container, this.themeManager.getTheme().background) : null;
|
|
818
822
|
}
|
|
819
823
|
addAlert(e, t = "crossing", n) {
|
|
820
824
|
if (!this.features.alerts) return null;
|
|
@@ -992,13 +996,13 @@ var J = class {
|
|
|
992
996
|
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 = "";
|
|
993
997
|
}
|
|
994
998
|
createChartRenderer(e) {
|
|
995
|
-
return
|
|
999
|
+
return we(e);
|
|
996
1000
|
}
|
|
997
1001
|
getDisplayData() {
|
|
998
1002
|
if (this.displayDataCache) return this.displayDataCache;
|
|
999
1003
|
let e = this.dataManager.getData();
|
|
1000
1004
|
if (e.length === 0) return e;
|
|
1001
|
-
let t =
|
|
1005
|
+
let t = Te(this.options.chartType, e);
|
|
1002
1006
|
return this.displayDataCache = t, t;
|
|
1003
1007
|
}
|
|
1004
1008
|
scheduleRender() {
|
|
@@ -1035,7 +1039,7 @@ var J = class {
|
|
|
1035
1039
|
buildPanelRenderInfos() {
|
|
1036
1040
|
if (this.panelInfoCache) return this.panelInfoCache;
|
|
1037
1041
|
let e = this.getResolvedLayout(), t = this.viewport.getState(), { from: n, to: r } = t.visibleRange, i = e.panels.map((e) => {
|
|
1038
|
-
let i =
|
|
1042
|
+
let i = Ee(this.indicatorEngine.getOutput(e.config.id), n, r), a = {
|
|
1039
1043
|
x: e.rect.x,
|
|
1040
1044
|
y: e.rect.y + 20,
|
|
1041
1045
|
width: e.rect.width,
|
|
@@ -1100,6 +1104,6 @@ var J = class {
|
|
|
1100
1104
|
}
|
|
1101
1105
|
};
|
|
1102
1106
|
//#endregion
|
|
1103
|
-
export { J as a, Y as i, $ as n, Q as r,
|
|
1107
|
+
export { J as a, Y as i, $ as n, Q as r, Oe as t };
|
|
1104
1108
|
|
|
1105
|
-
//# sourceMappingURL=Chart-
|
|
1109
|
+
//# sourceMappingURL=Chart-Cn_TSMO7.js.map
|