+
);
@@ -196,8 +202,10 @@ export default function ChartContainer({
pointHoverBackgroundColor: color,
pointHoverBorderColor: color,
pointHoverBorderWidth: 1,
- animation: false,
- animations: { colors: false, x: false, y: false },
+ animation: {
+ duration: 500,
+ easing: 'easeOutQuart'
+ },
};
})
});
@@ -253,12 +261,19 @@ export default function ChartContainer({
const chartOptions = useMemo(() => ({
responsive: true,
maintainAspectRatio: false,
- animation: { duration: 0 },
- animations: { colors: false, x: false, y: false },
- hover: { animationDuration: 0 },
- responsiveAnimationDuration: 0,
+ animation: {
+ duration: 500,
+ easing: 'easeOutQuart'
+ },
interaction: { mode: 'index', intersect: false },
plugins: {
+ decimation: {
+ enabled: parsedData.some(file =>
+ Object.values(file.metricsData || {}).some(arr => arr.length > 1000)
+ ),
+ algorithm: 'lttb',
+ samples: 1000
+ },
zoom: {
pan: {
enabled: true,
@@ -308,7 +323,6 @@ export default function ChartContainer({
tooltip: {
mode: 'index',
intersect: false,
- animation: false,
backgroundColor: 'rgba(15, 23, 42, 0.92)',
titleColor: '#f1f5f9',
bodyColor: '#cbd5e1',
@@ -370,7 +384,7 @@ export default function ChartContainer({
}
},
elements: { point: { radius: 0 } }
- }), [xRange, onXRangeChange]);
+ }), [xRange, onXRangeChange, parsedData]);
const createComparisonChartData = (item1, item2, title) => {
const comparisonData = getComparisonData(item1.data, item2.data, compareMode);
@@ -392,8 +406,10 @@ export default function ChartContainer({
pointHoverBackgroundColor: '#dc2626',
pointHoverBorderColor: '#dc2626',
pointHoverBorderWidth: 1,
- animation: false,
- animations: { colors: false, x: false, y: false },
+ animation: {
+ duration: 500,
+ easing: 'easeOutQuart'
+ },
},
];
if (baseline > 0 && (compareMode === 'relative' || compareMode === 'absolute')) {
@@ -415,8 +431,10 @@ export default function ChartContainer({
pointHoverBackgroundColor: '#10b981',
pointHoverBorderColor: '#10b981',
pointHoverBorderWidth: 1,
- animation: false,
- animations: { colors: false, x: false, y: false },
+ animation: {
+ duration: 500,
+ easing: 'easeOutQuart'
+ },
});
}
return { datasets };
@@ -424,7 +442,7 @@ export default function ChartContainer({
if (parsedData.length === 0) {
return (
-
+
📊 暂无数据
📁 请上传日志文件开始分析
@@ -451,7 +469,7 @@ export default function ChartContainer({
if (metrics.length === 0) {
return (
-
+
@@ -523,7 +541,7 @@ export default function ChartContainer({
{comparisonChart}
{stats && (
-
+
{key} 差值统计
Mean Difference: {stats.meanNormal.toFixed(6)}
diff --git a/src/components/ComparisonControls.jsx b/src/components/ComparisonControls.jsx
index e2661ee..aa93409 100644
--- a/src/components/ComparisonControls.jsx
+++ b/src/components/ComparisonControls.jsx
@@ -12,7 +12,7 @@ export function ComparisonControls({
];
return (
-
+
- e.stopPropagation()}
>
diff --git a/src/components/FileList.jsx b/src/components/FileList.jsx
index 37fb183..7286201 100644
--- a/src/components/FileList.jsx
+++ b/src/components/FileList.jsx
@@ -4,7 +4,7 @@ import { FileText, X, Settings } from 'lucide-react';
export function FileList({ files, onFileRemove, onFileToggle, onFileConfig }) {
if (files.length === 0) {
return (
-
+
+
+
+
diff --git a/src/components/__tests__/ChartContainer.test.jsx b/src/components/__tests__/ChartContainer.test.jsx
index bb7039d..a992796 100644
--- a/src/components/__tests__/ChartContainer.test.jsx
+++ b/src/components/__tests__/ChartContainer.test.jsx
@@ -20,7 +20,8 @@ vi.mock('chart.js', () => {
LineElement: {},
Title: {},
Tooltip: {},
- Legend: {}
+ Legend: {},
+ Decimation: {}
};
});
diff --git a/src/index.css b/src/index.css
index 3d38cda..86c9dca 100644
--- a/src/index.css
+++ b/src/index.css
@@ -247,6 +247,28 @@ input[type="checkbox"]:focus {
}
}
+/* 通用元素入场动画 */
+@keyframes fadeSlideIn {
+ from {
+ opacity: 0;
+ transform: translateY(8px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.fade-slide-in {
+ animation: fadeSlideIn 0.4s ease-out;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .fade-slide-in {
+ animation: none !important;
+ }
+}
+
/* 渐变文字动画 */
@keyframes gradientShift {
0%, 100% {