<template>
  <svg class="wordcloud-container" ref="wordcloudContainer" @mousemove='listener($event)' @mouseenter='stopRotation'
    @mouseleave='startRotation'>
    <!-- 定义渐变 -->
    <defs>
      <linearGradient id="tagGradient1" x1="0%" y1="0%" x2="0%" y2="100%">
        <stop offset="0%" :stop-color="isRgb(gradientType[0], 0.5)" />
        <stop offset="100%" :stop-color="isRgb(gradientType[1], 0.5)" />
      </linearGradient>
      <linearGradient id="tagGradient2" x1="0%" y1="0%" x2="0%" y2="100%">
        <stop offset="0%" :stop-color="isRgb(gradientType[0], 0.7)" />
        <stop offset="100%" :stop-color="isRgb(gradientType[1], 0.7)" />
      </linearGradient>
      <linearGradient id="tagGradient3" x1="0%" y1="0%" x2="0%" y2="100%">
        <stop offset="0%" :stop-color="isRgb(gradientType[0], 0.9)" />
        <stop offset="100%" :stop-color="isRgb(gradientType[1], 0.9)" />
      </linearGradient>
    </defs>
    <a v-for='(tag, index) in tags' :key='index'>
      <!-- 使用rect作为标签背景，根据文本长度动态调整宽高 -->
      <rect :x='tag.x - getTagWidth(tag.text) / 2' :y='tag.y - getTagHeight() / 2' :width='getTagWidth(tag.text)'
        :height='getTagHeight()' rx='15' ry='15' :fill="getTagBackground(tag)" :stroke="getTagBorder(tag)"
        stroke-width="1" />
      <!-- 文本标签 -->
      <text :x='tag.x' :y='tag.y' :font-size='fontSize' :fill="fontColor" text-anchor="middle"
        dominant-baseline="middle" font-family="'Microsoft YaHei', '微软雅黑', Arial, sans-serif" font-weight="600">{{ tag.text }}</text>
    </a>
  </svg>
</template>

