移动的词云。
<template>
<div>
<div
class="wordCloud__tagBall"
:style="{ width: `${this.width}px`, height: `${this.height}px` }"
@mouseenter="stop"
@mouseleave="start"
>
<span
class="wordCloud__tag"
v-for="(item, index) of data"
:key="index"
:style="{
color: color[index % color.length],
fontSize: fontSizes[index],
...contentEle[index].style,
}"
:title="item.name + '\n' + item.value"
@click="handleClick(item)"
>{{ item.name }}</span
>
</div>
</div>
</template>
<script>
export default {
name: "cloudWork",
props: {
width: {
type: Number,
default: 300,
},
height: {
type: Number,
default: 300,
},
// 测试数据
data: {
type: Array,
default: () => [
{
name: "建议",
value: 72,
},
],
},
},
data: () => ({
color: ["#37A2DA", "#23517E"], // 字体颜色
fontSizes: ["30px", "29px", "28px"], // 字体大小
contentEle: [],
direction: "-1", // 运动方向 |x|<1水平方向 1<|x|<2 垂直方向
speed: 500, // 运动速度
animateID: null,
}),
created() {
this.data = this.data.sort(this.compare("value")); // 按value值的大小排序
this.contentEle = this.data.map(() => ({
x: 0,
y: 0,
z: 0,
style: {},
}));
},
mounted() {
this.innit();
},
methods: {
handleClick(item) {
// console.log("item===>", item);
},
// 排序
compare(property) {
return function (a, b) {
const value1 = a[property];
const value2 = b[property];
return value2 - value1;
};
},
// 初始化
innit() {
const RADIUSX = (this.width - 50) / 2;
const RADIUSY = (this.height - 50) / 2;
this.contentEle = [];
for (let i = 0; i < this.data.length; i += 1) {
const k = -1 + (2 * (i + 1) - 1) / this.data.length;
const a = Math.acos(k); // 取反余弦的值
const b = a * Math.sqrt(this.data.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();
},
animate() {
this.rotateX();
this.rotateY();
this.move();
this.animateID = window.requestAnimationFrame(this.animate);
},
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) => {
const y1 = t.y * cos - t.z * sin;
const z1 = t.z * cos + t.y * sin;
return {
...t,
y: y1,
z: z1,
};
});
},
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) => {
const x1 = t.x * cos - t.z * sin;
const z1 = t.z * cos + t.x * sin;
return {
...t,
x: x1,
z: z1,
};
});
},
move() {
const CX = this.width / 2;
const CY = this.height / 2;
this.contentEle = this.contentEle.map((singleEle) => {
const { x, y, z } = singleEle;
const fallLength = 700;
const RADIUS = (this.width - 50) / 2;
const scale = fallLength / (fallLength - z);
const alpha = (z + RADIUS) / (2 * RADIUS);
const left = `${x + CX - 30}px`;
const top = `${y + CY - 15}px`;
// const transform = `translate(${left}, ${top}) scale(${scale})`
const transform = `translate(${left}, ${top}) `;
const style = {
...singleEle.style,
opacity: alpha + 0.5,
zIndex: parseInt(scale * 100, 10),
transform,
};
return {
x,
y,
z,
style,
};
});
},
// 鼠标移入暂停
stop() {
window.cancelAnimationFrame(this.animateID);
},
// 鼠标离开恢复
start() {
this.animate();
},
},
};
</script>
<style scoped>
button {
margin: 20px;
}
.wordCloud__tagBall {
margin: 20px auto;
margin-left: 0px;
position: relative;
width: 100%;
height: 220px;
}
.wordCloud__tag {
display: block;
position: absolute;
left: 0px;
top: 0px;
color: green;
text-decoration: none;
font-size: 18px;
font-family: "微软雅黑";
font-weight: bold;
cursor: pointer;
}
.wordCloud__home {
display: flex;
justify-content: center;
}
</style>