feat: 优化延迟图表,添加连接断点控制

This commit is contained in:
Montia37
2025-08-27 16:19:28 +08:00
parent 3999b8b687
commit 018e15d78c
5 changed files with 39 additions and 9 deletions

View File

@@ -147,6 +147,13 @@
"default": true, "default": true,
"help": "启用后默认显示延迟图表" "help": "启用后默认显示延迟图表"
}, },
{
"key": "enableConnectBreaks",
"name": "启用连接断点",
"type": "switch",
"default": false,
"help": "启用后图表中的曲线将会跨过断点形成连续的线条,并使用半透明的垂直参考线来标记断点位置"
},
{ {
"key": "pingChatrtMaxPoints", "key": "pingChatrtMaxPoints",
"name": "延迟图表最大渲染点数", "name": "延迟图表最大渲染点数",

View File

@@ -97,6 +97,8 @@ export function ConfigProvider({
enableInstanceDetail: enableInstanceDetail:
theme.enableInstanceDetail ?? DEFAULT_CONFIG.enableInstanceDetail, theme.enableInstanceDetail ?? DEFAULT_CONFIG.enableInstanceDetail,
enablePingChart: theme.enablePingChart ?? DEFAULT_CONFIG.enablePingChart, enablePingChart: theme.enablePingChart ?? DEFAULT_CONFIG.enablePingChart,
enableConnectBreaks:
theme.enableConnectBreaks ?? DEFAULT_CONFIG.enableConnectBreaks,
pingChartMaxPoints: pingChartMaxPoints:
theme.pingChartMaxPoints || DEFAULT_CONFIG.pingChartMaxPoints, theme.pingChartMaxPoints || DEFAULT_CONFIG.pingChartMaxPoints,
backgroundImage, backgroundImage,

View File

@@ -16,6 +16,7 @@ export interface ConfigOptions {
enableGroupedBar?: boolean; // 是否启用分组栏 enableGroupedBar?: boolean; // 是否启用分组栏
enableInstanceDetail?: boolean; // 是否启用实例详情 enableInstanceDetail?: boolean; // 是否启用实例详情
enablePingChart?: boolean; // 是否启用延迟图表 enablePingChart?: boolean; // 是否启用延迟图表
enableConnectBreaks?: boolean; // 是否启用连接断点
pingChartMaxPoints?: number; // 延迟图表最大点数 pingChartMaxPoints?: number; // 延迟图表最大点数
enableSwap?: boolean; // 是否启用SWAP显示 enableSwap?: boolean; // 是否启用SWAP显示
} }
@@ -39,6 +40,7 @@ export const DEFAULT_CONFIG: ConfigOptions = {
enableGroupedBar: true, enableGroupedBar: true,
enableInstanceDetail: true, enableInstanceDetail: true,
enablePingChart: true, enablePingChart: true,
enableConnectBreaks: false,
pingChartMaxPoints: 0, pingChartMaxPoints: 0,
enableSwap: true, enableSwap: true,
}; };

View File

@@ -117,11 +117,13 @@ const Instance = memo(({ node }: InstanceProps) => {
<div> <div>
<p className="text-muted-foreground text-sm"></p> <p className="text-muted-foreground text-sm"></p>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{node.traffic_limit && isOnline && ( {node.traffic_limit !== 0 && isOnline && stats && (
<CircleProgress <CircleProgress
value={trafficPercentage} value={trafficPercentage}
maxValue={100} maxValue={100}
size={36} size={32}
strokeWidth={4}
showPercentage={true}
/> />
)} )}
<div> <div>

View File

@@ -31,7 +31,9 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
const [visiblePingTasks, setVisiblePingTasks] = useState<number[]>([]); const [visiblePingTasks, setVisiblePingTasks] = useState<number[]>([]);
const [timeRange, setTimeRange] = useState<[number, number] | null>(null); const [timeRange, setTimeRange] = useState<[number, number] | null>(null);
const [cutPeak, setCutPeak] = useState(false); const [cutPeak, setCutPeak] = useState(false);
const [connectBreaks, setConnectBreaks] = useState(false); const [connectBreaks, setConnectBreaks] = useState(
useConfigItem("enableConnectBreaks")
);
const maxPointsToRender = useConfigItem("pingChartMaxPoints") || 0; // 0表示不限制 const maxPointsToRender = useConfigItem("pingChartMaxPoints") || 0; // 0表示不限制
useEffect(() => { useEffect(() => {
@@ -147,12 +149,27 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
}, [pingHistory?.tasks]); }, [pingHistory?.tasks]);
const generateColor = useCallback( const generateColor = useCallback(
(taskName: string, total: number, isBreakPoints?: boolean) => { (taskName: string, total: number) => {
const index = sortedTasks.findIndex((t) => t.name === taskName); const index = sortedTasks.findIndex((t) => t.name === taskName);
if (index === -1) return "#000000"; // Fallback color if (index === -1) return "#000000"; // Fallback color
const hue = (index * (360 / total)) % 360; const hue = (index * (360 / total)) % 360;
return `hsla(${hue}, 50%, 60%, ${isBreakPoints ? 0.7 : 1})`;
// 使用OKLCH色彩空间优化折线图的颜色区分度
// L=0.7 (较高亮度,便于在图表背景上清晰显示)
// C=0.2 (较高饱和度,增强颜色区分度)
const oklchColor = `oklch(0.6 0.2 ${hue} / .8)`;
// 为不支持OKLCH的浏览器提供HSL备用色
// 使用更高的饱和度和适中的亮度来匹配OKLCH的视觉效果
const hslFallback = `hsl(${hue}, 50%, 60%)`;
// 检查浏览器是否支持OKLCH
if (CSS.supports("color", oklchColor)) {
return oklchColor;
} else {
return hslFallback;
}
}, },
[sortedTasks] [sortedTasks]
); );
@@ -180,7 +197,7 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
if (isBreak) { if (isBreak) {
points.push({ points.push({
x: currentPoint.time, x: currentPoint.time,
color: generateColor(task.name, sortedTasks.length, true), color: generateColor(task.name, sortedTasks.length),
}); });
} }
} }
@@ -271,7 +288,7 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
<span <span
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: __html:
'<h2 class="text-lg font-bold">关于连接断点的提示</h2><p>当您开启"连接断点"功能后,图表中的曲线将会跨过那些由于网络问题或其他原因导致的丢包点,形成一条连续的线条。同时,系统会在丢包位置显示<strong>半透明的垂直参考线</strong>来标记断点位置。</p>', '<h2 class="text-lg font-bold">关于连接断点的提示</h2><p><strong>默认关闭,可在后台配置</strong></p><p>当您开启"连接断点"功能后,图表中的曲线将会跨过那些由于网络问题或其他原因导致的丢包点,形成一条连续的线条。同时,系统会在丢包位置显示<strong>半透明的垂直参考线</strong>来标记断点位置。</p>',
}} }}
/> />
</Tips> </Tips>
@@ -322,14 +339,14 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
key={`break-${index}`} key={`break-${index}`}
x={point.x} x={point.x}
stroke={point.color} stroke={point.color}
strokeWidth={1} strokeWidth={1.5}
strokeOpacity={0.5} strokeOpacity={0.5}
/> />
))} ))}
{sortedTasks.map((task) => ( {sortedTasks.map((task) => (
<Line <Line
key={task.id} key={task.id}
type={"basis"} type={"monotone"}
dataKey={String(task.id)} dataKey={String(task.id)}
name={task.name} name={task.name}
stroke={generateColor(task.name, sortedTasks.length)} stroke={generateColor(task.name, sortedTasks.length)}