Menu
Documentation

Charts with Lightweight Charts

Optional dependency

This component uses the lightweight-charts library, which is a top performing financial charting library.

Display charts and graphs with the Lightweight Charts™ library.

Example

Show code
vue
<script setup lang="ts">
/**
 * Generates sample data for the Lightweight Charts™ example
 * @param  {boolean} ohlc Whether generated dat should include open, high, low, and close values
 * @returns {Array} sample data
 */
function generateSampleData(ohlc: boolean) {
  const randomFactor = 25 + Math.random() * 25
  function samplePoint(i: number) {
    return (
      i
      * (0.5
        + Math.sin(i / 10) * 0.2
        + Math.sin(i / 20) * 0.4
        + Math.sin(i / randomFactor) * 0.8
        + Math.sin(i / 500) * 0.5)
      + 200
    )
  }

  const res = []
  const date = new Date(Date.UTC(2024, 0, 1, 0, 0, 0, 0))
  const numberOfPoints = ohlc ? 100 : 500
  for (let i = 0; i < numberOfPoints; ++i) {
    const time = date.getTime() / 1000
    const value = samplePoint(i)
    if (ohlc) {
      const randomRanges = [
        -1 * Math.random(),
        Math.random(),
        Math.random(),
      ].map(i => i * 10)
      const sign = Math.sin(Math.random() - 0.5)
      res.push({
        time,
        low: value + randomRanges[0]!,
        high: value + randomRanges[1]!,
        open: value + sign * randomRanges[2]!,
        close: samplePoint(i + 1),
      })
    }
    else {
      res.push({
        time,
        value,
      })
    }

    date.setUTCDate(date.getUTCDate() + 1)
  }

  return res
}

const chartOptions = shallowRef<any>({})

const colorMode = useColorMode()
watch(() => colorMode.preference, (preference) => {
  if (preference === 'dark') {
    chartOptions.value = {
      layout: {
        fontFamily: `'Inter', sans-serif`,
        background: { color: '#101828' }, // muted-900
        textColor: '#99a1af', // muted-400
      },
      grid: {
        vertLines: { color: '#364153' }, // muted-700
        horzLines: { color: '#364153' }, // muted-700
      },
      crosshair: {
        vertLine: {
          width: 1,
          color: '#8e51ff', // muted-700/50
          labelBackgroundColor: '#8e51ff', // #8e51ff - primary-500
        },
        horzLine: {
          width: 1,
          color: '#8e51ff', // muted-700/50
          labelBackgroundColor: '#8e51ff', // #8e51ff - primary-500
        },
      },
    }
  }
  else {
    chartOptions.value = {
      layout: {
        fontFamily: `'Inter', sans-serif`,
        background: { color: '#FFF' },
        textColor: '#364153', // muted-700
      },
      grid: {
        vertLines: { color: '#cad5e2' }, // muted-300
        horzLines: { color: '#cad5e2' }, // muted-300
      },
      crosshair: {
        vertLine: {
          width: 1,
          color: '#8e51ff', // muted-700/50
          labelBackgroundColor: '#8e51ff', // #8e51ff - primary-500
        },
        horzLine: {
          width: 1,
          color: '#8e51ff', // muted-700/50
          labelBackgroundColor: '#8e51ff', // #8e51ff - primary-500
        },
      },
    }
  }
}, { immediate: true })

const data = ref(generateSampleData(false))
const seriesOptions = ref<any>({
  color: '#8e51ff',
})
const chartType = ref<'line' | 'area' | 'bar' | 'candlestick' | 'histogram' | 'baseline'>('line')
const lwChart = useTemplateRef('lwChart')

function changeData() {
  const candlestickTypeData = ['candlestick', 'bar'].includes(chartType.value)
  const newData = generateSampleData(candlestickTypeData)
  data.value = newData
  if (chartType.value === 'baseline') {
    const average = newData.reduce((s, c) => {
      return s + c.value!
    }, 0) / newData.length
    seriesOptions.value = { baseValue: { type: 'price', price: average } }
  }
}

function changeType() {
  const types = [
    'line',
    'area',
    'baseline',
    'histogram',
    'candlestick',
    'bar',
  ].filter(t => t !== chartType.value)
  const randIndex = Math.round(Math.random() * (types.length - 1))
  chartType.value = types[randIndex] as 'line' | 'area' | 'bar' | 'candlestick' | 'histogram' | 'baseline'
  changeData()

  // call a method on the component.
  lwChart.value?.fitContent()
}
</script>

<template>
  <div class="h-[300px] w-full">
    <AddonLightweightCharts
      ref="lwChart"
      :type="chartType"
      :data="data"
      :autosize="true"
      :chart-options="chartOptions"
      :series-options="seriesOptions"
    />
  </div>
  <div class="flex gap-2 mt-4">
    <BaseButton @click="changeType">
      Change Chart Type
    </BaseButton>
    <BaseButton @click="changeData">
      Change Data
    </BaseButton>
  </div>
</template>

Components

AddonLightweightCharts