pref: src/views/LimitAnalyse 页面 "数据分析"卡片中的"热词云图" 依赖更新

This commit is contained in:
zdl
2025-11-21 17:37:56 +08:00
parent 834067f679
commit 39978c57d5
2 changed files with 78 additions and 25 deletions

View File

@@ -22,7 +22,11 @@
"@splidejs/react-splide": "^0.7.12",
"@tanstack/react-virtual": "^3.13.12",
"@tippyjs/react": "^4.2.6",
"@visx/responsive": "^3.12.0",
"@visx/scale": "^3.12.0",
"@visx/text": "^3.12.0",
"@visx/visx": "^3.12.0",
"@visx/wordcloud": "^3.12.0",
"antd": "^5.27.4",
"apexcharts": "^3.27.3",
"axios": "^1.10.0",
@@ -70,7 +74,6 @@
"react-tagsinput": "3.19.0",
"react-to-print": "^2.13.0",
"react-tsparticles": "^2.12.2",
"react-wordcloud": "^1.2.7",
"recharts": "^3.1.2",
"sass": "^1.49.9",
"scroll-lock": "^2.1.5",

View File

@@ -1,4 +1,4 @@
import React, { useMemo, useState, useEffect } from 'react';
import React, { useMemo, useState, useEffect, useRef } from 'react';
import {
Box,
Card,
@@ -39,7 +39,6 @@ import {
import { getFormattedTextProps } from '../../../utils/textUtils';
import { ExternalLinkIcon } from '@chakra-ui/icons';
import RiskDisclaimer from '../../../components/RiskDisclaimer';
import './WordCloud.css';
import {
BarChart, Bar,
PieChart, Pie, Cell,
@@ -51,15 +50,44 @@ import {
Treemap,
Area, AreaChart,
} from 'recharts';
import ReactWordcloud from 'react-wordcloud';
import { Wordcloud } from '@visx/wordcloud';
import { scaleLog } from '@visx/scale';
import { Text as VisxText } from '@visx/text';
// 颜色配置
const CHART_COLORS = [
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEEAD',
'#D4A5A5', '#9B6B6B', '#E9967A', '#B19CD9', '#87CEEB'
];
// 词云图组件
// 词云颜色
const WORDCLOUD_COLORS = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEEAD'];
// 词云图组件(使用 @visx/wordcloud兼容 React 18
const WordCloud = ({ data }) => {
const [dimensions, setDimensions] = useState({ width: 0, height: 400 });
const containerRef = useRef(null);
// 监听容器尺寸变化
useEffect(() => {
if (!containerRef.current) return;
const updateDimensions = () => {
if (containerRef.current) {
setDimensions({
width: containerRef.current.offsetWidth,
height: 400
});
}
};
updateDimensions();
const resizeObserver = new ResizeObserver(updateDimensions);
resizeObserver.observe(containerRef.current);
return () => resizeObserver.disconnect();
}, []);
if (!data || data.length === 0) {
return (
<Center h="400px">
@@ -75,29 +103,51 @@ const WordCloud = ({ data }) => {
value: item.value || item.count || 1
}));
const options = {
rotations: 2,
rotationAngles: [-90, 0],
fontFamily: 'Microsoft YaHei, sans-serif',
fontSizes: [16, 80],
fontWeight: 'bold',
padding: 3,
scale: 'sqrt',
};
// 计算字体大小比例
const fontScale = scaleLog({
domain: [
Math.min(...words.map(w => w.value)),
Math.max(...words.map(w => w.value))
],
range: [16, 80],
});
const callbacks = {
getWordColor: () => {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEEAD'];
return colors[Math.floor(Math.random() * colors.length)];
}
};
const fontSizeSetter = (datum) => fontScale(datum.value);
return (
<ReactWordcloud
words={words}
options={options}
callbacks={callbacks}
/>
<Box ref={containerRef} h="400px" w="100%">
{dimensions.width > 0 && (
<svg width={dimensions.width} height={dimensions.height}>
<Wordcloud
words={words}
width={dimensions.width}
height={dimensions.height}
fontSize={fontSizeSetter}
font="Microsoft YaHei, sans-serif"
padding={3}
spiral="archimedean"
rotate={0}
random={() => 0.5}
>
{(cloudWords) =>
cloudWords.map((w, i) => (
<VisxText
key={w.text}
fill={WORDCLOUD_COLORS[i % WORDCLOUD_COLORS.length]}
textAnchor="middle"
transform={`translate(${w.x}, ${w.y}) rotate(${w.rotate})`}
fontSize={w.size}
fontFamily={w.font}
fontWeight="bold"
>
{w.text}
</VisxText>
))
}
</Wordcloud>
</svg>
)}
</Box>
);
};