<script setup lang="ts">
defineOptions({
name: 'rightTop',
});
let timer: any = null;
const wrapperRef = ref()
const tagRef: any = ref([])
const rotateAngleX = ref()
const rotateAngleY = ref()
const option = ref({
radius: 80, // 滾動半徑,單位px
maxFont: 24, // 最大字體大小
color: 'white', // 字體顏色。為空時隨機
rotateAngleXbase: 600, // 默認旋轉速度基數,數越小速度越快
rotateAngleYbase: 600,
backgrounds: ['0 0 24px 3px #b7a47b inset', '0 0 24px 3px rgba(46, 144, 255.2) inset', '0 0 24px 3px #218a88 inset', '0 0 24px 3px #0065a9 inset'],
hover: true, // 是否開啟懸浮聯動
})
const tagList = ref([])
const data = ref([
{
name: '基層減負',
num: 100,
},
{
name: '收費政策',
num: 20,
},
{
name: '面子工程',
num: 88,
},
{
name: '形式主義',
num: 30,
},
{
name: '節慶活動',
num: 100,
},
{
name: '一刀切',
num: 20,
},
{
name: '展會',
num: 20,
},
{
name: '一票否決',
num: 20,
},
{
name: '文件多',
num: 20,
}
])
const getMineRef = (el: any, index: number) => {
if (el) {
tagRef.value[index] = el;
}
};
function _initTags() {
rotateAngleX.value = Math.PI / option.value.rotateAngleXbase;
rotateAngleY.value = Math.PI / option.value.rotateAngleYbase;
// 鼠標懸浮改變轉速和方向
if (option.value.hover) {
nextTick(() => {
wrapperRef.value.onmousemove = function (e: any) {
rotateAngleY.value =
(e.pageX - this.offsetLeft - this.offsetWidth / 2) / 10000;
rotateAngleX.value =
-(e.pageY - this.offsetTop - this.offsetHeight / 2) / 10000;
};
})
} else {
wrapperRef.value.onmousemove = null;
}
for (let i = 0, length = data.value.length; i < length; i++) {
// 獲取球面上均勻的點的經緯度 θ = arccos( ((2*num)-1)/all - 1); Φ = θ*sqrt(all * π);
let angleX = Math.acos((2 * (i + 1) - 1) / length - 1);
let angleY = angleX * Math.sqrt(length * Math.PI);
// 根據經緯度獲取點的坐標,球中心的點坐標是 (0,0,0) x=r*sinθ*cosΦ y=r*sinθ*sinΦ z=r*cosθ;
const x = option.value.radius * Math.sin(angleX) * Math.cos(angleY);
const y = option.value.radius * Math.sin(angleX) * Math.sin(angleY);
const z = option.value.radius * Math.cos(angleX);
nextTick(() => {
if (option.value.color) {
tagRef.value[i].style.color = option.value.color;
} else {
// 隨機顏色
tagRef.value[i].style.color =
'rgb(' +
Math.round(255 * Math.random()) +
',' +
Math.round(255 * Math.random()) +
',' +
Math.round(255 * Math.random()) +
')';
}
// 每個標簽對象都有四對值
let tag: any = {
x: x,
y: y,
z: z,
ele: tagRef.value[i],
};
tagList.value.push(tag);
})
}
timer = setInterval(function () {
for (var i = 0; i < tagList.value.length; i++) {
rotateX(tagList.value[i]);
rotateY(tagList.value[i]);
setPosition(
tagList.value[i],
option.value.radius,
option.value.maxFont
);
setBoxShadow(tagList.value[i], i)
}
}, 20);
}
_initTags()
function setBoxShadow(tag: any, i: any) {
let length = option.value.backgrounds.length
tag.ele.style.boxShadow = option.value.backgrounds[i % length]
}
function setPosition(tag: any, r: any, maxFont: any) {
// 設置每個標簽的坐標位置和字體大小以及透明度
if (wrapperRef.value) {
tag.ele.style.transform =
'translate(' +
(tag.x +
wrapperRef.value.offsetWidth / 2 -
tag.ele.offsetWidth / 2) +
'px,' +
(tag.y +
wrapperRef.value.offsetHeight / 2 -
tag.ele.offsetHeight / 2) +
'px)';
tag.ele.style.opacity = tag.z / r / 2 + 0.7;
// tag.ele.style.fontSize = (tag.z / r / 2 + 0.5) * maxFont + 'px';
}
}
function rotateX(tag: any) {
var cos = Math.cos(rotateAngleX.value);
var sin = Math.sin(rotateAngleX.value);
var y1 = tag.y * cos - tag.z * sin;
var z1 = tag.y * sin + tag.z * cos;
tag.y = y1;
tag.z = z1;
}
function rotateY(tag: any) {
var cos = Math.cos(rotateAngleY.value);
var sin = Math.sin(rotateAngleY.value);
var x1 = tag.z * sin + tag.x * cos;
var z1 = tag.z * cos - tag.x * sin;
tag.x = x1;
tag.z = z1;
}
function dbclickTag() {
if (timer) {
clearInterval(timer);
timer = null;
} else {
timer = setInterval(function () {
for (var i = 0; i < tagList.value.length; i++) {
rotateX(tagList.value[i]);
rotateY(tagList.value[i]);
setPosition(
tagList.value[i],
option.value.radius,
option.value.maxFont
);
}
}, 20);
}
}
function clickTag(item: any) {
// this.$emit('clickTag', item);
}
onUnmounted(() => {
if (timer) {
clearInterval(timer);
}
});
</script>
<template>
<div class="cont-box w-full h-full">
<div class="tag-cloud" ref="wrapperRef">
<p v-for="(item, index) in data" :key="index" :ref="el => getMineRef(el, index)" @click="clickTag(item)"
@dblclick="dbclickTag()">
<!-- {{ item.num }}家
<br />
<br /> -->
<span class="num">{{ item.num }}</span> 家
<br />
{{ item.name }}
</p>
</div>
</div>
</template>
<style lang="less" scoped>
.cont-box {
background: url("@/assets/images/home/hot-bg.png") no-repeat center center;
background-size: contain;
.tag-cloud {
width: 100%;
height: 100%;
position: relative;
color: #333;
margin: 0 auto;
text-align: center;
}
.tag-cloud p {
position: absolute;
top: 0px;
left: 0px;
color: white;
font-family: Arial;
text-decoration: none;
margin: 0 10px 15px 0;
text-align: center;
font-size: 15px;
padding: 4px 9px;
display: inline-block;
border-radius: 50%;
width: 80px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
height: 80px;
line-height: 18px;
background: rgba(50, 85, 113, 0.3);
box-shadow: 0 0 24px 3px rgba(46, 144, 255.2) inset;
padding-top: 19px;
}
.num {
font-size: 20px;
padding-top: 10px;
font-weight: bold;
}
}
</style>