feat: 行业词云图
This commit is contained in:
@ -26,19 +26,18 @@
|
||||
<a-tag
|
||||
v-for="(tag, tagIndex) in row.tags"
|
||||
:key="tagIndex"
|
||||
class="cursor-pointer"
|
||||
:style="{
|
||||
fontSize: `${getFontSize(rowIndex, tagIndex)}px`,
|
||||
lineHeight: `${getLineHeight(rowIndex, tagIndex) + 10}px`,
|
||||
fontSize: `${getTagStyle(rowIndex, tagIndex, row.tags.length).fontSize}px`,
|
||||
height: `${getTagStyle(rowIndex, tagIndex, row.tags.length).lineHeight}px`,
|
||||
color: '#6d4cfe',
|
||||
backgroundColor: '#F0EDFF',
|
||||
margin: '12px',
|
||||
margin: '0 12px 12px 0',
|
||||
transition: 'all 0.3s',
|
||||
paddingLeft: `${getPaddingLeft(rowIndex, tagIndex)}px`,
|
||||
paddingRight: `${getPaddingLeft(rowIndex, tagIndex)}px`,
|
||||
paddingTop: `${getPadding(rowIndex, tagIndex)}px`,
|
||||
paddingBottom: `${getPadding(rowIndex, tagIndex)}px`,
|
||||
borderRadius: '100px',
|
||||
borderRadius: '100px',
|
||||
borderRadius: '32px',
|
||||
fontWeight: 400,
|
||||
}"
|
||||
@mouseenter="hoverTag = tag"
|
||||
@mouseleave="hoverTag = null"
|
||||
@ -85,30 +84,34 @@ const getIndustryTerms = async () => {
|
||||
industry_id: selectedIndustry.value,
|
||||
time_dimension: selectedTimePeriod.value,
|
||||
};
|
||||
if (selectedSubCategory.value != 0) {
|
||||
if (selectedSubCategory.value !== 0) {
|
||||
params['industry_id'] = selectedSubCategory.value;
|
||||
}
|
||||
const res = await fetchindustryTerms(params);
|
||||
// 这里需要根据API返回的数据结构处理成tagRows需要的格式
|
||||
tagRows.value = processTagData(res);
|
||||
tagRows.value = processTagData(res.slice(0, 70));
|
||||
};
|
||||
|
||||
// 标签数据(按行分组)
|
||||
const tagRows = ref();
|
||||
const hoverTag = ref(null);
|
||||
|
||||
// 根据行列位置计算字体大小(中间最大)
|
||||
const getFontSize = (rowIndex, tagIndex) => {
|
||||
const centerRow = Math.floor(tagRows.value.length / 2);
|
||||
const distance = Math.abs(rowIndex - centerRow);
|
||||
return 38 - distance * 8 + (tagIndex % 2) * 5; // 基础24px,行距影响4px,微调差异2px
|
||||
};
|
||||
const lineHeightStart = [28, 52, 58, 72, 58, 52, 28]; // 7行时
|
||||
const fontSizeStart = [12, 26, 28, 38, 28, 26, 12]; // 7行时
|
||||
const stepLineHeight = 10; // 行高每步递减
|
||||
const stepFontSize = 6; // 字号每步递减
|
||||
|
||||
const getLineHeight = (rowIndex, tagIndex) => {
|
||||
const centerRow = Math.floor(tagRows.value.length / 2);
|
||||
const distance = Math.abs(rowIndex - centerRow);
|
||||
return 48 - distance * 8 + (tagIndex % 2) * 5; // 基础24px,行距影响4px,微调差异2px
|
||||
};
|
||||
function getTagStyle(rowIndex, tagIndex, tagsLength) {
|
||||
// 计算当前行的中间起点
|
||||
const center = Math.floor(tagsLength / 2);
|
||||
const distance = Math.abs(tagIndex - center);
|
||||
|
||||
// 递减,最小值保护
|
||||
const lineHeight = Math.max(lineHeightStart[rowIndex] - stepLineHeight * distance, 28);
|
||||
const fontSize = Math.max(fontSizeStart[rowIndex] - stepFontSize * distance, 12);
|
||||
|
||||
return { fontSize, lineHeight };
|
||||
}
|
||||
|
||||
const getPaddingLeft = (rowIndex, tagIndex) => {
|
||||
const centerRow = Math.floor(tagRows.value.length / 2);
|
||||
@ -124,35 +127,34 @@ const getPadding = (rowIndex, tagIndex) => {
|
||||
|
||||
// 处理API返回数据为tagRows格式
|
||||
const processTagData = (apiData) => {
|
||||
const totalGroups = 4; // 总组数
|
||||
const middleIndex = Math.floor(totalGroups / 2); // 中间位置(索引3)
|
||||
const chunkSize = Math.ceil(apiData.length / totalGroups); // 每组大小
|
||||
const arr = [];
|
||||
// 计算应该分几行,最多7行
|
||||
const maxRows = 7;
|
||||
const rowCount = Math.min(Math.ceil(apiData.length / 7), maxRows);
|
||||
|
||||
// 1. 先按顺序分组
|
||||
const tempGroups = [];
|
||||
for (let i = 0; i < totalGroups; i++) {
|
||||
const start = i * chunkSize;
|
||||
const end = start + chunkSize;
|
||||
tempGroups.push(apiData.slice(start, end));
|
||||
// 均分数据到rowCount行
|
||||
const baseCount = Math.floor(apiData.length / rowCount);
|
||||
let remain = apiData.length % rowCount;
|
||||
const rows = [];
|
||||
let start = 0;
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
let count = baseCount + (remain > 0 ? 1 : 0);
|
||||
if (remain > 0) remain--;
|
||||
rows.push(apiData.slice(start, start + count));
|
||||
start += count;
|
||||
}
|
||||
|
||||
// 2. 从中间开始,左右交替插入
|
||||
for (let i = 0; i < totalGroups; i++) {
|
||||
// 计算当前组应该插入的位置
|
||||
const insertPos = i % 2 === 0 ? middleIndex + i / 2 : middleIndex - Math.ceil(i / 2);
|
||||
|
||||
// 确保不越界
|
||||
if (insertPos >= 0 && insertPos < totalGroups) {
|
||||
arr[insertPos] = { tags: tempGroups[i], align: 'center' };
|
||||
// 居中分布,从中间往两侧
|
||||
const result = [];
|
||||
const center = Math.floor(rowCount / 2);
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const pos = i % 2 === 0 ? center + Math.floor(i / 2) : center - Math.ceil(i / 2);
|
||||
result[pos] = { tags: rows[i], align: 'center' };
|
||||
}
|
||||
}
|
||||
|
||||
return arr.filter(Boolean); // 移除可能的空项
|
||||
return result;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="less">
|
||||
/* 自定义样式 */
|
||||
:deep(.arco-table-th) {
|
||||
background-color: var(--color-fill-2);
|
||||
@ -168,14 +170,29 @@ const processTagData = (apiData) => {
|
||||
:deep(.arco-modal-body) {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.multi-row-tag-cloud {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.tag-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
// flex-wrap: wrap;
|
||||
:deep(.arco-tag) {
|
||||
transition: all 0.3s;
|
||||
border-radius: 32px;
|
||||
font-weight: 400;
|
||||
// min-width: 100px;
|
||||
max-width: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
&:hover {
|
||||
background-color: #ffffff !important;
|
||||
color: #6d4cfe !important;
|
||||
box-shadow: 0px 4px 12px 0px #0000001a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 悬停放大效果 */
|
||||
|
||||
Reference in New Issue
Block a user