<script>
export default {
  name: 'WordCloud',
  props: {
    // svg宽高
    svgWidth: {
      type: Number,
      default: 580
    },
    // svg高度  
    svgHeight: {
      type: Number,
      default: 580
    },
    // 球半径X轴
    RADIUSX: {
      type: Number,
      default: 240
    },
    // 球半径Y轴
    RADIUSY: {
      type: Number,
      default: 240
    },
    // 球半径Z轴
    RADIUSZ: {
      type: Number,
      default: 240
    },
    // 标签数据
    tagsTemp: {
      type: Array,
      default: () => []
    },
    // 旋转方式 - x轴旋转，y轴旋转，both同时旋转
    rotateType: {
      type: String,
      default: 'y'
    },
    // 标签背景色-渐变色（数组格式：['#009fff', '#002255']/['rgb(0,159,255)', 'rgb(0,34,85)']）
    gradientType: {
      type: Array,
      default: () => ['rgb(0,159,255)', 'rgb(0,34,85)']
    },
    // 标签字体颜色
    fontColor: {
      type: String,
      default: '#FFFFFF'
    },
    // 标签字体大小
    fontSize: {
      type: Number,
      default: 18
    },
    // 鼠标移入球停止旋转
    mouseOver: {
      type: Boolean,
      default: true
    },
    // X轴默认旋转速度
    defaultSpeedX: {
      type: Number,
      default: Math.PI / 360
    },
    // Y轴默认旋转速度
    defaultSpeedY: {
      type: Number,
      default: Math.PI / 360
    },
  },
  data() {
    return {
      speedX: Math.PI / 360,
      speedY: Math.PI / 360,
      tags: [],
      rotationTimer: null,
      resizeTimer: null,
      // 保存实际的SVG宽高，不直接修改props
      currentWidth: this.svgWidth,
      currentHeight: this.svgHeight
    }
  },
  watch: {
    tagsTemp: {
      handler(newTags) {
        this.initTags();
      },
      deep: true
    }
  },
  computed: {
    CX() {
      return this.currentWidth / 2;
    },
    CY() {
      return this.currentHeight / 2;
    }
  },
  mounted() {
    this.updateSvgSize();
    // 使球开始旋转
    this.startRotation();
    // 添加窗口大小变化监听
    window.addEventListener('resize', this.handleResize);
  },
  beforeUnmount() {
    // 清理定时器
    if (this.rotationTimer) {
      clearInterval(this.rotationTimer);
    }
    // 移除窗口大小变化监听
    window.removeEventListener('resize', this.handleResize);
  },
  created() {
    // 生成关键词、初始化标签位置
    this.initTags();
  },
  methods: {
    // 生成关键词、初始化标签位置
    initTags() {
      let tags = [];
      this.tagsTemp.forEach((element, index) => {
        let tag = {};
        let k = -1 + (2 * (index + 1) - 1) / this.tagsTemp.length;
        let a = Math.acos(k);
        let b = a * Math.sqrt(this.tagsTemp.length * Math.PI)
        tag.text = element;
        tag.x = this.CX + this.RADIUSX * Math.sin(a) * Math.cos(b);
        tag.y = this.CY + this.RADIUSY * Math.sin(a) * Math.sin(b);
        tag.z = this.RADIUSZ * Math.cos(a);
        tags.push(tag)
      });
      this.tags = tags;
    },
    // 绕Y轴旋转
    rotateY(speedX) {
      var cos = Math.cos(speedX);
      var sin = Math.sin(speedX);
      for (let tag of this.tags) {
        var y1 = (tag.y - this.CY) * cos - tag.z * sin + this.CY;
        var z1 = tag.z * cos + (tag.y - this.CY) * sin;
        tag.y = y1;
        tag.z = z1;
      }
    },
    // 绕X轴旋转
    rotateX(speedY) {
      var cos = Math.cos(speedY);
      var sin = Math.sin(speedY);
      for (let tag of this.tags) {
        var x1 = (tag.x - this.CX) * cos - tag.z * sin + this.CX;
        var z1 = tag.z * cos + (tag.x - this.CX) * sin;
        tag.x = x1;
        tag.z = z1;
      }
    },
    //响应鼠标移动
    listener(event) {
      var x = event.clientX - this.CX;
      var y = event.clientY - this.CY;
      this.speedX = x * 0.0001 > 0 ? Math.min(this.RADIUSX * 0.00002, x * 0.0001) : Math.max(-this.RADIUSX * 0.00002, x * 0.0001);
      this.speedY = y * 0.0001 > 0 ? Math.min(this.RADIUSY * 0.00002, y * 0.0001) : Math.max(-this.RADIUSY * 0.00002, y * 0.0001);
    },
    // 开始旋转
    startRotation() {
      // 先清理可能存在的定时器
      if (this.rotationTimer) {
        clearInterval(this.rotationTimer);
      }
      // 恢复默认旋转速度，避免速度变得过慢
      this.speedX = this.defaultSpeedX;
      this.speedY = this.defaultSpeedY;
      // 创建新的定时器
      this.rotationTimer = setInterval(() => {
        if (this.rotateType === 'x') this.rotateY(this.speedX);
        if (this.rotateType === 'y') this.rotateX(this.speedY);
        if (this.rotateType === 'both') {
          this.rotateY(this.speedX);
          this.rotateX(this.speedY);
        }
      }, 17);
    },
    // 停止旋转
    stopRotation() {
      if (this.rotationTimer && this.mouseOver) {
        clearInterval(this.rotationTimer);
        this.rotationTimer = null;
      }
    },
    // 更新SVG尺寸
    updateSvgSize() {
      if (this.$refs.wordcloudContainer) {
        // 保存到data中的响应式属性，不直接修改props
        this.currentWidth = this.$refs.wordcloudContainer.clientWidth || this.svgWidth;
        this.currentHeight = this.$refs.wordcloudContainer.clientHeight || this.svgHeight;
        // 重新初始化标签位置，确保居中
        this.initTags();
      }
    },
    // 处理窗口大小变化
    handleResize() {
      // 使用防抖处理，避免频繁更新
      if (this.resizeTimer) {
        clearTimeout(this.resizeTimer);
      }
      this.resizeTimer = setTimeout(() => {
        this.updateSvgSize();
      }, 200);
    },
    // 根据z轴位置获取标签背景颜色
    getTagBackground(tag) {
      // 计算基于z轴位置的渐变ID
      const position = (tag.z + this.RADIUSZ) / (2 * this.RADIUSZ);
      if (position > 0.7) {
        return 'url(#tagGradient3)'; // 最前面的标签，透明度最高
      } else if (position > 0.3) {
        return 'url(#tagGradient2)'; // 中间位置的标签
      } else {
        return 'url(#tagGradient1)'; // 后面的标签，透明度最低
      }
    },
    // 根据z轴位置获取标签边框颜色
    getTagBorder(tag) {
      const opacity = 0.3 + ((tag.z + this.RADIUSZ) / (2 * this.RADIUSZ)) * 0.3;
      return `rgba(0, 192, 255, ${opacity})`;
    },
    // 根据文本长度计算标签宽度
    getTagWidth(text) {
      // 基础宽度 + 每个字符的宽度
      // 中文字符通常需要更多宽度,中文字符设置为字体的大小，英文字符设置为字体大小的一半
      let charWidth = Number(this.fontSize);
      let baseWidth = 32; // 左右padding

      // 根据文本字符类型计算总宽度
      let totalWidth = baseWidth;
      for (let i = 0; i < text.length; i++) {
        const char = text.charAt(i);
        // 判断是否为英文字母或数字
        if (/[a-zA-Z0-9]/.test(char)) {
          totalWidth += Number(this.fontSize) / 2;
        } else {
          totalWidth += charWidth;
        }
      }
      // 确保最小宽度
      return Math.max(totalWidth, 80);
    },
    // 获取标签高度（固定高度，可根据需要调整）
    getTagHeight() {
      // 字体大小+上下padding
      return Number(this.fontSize) + 18;
    },
    // 判断颜色是rgb格式还是HEX格式
    isRgb(color, alpha) {
      if (color.startsWith('rgb')) {
        return this.rgbToRgba(color, alpha)
      } else if (color.startsWith('#')) {
        return this.hexToRgba(color, alpha)
      }
    },
    // 将HEX(#0569FF)颜色转换为rgba颜色
    hexToRgba(hex, alpha = 0.5) {
      const r = parseInt(hex.slice(1, 3), 16);
      const g = parseInt(hex.slice(3, 5), 16);
      const b = parseInt(hex.slice(5, 7), 16);
      return `rgba(${r},${g},${b},${alpha})`;
    },

    // 将rgb颜色转换为rgba颜色
    rgbToRgba(rgb, alpha = 0.5) {
      const [r, g, b] = rgb.match(/\d+/g).map(Number);
      return `rgba(${r},${g},${b},${alpha})`;
    }
  }
}
</script>

<style>
.wordcloud-container {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
}

a {
  display: block;
}

a:hover {
  text-decoration: none;
}
</style>