发布于 2026-01-06 2 阅读
0

Using Apache ECharts with React and TypeScript DEV's Worldwide Show and Tell Challenge Presented by Mux: Pitch Your Projects!

在 React 和 TypeScript 中使用 Apache ECharts

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

什么是Apache ECharts

它是一款很棒的数据可视化库,类似于HighchartsChart.jsamChartsVega-Lite等等。包括 AWS 在内的许多公司/产品都在生产环境中使用它。

它开箱即用,支持多种图表。这里有大量示例供您参考。我们也发现他们的echarts-liquidfill扩展程序非常实用。

不同的团队在选择数据可视化库时有不同的考量因素。如果您恰好使用Apache ECharts,那么本文或许能帮助您将其集成到您的 React + TypeScript 代码库中。

如何将 React 和 TypeScript 集成?

您可以实现一个 React 函数组件,并在应用程序的不同部分中重用它,以避免多次声明useEffecthook 和订阅/取消订阅事件。"resize"

// React-ECharts.tsx

import React, { useRef, useEffect } from "react";
import { init, getInstanceByDom } from "echarts";
import type { CSSProperties } from "react";
import type { EChartsOption, ECharts, SetOptionOpts } from "echarts";

export interface ReactEChartsProps {
  option: EChartsOption;
  style?: CSSProperties;
  settings?: SetOptionOpts;
  loading?: boolean;
  theme?: "light" | "dark";
}

export function ReactECharts({
  option,
  style,
  settings,
  loading,
  theme,
}: ReactEChartsProps): JSX.Element {
  const chartRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    // Initialize chart
    let chart: ECharts | undefined;
    if (chartRef.current !== null) {
      chart = init(chartRef.current, theme);
    }

    // Add chart resize listener
    // ResizeObserver is leading to a bit janky UX
    function resizeChart() {
      chart?.resize();
    }
    window.addEventListener("resize", resizeChart);

    // Return cleanup function
    return () => {
      chart?.dispose();
      window.removeEventListener("resize", resizeChart);
    };
  }, [theme]);

  useEffect(() => {
    // Update chart
    if (chartRef.current !== null) {
      const chart = getInstanceByDom(chartRef.current);
      chart.setOption(option, settings);
    }
  }, [option, settings, theme]); // Whenever theme changes we need to add option and setting due to it being deleted in cleanup function

  useEffect(() => {
    // Update chart
    if (chartRef.current !== null) {
      const chart = getInstanceByDom(chartRef.current);
      // eslint-disable-next-line @typescript-eslint/no-unused-expressions
      loading === true ? chart.showLoading() : chart.hideLoading();
    }
  }, [loading, theme]);

  return <div ref={chartRef} style={{ width: "100%", height: "100px", ...style }} />;
}

Enter fullscreen mode Exit fullscreen mode

那呢echarts-for-react

它的功能与上面实现的 React 组件类似。但我们遇到了一个问题,就是如何确保图表在窗口宽度变化时也能自动调整大小。此外,在撰写本文时,该库似乎已经不再积极维护。

您可以尝试一下,echarts-for-react因为它似乎比上面实现的组件为最终用户提供了更多功能。

但是,创建我们自己的组件消除了添加额外依赖项的需要,并让我们能够更好地控制我们的组件应该如何将输入映射props到 ECharts API。

了解 React 和 TypeScript 集成的底层工作原理后,我们可以根据需要自行扩展组件,而无需依赖外部库。

显然,这其中存在权衡取舍,因此请根据您的使用情况选择更合理的方案。

如何集成echarts-liquidfill扩展程序?

该方法与上面实现的组件非常相似。

首先,我们需要指定liquidfill图表的类型定义。我们使用以下定义:

// utils.ts

import type { DefaultLabelFormatterCallbackParams, EChartsOption } from "echarts";

/**
 * interface for LiquidFillGauge series config
 */
interface LiquidFillGaugeSeries {
  name?: string;
  type: "liquidFill";
  data: (
    | number
    | {
        name?: string;
        value: number;
        direction?: "left" | "right";
        itemStyle?: {
          color?: string;
          opacity?: number;
        };
        emphasis?: {
          itemStyle?: {
            opacity?: number;
          };
        };
      }
  )[];
  silent?: boolean;

