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", "@splidejs/react-splide": "^0.7.12",
"@tanstack/react-virtual": "^3.13.12", "@tanstack/react-virtual": "^3.13.12",
"@tippyjs/react": "^4.2.6", "@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/visx": "^3.12.0",
"@visx/wordcloud": "^3.12.0",
"antd": "^5.27.4", "antd": "^5.27.4",
"apexcharts": "^3.27.3", "apexcharts": "^3.27.3",
"axios": "^1.10.0", "axios": "^1.10.0",
@@ -70,7 +74,6 @@
"react-tagsinput": "3.19.0", "react-tagsinput": "3.19.0",
"react-to-print": "^2.13.0", "react-to-print": "^2.13.0",
"react-tsparticles": "^2.12.2", "react-tsparticles": "^2.12.2",
"react-wordcloud": "^1.2.7",
"recharts": "^3.1.2", "recharts": "^3.1.2",
"sass": "^1.49.9", "sass": "^1.49.9",
"scroll-lock": "^2.1.5", "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 { import {
Box, Box,
Card, Card,
@@ -39,7 +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 './WordCloud.css';
import { import {
BarChart, Bar, BarChart, Bar,
PieChart, Pie, Cell, PieChart, Pie, Cell,
@@ -51,15 +50,44 @@ import {
Treemap, Treemap,
Area, AreaChart, Area, AreaChart,
} from 'recharts'; } 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 = [ const CHART_COLORS = [
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEEAD', '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEEAD',
'#D4A5A5', '#9B6B6B', '#E9967A', '#B19CD9', '#87CEEB' '#D4A5A5', '#9B6B6B', '#E9967A', '#B19CD9', '#87CEEB'
]; ];
// 词云图组件 // 词云颜色
const WORDCLOUD_COLORS = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEEAD'];
// 词云图组件(使用 @visx/wordcloud兼容 React 18
const WordCloud = ({ data }) => { 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) { if (!data || data.length === 0) {
return ( return (
<Center h="400px"> <Center h="400px">
@@ -75,29 +103,51 @@ const WordCloud = ({ data }) => {
value: item.value || item.count || 1 value: item.value || item.count || 1
})); }));
const options = { // 计算字体大小比例
rotations: 2, const fontScale = scaleLog({
rotationAngles: [-90, 0], domain: [
fontFamily: 'Microsoft YaHei, sans-serif', Math.min(...words.map(w => w.value)),
fontSizes: [16, 80], Math.max(...words.map(w => w.value))
fontWeight: 'bold', ],
padding: 3, range: [16, 80],
scale: 'sqrt', });
};
const callbacks = { const fontSizeSetter = (datum) => fontScale(datum.value);
getWordColor: () => {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEEAD'];
return colors[Math.floor(Math.random() * colors.length)];
}
};
return ( return (
<ReactWordcloud <Box ref={containerRef} h="400px" w="100%">
words={words} {dimensions.width > 0 && (
options={options} <svg width={dimensions.width} height={dimensions.height}>
callbacks={callbacks} <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>
); );
}; };