Search code examples
lightningchart

Drawing Real Time Timeseries Line Chart with Lightning Chart JS?


I'm trying to draw real time chart with data coming Websockets, it's been great but I can't get the X axis to work like I want it to, right now I got it as

    const axisX = chart
      .getDefaultAxisX()
      // Enable TimeTickStrategy for X Axis.
      .setTickStrategy(AxisTickStrategies.Time)

and with my data as:

socket.on('data', (data) => {
      console.log(data)
      series.add({ x: data.x - timeBegin, y: data.y })
    })

So right now the X axis starts from the time my React app loaded and are actually zoomable into the miliseconds and the tooltip does show time in with ms included but I want the x in the data to be the actual timestamp of the data, how do I make it work? Also, how do I make it so that the chart component only takes up the size of its container? it takes up the whole screen even though I put it in a React-Bootstrap Container and tried to do various methods to make it small and centered to no avail.

import {
  lightningChart, AxisScrollStrategies, AxisTickStrategies, UIElementBuilders, Themes, IndividualPointFill, emptyLine,
  PointShape
} from '@arction/lcjs'
import React, { useRef, useEffect } from 'react'
import { io } from 'socket.io-client'

const timeBegin = new Date().getTime()
const Chart = ({ data, id }) => {
  const count = useRef(0)
  const chartRef = useRef(undefined)
  const DEFAULT_X_RANGE_MS = 30 * 1000; // 30 seconds

  useEffect(() => {
    // Create chart, series and any other static components.
    // NOTE: console log is used to make sure that chart is only created once, even if data is changed!
    console.log('create chart')

    // Create a XY Chart.
    const chart = lightningChart()
      .ChartXY({
        theme: Themes.light,
      })
      .setTitle('Custom X ticks with scrolling Axis')

    const fillStyle = new IndividualPointFill({ color: 'red' })

    // Create line series optimized for regular progressive X data.
    const series = chart.addPointLineSeries({
      pointShape: PointShape.Circle,
      // dataPattern: {
      //   // pattern: 'ProgressiveX' => Each consecutive data point has increased X coordinate.
      //   pattern: 'ProgressiveX',
      //   // regularProgressiveStep: true => The X step between each consecutive data point is regular (for example, always `1.0`).
      //   regularProgressiveStep: true,
      // },
    })
      .setDataCleaning({ minDataPointCount: 120000 });

    series.setPointSize(10)

    const axisX = chart
      .getDefaultAxisX()
      // Enable TimeTickStrategy for X Axis.
      .setTickStrategy(AxisTickStrategies.Time)


    chart.getDefaultAxisY().setTitle('Y Axis')

    chart.setAutoCursor((cursor) =>
      cursor.setResultTableAutoTextStyle(true).setTickMarkerXAutoTextStyle(true).setTickMarkerYAutoTextStyle(true),
    )

    // Store references to chart components.
    chartRef.current = { chart, series }

    // Return function that will destroy the chart when component is unmounted.
    return () => {
      // Destroy chart.
      console.log('destroy chart')
      chart.dispose()
      chartRef.current = undefined
    }
  }, [id])


  useEffect(() => {
    const components = chartRef.current
    if (!components) return

    // Set chart data.
    const { series } = components
    console.log('set chart data', data)
    const socket = io('http://localhost:8080')

    socket.on('data', (data) => {
      console.log(data)
      series.add({ x: data.x - timeBegin, y: data.y })
    })

  }, [data, chartRef])

  return <div id={id} className='chart'></div>
}

export default Chart

I have tried to substract the timestamp of the data with the time the app loaded which works great but I want the actual timestamp as X.


Solution

  • The minimum for AxisTickStrategies.DateTime is 1 minute which is why it didn't work, you need AxisTickStrategies.Time and have it set up as

    // Save the "total" time in ms
    const timeBeginSince1970 = new Date().getTime()
        
    // Do this to get the time of the day in ms
    const timeBegin = new Date().getHours() * 3600 * 1000 + new Date().getMinutes() * 60 * 1000 + new Date().getSeconds() * 1000 + new Date().getMilliseconds()
        
    // Set the origin equal to the starting time
    chart.setTickStrategy(AxisTickStrategies.Time, (tickStrategy) => tickStrategy.setTimeOrigin(timeBegin))
    
    
    // Adding data to the series
    const timeStamp = data.x - timeBeginInMS
    series.add({ x: timeStamp, y: data.y })
    

    Assuming that your data.x is total time since 1970 in ms, data.x - timeBeginMS will equal the time of the day of the data which will fit right on to the X axis of the chart.

    I forgot to pass an id as props for the div of the chart which is why it didnt get appended to the 'root' element which explains why the CSS didnt apply to the chart, rookies' mistake.