You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
4.7 KiB

<template>
<!-- 词云 -->
<div class="tag-wrap">
<p v-for="(item, index) in data" :key="index" class="tag">
<span class="tag-name">{{ item.name }}</span>
<span class="tag-value">{{ item.count }}</span>
</p>
</div>
</template>
<script>
const colors = [
"rgba(0,236,255,0.8)",
"#fcd338",
"rgba(0,236,255,0.9)",
"#fcd338",
"#fcd338",
"rgba(255,255,255,0.9)",
"#fff",
"#fff",
"#fff",
"rgba(255,255,255,0.8)",
];
const RADIUS = 166; // 3d球的半径
const FALLLENGTH = 420;
let CX = null;
let CY = null;
class Tag {
constructor(el, x, y, z) {
this.el = el;
this.x = x;
this.y = y;
this.z = z;
}
move() {
const scale = FALLLENGTH / (FALLLENGTH - this.z);
const alpha = (this.z + RADIUS) / (2 * RADIUS);
const left = this.x + CX - this.el.offsetWidth / 2 + 30 + "px"; // 水平偏移
const top = this.y + CY - this.el.offsetHeight / 2 + 10 + "px"; // 竖直偏移
this.el.style.opacity = alpha;
this.el.style.zIndex = parseInt(scale * 100);
this.el.style.transform = `translate(${left},${top}) scale(${scale})`;
}
}
import { keyWords } from "@/api/common";
import { wordCloud } from "@/api/publicOpinion";
export default {
props: {},
data() {
return {
tagList: [],
data: [
{ name: "太仓市委", count: 200 },
{ name: "“交通先行”抢位长三角", count: 400 },
{ name: "太仓速度", count: 600 },
{ name: "最具幸福感城市", count: 2000 },
{ name: "振翅高飞", count: 350 },
{ name: "娄城防疫", count: 666 },
{ name: "城市更新", count: 899 },
{ name: "争当猛虎尖兵", count: 899 },
{ name: "家在太仓 情暖娄城", count: 899 },
{ name: "国土空间全域整治", count: 899 },
],
};
},
created() {
},
mounted() {
this.init();
this.animate();
},
methods: {
getDataList() {
wordCloud().then((res) => {
res.data.forEach((value) => {
this.data.push({
name: this.$filterDict("tc_cy_type", value.type),
count: 3,
});
});
});
},
init() {
const tags = document.querySelectorAll(".tag");
const wrap = document.querySelector(".tag-wrap");
const len = tags.length;
const valueList = Array.from(new Set(this.data.map((i) => i.count)));
const min = Math.min(...valueList);
CX = wrap.offsetWidth / 2;
CY = wrap.offsetHeight / 2;
tags.forEach((i, index) => {
const fontScale = (this.data[index].count / min) * 16;
i.style.fontSize = fontScale > 35 ? "35px" : fontScale + "px";
i.style.color = colors[parseInt(Math.random() * 10)];
const k = -1 + (2 * (index + 1) - 1) / len;
const a = Math.acos(k);
const b = a * Math.sqrt(len * Math.PI);
const x = RADIUS * 1.15 * Math.sin(a) * Math.cos(b);
const y = RADIUS * Math.sin(a) * Math.sin(b);
const z = RADIUS * Math.cos(a);
const tag = new Tag(i, x, y, z);
this.tagList.push(tag);
});
},
rotateX() {
const angleX = Math.PI / 300;
const cos = Math.cos(angleX);
const sin = Math.sin(angleX);
this.tagList.forEach((i) => {
const y1 = i.y * cos - i.z * sin;
const z1 = i.z * cos + i.y * sin;
i.y = y1;
i.z = z1;
});
},
rotateY() {
const angleY = Math.PI / 500;
const cos = Math.cos(angleY);
const sin = Math.sin(angleY);
this.tagList.forEach((i) => {
const x1 = i.x * cos - i.z * sin;
const z1 = i.z * cos + i.x * sin;
i.x = x1;
i.z = z1;
});
},
animate() {
this.rotateX();
this.rotateY();
this.tagList.forEach((i) => {
i.move();
});
requestAnimationFrame(this.animate);
},
},
};
</script>
<style lang="scss" scoped>
.tag-wrap {
position: relative;
width: 100%;
height: 356px;
background-size: 100% 100%;
background: url("~@/assets/sentimeent/icon-正面.png") no-repeat center;
margin-top: 20px;
.tag {
opacity: 0;
position: absolute;
left: 0;
top: 0;
text-decoration: none;
font-size: 34px;
cursor: pointer;
will-change: transform;
color: #fff;
span {
display: inline-block;
}
.tag-value {
opacity: 0;
height: 35px;
padding: 0 30px 0 20px;
color: #f6f600;
line-height: 35px;
margin-left: 5px;
visibility: middle;
font-size: 34px;
transition: all 0.2s;
background: linear-gradient(
90deg,
rgba(216, 255, 0, 0.7) 0%,
rgba(58, 51, 255, 0) 100%
);
}
&:hover {
.tag-value {
opacity: 1;
}
}
}
}
</style>