效果如下:
主要替换的数据为:
wordData:词云数据(图示效果为20词,每个词的长度在4-5效果最好)
colorList:颜色组
html
<div class="wordCloudTagBall">
<span
class="wordCloudTag"
v-for="(item, index) of wordData"
:key="index"
:style="{
color: colorList[index % colorList.length],
...contentEle[index].style,
}"
:title="item">{{ item }}</span>
</div>
ts
// 词云数据
private wordData: any = [
'高新企业',
'100.9万',
'怀柔区国家',
'一核四区',
'实验室挂牌',
'高新企业',
'企业入驻',
'一核四区',
];
// 颜色组
private colorList: any = [
'#FF7866',
'#5DEC6B',
'#ff646f',
'#00F6FF',
'#2eccff',
'#E2CE22',
'#0090FF',
'#1BDA87',
];
private contentEle: any = []; // 词云的位置信息
private direction: string = '-1'; // 方向 (-1 从左到右 1 从右到左 2从下到上 -2从上到下)
private speed: number = 1000; // 速度
private width: number = 360; // 词云宽
private height: number = 200; // 词云高
// @author: 奥特蛋 @date: 2022-05-11 18:51:35 @description:初始化
private init() {
const RADIUSX = (this.width - 50) / 2;
const RADIUSY = (this.height - 50) / 2;
this.contentEle = [];
for (let i = 0; i < this.currentData.wordData.length; i += 1) {
const k = -1 + (2 * (i + 1) - 1) / this.currentData.wordData.length;
const a = Math.acos(k);
const b = a * Math.sqrt(this.currentData.wordData.length * Math.PI);
const x = RADIUSX * Math.sin(a) * Math.cos(b);
const y = RADIUSY * Math.sin(a) * Math.sin(b);
const z = RADIUSX * Math.cos(a);
const singleEle = {
x,
y,
z,
style: {},
};
this.contentEle.push(singleEle);
}
this.animate();
}
// @author: 奥特蛋 @date: 2022-05-12 09:20:49 @description: 词云运动效果添加
private animate() {
this.rotateX();
this.rotateY();
this.move();
window.requestAnimationFrame(this.animate);
}
// @author: 奥特蛋 @date: 2022-05-11 18:52:02 @description: 设置X轴旋转
private rotateX() {
const angleX = ['-1', '1'].includes(this.direction)
? Math.PI / Infinity
: Math.PI / ((Number(this.direction) / 2) * Number(this.speed));
const cos = Math.cos(angleX);
const sin = Math.sin(angleX);
this.contentEle = this.contentEle.map((t: any) => {
const y1 = t.y * cos - t.z * sin;
const z1 = t.z * cos + t.y * sin;
return {
...t,
y: y1,
z: z1,
};
});
}
// @author: 奥特蛋 @date: 2022-05-11 18:52:02 @description: 设置Y轴旋转
private rotateY() {
const angleY = ['-2', '2'].includes(this.direction)
? Math.PI / Infinity
: Math.PI / (Number(this.direction) * Number(this.speed));
const cos = Math.cos(angleY);
const sin = Math.sin(angleY);
this.contentEle = this.contentEle.map((t: any) => {
const x1 = t.x * cos - t.z * sin;
const z1 = t.z * cos + t.x * sin;
return {
...t,
x: x1,
z: z1,
};
});
}
// @author: 奥特蛋 @date: 2022-05-11 18:52:02 @description: 移动
private move() {
const CX = this.width / 2;
const CY = this.height / 2;
this.contentEle = this.contentEle.map((singleEle: any) => {
const { x, y, z } = singleEle;
const fallLength = 500;
const RADIUS = (this.width - 50) / 2;
const scale = fallLength / (fallLength - z);
const alpha = (z + RADIUS) / (2 * RADIUS);
const left = `${x + CX - 15}px`;
const top = `${y + CY - 15}px`;
const transform = `translate(${left}, ${top}) scale(${scale})`;
const style = {
...singleEle.style,
opacity: alpha + 0.5,
zIndex: parseInt(String(scale * 100), 10),
transform,
};
return {
x,
y,
z,
style,
};
});
}
private created() {
this.init();
}
css
.wordCloudTagBall {
position: relative;
overflow: hidden;
width: 360px;
height: 200px;
}
.wordCloudTag {
display: block;
position: absolute;
left: 0px;
top: 0px;
text-decoration: none;
font-size: 18px;
font-weight: bold;
}