Skip to content

A chart container component that can be used to wrap various charts. It will handle 'init ', 'update', and 'resize' of chart appropriatly.

License

Notifications You must be signed in to change notification settings

BboyAwey/react-chart-container

Repository files navigation

React Chart Container

React Chart Container is a React component that can wrap chart elements and handle it's init, update and resize event properly.

Why you need React Chart Container?

If you render a chart on an element like div with some library like ECharts, you'll have to consider all the concepts bellow:

  • init a chart instance and render it on the target element
  • handle resizing of the chart when size of any of the ancestral elements changing or the browser window size changing
  • handle updatingof the chart when data or chart setting changing
  • handle loading status when fetching chart data
  • destroy chart instance at proper time

it's really annoying to do all the things.

React Chart Container can help you with all the stuff above.

Usage

A typical example is as bellow:

import { FC, useEffect, useState } from 'react'
import * as echarts from 'echarts/core'
import { LineChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'
import { GridComponent } from 'echarts/components'
import { TimelineData, getMockData } from './mock-data'
import { ReactChartContainer, useReactChartContainer } from '../react-chart-container'
import k from './k'

echarts.use([LineChart, CanvasRenderer, GridComponent])

const Spin: FC = () => <div>Loading...</div>

function transformData (data: TimelineData) {
  return data.values.map(line => {
    return {
      type: 'line',
      name: line.name,
      id: line.alias + ':::' + line.name,
      data: line.data.map((point, index) => {
        if (!data.timestamps[index]) return null
        return {
          name: data.timestamps[index],
          value: [data.timestamps[index], point]
        }
      })
    }
  })
}

function App () {
  const [mockData, setMockData] = useState(getMockData())

  const { elRef, onReady, onResize } = useReactChartContainer<echarts.ECharts, TimelineData, string>({
    init: (el, d, _s) => {
      // console.log('settings in init function:', s)
      const instance = echarts.init(el)

      instance.setOption({
        xAxis: {
          type: 'time'
        },
        yAxis: {
          type: 'value',
          axisLabel: { formatter: (v: number) => k(v) }
        },
        grid: {
          show: true,
          left: 56,
          bottom: 24,
          right: 8,
          top: 28
        },
        series: transformData(d)
      }, { lazyUpdate: true })

      return instance
    },
    resize: (graphRef) => graphRef.current?.resize(),
    update: (graphRef, d, _s) => {
      // console.log('settings in update function:', s)
      graphRef.current?.setOption({
        series: transformData(d)
      }, { lazyUpdate: true, replaceMerge: 'series' })
    },
    destroy: (graphRef, _el) => graphRef.current?.dispose()
  }, mockData as TimelineData, 'hello')

  useEffect(() => {
    window.setInterval(() => {
      setMockData(getMockData())
    }, 3000)
  }, [])

  return (
    <div >
      <ReactChartContainer
        onReady={onReady}
        onResize={onResize}
        spinIcon={<Spin />}
        loading={false}>
        <div ref={elRef} style={{ height: 400 }}></div>
      </ReactChartContainer>
    </div>
  )
}

export default App

API

ReactChartContainer

prop type required/default description
onReady (size: Rect) => void - the callback of container ready
onResize (size: Rect) => void - the callback of container resizing
loading boolean false indecate loading status
className string '' class name

useReactChartContainer

const useReactChartContainer: <
  GraphType,
  Data,
  Settings = undefined
>(
  chart: Chart<GraphType, Data, Settings>,
  data: Data,
  settings: Settings
) => {
  elRef: MutableRefObject<null>;
  graphRef: GraphRef<GraphType>;
  onResize: () => void;
  onReady: () => void;
}

interface Chart<GraphType, Data, Settings = undefined> {
  init (element: HTMLDivElement, data: Data, settings: Settings): GraphType
  resize (graphRef: GraphRef<GraphType>, data: Data, settings: Settings): void
  update (graphRef: GraphRef<GraphType>, data: Data, settings: Settings): void
  destroy (graphRef: GraphRef<GraphType>, element: HTMLDivElement): void
}

export type GraphRef<GraphType> = MutableRefObject<GraphType | null>

About

A chart container component that can be used to wrap various charts. It will handle 'init ', 'update', and 'resize' of chart appropriatly.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published