在 React 和 TypeScript 中使用 Apache ECharts
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
什么是Apache ECharts?
它是一款很棒的数据可视化库,类似于Highcharts、Chart.js、amCharts、Vega-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 }} />;
}
那呢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;
}
然后,更新ReactEChartsProps:
export interface ReactEChartsProps {
option: EChartsOption | LiquidFillGaugeOption;
style?: CSSProperties;
settings?: SetOptionOpts;
loading?: boolean;
theme?: "light" | "dark";
}
最后,重用该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}
/>
);
}
如何在应用程序中调用此组件?
创建一个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,
},
},
],
}
现在,只需像prop使用其他任何组件一样使用它即可:
<div>
<ReactECharts option={option} />
</div>
如果您正在为您的项目寻找数据可视化库,请考虑使用 Apache Echarts。
如果您也想减小打包大小,不妨看看《使用 Apache ECharts 与 React 和 TypeScript:优化打包大小》 。
文章来源:https://dev.to/manufac/using-apache-echarts-with-react-and-typescript-353k