echarts.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. "use client"
  2. import React, {useEffect, useRef} from "react"
  3. import {
  4. type ECharts,
  5. type EChartsCoreOption,
  6. getInstanceByDom,
  7. init as echartsInit,
  8. type SetOptionOpts,
  9. use as echartsUse
  10. } from "echarts/core"
  11. import {BarChart, GaugeChart, LineChart, PieChart, RadarChart, ScatterChart} from "echarts/charts"
  12. import {
  13. DatasetComponent,
  14. GraphicComponent,
  15. GridComponent,
  16. LegendComponent,
  17. TitleComponent,
  18. ToolboxComponent,
  19. TooltipComponent,
  20. VisualMapComponent,
  21. } from "echarts/components"
  22. import {CanvasRenderer} from "echarts/renderers"
  23. echartsUse([
  24. BarChart,
  25. LineChart,
  26. PieChart,
  27. GaugeChart,
  28. RadarChart,
  29. ScatterChart,
  30. GridComponent,
  31. TooltipComponent,
  32. LegendComponent,
  33. TitleComponent,
  34. ToolboxComponent,
  35. VisualMapComponent,
  36. DatasetComponent,
  37. GraphicComponent,
  38. CanvasRenderer,
  39. ])
  40. export type EChartProps = {
  41. option: EChartsCoreOption
  42. className?: string
  43. style?: React.CSSProperties
  44. theme?: "light" | "dark"
  45. opts?: SetOptionOpts
  46. }
  47. export default function EChart({ option, className, style, theme = "light", opts }: EChartProps) {
  48. const ref = useRef<HTMLDivElement | null>(null)
  49. const chartRef = useRef<ECharts | null>(null)
  50. useEffect(() => {
  51. if (!ref.current) return
  52. const el = ref.current
  53. let chart = getInstanceByDom(el)
  54. if (!chart) {
  55. chart = echartsInit(el, theme, { renderer: "canvas", locale: "ZH" })
  56. }
  57. chartRef.current = chart
  58. // Apply option
  59. chart.setOption(option, opts)
  60. const resize = () => chart && chart.resize()
  61. window.addEventListener("resize", resize)
  62. // Resize observer for container changes
  63. const ro = new ResizeObserver(() => resize())
  64. ro.observe(el)
  65. return () => {
  66. window.removeEventListener("resize", resize)
  67. ro.disconnect()
  68. // dispose only if element is being removed to avoid issues in fast refresh
  69. if (chart && !el.isConnected) {
  70. chart.dispose()
  71. chartRef.current = null
  72. }
  73. }
  74. }, [option, theme, opts])
  75. return <div ref={ref} className={className} style={{ width: "100%", height: 320, ...style }} />
  76. }