feat(LimitAnalyse): 优化数据可视化组件
- 改进板块分布饼图展示 - 优化涨停时段统计图表 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -39,17 +39,6 @@ import {
|
||||
import { getFormattedTextProps } from '../../../utils/textUtils';
|
||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
||||
import RiskDisclaimer from '../../../components/RiskDisclaimer';
|
||||
import {
|
||||
BarChart, Bar,
|
||||
PieChart, Pie, Cell,
|
||||
XAxis, YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip as RechartsTooltip,
|
||||
Legend,
|
||||
ResponsiveContainer,
|
||||
Treemap,
|
||||
Area, AreaChart,
|
||||
} from 'recharts';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import 'echarts-wordcloud';
|
||||
// 颜色配置
|
||||
@@ -137,6 +126,149 @@ const WordCloud = ({ data }) => {
|
||||
return <EChartsWordCloud data={data} />;
|
||||
};
|
||||
|
||||
// 板块分布饼图 - ECharts 实现
|
||||
const SectorPieChart = ({ data }) => {
|
||||
if (!data || data.length === 0) {
|
||||
return (
|
||||
<Center h="400px">
|
||||
<Text color="gray.500">暂无数据</Text>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
textStyle: { fontSize: 12 }
|
||||
},
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['0%', '65%'],
|
||||
center: ['40%', '50%'],
|
||||
avoidLabelOverlap: true,
|
||||
itemStyle: {
|
||||
borderRadius: 4,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{b} {d}%',
|
||||
fontSize: 12
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 10,
|
||||
length2: 15
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
},
|
||||
data: data.map((item, index) => ({
|
||||
name: item.name,
|
||||
value: item.value,
|
||||
itemStyle: { color: CHART_COLORS[index % CHART_COLORS.length] }
|
||||
})),
|
||||
animationDuration: 800
|
||||
}]
|
||||
};
|
||||
|
||||
return (
|
||||
<ReactECharts
|
||||
option={option}
|
||||
style={{ height: '400px', width: '100%' }}
|
||||
opts={{ renderer: 'canvas' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// 时间分布环形图 - ECharts 实现
|
||||
const TimeDistributionChart = ({ data }) => {
|
||||
if (!data || data.length === 0) {
|
||||
return (
|
||||
<Center h="300px">
|
||||
<Text color="gray.500">暂无数据</Text>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'horizontal',
|
||||
bottom: 10,
|
||||
textStyle: { fontSize: 12 }
|
||||
},
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['45%', '70%'],
|
||||
center: ['50%', '45%'],
|
||||
avoidLabelOverlap: true,
|
||||
padAngle: 3,
|
||||
itemStyle: {
|
||||
borderRadius: 6,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
formatter: '{b}\n{c}只',
|
||||
fontSize: 11
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 8,
|
||||
length2: 12
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: 13,
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
},
|
||||
data: data.map(item => ({
|
||||
name: item.name,
|
||||
value: item.value,
|
||||
itemStyle: { color: item.color }
|
||||
})),
|
||||
animationDuration: 800
|
||||
}]
|
||||
};
|
||||
|
||||
return (
|
||||
<ReactECharts
|
||||
option={option}
|
||||
style={{ height: '300px', width: '100%' }}
|
||||
opts={{ renderer: 'canvas' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// 板块热力图组件
|
||||
const SectorHeatMap = ({ data }) => {
|
||||
if (!data) return null;
|
||||
@@ -496,27 +628,7 @@ export const DataAnalysis = ({ dailyData, wordCloudData, totalStocks, dateStr })
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel>
|
||||
<ResponsiveContainer width="100%" height={400}>
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={pieData}
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
labelLine={false}
|
||||
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
|
||||
outerRadius={120}
|
||||
fill="#8884d8"
|
||||
dataKey="value"
|
||||
animationBegin={0}
|
||||
animationDuration={800}
|
||||
>
|
||||
{pieData.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
<RechartsTooltip />
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
<SectorPieChart data={pieData} />
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel>
|
||||
@@ -545,25 +657,7 @@ export const DataAnalysis = ({ dailyData, wordCloudData, totalStocks, dateStr })
|
||||
|
||||
<TabPanel>
|
||||
<VStack spacing={4}>
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={timeDistributionData}
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
innerRadius={60}
|
||||
outerRadius={100}
|
||||
fill="#8884d8"
|
||||
paddingAngle={5}
|
||||
dataKey="value"
|
||||
>
|
||||
{timeDistributionData.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={entry.color} />
|
||||
))}
|
||||
</Pie>
|
||||
<RechartsTooltip />
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
<TimeDistributionChart data={timeDistributionData} />
|
||||
<SimpleGrid columns={3} spacing={4} w="full">
|
||||
{timeDistributionData.map((item, index) => (
|
||||
<Stat key={index} textAlign="center">
|
||||
|
||||
Reference in New Issue
Block a user