@tradecanvas/vue 1.3.34 → 1.3.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +76 -76
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vue`),t=require(`@tradecanvas/chart`);var n=(0,e.defineComponent)({__name:`TradeCanvas`,props:{symbol:{default:`BTCUSDT`},timeframe:{default:`5m`},theme:{default:`dark`},chartType:{default:`candlestick`},indicators:{default:()=>[]},data:{},adapter:{},stream:{type:Boolean,default:!0},historyLimit:{default:500},features:{},autoScale:{type:Boolean,default:!0},signalMarkers:{},signalMarkerStyle:{},tradeZones:{},tradeZoneStyle:{},overrides:{},watermarkText:{},options:{}},emits:[`ready`,`crosshairMove`],setup(n,{expose:r,emit:i}){let a=n,o=i;function s(e){return e===`dark`?t.DARK_THEME:e===`light`?t.LIGHT_THEME:e}let c=(0,e.ref)(),l=null,u=new Map,d=null,f=e=>e.map(e=>typeof e==`string`?e:{id:e.id,...e.params?{params:{...e.params}}:{},...e.position?{position:e.position}:{}}),p=JSON.stringify(a.features??null);function m(){if(!l)return;if(!a.stream){d!==null&&l.disconnectStream(),d=null;return}if(a.data)return;let e=`${a.symbol}|${a.timeframe}`;if(d===e)return;let n=d!==null;d=e,n&&l.disconnectStream();let r=a.adapter??new t.BinanceAdapter;l.connect({adapter:r,symbol:a.symbol,timeframe:a.timeframe,historyLimit:a.historyLimit}),n&&a.watermarkText&&l.setWatermark(a.watermarkText)}function h(){return l}function g(e){l?.screenshot(e)}function _(){return l?.screenshotDataURL()??null}r({getChart:h,screenshot:g,screenshotDataURL:_}),(0,e.onMounted)(()=>{c.value&&(l=new t.Chart(c.value,{rightMargin:5,crosshair:{mode:`magnet`},...a.options,chartType:a.chartType,theme:s(a.theme),autoScale:a.autoScale,...a.watermarkText?{watermark:{text:a.watermarkText,fontSize:48,color:`rgba(255,255,255,0.03)`}}:{},features:{drawings:!0,drawingMagnet:!0,drawingUndoRedo:!0,indicators:!0,trading:!0,volume:!0,legend:!0,crosshair:!0,keyboard:!0,screenshot:!0,alerts:!0,barCountdown:!0,logScale:!0,watermark:!0,...a.options?.features,...a.features}}),a.data?
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`vue`),t=require(`@tradecanvas/chart`);var n=(0,e.defineComponent)({__name:`TradeCanvas`,props:{symbol:{default:`BTCUSDT`},timeframe:{default:`5m`},theme:{default:`dark`},chartType:{default:`candlestick`},indicators:{default:()=>[]},data:{},adapter:{},stream:{type:Boolean,default:!0},historyLimit:{default:500},features:{},autoScale:{type:Boolean,default:!0},signalMarkers:{},signalMarkerStyle:{},tradeZones:{},tradeZoneStyle:{},overrides:{},watermarkText:{},options:{}},emits:[`ready`,`crosshairMove`],setup(n,{expose:r,emit:i}){let a=n,o=i;function s(e){return e===`dark`?t.DARK_THEME:e===`light`?t.LIGHT_THEME:e}let c=(0,e.ref)(),l=null,u=new Map,d=null,f=e=>e.map(e=>typeof e==`string`?e:{id:e.id,...e.params?{params:{...e.params}}:{},...e.position?{position:e.position}:{}}),p=JSON.stringify(a.features??null);function m(){if(!l)return;if(!a.stream){d!==null&&l.disconnectStream(),d=null;return}if(a.data)return;let e=`${a.symbol}|${a.timeframe}`;if(d===e)return;let n=d!==null;d=e,n&&l.disconnectStream();let r=a.adapter??new t.BinanceAdapter;l.connect({adapter:r,symbol:a.symbol,timeframe:a.timeframe,historyLimit:a.historyLimit}),n&&a.watermarkText&&l.setWatermark(a.watermarkText)}function h(){return l}function g(e){l?.screenshot(e)}function _(){return l?.screenshotDataURL()??null}r({getChart:h,screenshot:g,screenshotDataURL:_}),(0,e.onMounted)(()=>{c.value&&(l=new t.Chart(c.value,{rightMargin:5,crosshair:{mode:`magnet`},...a.options,chartType:a.chartType,theme:s(a.theme),autoScale:a.autoScale,...a.watermarkText?{watermark:{text:a.watermarkText,fontSize:48,color:`rgba(255,255,255,0.03)`}}:{},features:{drawings:!0,drawingMagnet:!0,drawingUndoRedo:!0,indicators:!0,trading:!0,volume:!0,legend:!0,crosshair:!0,keyboard:!0,screenshot:!0,alerts:!0,barCountdown:!0,logScale:!0,watermark:!0,...a.options?.features,...a.features}}),a.data?x(l,a.data):m(),(0,t.syncIndicators)(l,f(a.indicators),u),a.signalMarkers&&l.setSignalMarkers(a.signalMarkers),a.signalMarkerStyle&&l.setSignalMarkerStyle(a.signalMarkerStyle),a.tradeZones&&l.setTradeZones(a.tradeZones),a.tradeZoneStyle&&l.setTradeZoneStyle(a.tradeZoneStyle),a.overrides&&l.setOverrides(a.overrides),o(`ready`,l))}),(0,e.onUnmounted)(()=>{l&&=(l.disconnectStream(),l.destroy(),null)}),(0,e.watch)(()=>[a.symbol,a.timeframe,!a.data,a.stream],m);let v=null,y=e=>e?`${e.time},${e.open},${e.high},${e.low},${e.close},${e.volume}`:``,b=e=>e?e.slice(-1-t.CORRECTABLE_BARS).map(y).join(`;`):``;function x(n,r){v=(0,t.feedBars)(n,(0,e.toRaw)(r),v)}return(0,e.watch)(()=>a.features,e=>{let t=JSON.stringify(e??null);t!==p&&(p=t,e&&l?.setFeatures({...e}))},{deep:!0}),(0,e.watch)(()=>a.theme,e=>{l?.setTheme(s(e))}),(0,e.watch)(()=>a.chartType,e=>{l?.setChartType(e)}),(0,e.watch)(()=>[a.data,a.data?.length,b(a.data)],()=>{l&&(a.data?x(l,a.data):v=null)}),(0,e.watch)(()=>a.indicators,e=>{l&&(0,t.syncIndicators)(l,f(e),u)},{deep:!0}),(0,e.watch)(()=>a.signalMarkers,e=>{e&&l?.setSignalMarkers(e)},{deep:!0}),(0,e.watch)(()=>a.signalMarkerStyle,e=>{e&&l?.setSignalMarkerStyle(e)},{deep:!0}),(0,e.watch)(()=>a.tradeZones,e=>{e&&l?.setTradeZones(e)},{deep:!0}),(0,e.watch)(()=>a.tradeZoneStyle,e=>{e&&l?.setTradeZoneStyle(e)},{deep:!0}),(0,e.watch)(()=>a.overrides,e=>{l?.setOverrides({...e})},{deep:!0}),(t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)(`div`,{ref_key:`containerEl`,ref:c,style:{width:`100%`,height:`100%`}},null,512))}});exports.TradeCanvas=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/TradeCanvas.vue","../src/TradeCanvas.vue"],"sourcesContent":["<template>\n <div ref=\"containerEl\" :style=\"{ width: '100%', height: '100%' }\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, toRaw } from 'vue';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n feedBars,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n ChartStyleOverrides,\n ChartOptions,\n IndicatorSpec,\n FedBars,\n} from '@tradecanvas/chart';\n\nconst props = withDefaults(\n defineProps<{\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /**\n * Bars: the chart shows these, and opens no stream of its own when it has\n * them at mount. Bars that go on from those given before, the last one\n * changed or bars added after it, go in as live ticks (the view isn't\n * reset): pushed onto the same array, changed in place, or in a new array.\n * Any other bars are a new series, as are yours after a stream gave the\n * chart bars of its own. An older bar changed needs a new array with a new\n * bar in its place.\n */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\n }>(),\n {\n symbol: 'BTCUSDT',\n timeframe: '5m' as TimeFrame,\n theme: 'dark',\n chartType: 'candlestick' as ChartType,\n indicators: () => [],\n stream: true,\n historyLimit: 500,\n autoScale: true,\n },\n);\n\nconst emit = defineEmits<{\n ready: [chart: Chart];\n crosshairMove: [payload: unknown];\n}>();\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme): Theme {\n if (theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\nconst containerEl = ref<HTMLDivElement>();\nlet chart: Chart | null = null;\nconst indicatorIds = new Map<string, string>();\n/** The stream open now (`symbol|timeframe`), or null. */\nlet streamKey: string | null = null;\n\n/** The specs as plain values (not Vue's proxies), for the chart to keep. */\nconst plainSpecs = (specs: readonly IndicatorSpec[]): IndicatorSpec[] =>\n specs.map((spec) => (typeof spec === 'string'\n ? spec\n : { id: spec.id, ...(spec.params ? { params: { ...spec.params } } : {}), ...(spec.position ? { position: spec.position } : {}) }));\n/** The features last applied, as text. */\nlet featuresKey = JSON.stringify(props.features ?? null);\n\n/** A stream of its own while it has no data; `stream: false` closes it. Data given later leaves it be. */\nfunction syncStream(): void {\n if (!chart) return;\n if (!props.stream) {\n if (streamKey !== null) chart.disconnectStream();\n streamKey = null;\n return;\n }\n if (props.data) return;\n const key = `${props.symbol}|${props.timeframe}`;\n if (streamKey === key) return;\n const opened = streamKey !== null;\n streamKey = key;\n if (opened) chart.disconnectStream();\n const adapter = props.adapter ?? new BinanceAdapter();\n chart.connect({ adapter, symbol: props.symbol, timeframe: props.timeframe, historyLimit: props.historyLimit });\n if (opened && props.watermarkText) chart.setWatermark(props.watermarkText);\n}\n\nfunction getChart(): Chart | null {\n return chart;\n}\n\nfunction screenshot(filename?: string): void {\n chart?.screenshot(filename);\n}\n\nfunction screenshotDataURL(): string | null {\n return chart?.screenshotDataURL() ?? null;\n}\n\ndefineExpose({ getChart, screenshot, screenshotDataURL });\n\nonMounted(() => {\n if (!containerEl.value) return;\n\n chart = new Chart(containerEl.value, {\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...props.options,\n chartType: props.chartType,\n theme: resolveTheme(props.theme),\n autoScale: props.autoScale,\n ...(props.watermarkText\n ? { watermark: { text: props.watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' } }\n : {}),\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...props.options?.features,\n ...props.features,\n },\n });\n\n if (props.data) feed(chart, props.data);\n else syncStream();\n\n // Apply initial reactive collections not covered by the constructor options.\n // Vue's watches aren't immediate, so without this the first render of\n // indicators / signal markers / trade zones would be dropped.\n syncIndicators(chart, plainSpecs(props.indicators), indicatorIds);\n if (props.signalMarkers) chart.setSignalMarkers(props.signalMarkers);\n if (props.signalMarkerStyle) chart.setSignalMarkerStyle(props.signalMarkerStyle);\n if (props.tradeZones) chart.setTradeZones(props.tradeZones);\n if (props.tradeZoneStyle) chart.setTradeZoneStyle(props.tradeZoneStyle);\n if (props.overrides) chart.setOverrides(props.overrides);\n\n emit('ready', chart);\n});\n\nonUnmounted(() => {\n if (chart) {\n chart.disconnectStream();\n chart.destroy();\n chart = null;\n }\n});\n\nwatch(() => [props.symbol, props.timeframe, !props.data, props.stream] as const, syncStream);\n/** The bars last given to the chart (`feedBars`). */\nlet fed: FedBars | null = null;\nconst barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');\n\n/**\n * Bars into the chart: bars that go on from those given before (a bar pushed\n * or the last one changed, in place or in a new array) go in as ticks, so the\n * view stays put and only the end is recalculated; anything else is a new\n * series. The chart gets plain copies, not Vue's proxies, to read in its frames.\n */\nfunction feed(target: Chart, data: readonly OHLCBar[]): void {\n fed = feedBars(target, toRaw(data), fed);\n}\n\nwatch(() => props.features, (f) => {\n const key = JSON.stringify(f ?? null);\n if (key === featuresKey) return;\n featuresKey = key;\n if (f) chart?.setFeatures({ ...f });\n}, { deep: true });\n\nwatch(() => props.theme, (t) => { chart?.setTheme(resolveTheme(t)); });\nwatch(() => props.chartType, (ct) => { chart?.setChartType(ct); });\n// The array, its length and the last bar's fields: a bar pushed or the\n// forming bar changed, without walking every bar as a deep watch does.\nwatch(\n () => [props.data, props.data?.length, barKey(props.data?.[props.data.length - 1])],\n () => {\n if (!chart) return;\n // Without data, the next bars are a new series: a stream may have come in between.\n if (props.data) feed(chart, props.data);\n else fed = null;\n },\n);\n\nwatch(\n () => props.indicators,\n (specs) => { if (chart) syncIndicators(chart, plainSpecs(specs), indicatorIds); },\n { deep: true },\n);\n\nwatch(() => props.signalMarkers, (m) => { if (m) chart?.setSignalMarkers(m); }, { deep: true });\nwatch(() => props.signalMarkerStyle, (s) => { if (s) chart?.setSignalMarkerStyle(s); }, { deep: true });\nwatch(() => props.tradeZones, (z) => { if (z) chart?.setTradeZones(z); }, { deep: true });\nwatch(() => props.tradeZoneStyle, (s) => { if (s) chart?.setTradeZoneStyle(s); }, { deep: true });\n// All of the host's overrides: keys left out of the prop are taken away.\nwatch(() => props.overrides, (o) => { chart?.setOverrides({ ...o }); }, { deep: true });\n</script>\n","<template>\n <div ref=\"containerEl\" :style=\"{ width: '100%', height: '100%' }\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, toRaw } from 'vue';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n feedBars,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n ChartStyleOverrides,\n ChartOptions,\n IndicatorSpec,\n FedBars,\n} from '@tradecanvas/chart';\n\nconst props = withDefaults(\n defineProps<{\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /**\n * Bars: the chart shows these, and opens no stream of its own when it has\n * them at mount. Bars that go on from those given before, the last one\n * changed or bars added after it, go in as live ticks (the view isn't\n * reset): pushed onto the same array, changed in place, or in a new array.\n * Any other bars are a new series, as are yours after a stream gave the\n * chart bars of its own. An older bar changed needs a new array with a new\n * bar in its place.\n */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\n }>(),\n {\n symbol: 'BTCUSDT',\n timeframe: '5m' as TimeFrame,\n theme: 'dark',\n chartType: 'candlestick' as ChartType,\n indicators: () => [],\n stream: true,\n historyLimit: 500,\n autoScale: true,\n },\n);\n\nconst emit = defineEmits<{\n ready: [chart: Chart];\n crosshairMove: [payload: unknown];\n}>();\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme): Theme {\n if (theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\nconst containerEl = ref<HTMLDivElement>();\nlet chart: Chart | null = null;\nconst indicatorIds = new Map<string, string>();\n/** The stream open now (`symbol|timeframe`), or null. */\nlet streamKey: string | null = null;\n\n/** The specs as plain values (not Vue's proxies), for the chart to keep. */\nconst plainSpecs = (specs: readonly IndicatorSpec[]): IndicatorSpec[] =>\n specs.map((spec) => (typeof spec === 'string'\n ? spec\n : { id: spec.id, ...(spec.params ? { params: { ...spec.params } } : {}), ...(spec.position ? { position: spec.position } : {}) }));\n/** The features last applied, as text. */\nlet featuresKey = JSON.stringify(props.features ?? null);\n\n/** A stream of its own while it has no data; `stream: false` closes it. Data given later leaves it be. */\nfunction syncStream(): void {\n if (!chart) return;\n if (!props.stream) {\n if (streamKey !== null) chart.disconnectStream();\n streamKey = null;\n return;\n }\n if (props.data) return;\n const key = `${props.symbol}|${props.timeframe}`;\n if (streamKey === key) return;\n const opened = streamKey !== null;\n streamKey = key;\n if (opened) chart.disconnectStream();\n const adapter = props.adapter ?? new BinanceAdapter();\n chart.connect({ adapter, symbol: props.symbol, timeframe: props.timeframe, historyLimit: props.historyLimit });\n if (opened && props.watermarkText) chart.setWatermark(props.watermarkText);\n}\n\nfunction getChart(): Chart | null {\n return chart;\n}\n\nfunction screenshot(filename?: string): void {\n chart?.screenshot(filename);\n}\n\nfunction screenshotDataURL(): string | null {\n return chart?.screenshotDataURL() ?? null;\n}\n\ndefineExpose({ getChart, screenshot, screenshotDataURL });\n\nonMounted(() => {\n if (!containerEl.value) return;\n\n chart = new Chart(containerEl.value, {\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...props.options,\n chartType: props.chartType,\n theme: resolveTheme(props.theme),\n autoScale: props.autoScale,\n ...(props.watermarkText\n ? { watermark: { text: props.watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' } }\n : {}),\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...props.options?.features,\n ...props.features,\n },\n });\n\n if (props.data) feed(chart, props.data);\n else syncStream();\n\n // Apply initial reactive collections not covered by the constructor options.\n // Vue's watches aren't immediate, so without this the first render of\n // indicators / signal markers / trade zones would be dropped.\n syncIndicators(chart, plainSpecs(props.indicators), indicatorIds);\n if (props.signalMarkers) chart.setSignalMarkers(props.signalMarkers);\n if (props.signalMarkerStyle) chart.setSignalMarkerStyle(props.signalMarkerStyle);\n if (props.tradeZones) chart.setTradeZones(props.tradeZones);\n if (props.tradeZoneStyle) chart.setTradeZoneStyle(props.tradeZoneStyle);\n if (props.overrides) chart.setOverrides(props.overrides);\n\n emit('ready', chart);\n});\n\nonUnmounted(() => {\n if (chart) {\n chart.disconnectStream();\n chart.destroy();\n chart = null;\n }\n});\n\nwatch(() => [props.symbol, props.timeframe, !props.data, props.stream] as const, syncStream);\n/** The bars last given to the chart (`feedBars`). */\nlet fed: FedBars | null = null;\nconst barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');\n\n/**\n * Bars into the chart: bars that go on from those given before (a bar pushed\n * or the last one changed, in place or in a new array) go in as ticks, so the\n * view stays put and only the end is recalculated; anything else is a new\n * series. The chart gets plain copies, not Vue's proxies, to read in its frames.\n */\nfunction feed(target: Chart, data: readonly OHLCBar[]): void {\n fed = feedBars(target, toRaw(data), fed);\n}\n\nwatch(() => props.features, (f) => {\n const key = JSON.stringify(f ?? null);\n if (key === featuresKey) return;\n featuresKey = key;\n if (f) chart?.setFeatures({ ...f });\n}, { deep: true });\n\nwatch(() => props.theme, (t) => { chart?.setTheme(resolveTheme(t)); });\nwatch(() => props.chartType, (ct) => { chart?.setChartType(ct); });\n// The array, its length and the last bar's fields: a bar pushed or the\n// forming bar changed, without walking every bar as a deep watch does.\nwatch(\n () => [props.data, props.data?.length, barKey(props.data?.[props.data.length - 1])],\n () => {\n if (!chart) return;\n // Without data, the next bars are a new series: a stream may have come in between.\n if (props.data) feed(chart, props.data);\n else fed = null;\n },\n);\n\nwatch(\n () => props.indicators,\n (specs) => { if (chart) syncIndicators(chart, plainSpecs(specs), indicatorIds); },\n { deep: true },\n);\n\nwatch(() => props.signalMarkers, (m) => { if (m) chart?.setSignalMarkers(m); }, { deep: true });\nwatch(() => props.signalMarkerStyle, (s) => { if (s) chart?.setSignalMarkerStyle(s); }, { deep: true });\nwatch(() => props.tradeZones, (z) => { if (z) chart?.setTradeZones(z); }, { deep: true });\nwatch(() => props.tradeZoneStyle, (s) => { if (s) chart?.setTradeZoneStyle(s); }, { deep: true });\n// All of the host's overrides: keys left out of the prop are taken away.\nwatch(() => props.overrides, (o) => { chart?.setOverrides({ ...o }); }, { deep: true });\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/TradeCanvas.vue","../src/TradeCanvas.vue"],"sourcesContent":["<template>\n <div ref=\"containerEl\" :style=\"{ width: '100%', height: '100%' }\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, toRaw } from 'vue';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n feedBars,\n CORRECTABLE_BARS,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n ChartStyleOverrides,\n ChartOptions,\n IndicatorSpec,\n FedBars,\n} from '@tradecanvas/chart';\n\nconst props = withDefaults(\n defineProps<{\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /**\n * Bars: the chart shows these, and opens no stream of its own when it has\n * them at mount. Bars that go on from those given before, the last one\n * changed or bars added after it, go in as live ticks (the view isn't\n * reset): pushed onto the same array, changed in place, or in a new array.\n * A change to one of the last three bars before the forming one, its time\n * the same, goes in as a correction (`updateBar`), the view kept too.\n * Any other bars are a new series, as are yours after a stream gave the\n * chart bars of its own. A bar further back changed in place isn't seen;\n * in a new array it makes a new series.\n */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\n }>(),\n {\n symbol: 'BTCUSDT',\n timeframe: '5m' as TimeFrame,\n theme: 'dark',\n chartType: 'candlestick' as ChartType,\n indicators: () => [],\n stream: true,\n historyLimit: 500,\n autoScale: true,\n },\n);\n\nconst emit = defineEmits<{\n ready: [chart: Chart];\n crosshairMove: [payload: unknown];\n}>();\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme): Theme {\n if (theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\nconst containerEl = ref<HTMLDivElement>();\nlet chart: Chart | null = null;\nconst indicatorIds = new Map<string, string>();\n/** The stream open now (`symbol|timeframe`), or null. */\nlet streamKey: string | null = null;\n\n/** The specs as plain values (not Vue's proxies), for the chart to keep. */\nconst plainSpecs = (specs: readonly IndicatorSpec[]): IndicatorSpec[] =>\n specs.map((spec) => (typeof spec === 'string'\n ? spec\n : { id: spec.id, ...(spec.params ? { params: { ...spec.params } } : {}), ...(spec.position ? { position: spec.position } : {}) }));\n/** The features last applied, as text. */\nlet featuresKey = JSON.stringify(props.features ?? null);\n\n/** A stream of its own while it has no data; `stream: false` closes it. Data given later leaves it be. */\nfunction syncStream(): void {\n if (!chart) return;\n if (!props.stream) {\n if (streamKey !== null) chart.disconnectStream();\n streamKey = null;\n return;\n }\n if (props.data) return;\n const key = `${props.symbol}|${props.timeframe}`;\n if (streamKey === key) return;\n const opened = streamKey !== null;\n streamKey = key;\n if (opened) chart.disconnectStream();\n const adapter = props.adapter ?? new BinanceAdapter();\n chart.connect({ adapter, symbol: props.symbol, timeframe: props.timeframe, historyLimit: props.historyLimit });\n if (opened && props.watermarkText) chart.setWatermark(props.watermarkText);\n}\n\nfunction getChart(): Chart | null {\n return chart;\n}\n\nfunction screenshot(filename?: string): void {\n chart?.screenshot(filename);\n}\n\nfunction screenshotDataURL(): string | null {\n return chart?.screenshotDataURL() ?? null;\n}\n\ndefineExpose({ getChart, screenshot, screenshotDataURL });\n\nonMounted(() => {\n if (!containerEl.value) return;\n\n chart = new Chart(containerEl.value, {\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...props.options,\n chartType: props.chartType,\n theme: resolveTheme(props.theme),\n autoScale: props.autoScale,\n ...(props.watermarkText\n ? { watermark: { text: props.watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' } }\n : {}),\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...props.options?.features,\n ...props.features,\n },\n });\n\n if (props.data) feed(chart, props.data);\n else syncStream();\n\n // Apply initial reactive collections not covered by the constructor options.\n // Vue's watches aren't immediate, so without this the first render of\n // indicators / signal markers / trade zones would be dropped.\n syncIndicators(chart, plainSpecs(props.indicators), indicatorIds);\n if (props.signalMarkers) chart.setSignalMarkers(props.signalMarkers);\n if (props.signalMarkerStyle) chart.setSignalMarkerStyle(props.signalMarkerStyle);\n if (props.tradeZones) chart.setTradeZones(props.tradeZones);\n if (props.tradeZoneStyle) chart.setTradeZoneStyle(props.tradeZoneStyle);\n if (props.overrides) chart.setOverrides(props.overrides);\n\n emit('ready', chart);\n});\n\nonUnmounted(() => {\n if (chart) {\n chart.disconnectStream();\n chart.destroy();\n chart = null;\n }\n});\n\nwatch(() => [props.symbol, props.timeframe, !props.data, props.stream] as const, syncStream);\n/** The bars last given to the chart (`feedBars`). */\nlet fed: FedBars | null = null;\nconst barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');\n/** The fields of the forming bar and of the bars before it a change to is a correction (`CORRECTABLE_BARS`). */\nconst tailKey = (bars: readonly OHLCBar[] | undefined) => (bars ? bars.slice(-1 - CORRECTABLE_BARS).map(barKey).join(';') : '');\n\n/**\n * Bars into the chart: bars that go on from those given before (a bar pushed\n * or the last one changed, in place or in a new array) go in as ticks, so the\n * view stays put and only the end is recalculated; anything else is a new\n * series. The chart gets plain copies, not Vue's proxies, to read in its frames.\n */\nfunction feed(target: Chart, data: readonly OHLCBar[]): void {\n fed = feedBars(target, toRaw(data), fed);\n}\n\nwatch(() => props.features, (f) => {\n const key = JSON.stringify(f ?? null);\n if (key === featuresKey) return;\n featuresKey = key;\n if (f) chart?.setFeatures({ ...f });\n}, { deep: true });\n\nwatch(() => props.theme, (t) => { chart?.setTheme(resolveTheme(t)); });\nwatch(() => props.chartType, (ct) => { chart?.setChartType(ct); });\n// The array, its length and the fields of its last bars: a bar pushed, the\n// forming bar changed or one just before it corrected, without walking\n// every bar as a deep watch does.\nwatch(\n () => [props.data, props.data?.length, tailKey(props.data)],\n () => {\n if (!chart) return;\n // Without data, the next bars are a new series: a stream may have come in between.\n if (props.data) feed(chart, props.data);\n else fed = null;\n },\n);\n\nwatch(\n () => props.indicators,\n (specs) => { if (chart) syncIndicators(chart, plainSpecs(specs), indicatorIds); },\n { deep: true },\n);\n\nwatch(() => props.signalMarkers, (m) => { if (m) chart?.setSignalMarkers(m); }, { deep: true });\nwatch(() => props.signalMarkerStyle, (s) => { if (s) chart?.setSignalMarkerStyle(s); }, { deep: true });\nwatch(() => props.tradeZones, (z) => { if (z) chart?.setTradeZones(z); }, { deep: true });\nwatch(() => props.tradeZoneStyle, (s) => { if (s) chart?.setTradeZoneStyle(s); }, { deep: true });\n// All of the host's overrides: keys left out of the prop are taken away.\nwatch(() => props.overrides, (o) => { chart?.setOverrides({ ...o }); }, { deep: true });\n</script>\n","<template>\n <div ref=\"containerEl\" :style=\"{ width: '100%', height: '100%' }\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, toRaw } from 'vue';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n feedBars,\n CORRECTABLE_BARS,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n ChartStyleOverrides,\n ChartOptions,\n IndicatorSpec,\n FedBars,\n} from '@tradecanvas/chart';\n\nconst props = withDefaults(\n defineProps<{\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /**\n * Bars: the chart shows these, and opens no stream of its own when it has\n * them at mount. Bars that go on from those given before, the last one\n * changed or bars added after it, go in as live ticks (the view isn't\n * reset): pushed onto the same array, changed in place, or in a new array.\n * A change to one of the last three bars before the forming one, its time\n * the same, goes in as a correction (`updateBar`), the view kept too.\n * Any other bars are a new series, as are yours after a stream gave the\n * chart bars of its own. A bar further back changed in place isn't seen;\n * in a new array it makes a new series.\n */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\n }>(),\n {\n symbol: 'BTCUSDT',\n timeframe: '5m' as TimeFrame,\n theme: 'dark',\n chartType: 'candlestick' as ChartType,\n indicators: () => [],\n stream: true,\n historyLimit: 500,\n autoScale: true,\n },\n);\n\nconst emit = defineEmits<{\n ready: [chart: Chart];\n crosshairMove: [payload: unknown];\n}>();\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme): Theme {\n if (theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\nconst containerEl = ref<HTMLDivElement>();\nlet chart: Chart | null = null;\nconst indicatorIds = new Map<string, string>();\n/** The stream open now (`symbol|timeframe`), or null. */\nlet streamKey: string | null = null;\n\n/** The specs as plain values (not Vue's proxies), for the chart to keep. */\nconst plainSpecs = (specs: readonly IndicatorSpec[]): IndicatorSpec[] =>\n specs.map((spec) => (typeof spec === 'string'\n ? spec\n : { id: spec.id, ...(spec.params ? { params: { ...spec.params } } : {}), ...(spec.position ? { position: spec.position } : {}) }));\n/** The features last applied, as text. */\nlet featuresKey = JSON.stringify(props.features ?? null);\n\n/** A stream of its own while it has no data; `stream: false` closes it. Data given later leaves it be. */\nfunction syncStream(): void {\n if (!chart) return;\n if (!props.stream) {\n if (streamKey !== null) chart.disconnectStream();\n streamKey = null;\n return;\n }\n if (props.data) return;\n const key = `${props.symbol}|${props.timeframe}`;\n if (streamKey === key) return;\n const opened = streamKey !== null;\n streamKey = key;\n if (opened) chart.disconnectStream();\n const adapter = props.adapter ?? new BinanceAdapter();\n chart.connect({ adapter, symbol: props.symbol, timeframe: props.timeframe, historyLimit: props.historyLimit });\n if (opened && props.watermarkText) chart.setWatermark(props.watermarkText);\n}\n\nfunction getChart(): Chart | null {\n return chart;\n}\n\nfunction screenshot(filename?: string): void {\n chart?.screenshot(filename);\n}\n\nfunction screenshotDataURL(): string | null {\n return chart?.screenshotDataURL() ?? null;\n}\n\ndefineExpose({ getChart, screenshot, screenshotDataURL });\n\nonMounted(() => {\n if (!containerEl.value) return;\n\n chart = new Chart(containerEl.value, {\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...props.options,\n chartType: props.chartType,\n theme: resolveTheme(props.theme),\n autoScale: props.autoScale,\n ...(props.watermarkText\n ? { watermark: { text: props.watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' } }\n : {}),\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...props.options?.features,\n ...props.features,\n },\n });\n\n if (props.data) feed(chart, props.data);\n else syncStream();\n\n // Apply initial reactive collections not covered by the constructor options.\n // Vue's watches aren't immediate, so without this the first render of\n // indicators / signal markers / trade zones would be dropped.\n syncIndicators(chart, plainSpecs(props.indicators), indicatorIds);\n if (props.signalMarkers) chart.setSignalMarkers(props.signalMarkers);\n if (props.signalMarkerStyle) chart.setSignalMarkerStyle(props.signalMarkerStyle);\n if (props.tradeZones) chart.setTradeZones(props.tradeZones);\n if (props.tradeZoneStyle) chart.setTradeZoneStyle(props.tradeZoneStyle);\n if (props.overrides) chart.setOverrides(props.overrides);\n\n emit('ready', chart);\n});\n\nonUnmounted(() => {\n if (chart) {\n chart.disconnectStream();\n chart.destroy();\n chart = null;\n }\n});\n\nwatch(() => [props.symbol, props.timeframe, !props.data, props.stream] as const, syncStream);\n/** The bars last given to the chart (`feedBars`). */\nlet fed: FedBars | null = null;\nconst barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');\n/** The fields of the forming bar and of the bars before it a change to is a correction (`CORRECTABLE_BARS`). */\nconst tailKey = (bars: readonly OHLCBar[] | undefined) => (bars ? bars.slice(-1 - CORRECTABLE_BARS).map(barKey).join(';') : '');\n\n/**\n * Bars into the chart: bars that go on from those given before (a bar pushed\n * or the last one changed, in place or in a new array) go in as ticks, so the\n * view stays put and only the end is recalculated; anything else is a new\n * series. The chart gets plain copies, not Vue's proxies, to read in its frames.\n */\nfunction feed(target: Chart, data: readonly OHLCBar[]): void {\n fed = feedBars(target, toRaw(data), fed);\n}\n\nwatch(() => props.features, (f) => {\n const key = JSON.stringify(f ?? null);\n if (key === featuresKey) return;\n featuresKey = key;\n if (f) chart?.setFeatures({ ...f });\n}, { deep: true });\n\nwatch(() => props.theme, (t) => { chart?.setTheme(resolveTheme(t)); });\nwatch(() => props.chartType, (ct) => { chart?.setChartType(ct); });\n// The array, its length and the fields of its last bars: a bar pushed, the\n// forming bar changed or one just before it corrected, without walking\n// every bar as a deep watch does.\nwatch(\n () => [props.data, props.data?.length, tailKey(props.data)],\n () => {\n if (!chart) return;\n // Without data, the next bars are a new series: a stream may have come in between.\n if (props.data) feed(chart, props.data);\n else fed = null;\n },\n);\n\nwatch(\n () => props.indicators,\n (specs) => { if (chart) syncIndicators(chart, plainSpecs(specs), indicatorIds); },\n { deep: true },\n);\n\nwatch(() => props.signalMarkers, (m) => { if (m) chart?.setSignalMarkers(m); }, { deep: true });\nwatch(() => props.signalMarkerStyle, (s) => { if (s) chart?.setSignalMarkerStyle(s); }, { deep: true });\nwatch(() => props.tradeZones, (z) => { if (z) chart?.setTradeZones(z); }, { deep: true });\nwatch(() => props.tradeZoneStyle, (s) => { if (s) chart?.setTradeZoneStyle(s); }, { deep: true });\n// All of the host's overrides: keys left out of the prop are taken away.\nwatch(() => props.overrides, (o) => { chart?.setOverrides({ ...o }); }, { deep: true });\n</script>\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -29,9 +29,11 @@ declare type __VLS_Props = {
|
|
|
29
29
|
* them at mount. Bars that go on from those given before, the last one
|
|
30
30
|
* changed or bars added after it, go in as live ticks (the view isn't
|
|
31
31
|
* reset): pushed onto the same array, changed in place, or in a new array.
|
|
32
|
+
* A change to one of the last three bars before the forming one, its time
|
|
33
|
+
* the same, goes in as a correction (`updateBar`), the view kept too.
|
|
32
34
|
* Any other bars are a new series, as are yours after a stream gave the
|
|
33
|
-
* chart bars of its own.
|
|
34
|
-
*
|
|
35
|
+
* chart bars of its own. A bar further back changed in place isn't seen;
|
|
36
|
+
* in a new array it makes a new series.
|
|
35
37
|
*/
|
|
36
38
|
data?: OHLCBar[];
|
|
37
39
|
adapter?: DataAdapter;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createElementBlock as e, defineComponent as t, onMounted as n, onUnmounted as r, openBlock as i, ref as a, toRaw as o, watch as s } from "vue";
|
|
2
|
-
import { BinanceAdapter as c,
|
|
2
|
+
import { BinanceAdapter as c, CORRECTABLE_BARS as l, Chart as u, DARK_THEME as d, LIGHT_THEME as f, feedBars as p, syncIndicators as m } from "@tradecanvas/chart";
|
|
3
3
|
//#endregion
|
|
4
4
|
//#region src/TradeCanvas.vue
|
|
5
|
-
var
|
|
5
|
+
var h = /* @__PURE__ */ t({
|
|
6
6
|
__name: "TradeCanvas",
|
|
7
7
|
props: {
|
|
8
8
|
symbol: { default: "BTCUSDT" },
|
|
@@ -31,58 +31,58 @@ var m = /* @__PURE__ */ t({
|
|
|
31
31
|
options: {}
|
|
32
32
|
},
|
|
33
33
|
emits: ["ready", "crosshairMove"],
|
|
34
|
-
setup(t, { expose:
|
|
35
|
-
let
|
|
36
|
-
function
|
|
37
|
-
return e === "dark" ?
|
|
34
|
+
setup(t, { expose: h, emit: g }) {
|
|
35
|
+
let _ = t, v = g;
|
|
36
|
+
function y(e) {
|
|
37
|
+
return e === "dark" ? d : e === "light" ? f : e;
|
|
38
38
|
}
|
|
39
|
-
let
|
|
39
|
+
let b = a(), x = null, S = /* @__PURE__ */ new Map(), C = null, w = (e) => e.map((e) => typeof e == "string" ? e : {
|
|
40
40
|
id: e.id,
|
|
41
41
|
...e.params ? { params: { ...e.params } } : {},
|
|
42
42
|
...e.position ? { position: e.position } : {}
|
|
43
|
-
}),
|
|
44
|
-
function
|
|
45
|
-
if (!
|
|
46
|
-
if (!
|
|
47
|
-
|
|
43
|
+
}), T = JSON.stringify(_.features ?? null);
|
|
44
|
+
function E() {
|
|
45
|
+
if (!x) return;
|
|
46
|
+
if (!_.stream) {
|
|
47
|
+
C !== null && x.disconnectStream(), C = null;
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
if (
|
|
51
|
-
let e = `${
|
|
52
|
-
if (
|
|
53
|
-
let t =
|
|
54
|
-
|
|
55
|
-
let n =
|
|
56
|
-
|
|
50
|
+
if (_.data) return;
|
|
51
|
+
let e = `${_.symbol}|${_.timeframe}`;
|
|
52
|
+
if (C === e) return;
|
|
53
|
+
let t = C !== null;
|
|
54
|
+
C = e, t && x.disconnectStream();
|
|
55
|
+
let n = _.adapter ?? new c();
|
|
56
|
+
x.connect({
|
|
57
57
|
adapter: n,
|
|
58
|
-
symbol:
|
|
59
|
-
timeframe:
|
|
60
|
-
historyLimit:
|
|
61
|
-
}), t &&
|
|
58
|
+
symbol: _.symbol,
|
|
59
|
+
timeframe: _.timeframe,
|
|
60
|
+
historyLimit: _.historyLimit
|
|
61
|
+
}), t && _.watermarkText && x.setWatermark(_.watermarkText);
|
|
62
62
|
}
|
|
63
|
-
function
|
|
64
|
-
return
|
|
63
|
+
function D() {
|
|
64
|
+
return x;
|
|
65
65
|
}
|
|
66
|
-
function
|
|
67
|
-
|
|
66
|
+
function O(e) {
|
|
67
|
+
x?.screenshot(e);
|
|
68
68
|
}
|
|
69
|
-
function
|
|
70
|
-
return
|
|
69
|
+
function k() {
|
|
70
|
+
return x?.screenshotDataURL() ?? null;
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
getChart:
|
|
74
|
-
screenshot:
|
|
75
|
-
screenshotDataURL:
|
|
72
|
+
h({
|
|
73
|
+
getChart: D,
|
|
74
|
+
screenshot: O,
|
|
75
|
+
screenshotDataURL: k
|
|
76
76
|
}), n(() => {
|
|
77
|
-
|
|
77
|
+
b.value && (x = new u(b.value, {
|
|
78
78
|
rightMargin: 5,
|
|
79
79
|
crosshair: { mode: "magnet" },
|
|
80
|
-
...
|
|
81
|
-
chartType:
|
|
82
|
-
theme:
|
|
83
|
-
autoScale:
|
|
84
|
-
...
|
|
85
|
-
text:
|
|
80
|
+
..._.options,
|
|
81
|
+
chartType: _.chartType,
|
|
82
|
+
theme: y(_.theme),
|
|
83
|
+
autoScale: _.autoScale,
|
|
84
|
+
..._.watermarkText ? { watermark: {
|
|
85
|
+
text: _.watermarkText,
|
|
86
86
|
fontSize: 48,
|
|
87
87
|
color: "rgba(255,255,255,0.03)"
|
|
88
88
|
} } : {},
|
|
@@ -101,50 +101,50 @@ var m = /* @__PURE__ */ t({
|
|
|
101
101
|
barCountdown: !0,
|
|
102
102
|
logScale: !0,
|
|
103
103
|
watermark: !0,
|
|
104
|
-
...
|
|
105
|
-
...
|
|
104
|
+
..._.options?.features,
|
|
105
|
+
..._.features
|
|
106
106
|
}
|
|
107
|
-
}),
|
|
107
|
+
}), _.data ? N(x, _.data) : E(), m(x, w(_.indicators), S), _.signalMarkers && x.setSignalMarkers(_.signalMarkers), _.signalMarkerStyle && x.setSignalMarkerStyle(_.signalMarkerStyle), _.tradeZones && x.setTradeZones(_.tradeZones), _.tradeZoneStyle && x.setTradeZoneStyle(_.tradeZoneStyle), _.overrides && x.setOverrides(_.overrides), v("ready", x));
|
|
108
108
|
}), r(() => {
|
|
109
|
-
|
|
109
|
+
x &&= (x.disconnectStream(), x.destroy(), null);
|
|
110
110
|
}), s(() => [
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
!
|
|
114
|
-
|
|
115
|
-
],
|
|
116
|
-
let
|
|
117
|
-
function
|
|
118
|
-
|
|
111
|
+
_.symbol,
|
|
112
|
+
_.timeframe,
|
|
113
|
+
!_.data,
|
|
114
|
+
_.stream
|
|
115
|
+
], E);
|
|
116
|
+
let A = null, j = (e) => e ? `${e.time},${e.open},${e.high},${e.low},${e.close},${e.volume}` : "", M = (e) => e ? e.slice(-1 - l).map(j).join(";") : "";
|
|
117
|
+
function N(e, t) {
|
|
118
|
+
A = p(e, o(t), A);
|
|
119
119
|
}
|
|
120
|
-
return s(() =>
|
|
120
|
+
return s(() => _.features, (e) => {
|
|
121
121
|
let t = JSON.stringify(e ?? null);
|
|
122
|
-
t !==
|
|
123
|
-
}, { deep: !0 }), s(() =>
|
|
124
|
-
|
|
125
|
-
}), s(() =>
|
|
126
|
-
|
|
122
|
+
t !== T && (T = t, e && x?.setFeatures({ ...e }));
|
|
123
|
+
}, { deep: !0 }), s(() => _.theme, (e) => {
|
|
124
|
+
x?.setTheme(y(e));
|
|
125
|
+
}), s(() => _.chartType, (e) => {
|
|
126
|
+
x?.setChartType(e);
|
|
127
127
|
}), s(() => [
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
_.data,
|
|
129
|
+
_.data?.length,
|
|
130
|
+
M(_.data)
|
|
131
131
|
], () => {
|
|
132
|
-
|
|
133
|
-
}), s(() =>
|
|
134
|
-
|
|
135
|
-
}, { deep: !0 }), s(() =>
|
|
136
|
-
e &&
|
|
137
|
-
}, { deep: !0 }), s(() =>
|
|
138
|
-
e &&
|
|
139
|
-
}, { deep: !0 }), s(() =>
|
|
140
|
-
e &&
|
|
141
|
-
}, { deep: !0 }), s(() =>
|
|
142
|
-
e &&
|
|
143
|
-
}, { deep: !0 }), s(() =>
|
|
144
|
-
|
|
132
|
+
x && (_.data ? N(x, _.data) : A = null);
|
|
133
|
+
}), s(() => _.indicators, (e) => {
|
|
134
|
+
x && m(x, w(e), S);
|
|
135
|
+
}, { deep: !0 }), s(() => _.signalMarkers, (e) => {
|
|
136
|
+
e && x?.setSignalMarkers(e);
|
|
137
|
+
}, { deep: !0 }), s(() => _.signalMarkerStyle, (e) => {
|
|
138
|
+
e && x?.setSignalMarkerStyle(e);
|
|
139
|
+
}, { deep: !0 }), s(() => _.tradeZones, (e) => {
|
|
140
|
+
e && x?.setTradeZones(e);
|
|
141
|
+
}, { deep: !0 }), s(() => _.tradeZoneStyle, (e) => {
|
|
142
|
+
e && x?.setTradeZoneStyle(e);
|
|
143
|
+
}, { deep: !0 }), s(() => _.overrides, (e) => {
|
|
144
|
+
x?.setOverrides({ ...e });
|
|
145
145
|
}, { deep: !0 }), (t, n) => (i(), e("div", {
|
|
146
146
|
ref_key: "containerEl",
|
|
147
|
-
ref:
|
|
147
|
+
ref: b,
|
|
148
148
|
style: {
|
|
149
149
|
width: "100%",
|
|
150
150
|
height: "100%"
|
|
@@ -153,6 +153,6 @@ var m = /* @__PURE__ */ t({
|
|
|
153
153
|
}
|
|
154
154
|
});
|
|
155
155
|
//#endregion
|
|
156
|
-
export {
|
|
156
|
+
export { h as TradeCanvas };
|
|
157
157
|
|
|
158
158
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/TradeCanvas.vue","../src/TradeCanvas.vue"],"sourcesContent":["<template>\n <div ref=\"containerEl\" :style=\"{ width: '100%', height: '100%' }\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, toRaw } from 'vue';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n feedBars,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n ChartStyleOverrides,\n ChartOptions,\n IndicatorSpec,\n FedBars,\n} from '@tradecanvas/chart';\n\nconst props = withDefaults(\n defineProps<{\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /**\n * Bars: the chart shows these, and opens no stream of its own when it has\n * them at mount. Bars that go on from those given before, the last one\n * changed or bars added after it, go in as live ticks (the view isn't\n * reset): pushed onto the same array, changed in place, or in a new array.\n * Any other bars are a new series, as are yours after a stream gave the\n * chart bars of its own. An older bar changed needs a new array with a new\n * bar in its place.\n */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\n }>(),\n {\n symbol: 'BTCUSDT',\n timeframe: '5m' as TimeFrame,\n theme: 'dark',\n chartType: 'candlestick' as ChartType,\n indicators: () => [],\n stream: true,\n historyLimit: 500,\n autoScale: true,\n },\n);\n\nconst emit = defineEmits<{\n ready: [chart: Chart];\n crosshairMove: [payload: unknown];\n}>();\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme): Theme {\n if (theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\nconst containerEl = ref<HTMLDivElement>();\nlet chart: Chart | null = null;\nconst indicatorIds = new Map<string, string>();\n/** The stream open now (`symbol|timeframe`), or null. */\nlet streamKey: string | null = null;\n\n/** The specs as plain values (not Vue's proxies), for the chart to keep. */\nconst plainSpecs = (specs: readonly IndicatorSpec[]): IndicatorSpec[] =>\n specs.map((spec) => (typeof spec === 'string'\n ? spec\n : { id: spec.id, ...(spec.params ? { params: { ...spec.params } } : {}), ...(spec.position ? { position: spec.position } : {}) }));\n/** The features last applied, as text. */\nlet featuresKey = JSON.stringify(props.features ?? null);\n\n/** A stream of its own while it has no data; `stream: false` closes it. Data given later leaves it be. */\nfunction syncStream(): void {\n if (!chart) return;\n if (!props.stream) {\n if (streamKey !== null) chart.disconnectStream();\n streamKey = null;\n return;\n }\n if (props.data) return;\n const key = `${props.symbol}|${props.timeframe}`;\n if (streamKey === key) return;\n const opened = streamKey !== null;\n streamKey = key;\n if (opened) chart.disconnectStream();\n const adapter = props.adapter ?? new BinanceAdapter();\n chart.connect({ adapter, symbol: props.symbol, timeframe: props.timeframe, historyLimit: props.historyLimit });\n if (opened && props.watermarkText) chart.setWatermark(props.watermarkText);\n}\n\nfunction getChart(): Chart | null {\n return chart;\n}\n\nfunction screenshot(filename?: string): void {\n chart?.screenshot(filename);\n}\n\nfunction screenshotDataURL(): string | null {\n return chart?.screenshotDataURL() ?? null;\n}\n\ndefineExpose({ getChart, screenshot, screenshotDataURL });\n\nonMounted(() => {\n if (!containerEl.value) return;\n\n chart = new Chart(containerEl.value, {\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...props.options,\n chartType: props.chartType,\n theme: resolveTheme(props.theme),\n autoScale: props.autoScale,\n ...(props.watermarkText\n ? { watermark: { text: props.watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' } }\n : {}),\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...props.options?.features,\n ...props.features,\n },\n });\n\n if (props.data) feed(chart, props.data);\n else syncStream();\n\n // Apply initial reactive collections not covered by the constructor options.\n // Vue's watches aren't immediate, so without this the first render of\n // indicators / signal markers / trade zones would be dropped.\n syncIndicators(chart, plainSpecs(props.indicators), indicatorIds);\n if (props.signalMarkers) chart.setSignalMarkers(props.signalMarkers);\n if (props.signalMarkerStyle) chart.setSignalMarkerStyle(props.signalMarkerStyle);\n if (props.tradeZones) chart.setTradeZones(props.tradeZones);\n if (props.tradeZoneStyle) chart.setTradeZoneStyle(props.tradeZoneStyle);\n if (props.overrides) chart.setOverrides(props.overrides);\n\n emit('ready', chart);\n});\n\nonUnmounted(() => {\n if (chart) {\n chart.disconnectStream();\n chart.destroy();\n chart = null;\n }\n});\n\nwatch(() => [props.symbol, props.timeframe, !props.data, props.stream] as const, syncStream);\n/** The bars last given to the chart (`feedBars`). */\nlet fed: FedBars | null = null;\nconst barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');\n\n/**\n * Bars into the chart: bars that go on from those given before (a bar pushed\n * or the last one changed, in place or in a new array) go in as ticks, so the\n * view stays put and only the end is recalculated; anything else is a new\n * series. The chart gets plain copies, not Vue's proxies, to read in its frames.\n */\nfunction feed(target: Chart, data: readonly OHLCBar[]): void {\n fed = feedBars(target, toRaw(data), fed);\n}\n\nwatch(() => props.features, (f) => {\n const key = JSON.stringify(f ?? null);\n if (key === featuresKey) return;\n featuresKey = key;\n if (f) chart?.setFeatures({ ...f });\n}, { deep: true });\n\nwatch(() => props.theme, (t) => { chart?.setTheme(resolveTheme(t)); });\nwatch(() => props.chartType, (ct) => { chart?.setChartType(ct); });\n// The array, its length and the last bar's fields: a bar pushed or the\n// forming bar changed, without walking every bar as a deep watch does.\nwatch(\n () => [props.data, props.data?.length, barKey(props.data?.[props.data.length - 1])],\n () => {\n if (!chart) return;\n // Without data, the next bars are a new series: a stream may have come in between.\n if (props.data) feed(chart, props.data);\n else fed = null;\n },\n);\n\nwatch(\n () => props.indicators,\n (specs) => { if (chart) syncIndicators(chart, plainSpecs(specs), indicatorIds); },\n { deep: true },\n);\n\nwatch(() => props.signalMarkers, (m) => { if (m) chart?.setSignalMarkers(m); }, { deep: true });\nwatch(() => props.signalMarkerStyle, (s) => { if (s) chart?.setSignalMarkerStyle(s); }, { deep: true });\nwatch(() => props.tradeZones, (z) => { if (z) chart?.setTradeZones(z); }, { deep: true });\nwatch(() => props.tradeZoneStyle, (s) => { if (s) chart?.setTradeZoneStyle(s); }, { deep: true });\n// All of the host's overrides: keys left out of the prop are taken away.\nwatch(() => props.overrides, (o) => { chart?.setOverrides({ ...o }); }, { deep: true });\n</script>\n","<template>\n <div ref=\"containerEl\" :style=\"{ width: '100%', height: '100%' }\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, toRaw } from 'vue';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n feedBars,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n ChartStyleOverrides,\n ChartOptions,\n IndicatorSpec,\n FedBars,\n} from '@tradecanvas/chart';\n\nconst props = withDefaults(\n defineProps<{\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /**\n * Bars: the chart shows these, and opens no stream of its own when it has\n * them at mount. Bars that go on from those given before, the last one\n * changed or bars added after it, go in as live ticks (the view isn't\n * reset): pushed onto the same array, changed in place, or in a new array.\n * Any other bars are a new series, as are yours after a stream gave the\n * chart bars of its own. An older bar changed needs a new array with a new\n * bar in its place.\n */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\n }>(),\n {\n symbol: 'BTCUSDT',\n timeframe: '5m' as TimeFrame,\n theme: 'dark',\n chartType: 'candlestick' as ChartType,\n indicators: () => [],\n stream: true,\n historyLimit: 500,\n autoScale: true,\n },\n);\n\nconst emit = defineEmits<{\n ready: [chart: Chart];\n crosshairMove: [payload: unknown];\n}>();\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme): Theme {\n if (theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\nconst containerEl = ref<HTMLDivElement>();\nlet chart: Chart | null = null;\nconst indicatorIds = new Map<string, string>();\n/** The stream open now (`symbol|timeframe`), or null. */\nlet streamKey: string | null = null;\n\n/** The specs as plain values (not Vue's proxies), for the chart to keep. */\nconst plainSpecs = (specs: readonly IndicatorSpec[]): IndicatorSpec[] =>\n specs.map((spec) => (typeof spec === 'string'\n ? spec\n : { id: spec.id, ...(spec.params ? { params: { ...spec.params } } : {}), ...(spec.position ? { position: spec.position } : {}) }));\n/** The features last applied, as text. */\nlet featuresKey = JSON.stringify(props.features ?? null);\n\n/** A stream of its own while it has no data; `stream: false` closes it. Data given later leaves it be. */\nfunction syncStream(): void {\n if (!chart) return;\n if (!props.stream) {\n if (streamKey !== null) chart.disconnectStream();\n streamKey = null;\n return;\n }\n if (props.data) return;\n const key = `${props.symbol}|${props.timeframe}`;\n if (streamKey === key) return;\n const opened = streamKey !== null;\n streamKey = key;\n if (opened) chart.disconnectStream();\n const adapter = props.adapter ?? new BinanceAdapter();\n chart.connect({ adapter, symbol: props.symbol, timeframe: props.timeframe, historyLimit: props.historyLimit });\n if (opened && props.watermarkText) chart.setWatermark(props.watermarkText);\n}\n\nfunction getChart(): Chart | null {\n return chart;\n}\n\nfunction screenshot(filename?: string): void {\n chart?.screenshot(filename);\n}\n\nfunction screenshotDataURL(): string | null {\n return chart?.screenshotDataURL() ?? null;\n}\n\ndefineExpose({ getChart, screenshot, screenshotDataURL });\n\nonMounted(() => {\n if (!containerEl.value) return;\n\n chart = new Chart(containerEl.value, {\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...props.options,\n chartType: props.chartType,\n theme: resolveTheme(props.theme),\n autoScale: props.autoScale,\n ...(props.watermarkText\n ? { watermark: { text: props.watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' } }\n : {}),\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...props.options?.features,\n ...props.features,\n },\n });\n\n if (props.data) feed(chart, props.data);\n else syncStream();\n\n // Apply initial reactive collections not covered by the constructor options.\n // Vue's watches aren't immediate, so without this the first render of\n // indicators / signal markers / trade zones would be dropped.\n syncIndicators(chart, plainSpecs(props.indicators), indicatorIds);\n if (props.signalMarkers) chart.setSignalMarkers(props.signalMarkers);\n if (props.signalMarkerStyle) chart.setSignalMarkerStyle(props.signalMarkerStyle);\n if (props.tradeZones) chart.setTradeZones(props.tradeZones);\n if (props.tradeZoneStyle) chart.setTradeZoneStyle(props.tradeZoneStyle);\n if (props.overrides) chart.setOverrides(props.overrides);\n\n emit('ready', chart);\n});\n\nonUnmounted(() => {\n if (chart) {\n chart.disconnectStream();\n chart.destroy();\n chart = null;\n }\n});\n\nwatch(() => [props.symbol, props.timeframe, !props.data, props.stream] as const, syncStream);\n/** The bars last given to the chart (`feedBars`). */\nlet fed: FedBars | null = null;\nconst barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');\n\n/**\n * Bars into the chart: bars that go on from those given before (a bar pushed\n * or the last one changed, in place or in a new array) go in as ticks, so the\n * view stays put and only the end is recalculated; anything else is a new\n * series. The chart gets plain copies, not Vue's proxies, to read in its frames.\n */\nfunction feed(target: Chart, data: readonly OHLCBar[]): void {\n fed = feedBars(target, toRaw(data), fed);\n}\n\nwatch(() => props.features, (f) => {\n const key = JSON.stringify(f ?? null);\n if (key === featuresKey) return;\n featuresKey = key;\n if (f) chart?.setFeatures({ ...f });\n}, { deep: true });\n\nwatch(() => props.theme, (t) => { chart?.setTheme(resolveTheme(t)); });\nwatch(() => props.chartType, (ct) => { chart?.setChartType(ct); });\n// The array, its length and the last bar's fields: a bar pushed or the\n// forming bar changed, without walking every bar as a deep watch does.\nwatch(\n () => [props.data, props.data?.length, barKey(props.data?.[props.data.length - 1])],\n () => {\n if (!chart) return;\n // Without data, the next bars are a new series: a stream may have come in between.\n if (props.data) feed(chart, props.data);\n else fed = null;\n },\n);\n\nwatch(\n () => props.indicators,\n (specs) => { if (chart) syncIndicators(chart, plainSpecs(specs), indicatorIds); },\n { deep: true },\n);\n\nwatch(() => props.signalMarkers, (m) => { if (m) chart?.setSignalMarkers(m); }, { deep: true });\nwatch(() => props.signalMarkerStyle, (s) => { if (s) chart?.setSignalMarkerStyle(s); }, { deep: true });\nwatch(() => props.tradeZones, (z) => { if (z) chart?.setTradeZones(z); }, { deep: true });\nwatch(() => props.tradeZoneStyle, (s) => { if (s) chart?.setTradeZoneStyle(s); }, { deep: true });\n// All of the host's overrides: keys left out of the prop are taken away.\nwatch(() => props.overrides, (o) => { chart?.setOverrides({ ...o }); }, { deep: true });\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/TradeCanvas.vue","../src/TradeCanvas.vue"],"sourcesContent":["<template>\n <div ref=\"containerEl\" :style=\"{ width: '100%', height: '100%' }\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, toRaw } from 'vue';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n feedBars,\n CORRECTABLE_BARS,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n ChartStyleOverrides,\n ChartOptions,\n IndicatorSpec,\n FedBars,\n} from '@tradecanvas/chart';\n\nconst props = withDefaults(\n defineProps<{\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /**\n * Bars: the chart shows these, and opens no stream of its own when it has\n * them at mount. Bars that go on from those given before, the last one\n * changed or bars added after it, go in as live ticks (the view isn't\n * reset): pushed onto the same array, changed in place, or in a new array.\n * A change to one of the last three bars before the forming one, its time\n * the same, goes in as a correction (`updateBar`), the view kept too.\n * Any other bars are a new series, as are yours after a stream gave the\n * chart bars of its own. A bar further back changed in place isn't seen;\n * in a new array it makes a new series.\n */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\n }>(),\n {\n symbol: 'BTCUSDT',\n timeframe: '5m' as TimeFrame,\n theme: 'dark',\n chartType: 'candlestick' as ChartType,\n indicators: () => [],\n stream: true,\n historyLimit: 500,\n autoScale: true,\n },\n);\n\nconst emit = defineEmits<{\n ready: [chart: Chart];\n crosshairMove: [payload: unknown];\n}>();\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme): Theme {\n if (theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\nconst containerEl = ref<HTMLDivElement>();\nlet chart: Chart | null = null;\nconst indicatorIds = new Map<string, string>();\n/** The stream open now (`symbol|timeframe`), or null. */\nlet streamKey: string | null = null;\n\n/** The specs as plain values (not Vue's proxies), for the chart to keep. */\nconst plainSpecs = (specs: readonly IndicatorSpec[]): IndicatorSpec[] =>\n specs.map((spec) => (typeof spec === 'string'\n ? spec\n : { id: spec.id, ...(spec.params ? { params: { ...spec.params } } : {}), ...(spec.position ? { position: spec.position } : {}) }));\n/** The features last applied, as text. */\nlet featuresKey = JSON.stringify(props.features ?? null);\n\n/** A stream of its own while it has no data; `stream: false` closes it. Data given later leaves it be. */\nfunction syncStream(): void {\n if (!chart) return;\n if (!props.stream) {\n if (streamKey !== null) chart.disconnectStream();\n streamKey = null;\n return;\n }\n if (props.data) return;\n const key = `${props.symbol}|${props.timeframe}`;\n if (streamKey === key) return;\n const opened = streamKey !== null;\n streamKey = key;\n if (opened) chart.disconnectStream();\n const adapter = props.adapter ?? new BinanceAdapter();\n chart.connect({ adapter, symbol: props.symbol, timeframe: props.timeframe, historyLimit: props.historyLimit });\n if (opened && props.watermarkText) chart.setWatermark(props.watermarkText);\n}\n\nfunction getChart(): Chart | null {\n return chart;\n}\n\nfunction screenshot(filename?: string): void {\n chart?.screenshot(filename);\n}\n\nfunction screenshotDataURL(): string | null {\n return chart?.screenshotDataURL() ?? null;\n}\n\ndefineExpose({ getChart, screenshot, screenshotDataURL });\n\nonMounted(() => {\n if (!containerEl.value) return;\n\n chart = new Chart(containerEl.value, {\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...props.options,\n chartType: props.chartType,\n theme: resolveTheme(props.theme),\n autoScale: props.autoScale,\n ...(props.watermarkText\n ? { watermark: { text: props.watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' } }\n : {}),\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...props.options?.features,\n ...props.features,\n },\n });\n\n if (props.data) feed(chart, props.data);\n else syncStream();\n\n // Apply initial reactive collections not covered by the constructor options.\n // Vue's watches aren't immediate, so without this the first render of\n // indicators / signal markers / trade zones would be dropped.\n syncIndicators(chart, plainSpecs(props.indicators), indicatorIds);\n if (props.signalMarkers) chart.setSignalMarkers(props.signalMarkers);\n if (props.signalMarkerStyle) chart.setSignalMarkerStyle(props.signalMarkerStyle);\n if (props.tradeZones) chart.setTradeZones(props.tradeZones);\n if (props.tradeZoneStyle) chart.setTradeZoneStyle(props.tradeZoneStyle);\n if (props.overrides) chart.setOverrides(props.overrides);\n\n emit('ready', chart);\n});\n\nonUnmounted(() => {\n if (chart) {\n chart.disconnectStream();\n chart.destroy();\n chart = null;\n }\n});\n\nwatch(() => [props.symbol, props.timeframe, !props.data, props.stream] as const, syncStream);\n/** The bars last given to the chart (`feedBars`). */\nlet fed: FedBars | null = null;\nconst barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');\n/** The fields of the forming bar and of the bars before it a change to is a correction (`CORRECTABLE_BARS`). */\nconst tailKey = (bars: readonly OHLCBar[] | undefined) => (bars ? bars.slice(-1 - CORRECTABLE_BARS).map(barKey).join(';') : '');\n\n/**\n * Bars into the chart: bars that go on from those given before (a bar pushed\n * or the last one changed, in place or in a new array) go in as ticks, so the\n * view stays put and only the end is recalculated; anything else is a new\n * series. The chart gets plain copies, not Vue's proxies, to read in its frames.\n */\nfunction feed(target: Chart, data: readonly OHLCBar[]): void {\n fed = feedBars(target, toRaw(data), fed);\n}\n\nwatch(() => props.features, (f) => {\n const key = JSON.stringify(f ?? null);\n if (key === featuresKey) return;\n featuresKey = key;\n if (f) chart?.setFeatures({ ...f });\n}, { deep: true });\n\nwatch(() => props.theme, (t) => { chart?.setTheme(resolveTheme(t)); });\nwatch(() => props.chartType, (ct) => { chart?.setChartType(ct); });\n// The array, its length and the fields of its last bars: a bar pushed, the\n// forming bar changed or one just before it corrected, without walking\n// every bar as a deep watch does.\nwatch(\n () => [props.data, props.data?.length, tailKey(props.data)],\n () => {\n if (!chart) return;\n // Without data, the next bars are a new series: a stream may have come in between.\n if (props.data) feed(chart, props.data);\n else fed = null;\n },\n);\n\nwatch(\n () => props.indicators,\n (specs) => { if (chart) syncIndicators(chart, plainSpecs(specs), indicatorIds); },\n { deep: true },\n);\n\nwatch(() => props.signalMarkers, (m) => { if (m) chart?.setSignalMarkers(m); }, { deep: true });\nwatch(() => props.signalMarkerStyle, (s) => { if (s) chart?.setSignalMarkerStyle(s); }, { deep: true });\nwatch(() => props.tradeZones, (z) => { if (z) chart?.setTradeZones(z); }, { deep: true });\nwatch(() => props.tradeZoneStyle, (s) => { if (s) chart?.setTradeZoneStyle(s); }, { deep: true });\n// All of the host's overrides: keys left out of the prop are taken away.\nwatch(() => props.overrides, (o) => { chart?.setOverrides({ ...o }); }, { deep: true });\n</script>\n","<template>\n <div ref=\"containerEl\" :style=\"{ width: '100%', height: '100%' }\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, toRaw } from 'vue';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n feedBars,\n CORRECTABLE_BARS,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n ChartStyleOverrides,\n ChartOptions,\n IndicatorSpec,\n FedBars,\n} from '@tradecanvas/chart';\n\nconst props = withDefaults(\n defineProps<{\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /**\n * Bars: the chart shows these, and opens no stream of its own when it has\n * them at mount. Bars that go on from those given before, the last one\n * changed or bars added after it, go in as live ticks (the view isn't\n * reset): pushed onto the same array, changed in place, or in a new array.\n * A change to one of the last three bars before the forming one, its time\n * the same, goes in as a correction (`updateBar`), the view kept too.\n * Any other bars are a new series, as are yours after a stream gave the\n * chart bars of its own. A bar further back changed in place isn't seen;\n * in a new array it makes a new series.\n */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\n }>(),\n {\n symbol: 'BTCUSDT',\n timeframe: '5m' as TimeFrame,\n theme: 'dark',\n chartType: 'candlestick' as ChartType,\n indicators: () => [],\n stream: true,\n historyLimit: 500,\n autoScale: true,\n },\n);\n\nconst emit = defineEmits<{\n ready: [chart: Chart];\n crosshairMove: [payload: unknown];\n}>();\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme): Theme {\n if (theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme as Theme;\n}\n\nconst containerEl = ref<HTMLDivElement>();\nlet chart: Chart | null = null;\nconst indicatorIds = new Map<string, string>();\n/** The stream open now (`symbol|timeframe`), or null. */\nlet streamKey: string | null = null;\n\n/** The specs as plain values (not Vue's proxies), for the chart to keep. */\nconst plainSpecs = (specs: readonly IndicatorSpec[]): IndicatorSpec[] =>\n specs.map((spec) => (typeof spec === 'string'\n ? spec\n : { id: spec.id, ...(spec.params ? { params: { ...spec.params } } : {}), ...(spec.position ? { position: spec.position } : {}) }));\n/** The features last applied, as text. */\nlet featuresKey = JSON.stringify(props.features ?? null);\n\n/** A stream of its own while it has no data; `stream: false` closes it. Data given later leaves it be. */\nfunction syncStream(): void {\n if (!chart) return;\n if (!props.stream) {\n if (streamKey !== null) chart.disconnectStream();\n streamKey = null;\n return;\n }\n if (props.data) return;\n const key = `${props.symbol}|${props.timeframe}`;\n if (streamKey === key) return;\n const opened = streamKey !== null;\n streamKey = key;\n if (opened) chart.disconnectStream();\n const adapter = props.adapter ?? new BinanceAdapter();\n chart.connect({ adapter, symbol: props.symbol, timeframe: props.timeframe, historyLimit: props.historyLimit });\n if (opened && props.watermarkText) chart.setWatermark(props.watermarkText);\n}\n\nfunction getChart(): Chart | null {\n return chart;\n}\n\nfunction screenshot(filename?: string): void {\n chart?.screenshot(filename);\n}\n\nfunction screenshotDataURL(): string | null {\n return chart?.screenshotDataURL() ?? null;\n}\n\ndefineExpose({ getChart, screenshot, screenshotDataURL });\n\nonMounted(() => {\n if (!containerEl.value) return;\n\n chart = new Chart(containerEl.value, {\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...props.options,\n chartType: props.chartType,\n theme: resolveTheme(props.theme),\n autoScale: props.autoScale,\n ...(props.watermarkText\n ? { watermark: { text: props.watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' } }\n : {}),\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...props.options?.features,\n ...props.features,\n },\n });\n\n if (props.data) feed(chart, props.data);\n else syncStream();\n\n // Apply initial reactive collections not covered by the constructor options.\n // Vue's watches aren't immediate, so without this the first render of\n // indicators / signal markers / trade zones would be dropped.\n syncIndicators(chart, plainSpecs(props.indicators), indicatorIds);\n if (props.signalMarkers) chart.setSignalMarkers(props.signalMarkers);\n if (props.signalMarkerStyle) chart.setSignalMarkerStyle(props.signalMarkerStyle);\n if (props.tradeZones) chart.setTradeZones(props.tradeZones);\n if (props.tradeZoneStyle) chart.setTradeZoneStyle(props.tradeZoneStyle);\n if (props.overrides) chart.setOverrides(props.overrides);\n\n emit('ready', chart);\n});\n\nonUnmounted(() => {\n if (chart) {\n chart.disconnectStream();\n chart.destroy();\n chart = null;\n }\n});\n\nwatch(() => [props.symbol, props.timeframe, !props.data, props.stream] as const, syncStream);\n/** The bars last given to the chart (`feedBars`). */\nlet fed: FedBars | null = null;\nconst barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');\n/** The fields of the forming bar and of the bars before it a change to is a correction (`CORRECTABLE_BARS`). */\nconst tailKey = (bars: readonly OHLCBar[] | undefined) => (bars ? bars.slice(-1 - CORRECTABLE_BARS).map(barKey).join(';') : '');\n\n/**\n * Bars into the chart: bars that go on from those given before (a bar pushed\n * or the last one changed, in place or in a new array) go in as ticks, so the\n * view stays put and only the end is recalculated; anything else is a new\n * series. The chart gets plain copies, not Vue's proxies, to read in its frames.\n */\nfunction feed(target: Chart, data: readonly OHLCBar[]): void {\n fed = feedBars(target, toRaw(data), fed);\n}\n\nwatch(() => props.features, (f) => {\n const key = JSON.stringify(f ?? null);\n if (key === featuresKey) return;\n featuresKey = key;\n if (f) chart?.setFeatures({ ...f });\n}, { deep: true });\n\nwatch(() => props.theme, (t) => { chart?.setTheme(resolveTheme(t)); });\nwatch(() => props.chartType, (ct) => { chart?.setChartType(ct); });\n// The array, its length and the fields of its last bars: a bar pushed, the\n// forming bar changed or one just before it corrected, without walking\n// every bar as a deep watch does.\nwatch(\n () => [props.data, props.data?.length, tailKey(props.data)],\n () => {\n if (!chart) return;\n // Without data, the next bars are a new series: a stream may have come in between.\n if (props.data) feed(chart, props.data);\n else fed = null;\n },\n);\n\nwatch(\n () => props.indicators,\n (specs) => { if (chart) syncIndicators(chart, plainSpecs(specs), indicatorIds); },\n { deep: true },\n);\n\nwatch(() => props.signalMarkers, (m) => { if (m) chart?.setSignalMarkers(m); }, { deep: true });\nwatch(() => props.signalMarkerStyle, (s) => { if (s) chart?.setSignalMarkerStyle(s); }, { deep: true });\nwatch(() => props.tradeZones, (z) => { if (z) chart?.setTradeZones(z); }, { deep: true });\nwatch(() => props.tradeZoneStyle, (s) => { if (s) chart?.setTradeZoneStyle(s); }, { deep: true });\n// All of the host's overrides: keys left out of the prop are taken away.\nwatch(() => props.overrides, (o) => { chart?.setOverrides({ ...o }); }, { deep: true });\n</script>\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradecanvas/vue",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.36",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vue 3 component for @tradecanvas/chart — reactive props, template ref, zero boilerplate.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"README.md"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@tradecanvas/chart": "1.
|
|
41
|
+
"@tradecanvas/chart": "1.53.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"vue": ">=3.3.0"
|