From 5189fdb6211bef336f3eedd5cea5cff04254b7f9 Mon Sep 17 00:00:00 2001 From: mmc <1556375442@qq.com> Date: Mon, 31 Aug 2026 11:27:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=20=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=8F=B0=E8=AD=A6=E5=91=8A=E4=BF=A1=E6=81=AF=20=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E5=A4=A7=E5=B0=8F=E5=9C=A8=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=20=20=E4=BC=9A=E8=AD=A6=E5=91=8A=20=E9=95=BF=E5=AE=BD-1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/recharts.jsx | 295 +++++++++++++++++++++++++++++++----- 1 file changed, 258 insertions(+), 37 deletions(-) diff --git a/src/components/recharts.jsx b/src/components/recharts.jsx index e76d002..86e8136 100644 --- a/src/components/recharts.jsx +++ b/src/components/recharts.jsx @@ -1,6 +1,5 @@ -import React from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { - ResponsiveContainer, LineChart, Line, XAxis, @@ -15,8 +14,10 @@ import { Bar, } from 'recharts'; - +// ========================= // 默认颜色池 +// ========================= + const DEFAULT_COLORS = [ '#1677ff', '#52c41a', @@ -29,11 +30,114 @@ const DEFAULT_COLORS = [ ]; +// ========================= +// 通用自适应容器 +// ========================= +// +// 不再使用 ResponsiveContainer。 +// 通过 ResizeObserver 获取真实尺寸, +// 只有 width / height > 0 时才渲染 Recharts。 +// 这样可以彻底避免: +// +// width(-1) and height(-1) +// +// ========================= + +const ChartResizeContainer = ({ + children, + width = '100%', + height = 360, + className, + style, +}) => { + const containerRef = useRef(null); + + const [size, setSize] = useState({ + width: 0, + height: 0, + }); + + useEffect(() => { + const element = containerRef.current; + + if (!element) { + return; + } + + const updateSize = () => { + const rect = element.getBoundingClientRect(); + + const nextWidth = Math.floor(rect.width); + const nextHeight = Math.floor(rect.height); + + // 非法尺寸直接忽略 + if (nextWidth <= 0 || nextHeight <= 0) { + return; + } + + setSize((prev) => { + if ( + prev.width === nextWidth && + prev.height === nextHeight + ) { + return prev; + } + + return { + width: nextWidth, + height: nextHeight, + }; + }); + }; + + // 首次主动测量 + updateSize(); + + // 后续监听尺寸变化 + const observer = new ResizeObserver(() => { + updateSize(); + }); + + observer.observe(element); + + return () => { + observer.disconnect(); + }; + }, []); + + return ( +
+ {size.width > 0 && size.height > 0 + ? React.cloneElement(children, { + width: size.width, + height: size.height, + }) + : null} +
+ ); +}; + + +// ========================= +// Universal Line Chart +// ========================= export const UniversalLineChart = ({ - data, + data = [], xKey, - series, + series = [], width = '100%', height = 360, showGrid = true, @@ -43,6 +147,7 @@ export const UniversalLineChart = ({ smooth = true, dot = false, className, + style, }) => { return (
- - + + {showGrid && ( - + )} + {showTooltip && } + {showLegend && } {series.map((item, index) => ( ))} - +
); }; +// ========================= +// Universal Bar Chart +// ========================= export const UniversalBarChart = ({ - data, + data = [], xKey, - series, + series = [], width = '100%', height = 360, showGrid = true, @@ -102,6 +239,7 @@ export const UniversalBarChart = ({ radius = 6, stack = false, className, + style, }) => { return (
- - + + {showGrid && ( - + )} + {showTooltip && } + {showLegend && } {series.map((item, index) => ( @@ -131,22 +282,35 @@ export const UniversalBarChart = ({ key={item.key} dataKey={item.key} name={item.name} - fill={item.color || DEFAULT_COLORS[index % DEFAULT_COLORS.length]} + fill={ + item.color || + DEFAULT_COLORS[ + index % + DEFAULT_COLORS.length + ] + } barSize={barSize} radius={radius} - stackId={stack ? 'stack' : undefined} + stackId={ + stack + ? 'stack' + : undefined + } /> ))} - +
); }; +// ========================= +// Universal Pie Chart +// ========================= export const UniversalPieChart = ({ - data, + data = [], width = '100%', height = 360, showLegend = true, @@ -157,7 +321,7 @@ export const UniversalPieChart = ({ paddingAngle = 2, showLabel = true, className, - style + style, }) => { return (
- - + + {showTooltip && } + {showLegend && } ( ))} - +
); }; + // ========================= // 使用示例 // ========================= export const DemoCharts = () => { const lineData = [ - { month: '1月', uv: 400, pv: 240, amt: 240 }, - { month: '2月', uv: 300, pv: 456, amt: 300 }, - { month: '3月', uv: 500, pv: 139, amt: 200 }, - { month: '4月', uv: 278, pv: 390, amt: 278 }, - { month: '5月', uv: 189, pv: 480, amt: 189 }, + { + month: '1月', + uv: 400, + pv: 240, + amt: 240, + }, + { + month: '2月', + uv: 300, + pv: 456, + amt: 300, + }, + { + month: '3月', + uv: 500, + pv: 139, + amt: 200, + }, + { + month: '4月', + uv: 278, + pv: 390, + amt: 278, + }, + { + month: '5月', + uv: 189, + pv: 480, + amt: 189, + }, ]; const pieData = [ - { name: 'Vue', value: 40 }, - { name: 'React', value: 35 }, - { name: 'Angular', value: 25 }, + { + name: 'Vue', + value: 40, + }, + { + name: 'React', + value: 35, + }, + { + name: 'Angular', + value: 25, + }, ]; return ( -
+