vue 螺旋线与旋转词云功能

88 阅读1分钟

效果图:

image.png

highcharts也提供了类似的词云的效果(但效果是静态的),附上链接: www.hcharts.cn/demo/highch…

vue代码:

     <div class="helix-tag-cloud">
    <!-- 绘制螺旋线 -->
    <div id="helix-wrap">
      <canvas id="myCanvas" width="700" height="700"></canvas>
    </div>
    <!-- 绘制词云 -->
    <div class="tagBall" ref="tagBall">
      <p v-for="(item, index) in tagList" :key="index" class="tag">
        {{ item }}
      </p>
    </div>
  </div>

js代码:

<script>
export default {
  components: {},
  props: {},
  data() {
    return {
      // 螺旋线
      canvas: '',
      context: {},
      //   词云
      tagEle: '',
      paper: '',
      RADIUS: 150,
      fallLength: 500,
      tags: [],
      angleX: Math.PI / 500,
      angleY: Math.PI / 500,
      CX: '',
      CY: '',
      EX: '',
      EY: '',
      timing: null,
      tagList: [
        '11111',
        '222',
        '33333',
        '444444444444',
        '55',
        '666',
        '777',
        'ggg',
        '55353',
        'hhgs',
        'jjj',
        'jsnn',
        'i77kdt',
        '2htsjnn',
        'kddf67',
        'kl888888osv',
        'aqvvsr',
        'wgnre55',
        '667utgh',
        'k56e4rgg',
      ],
    };
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {
    // 螺旋线
    this.canvas = document.getElementById('myCanvas');
    this.context = this.canvas.getContext('2d');
    this.initCanvas();
    // 词云
    this.tagEle = this.$refs.tagBall.children;
    this.paper = this.$refs.tagBall;
    this.CX = this.paper.offsetWidth / 2;
    this.CY = this.paper.offsetHeight / 2;
    this.EX =
      this.paper.offsetLeft +
      document.body.scrollLeft +
      document.documentElement.scrollLeft;
    this.EY =
      this.paper.offsetTop +
      document.body.scrollTop +
      document.documentElement.scrollTop;
    this.innit();
    this.animate();
  },
  methods: {
    initCanvas() {
      let radius = 0;
      let angle = 0;
      this.context.lineWidth = 3;
      this.context.strokeStyle = 'rgba(0, 150, 255,0.2)';
      this.context.beginPath();
      this.context.moveTo(this.canvas.width / 2, this.canvas.height / 2);

      for (var n = 0; n < 150; n++) {
        radius += 2.15;
        angle += (Math.PI * 2) / 50;
        var x = this.canvas.width / 2 + radius * Math.cos(angle);
        var y = this.canvas.height / 2 + radius * Math.sin(angle);
        this.context.lineTo(x, y);
      }
      this.context.stroke();
    },
    innit() {
      for (var i = 0; i < this.tagEle.length; i++) {
        var a, b;
        var k = (2 * (i + 1) - 1) / this.tagEle.length - 1;
        var a = Math.acos(k);
        var b = a * Math.sqrt(this.tagEle.length * Math.PI);
        var x = this.RADIUS * Math.sin(a) * Math.cos(b);
        var y = this.RADIUS * Math.sin(a) * Math.sin(b);
        var z = this.RADIUS * Math.cos(a);
        // var t = this.tag({ ele: this.tagEle[i], x, y, z });
        this.tagEle[i].style.color =
          'rgb(' +
          parseInt(Math.random() * 255) +
          ',' +
          parseInt(Math.random() * 255) +
          ',' +
          parseInt(Math.random() * 255) +
          ')';
        this.tags.push({ ele: this.tagEle[i], x, y, z });
      }
    },
    tag({ ele, x, y, z }) {
      var scale = this.fallLength / (this.fallLength - z);
      var alpha = (z + this.RADIUS) / (2 * this.RADIUS);
      ele.style.fontSize = 20 * scale + 'px';
      ele.style.opacity = alpha + 0.5;
      ele.style.filter = 'alpha(opacity = ' + (alpha + 0.5) * 100 + ')';
      ele.style.zIndex = parseInt(scale * 100);
      ele.style.left = x + this.CX - ele.offsetWidth / 2 + 'px';
      ele.style.top = y + this.CY - ele.offsetHeight / 2 + 'px';
    },
    animate() {
      this.timing = setInterval(() => {
        this.rotateX();
        this.rotateY();
        this.tags.forEach((item) => {
          this.tag(item);
        });
      }, 20);
    },
    rotateX() {
      var cos = Math.cos(this.angleX);
      var sin = Math.sin(this.angleX);
      this.tags.forEach((item) => {
        var y1 = item.y * cos - item.z * sin;
        var z1 = item.z * cos + item.y * sin;
        item.y = y1;
        item.z = z1;
      });
    },
    rotateY() {
      var cos = Math.cos(this.angleY);
      var sin = Math.sin(this.angleY);
      this.tags.forEach((item) => {
        var x1 = item.x * cos - item.z * sin;
        var z1 = item.z * cos + item.x * sin;
        item.x = x1;
        item.z = z1;
      });
    },
    mouseOver(event) {
      var x = event.clientX - this.EX - this.CX;
      var y = event.clientY - this.EY - this.CY;
      this.angleY = x * 0.0001;
      this.angleX = y * 0.0001;
      if (!this.timing) this.animate();
    },
    mouseLeave(event) {
      var x = event.clientX - this.EX - this.CX;
      var y = event.clientY - this.EY - this.CY;
      this.angleY = x * 0.0001;
      this.angleX = y * 0.0001;
    },
    cheMouseOver() {
      clearInterval(this.timing);
      this.timing = null;
    },
  },
};
</script>
<style scoped lang="less">
.helix-tag-cloud {
  width: 70rem;
  height: 70rem;
  border: 1px solid;
  margin: 0 auto;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  .tagBall {
    width: 70rem;
    height: 70rem;
    position: absolute;
    top: -5rem;
    .tag {
      display: block;
      position: absolute;
      left: 0px;
      top: 0px;
      color: #000;
      text-decoration: none;
      font-size: 1.5rem;
      font-family: '微软雅黑';
      font-weight: bold;
    }
  }
}
</style>

方法源于百度,这里记录仅供个人学习使用;如有侵权,请联系删除

2023.7.4补充: 想要实现鼠标悬浮到词云上会显示对应的气泡内容,在这里刚好又找到一篇符合该需求的文章: www.jianshu.com/p/97fd52f27… 附上git地址: github.com/zhaowhY/sam…