修复 控制台警告信息 图标大小在初始化 会警告 长宽-1

This commit is contained in:
mmc
2026-08-31 11:27:25 +08:00
parent db539893ce
commit 5189fdb621

View File

@@ -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 (
<div
ref={containerRef}
className={className}
style={{
width,
height,
minWidth: 0,
minHeight: 0,
boxSizing: 'border-box',
overflow: 'hidden',
...style,
}}
>
{size.width > 0 && size.height > 0
? React.cloneElement(children, {
width: size.width,
height: size.height,
})
: null}
</div>
);
};
// =========================
// 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 (
<div
@@ -50,48 +155,80 @@ export const UniversalLineChart = ({
style={{
width,
height,
minWidth: 0,
minHeight: 0,
boxSizing: 'border-box',
background: backgroundColor,
borderRadius: 12,
padding: 12,
overflow: 'hidden',
...style,
}}
>
<ResponsiveContainer width="100%" height="100%" minWidth={0} minHeight={0}>
<LineChart data={data} minWidth={0} minHeight={0} width="100%" height="100%" >
<ChartResizeContainer
width="100%"
height="100%"
>
<LineChart data={data}>
{showGrid && (
<CartesianGrid strokeDasharray="3 3" opacity={0.25} />
<CartesianGrid
strokeDasharray="3 3"
opacity={0.25}
/>
)}
<XAxis dataKey={xKey} />
<YAxis />
{showTooltip && <Tooltip />}
{showLegend && <Legend />}
{series.map((item, index) => (
<Line
key={item.key}
type={smooth ? 'monotone' : 'linear'}
type={
smooth
? 'monotone'
: 'linear'
}
dataKey={item.key}
name={item.name}
stroke={item.color || DEFAULT_COLORS[index % DEFAULT_COLORS.length]}
strokeWidth={item.strokeWidth || 2}
strokeDasharray={item.dashed ? '6 6' : undefined}
stroke={
item.color ||
DEFAULT_COLORS[
index %
DEFAULT_COLORS.length
]
}
strokeWidth={
item.strokeWidth || 2
}
strokeDasharray={
item.dashed
? '6 6'
: undefined
}
dot={dot}
activeDot={{ r: 6 }}
/>
))}
</LineChart>
</ResponsiveContainer>
</ChartResizeContainer>
</div>
);
};
// =========================
// 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 (
<div
@@ -109,21 +247,34 @@ export const UniversalBarChart = ({
style={{
width,
height,
minWidth: 0,
minHeight: 0,
boxSizing: 'border-box',
background: backgroundColor,
borderRadius: 12,
padding: 12,
overflow: 'hidden',
...style,
}}
>
<ResponsiveContainer width="100%" height="100%" minWidth={0} minHeight={0}>
<BarChart data={data} minWidth={0} minHeight={0} width="100%" height="100%" >
<ChartResizeContainer
width="100%"
height="100%"
>
<BarChart data={data}>
{showGrid && (
<CartesianGrid strokeDasharray="3 3" opacity={0.25} />
<CartesianGrid
strokeDasharray="3 3"
opacity={0.25}
/>
)}
<XAxis dataKey={xKey} />
<YAxis />
{showTooltip && <Tooltip />}
{showLegend && <Legend />}
{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
}
/>
))}
</BarChart>
</ResponsiveContainer>
</ChartResizeContainer>
</div>
);
};
// =========================
// 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 (
<div
@@ -165,15 +329,23 @@ export const UniversalPieChart = ({
style={{
width,
height,
minWidth: 0,
minHeight: 0,
boxSizing: 'border-box',
background: backgroundColor,
borderRadius: 12,
padding: 12,
...style
overflow: 'hidden',
...style,
}}
>
<ResponsiveContainer width="100%" height="100%" minWidth={0} minHeight={0}>
<PieChart minWidth={0} minHeight={0} width="100%" height="100%" >
<ChartResizeContainer
width="100%"
height="100%"
>
<PieChart>
{showTooltip && <Tooltip />}
{showLegend && <Legend />}
<Pie
@@ -190,37 +362,86 @@ export const UniversalPieChart = ({
{data.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={entry.color || DEFAULT_COLORS[index % DEFAULT_COLORS.length]}
fill={
entry.color ||
DEFAULT_COLORS[
index %
DEFAULT_COLORS.length
]
}
/>
))}
</Pie>
</PieChart>
</ResponsiveContainer>
</ChartResizeContainer>
</div>
);
};
// =========================
// 使用示例
// =========================
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 (
<div className="grid grid-cols-1 gap-6 p-6">
<div
className="
grid
grid-cols-1
gap-6
p-6
min-w-0
"
>
<UniversalLineChart
data={lineData}
xKey="month"