<template>
<div>
<div id="tagscloud" class="word-cloud" ref="wordCloud">
<p :style="styleArray[index]" :class="item.color"
v-for="(item, index) in clouds"
@mouseover="mouseoverEvent($event, index)"
@mouseout="mouseoutEvent($event, index)"
@click="doSomething"
:key="index">
<span>{{item.featuretype}}</span>:
<span>{{item.featurecontent}}</span>
</p>
</div>
</div>
</template>
<script>
export default {
props: {
clouds:{
type: Array,
default: []
}
},
data(){
return {
mcList: [], // 存放每個雲標簽的可視寬度、高度(因vue數據驅動原因,故必須在dom生成之后獲取)
option:{ // 計算所需數值,沒太搞明白
radius: 90,
d: 200,
lasta: 1,
lastb: 1,
distr: true,
tspeed: 20,
size: 200,
mouseX: 0,
mouseY: 10,
howElliptical: 1
},
triFunc: {
},
timer: null,
styleArray: [], // 存放每個雲標簽的css樣式
}
},
mounted(){
this.init()
},
beforeDestroy () { // 組件銷毀,清除定時器(什么時候也不對自己再解釋)
if(this.timer){
clearTimeout(this.timer)
this.timer = null
}
},
watch: {
clouds() { // 子組件從父組件中獲取值之后不會實時更新,可通過watch監聽,做手動異步刷新
if(this.timer){
clearInterval(this.timer)
this.timer = null
}
this.$nextTick(() => {
this.init()
})
}
},
methods: {
doSomething(){
},
mouseoverEvent(e, index){ // 懸浮操作,未做處理(因對計算公式沒研究透)
// this.mcList[index].on = true;
},
mouseoutEvent(e, index){ // 離開操作,同上
// this.mcList[index].on = false;
},
setTimer(){
this.timer = setInterval(()=>{
this.update();
}, 50)
},
init(){
this.mcList = []; // 因原插件基於dom操作,所以此處選擇清除一下這個(其他部分因它而生,不及時清空,頁面帥不過10s)
for(let i=0;i<this.clouds.length;i++){
this.mcList.push({
offsetWidth: this.$refs.wordCloud.children[i].offsetWidth,
offsetHeight: 30
});
}
this.sineCosine( 0,0,0 );
this.positionAll();
this.setTimer();
},
update(){ // 三角函數只是已完全忘記...(大概是在有限范圍內取一個立體空間點,並基於z軸做一個透明效果)
let a,b,c = 0;
a = (Math.min(Math.max(-this.option.mouseY, -this.option.size), this.option.size) / this.option.radius) * this.option.tspeed;
b = (-Math.min(Math.max(-this.option.mouseX, -this.option.size), this.option.size) / this.option.radius) * this.option.tspeed;
this.option.lasta = a;
this.option.lastb = b;
if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) {
return;
}
this.sineCosine(a, b, c)
for(let i=0,len=this.mcList.length;i<len;i++){
if(this.mcList[i].on){
continue
}
let rx1 = this.mcList[i].cx;
let ry1 = this.mcList[i].cy * this.triFunc.ca + this.mcList[i].cz * (-this.triFunc.sa);
let rz1 = this.mcList[i].cy * this.triFunc.sa + this.mcList[i].cz * this.triFunc.ca;
let rx2 = rx1 * this.triFunc.cb + rz1 * this.triFunc.sb;
let ry2 = ry1;
let rz2 = rx1 * (-this.triFunc.sb) + rz1 * this.triFunc.cb;
let rx3 = rx2 * this.triFunc.cc + ry2 * (-this.triFunc.sc);
let ry3 = rx2 * this.triFunc.sc + ry2 * this.triFunc.cc;
let rz3 = rz2;
this.mcList[i].cx = rx3;
this.mcList[i].cy = ry3;
this.mcList[i].cz = rz3;
let per = this.option.d / (this.option.d + rz3);
this.mcList[i].x = (this.option.howElliptical * rx3 * per) - (this.option.howElliptical * 2);
this.mcList[i].y = ry3 * per;
this.mcList[i].scale = per;
let alpha = per;
alpha = (alpha - 0.6) * (10 / 6);
this.mcList[i].alpha = alpha * alpha * alpha - 0.2;
this.mcList[i].zIndex = Math.ceil(100 - Math.floor(this.mcList[i].cz));
}
this.doPosition()
},
positionAll(){ // 起點的計算
let phi = 0;
let theta = 0;
let max = this.mcList.length;
for (let i = 0; i < max; i++) {
if (this.option.distr) {
phi = Math.acos(-1 + (2 * (i + 1) - 1) / max);
theta = Math.sqrt(max * Math.PI) * phi;
} else {
phi = Math.random() * (Math.PI);
theta = Math.random() * (2 * Math.PI);
}
//坐標變換
this.mcList[i].cx = this.option.radius * Math.cos(theta) * Math.sin(phi)
this.mcList[i].cy = this.option.radius * Math.sin(theta) * Math.sin(phi) * 1.5
this.mcList[i].cz = this.option.radius * Math.cos(phi);
}
},
doPosition(){
let l = this.$refs.wordCloud.offsetWidth / 2;
let t = this.$refs.wordCloud.offsetHeight / 2;
this.styleArray = [];
for (let i=0,len=this.mcList.length; i<len; i++) {
if (this.mcList[i].on) {
continue;
}
this.styleArray.push({
left: this.mcList[i].cx + l - this.mcList[i].offsetWidth / 2 + 'px',
top: this.mcList[i].cy + t - this.mcList[i].offsetHeight / 2 + 'px',
filter: "alpha(opacity=" + 100 * this.mcList[i].alpha + ")",
zIndex: this.mcList[i].zIndex,
opacity: this.mcList[i].alpha,
})
}
},
sineCosine(a, b, c){
let PI = Math.PI / 180;
this.triFunc.sa = Math.sin(a * PI);
this.triFunc.ca = Math.cos(a * PI);
this.triFunc.sb = Math.sin(b * PI);
this.triFunc.cb = Math.cos(b * PI);
this.triFunc.sc = Math.sin(c * PI);
this.triFunc.cc = Math.cos(c * PI);
}
}
}
</script>
<style scoped>
.word-cloud{
position:relative;
margin:0.2rem auto 0;
width: 3rem;
height: 5rem;
text-align:center;
/* border: 1px solid pink; */
}
.word-cloud p{
position:absolute;
top:0px;
left:0px;
color:#fff;
font-family:Arial;
margin:0 10px 15px 0;
width:auto;
height:0.3rem;
line-height: 0.3rem;
text-align:center;
font-size: 0.16rem;
padding:1px 5px;
display:inline-block;
cursor: pointer;
white-space: nowrap;
}
.word-cloud .blue{
color:#00d3ff;
}
.word-cloud .yellow{
color:#f29712;
}
.word-cloud .green{
color:#00af5f;
}
</style>