  color?: string[];
  center?: string[];
  radius?: string;
  amplitude?: number;
  waveLength?: string | number;
  phase?: number | "auto";
  period?: number | "auto" | ((value: number, index: number) => number);
  direction?: "right" | "left";
  shape?: "circle" | "rect" | "roundRect" | "triangle" | "diamond" | "pin" | "arrow" | string;

  waveAnimation?: boolean;
  animationEasing?: string;
  animationEasingUpdate?: string;
  animationDuration?: number;
  animationDurationUpdate?: number;

  outline?: {
    show?: boolean;
    borderDistance?: number;
    itemStyle?: {
      color?: string;
      borderColor?: string;
      borderWidth?: number;
      shadowBlur?: number;
      shadowColor?: string;
    };
  };

  backgroundStyle?: {
    color?: string;
    borderWidth?: string;
    borderColor?: string;
    itemStyle?: {
      shadowBlur?: number;
      shadowColor?: string;
      opacity?: number;
    };
  };

  itemStyle?: {
    opacity?: number;
    shadowBlur?: number;
    shadowColor?: string;
  };

  label?: {
    show?: true;
    color?: string;
    insideColor?: string;
    fontSize?: number;
    fontWeight?: string;
    formatter?: string | ((params: DefaultLabelFormatterCallbackParams) => string);

    align?: "left" | "center" | "right";
    baseline?: "top" | "middle" | "bottom";
    position?: "inside" | "left" | "right" | "top" | "bottom" | string[];
  };

  emphasis?: {
    itemStyle?: {
      opacity?: number;
    };
  };
}

export interface LiquidFillGaugeOption extends Omit<EChartsOption, "series"> {
  series: LiquidFillGaugeSeries;
}
Enter fullscreen mode Exit fullscreen mode

然后,更新ReactEChartsProps

export interface ReactEChartsProps {
  option: EChartsOption | LiquidFillGaugeOption;
  style?: CSSProperties;
  settings?: SetOptionOpts;
  loading?: boolean;
  theme?: "light" | "dark";
}
Enter fullscreen mode Exit fullscreen mode

最后,重用该ReactECharts组件来创建LiquidFillGauge组件:

// LiquidFillGauge.tsx

import React from "react";
import "echarts-liquidfill";
import type { CSSProperties } from "react";
import { ReactECharts } from "../React-ECharts";
import type { LiquidFillGaugeOption } from "../utils";

export interface LiquidFillGaugeProps {
  option: LiquidFillGaugeOption;
  style?: CSSProperties;
}

export function LiquidFillGauge({ option, style }: LiquidFillGaugeProps): JSX.Element {
  return (
    <ReactECharts
      option={option}
      style={style}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

如何在应用程序中调用此组件?

创建一个option对象,例如:

const option: ReactEChartsProps["option"] = {
    dataset: {
      source: [
        ["Commodity", "Owned", "Financed"],
        ["Commodity 1", 4, 1],
        ["Commodity 2", 2, 4],
        ["Commodity 3", 3, 6],
        ["Commodity 4", 5, 3],
      ],
    },
    tooltip: {
      trigger: "axis",
      axisPointer: {
        type: "shadow",
      },
    },
    legend: {
      data: ["Owned", "Financed"],
    },
    grid: {
      left: "10%",
      right: "0%",
      top: "20%",
      bottom: "20%",
    },
    xAxis: {
      type: "value",
    },
    yAxis: {
      type: "category",
    },
    series: [
      {
        type: "bar",
        stack: "total",
        label: {
          show: true,
        },
      },
      {
        type: "bar",
        stack: "total",
        label: {
          show: true,
        },
      },
    ],
  }
Enter fullscreen mode Exit fullscreen mode

现在,只需像prop使用其他任何组件一样使用它即可:

<div>
  <ReactECharts option={option} />
</div>
Enter fullscreen mode Exit fullscreen mode

如果您正在为您的项目寻找数据可视化库,请考虑使用 Apache Echarts。


如果您也想减小打包大小,不妨看看《使用 Apache ECharts 与 React 和 TypeScript:优化打包大小》 。

文章来源:https://dev.to/manufac/using-apache-echarts-with-react-and-typescript-353k