Skip to content

Commit 6b7ef1b

Browse files
committed
Fixed PieChart Render Problem
1 parent eaac87c commit 6b7ef1b

File tree

6 files changed

+110
-64
lines changed

6 files changed

+110
-64
lines changed

public/build-meta.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"buildDate": "2025-05-27",
3-
"buildTime": "19:38:53",
4-
"buildTimestamp": "2025-05-27 19:38:53",
3+
"buildTime": "20:47:17",
4+
"buildTimestamp": "2025-05-27 20:47:17",
55
"lastUpdatedBy": "HKUSTSMARTLab"
66
}

src/components/Dashboard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,9 @@ export function Dashboard() {
363363

364364
<TabsContent value="overview" className="space-y-4 sm:space-y-6">
365365
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6">
366-
<PieDataDistributionChart />
367-
<TaskDistributionChart chartType="organ" />
368366
<TaskDistributionChart chartType="taskType" />
367+
<TaskDistributionChart chartType="organ" />
368+
<PieDataDistributionChart />
369369
</div>
370370

371371
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-6 mb-4 sm:mb-6">

src/components/charts/PieDataDistributionChart.tsx

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
11
"use client";
22

33
import { useEvaluation } from "@/context/EvaluationContext";
4-
import React, { useMemo } from "react";
4+
import React, { useMemo, useState, useEffect } from "react";
55
import ReactECharts from "echarts-for-react";
66
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
77
import type { EChartsOption, PieSeriesOption } from "echarts";
88

99

1010
export function PieDataDistributionChart() {
1111
const {
12-
allTasks,
13-
allPerformances
12+
allTasks
1413
} = useEvaluation();
1514

15+
// Use React state for responsive design instead of window object
16+
const [isMobile, setIsMobile] = useState(false);
17+
18+
useEffect(() => {
19+
const checkIsMobile = () => {
20+
setIsMobile(window.innerWidth < 768);
21+
};
22+
23+
checkIsMobile();
24+
window.addEventListener('resize', checkIsMobile);
25+
return () => window.removeEventListener('resize', checkIsMobile);
26+
}, []);
27+
1628
const chartOptions = useMemo((): EChartsOption => {
1729
if (allTasks.length === 0) {
1830
return {
@@ -25,30 +37,33 @@ export function PieDataDistributionChart() {
2537
};
2638
}
2739

28-
// 按organ分组并计算任务数量
29-
const organTaskCounts: Record<string, number> = {};
40+
// 按评估指标分组并计算任务数量
41+
const metricTaskCounts: Record<string, number> = {};
42+
43+
// 统计每个评估指标的任务数量
3044
allTasks.forEach(task => {
31-
const organ = task.organ;
32-
organTaskCounts[organ] = (organTaskCounts[organ] || 0) + 1;
45+
task.evaluationMetrics.forEach(metric => {
46+
metricTaskCounts[metric] = (metricTaskCounts[metric] || 0) + 1;
47+
});
3348
});
3449

3550
// 格式化数据用于饼图
36-
const data = Object.entries(organTaskCounts).map(([organ, taskCount]) => {
51+
const data = Object.entries(metricTaskCounts).map(([metric, taskCount]) => {
3752
return {
38-
name: organ,
53+
name: metric,
3954
value: taskCount,
4055
};
4156
});
4257

4358
// 任务总数
44-
const totalTasks = Object.values(organTaskCounts).reduce((sum, count) => sum + count, 0);
59+
const totalTasks = Object.values(metricTaskCounts).reduce((sum, count) => sum + count, 0);
4560

4661
// 创建饼图系列
4762
const pieSeries: PieSeriesOption = {
4863
name: "Task Distribution",
4964
type: "pie",
50-
radius: ["45%", "75%"],
51-
center: ["65%", "60%"],
65+
radius: isMobile ? ["35%", "65%"] : ["45%", "75%"], // Moderate size for better balance
66+
center: isMobile ? ["65%", "55%"] : ["60%", "55%"], // Move down for more space from title
5267
avoidLabelOverlap: true,
5368
itemStyle: {
5469
borderRadius: 10,
@@ -62,7 +77,7 @@ export function PieDataDistributionChart() {
6277
emphasis: {
6378
label: {
6479
show: true,
65-
fontSize: 16,
80+
fontSize: isMobile ? 14 : 16,
6681
fontWeight: "bold",
6782
},
6883
},
@@ -84,12 +99,13 @@ export function PieDataDistributionChart() {
8499
animationEasingUpdate: 'cubicOut',
85100

86101
title: {
87-
text: "Task Distribution by Organ",
88-
top: '4.5%',
102+
text: "Task Distribution by Metric",
103+
top: isMobile ? '2%' : '1%', // Higher on mobile too
89104
left: "center",
90105
z: 0,
91106
textStyle: {
92-
fontSize: (typeof window !== 'undefined' && window.innerWidth < 768) ? 14 : 16,
107+
fontSize: isMobile ? 14 : 18, // Larger font on desktop
108+
fontWeight: 'bold',
93109
}
94110
},
95111
tooltip: {
@@ -98,30 +114,33 @@ export function PieDataDistributionChart() {
98114
z: 4,
99115
},
100116
legend: {
101-
orient: (typeof window !== 'undefined' && window.innerWidth < 768) ? "horizontal" : "vertical",
102-
left: (typeof window !== 'undefined' && window.innerWidth < 768) ? "center" : 5,
103-
top: (typeof window !== 'undefined' && window.innerWidth < 768) ? 'bottom' : '42.5%',
104-
bottom: (typeof window !== 'undefined' && window.innerWidth < 768) ? 10 : undefined,
117+
orient: "vertical",
118+
left: isMobile ? 5 : 10,
119+
top: isMobile ? '47.5%' : '47.5%', // Adjust for fewer legend items
120+
bottom: undefined,
105121
type: "scroll",
106122
z: 0,
107123
textStyle: {
108-
fontSize: (typeof window !== 'undefined' && window.innerWidth < 768) ? 12 : 14,
124+
fontSize: isMobile ? 13 : 16, // Larger font for mobile too
109125
color: '#333',
110126
},
127+
itemWidth: isMobile ? 12 : 16, // Slightly larger icons for mobile
128+
itemHeight: isMobile ? 12 : 16,
129+
itemGap: isMobile ? 8 : 15, // More spacing for mobile
111130
},
112131
series: [pieSeries],
113132
};
114-
}, [allTasks]);
133+
}, [allTasks, isMobile]);
115134

116135
return (
117-
<Card className="w-full h-[250px] sm:h-[300px]">
118-
<CardContent className="h-[250px] sm:h-[300px] p-2 sm:p-6">
136+
<Card className="w-full h-[250px] sm:h-[350px]">
137+
<CardContent className="h-[250px] sm:h-[350px] p-2 sm:p-6">
119138
<ReactECharts
120139
option={chartOptions}
121140
style={{ height: "100%", width: "100%" }}
122141
opts={{
123142
renderer: "svg",
124-
devicePixelRatio: (typeof window !== 'undefined' && window.innerWidth < 768) ? 1 : 2
143+
devicePixelRatio: isMobile ? 1 : 2
125144
}}
126145
/>
127146
</CardContent>

src/components/charts/TaskDistributionChart.tsx

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22

33
import { useEvaluation } from "@/context/EvaluationContext";
4-
import React, { useMemo } from "react";
4+
import React, { useMemo, useState, useEffect } from "react";
55
import ReactECharts from "echarts-for-react";
66
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
77
import type { EChartsOption, PieSeriesOption } from "echarts";
@@ -15,6 +15,19 @@ export function TaskDistributionChart({ chartType = "organ" }: TaskDistributionC
1515
getFilteredTasks,
1616
} = useEvaluation();
1717

18+
// Use React state for responsive design instead of window object
19+
const [isMobile, setIsMobile] = useState(false);
20+
21+
useEffect(() => {
22+
const checkIsMobile = () => {
23+
setIsMobile(window.innerWidth < 768);
24+
};
25+
26+
checkIsMobile();
27+
window.addEventListener('resize', checkIsMobile);
28+
return () => window.removeEventListener('resize', checkIsMobile);
29+
}, []);
30+
1831
const chartOptions = useMemo((): EChartsOption => {
1932
const filteredTasks = getFilteredTasks();
2033

@@ -50,8 +63,8 @@ export function TaskDistributionChart({ chartType = "organ" }: TaskDistributionC
5063
const pieSeries: PieSeriesOption = {
5164
name: "Organ Distribution",
5265
type: "pie",
53-
radius: ["45%", "75%"], // Donut chart
54-
center: ["65%", "60%"],
66+
radius: isMobile ? ["35%", "65%"] : ["45%", "75%"], // Donut chart - moderate size
67+
center: isMobile ? ["65%", "55%"] : ["60%", "55%"], // Move down for more space from title
5568
avoidLabelOverlap: true,
5669
itemStyle: {
5770
borderRadius: 10,
@@ -65,7 +78,7 @@ export function TaskDistributionChart({ chartType = "organ" }: TaskDistributionC
6578
emphasis: {
6679
label: {
6780
show: true,
68-
fontSize: 16,
81+
fontSize: isMobile ? 14 : 16,
6982
fontWeight: "bold",
7083
},
7184
},
@@ -88,27 +101,31 @@ export function TaskDistributionChart({ chartType = "organ" }: TaskDistributionC
88101

89102
title: {
90103
text: "Task Distribution by Organ",
91-
top: '4.5%',
104+
top: isMobile ? '2%' : '1%', // Higher on mobile too
92105
left: "center",
93106
textStyle: {
94-
fontSize: (typeof window !== 'undefined' && window.innerWidth < 768) ? 14 : 16,
107+
fontSize: isMobile ? 14 : 18, // Larger font on desktop
108+
fontWeight: 'bold',
95109
}
96110
},
97111
tooltip: {
98112
trigger: "item",
99113
formatter: "{a} <br/>{b}: {c} ({d}%)",
100114
},
101115
legend: {
102-
orient: (typeof window !== 'undefined' && window.innerWidth < 768) ? "horizontal" : "vertical",
103-
left: (typeof window !== 'undefined' && window.innerWidth < 768) ? "center" : 5,
104-
top: (typeof window !== 'undefined' && window.innerWidth < 768) ? 'bottom' : '42.5%',
105-
bottom: (typeof window !== 'undefined' && window.innerWidth < 768) ? 10 : undefined,
116+
orient: "vertical",
117+
left: isMobile ? 5 : 10,
118+
top: isMobile ? '30%' : '30%', // Move down to match pie chart center
119+
bottom: undefined,
106120
type: "scroll",
107121
z: 0,
108122
textStyle: {
109-
fontSize: (typeof window !== 'undefined' && window.innerWidth < 768) ? 12 : 14,
123+
fontSize: isMobile ? 13 : 16, // Larger font for mobile too
110124
color: '#333',
111125
},
126+
itemWidth: isMobile ? 12 : 16, // Slightly larger icons for mobile
127+
itemHeight: isMobile ? 12 : 16,
128+
itemGap: isMobile ? 8 : 15, // More spacing for mobile
112129
},
113130
series: [pieSeries],
114131
};
@@ -120,20 +137,21 @@ export function TaskDistributionChart({ chartType = "organ" }: TaskDistributionC
120137
taskTypeCounts[taskType] = (taskTypeCounts[taskType] || 0) + 1;
121138
});
122139

123-
// Format data for pie chart
124-
const data = Object.entries(taskTypeCounts).map(([taskType, count]) => {
125-
return {
126-
name: taskType.replace('_', ' '),
127-
value: count,
128-
};
129-
});
140+
// Format data for pie chart with custom order
141+
const taskTypeOrder = ['Classification', 'DFS Prediction', 'DSS Prediction', 'OS Prediction'];
142+
const data = taskTypeOrder
143+
.filter(taskType => taskTypeCounts[taskType] > 0) // Only include types that exist
144+
.map(taskType => ({
145+
name: taskType,
146+
value: taskTypeCounts[taskType],
147+
}));
130148

131149
// Create pie series
132150
const pieSeries: PieSeriesOption = {
133151
name: "Task Type Distribution",
134152
type: "pie",
135-
radius: ["45%", "75%"],
136-
center: ["70%", "60%"],
153+
radius: isMobile ? ["35%", "65%"] : ["45%", "75%"], // Moderate size for better balance
154+
center: isMobile ? ["65%", "55%"] : ["70%", "55%"], // Move down and right for better spacing
137155
avoidLabelOverlap: true,
138156
itemStyle: {
139157
borderRadius: 10,
@@ -147,7 +165,7 @@ export function TaskDistributionChart({ chartType = "organ" }: TaskDistributionC
147165
emphasis: {
148166
label: {
149167
show: true,
150-
fontSize: 16,
168+
fontSize: isMobile ? 14 : 16,
151169
fontWeight: "bold",
152170
},
153171
},
@@ -170,42 +188,46 @@ export function TaskDistributionChart({ chartType = "organ" }: TaskDistributionC
170188

171189
title: {
172190
text: "Task Distribution by Type",
173-
top: '4.5%',
191+
top: isMobile ? '2%' : '1%', // Higher on mobile too
174192
left: "center",
175193
textStyle: {
176-
fontSize: (typeof window !== 'undefined' && window.innerWidth < 768) ? 14 : 16,
194+
fontSize: isMobile ? 14 : 18, // Larger font on desktop
195+
fontWeight: 'bold',
177196
}
178197
},
179198
tooltip: {
180199
trigger: "item",
181200
formatter: "{a} <br/>{b}: {c} ({d}%)",
182201
},
183202
legend: {
184-
orient: (typeof window !== 'undefined' && window.innerWidth < 768) ? "horizontal" : "vertical",
185-
left: (typeof window !== 'undefined' && window.innerWidth < 768) ? "center" : 0,
186-
top: (typeof window !== 'undefined' && window.innerWidth < 768) ? 'bottom' : '42.5%',
187-
bottom: (typeof window !== 'undefined' && window.innerWidth < 768) ? 10 : undefined,
203+
orient: "vertical",
204+
left: isMobile ? 5 : 2.5,
205+
top: isMobile ? '37.5%' : '37.5%', // Move down to match pie chart center
206+
bottom: undefined,
188207
type: "scroll",
189208
z: 0,
190209
textStyle: {
191-
fontSize: (typeof window !== 'undefined' && window.innerWidth < 768) ? 12 : 14,
210+
fontSize: isMobile ? 13 : 16, // Larger font for mobile too
192211
color: '#333',
193212
},
213+
itemWidth: isMobile ? 12 : 16, // Slightly larger icons for mobile
214+
itemHeight: isMobile ? 12 : 16,
215+
itemGap: isMobile ? 8 : 15, // More spacing for mobile
194216
},
195217
series: [pieSeries],
196218
};
197219
}
198-
}, [getFilteredTasks, chartType]);
220+
}, [getFilteredTasks, chartType, isMobile]);
199221

200222
return (
201-
<Card className="w-full h-[250px] sm:h-[300px]">
202-
<CardContent className="h-[250px] sm:h-[300px] p-2 sm:p-6">
223+
<Card className="w-full h-[250px] sm:h-[350px]">
224+
<CardContent className="h-[250px] sm:h-[350px] p-2 sm:p-6">
203225
<ReactECharts
204226
option={chartOptions}
205227
style={{ height: "100%", width: "100%" }}
206228
opts={{
207229
renderer: "svg",
208-
devicePixelRatio: (typeof window !== 'undefined' && window.innerWidth < 768) ? 1 : 2
230+
devicePixelRatio: isMobile ? 1 : 2
209231
}}
210232
/>
211233
</CardContent>

src/components/filters/TaskTypeFilter.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ export function TaskTypeFilter() {
2929
/>
3030
<Label
3131
htmlFor={`task-type-${taskType}`}
32-
className="text-xs sm:text-sm font-normal capitalize leading-tight"
32+
className="text-xs sm:text-sm font-normal leading-tight"
3333
>
34-
{taskType.replace('_', ' ')}
34+
{taskType}
3535
</Label>
3636
</div>
3737
))}

src/context/EvaluationContext.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ export function EvaluationProvider({ children }: { children: React.ReactNode })
7474

7575
// Computed values
7676
const allTaskTypes = useMemo(() => {
77-
return Array.from(new Set(tasks.map(task => task.taskType)));
77+
// Define custom order for task types
78+
const taskTypeOrder = ['Classification', 'DFS Prediction', 'DSS Prediction', 'OS Prediction'];
79+
const existingTaskTypes = new Set(tasks.map(task => task.taskType));
80+
81+
// Return ordered task types that actually exist in the data
82+
return taskTypeOrder.filter(taskType => existingTaskTypes.has(taskType));
7883
}, []);
7984

8085
// Create organs from tasks

0 commit comments

Comments
 (0)