Vue Integration
Learn how to integrate TradeX Chart into your Vue.js applications (Vue 3).
Installation
npm install tradex-chart
# or
yarn add tradex-chart
Basic Integration
Single File Component
<template>
<div ref="chartContainer" class="chart-container"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
const props = defineProps({
symbol: {
type: String,
required: true
},
data: {
type: Array,
default: () => []
}
})
const chartContainer = ref(null)
let chart = null
onMounted(() => {
// Create chart element
chart = document.createElement('tradex-chart')
chartContainer.value.appendChild(chart)
// Initialize chart
chart.start({
title: props.symbol,
state: {
ohlcv: props.data
}
})
})
onUnmounted(() => {
if (chart) {
chart.destroy()
chart = null
}
})
// Watch for data changes
watch(() => props.data, (newData) => {
if (chart && newData) {
chart.mergeData(newData)
}
})
</script>
<style scoped>
.chart-container {
width: 100%;
height: 600px;
}
</style>
Usage
<template>
<div class="app">
<h1>Trading Chart</h1>
<TradingChart :symbol="symbol" :data="chartData" />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import TradingChart from './components/TradingChart.vue'
const symbol = ref('BTC/USDT')
const chartData = ref([])
onMounted(async () => {
const response = await fetch('https://api.example.com/ohlcv')
chartData.value = await response.json()
})
</script>
Advanced Component
Reusable Chart Component
<template>
<div ref="containerRef" class="tradex-chart-wrapper">
<div v-if="loading" class="loading">Loading chart...</div>
<div v-if="error" class="error">{{ error }}</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch, defineExpose } from 'vue'
import * as talib from 'talib-web'
const props = defineProps({
symbol: {
type: String,
required: true
},
data: {
type: Array,
default: () => []
},
config: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['ready', 'error'])
const containerRef = ref(null)
const chartRef = ref(null)
const loading = ref(true)
const error = ref(null)
onMounted(async () => {
try {
// Create chart element
const chart = document.createElement('tradex-chart')
containerRef.value.appendChild(chart)
chartRef.value = chart
// Configure chart
const chartConfig = {
title: props.symbol,
talib: talib,
width: containerRef.value.offsetWidth,
height: containerRef.value.offsetHeight,
...props.config,
state: {
ohlcv: props.data,
...props.config.state
}
}
// Start chart
await chart.start(chartConfig)
loading.value = false
emit('ready', chart)
} catch (err) {
error.value = err.message
emit('error', err)
}
})
onUnmounted(() => {
if (chartRef.value) {
chartRef.value.destroy()
chartRef.value = null
}
})
// Watch for data updates
watch(() => props.data, (newData) => {
if (chartRef.value && newData) {
chartRef.value.mergeData(newData)
}
}, { deep: true })
// Watch for symbol changes
watch(() => props.symbol, (newSymbol) => {
if (chartRef.value && newSymbol) {
chartRef.value.setTitle(newSymbol)
}
})
// Expose methods to parent
defineExpose({
addIndicator: (name, params) => {
return chartRef.value?.addIndicator(name, params)
},
removeIndicator: (id) => {
chartRef.value?.removeIndicator(id)
},
exportImage: () => {
return chartRef.value?.exportImage()
},
getChart: () => chartRef.value
})
</script>
<style scoped>
.tradex-chart-wrapper {
width: 100%;
height: 100%;
position: relative;
}
.loading,
.error {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.error {
color: red;
}
</style>
Using the Advanced Component
<template>
<div class="trading-app">
<div class="controls">
<button @click="handleAddRSI">Add RSI</button>
<button @click="handleExport">Export Image</button>
</div>
<TradeXChart
ref="chartRef"
:symbol="symbol"
:data="chartData"
:config="chartConfig"
@ready="onChartReady"
@error="onChartError"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import TradeXChart from './components/TradeXChart.vue'
const chartRef = ref(null)
const symbol = ref('BTC/USDT')
const chartData = ref([])
const chartConfig = {
theme: {
candle: {
UpBodyColour: '#26a69a',
DnBodyColour: '#ef5350'
}
}
}
const handleAddRSI = () => {
chartRef.value?.addIndicator('RSI', { period: 14 })
}
const handleExport = () => {
const image = chartRef.value?.exportImage()
// Download or display image
}
const onChartReady = (chart) => {
console.log('Chart ready:', chart)
}
const onChartError = (error) => {
console.error('Chart error:', error)
}
</script>
Real-time Updates
WebSocket Integration
<template>
<TradeXChart ref="chartRef" :symbol="symbol" :data="chartData" />
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import TradeXChart from './components/TradeXChart.vue'
const props = defineProps({
symbol: {
type: String,
required: true
}
})
const chartRef = ref(null)
const chartData = ref([])
let ws = null
onMounted(() => {
// Connect WebSocket
ws = new WebSocket('wss://api.example.com/ws')
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'subscribe',
symbol: props.symbol
}))
}
ws.onmessage = (event) => {
const update = JSON.parse(event.data)
const chart = chartRef.value?.getChart()
if (chart) {
const candle = [
update.timestamp,
update.open,
update.high,
update.low,
update.close,
update.volume
]
if (update.isClosed) {
chart.addCandle(candle)
} else {
chart.updateStreamingCandle(candle)
}
}
}
ws.onerror = (error) => {
console.error('WebSocket error:', error)
}
})
onUnmounted(() => {
if (ws) {
ws.close()
}
})
</script>
Composables
useTradeXChart Composable
// composables/useTradeXChart.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useTradeXChart(config = {}) {
const containerRef = ref(null)
const chartRef = ref(null)
const isReady = ref(false)
const error = ref(null)
onMounted(async () => {
try {
if (!containerRef.value) return
const chart = document.createElement('tradex-chart')
containerRef.value.appendChild(chart)
chartRef.value = chart
await chart.start(config)
isReady.value = true
} catch (err) {
error.value = err
}
})
onUnmounted(() => {
if (chartRef.value) {
chartRef.value.destroy()
}
})
const addIndicator = (name, params) => {
return chartRef.value?.addIndicator(name, params)
}
const updateData = (data) => {
chartRef.value?.mergeData(data)
}
return {
containerRef,
chart: chartRef,
isReady,
error,
addIndicator,
updateData
}
}
Usage
<template>
<div>
<div v-if="!isReady">Loading chart...</div>
<div ref="containerRef" class="chart-container"></div>
<button v-if="isReady" @click="addIndicator('RSI')">Add RSI</button>
</div>
</template>
<script setup>
import { useTradeXChart } from './composables/useTradeXChart'
const props = defineProps({
data: Array
})
const { containerRef, isReady, addIndicator } = useTradeXChart({
title: 'BTC/USDT',
state: { ohlcv: props.data }
})
</script>
TypeScript Support
Type Definitions
// types/chart.ts
export interface ChartConfig {
title?: string
width?: number
height?: number
theme?: any
state?: {
ohlcv?: number[][]
[key: string]: any
}
[key: string]: any
}
export interface ChartMethods {
addIndicator: (name: string, params?: any) => string
removeIndicator: (id: string) => void
exportImage: () => string
getChart: () => any
}
TypeScript Component
<template>
<div ref="containerRef" class="chart-wrapper"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, defineExpose } from 'vue'
import type { ChartConfig, ChartMethods } from '../types/chart'
interface Props {
symbol: string
data: number[][]
config?: ChartConfig
}
const props = withDefaults(defineProps<Props>(), {
config: () => ({})
})
const emit = defineEmits<{
ready: [chart: any]
error: [error: Error]
}>()
const containerRef = ref<HTMLDivElement | null>(null)
const chartRef = ref<any>(null)
onMounted(async () => {
try {
if (!containerRef.value) return
const chart = document.createElement('tradex-chart')
containerRef.value.appendChild(chart)
chartRef.value = chart
await chart.start({
title: props.symbol,
state: { ohlcv: props.data },
...props.config
})
emit('ready', chart)
} catch (error) {
emit('error', error as Error)
}
})
onUnmounted(() => {
if (chartRef.value) {
chartRef.value.destroy()
}
})
defineExpose<ChartMethods>({
addIndicator: (name: string, params?: any) => {
return chartRef.value?.addIndicator(name, params)
},
removeIndicator: (id: string) => {
chartRef.value?.removeIndicator(id)
},
exportImage: () => {
return chartRef.value?.exportImage()
},
getChart: () => chartRef.value
})
</script>
State Management
With Pinia
// stores/chart.js
import { defineStore } from 'pinia'
export const useChartStore = defineStore('chart', {
state: () => ({
symbol: 'BTC/USDT',
data: [],
indicators: [],
timeframe: '1h'
}),
actions: {
setSymbol(symbol) {
this.symbol = symbol
},
setData(data) {
this.data = data
},
addIndicator(name, params) {
this.indicators.push({ name, params })
},
removeIndicator(index) {
this.indicators.splice(index, 1)
},
setTimeframe(timeframe) {
this.timeframe = timeframe
}
}
})
Usage with Pinia
<template>
<TradeXChart
:symbol="chartStore.symbol"
:data="chartStore.data"
/>
</template>
<script setup>
import { useChartStore } from './stores/chart'
import TradeXChart from './components/TradeXChart.vue'
const chartStore = useChartStore()
</script>
Options API (Vue 2 Style)
<template>
<div ref="chartContainer" class="chart-container"></div>
</template>
<script>
export default {
name: 'TradingChart',
props: {
symbol: {
type: String,
required: true
},
data: {
type: Array,
default: () => []
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeUnmount() {
if (this.chart) {
this.chart.destroy()
this.chart = null
}
},
watch: {
data(newData) {
if (this.chart && newData) {
this.chart.mergeData(newData)
}
}
},
methods: {
initChart() {
this.chart = document.createElement('tradex-chart')
this.$refs.chartContainer.appendChild(this.chart)
this.chart.start({
title: this.symbol,
state: {
ohlcv: this.data
}
})
},
addIndicator(name, params) {
return this.chart?.addIndicator(name, params)
},
removeIndicator(id) {
this.chart?.removeIndicator(id)
}
}
}
</script>
Common Patterns
Multi-Chart Layout
<template>
<div class="grid grid-cols-2 gap-4">
<TradeXChart
v-for="symbol in symbols"
:key="symbol"
:symbol="symbol"
:data="chartData[symbol]"
:config="{ height: 400 }"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import TradeXChart from './components/TradeXChart.vue'
const symbols = ['BTC/USDT', 'ETH/USDT', 'BNB/USDT']
const chartData = ref({})
</script>
Chart with Controls
<template>
<div class="chart-view">
<div class="controls">
<button
v-for="tf in timeframes"
:key="tf"
:class="{ active: timeframe === tf }"
@click="timeframe = tf"
>
{{ tf }}
</button>
</div>
<TradeXChart
ref="chartRef"
:symbol="symbol"
:data="chartData"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import TradeXChart from './components/TradeXChart.vue'
const chartRef = ref(null)
const timeframe = ref('1h')
const timeframes = ['1m', '5m', '15m', '1h', '4h', '1d']
const symbol = ref('BTC/USDT')
const chartData = ref([])
</script>
Troubleshooting
Chart Not Rendering
<template>
<!-- Ensure container has size -->
<div
ref="chartContainer"
class="chart-container"
style="width: 100%; height: 600px; min-height: 400px;"
></div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const chartContainer = ref(null)
onMounted(() => {
// Check if container exists
console.log('Container:', chartContainer.value)
console.log('Size:', {
width: chartContainer.value?.offsetWidth,
height: chartContainer.value?.offsetHeight
})
})
</script>
Memory Leaks
<script setup>
import { onUnmounted } from 'vue'
let chart = null
// Always cleanup
onUnmounted(() => {
if (chart) {
chart.destroy()
chart = null
}
})
</script>
Related Documentation
- Getting Started - Basic setup
- Configuration - Chart configuration
- WebSocket Integration - Real-time data
- API Reference - Complete API
- React Integration - React guide
- Angular Integration - Angular guide