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 { getFormattedTextProps } from '../../../utils/textUtils';
|
||||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
||||||
import RiskDisclaimer from '../../../components/RiskDisclaimer';
|
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 ReactECharts from 'echarts-for-react';
|
||||||
import 'echarts-wordcloud';
|
import 'echarts-wordcloud';
|
||||||
// 颜色配置
|
// 颜色配置
|
||||||
@@ -137,6 +126,149 @@ const WordCloud = ({ data }) => {
|
|||||||
return <EChartsWordCloud data={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 }) => {
|
const SectorHeatMap = ({ data }) => {
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
@@ -496,27 +628,7 @@ export const DataAnalysis = ({ dailyData, wordCloudData, totalStocks, dateStr })
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<ResponsiveContainer width="100%" height={400}>
|
<SectorPieChart data={pieData} />
|
||||||
<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>
|
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
@@ -545,25 +657,7 @@ export const DataAnalysis = ({ dailyData, wordCloudData, totalStocks, dateStr })
|
|||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<VStack spacing={4}>
|
<VStack spacing={4}>
|
||||||
<ResponsiveContainer width="100%" height={300}>
|
<TimeDistributionChart data={timeDistributionData} />
|
||||||
<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>
|
|
||||||
<SimpleGrid columns={3} spacing={4} w="full">
|
<SimpleGrid columns={3} spacing={4} w="full">
|
||||||
{timeDistributionData.map((item, index) => (
|
{timeDistributionData.map((item, index) => (
|
||||||
<Stat key={index} textAlign="center">
|
<Stat key={index} textAlign="center">
|
||||||
|
|||||||
Reference in New Issue
Block a user