Detailed code for implementing 3D tag cloud in Vue

Detailed code for implementing 3D tag cloud in Vue

Preview:

Code:
Page Sections:

<template>
  <div class="tagcloud-all"
       ref="tagcloudall">
    <a v-for="item in tagList" :href="item.url" rel="external nofollow" :style="'color:' + item.color + ';top: 0;left: 0;filter:none;'">{{item.name}}</a>
  </div>
</template>

CSS part:

// Tag cloud.tagcloud-all {
  position: relative;
  a {
    position: absolute;
    top: 0px;
    left: 0px;
    color: #fff;
    font-weight: bold;
    text-decoration: none;
    padding: 3px 6px;
    &:hover {
      color: #FF0000;
      letter-spacing: 2px;
    }
  }
}

JS part:

export default {
  name: "tagcloud",
  data() {
    return {
      tagList: [],
      radius: 120,
      dtr: Math.PI / 180,
      d: 300,
      mcList: [],
      active: false,
      lasta: 1,
      lastb: 1,
      distr: true,
      tspeed: 10,
      size: 250,
      mouseX: 0,
      mouseY: 0,
      howElliptical: 1,
      oList: null,
      oA: null,
      sa: 0,
      ca: 0,
      sb: 0,
      cb: 0,
      sc: 0,
      cc: 0
    }
  },
  methods: {
    // Generate a random number getRandomNum() {
      return Math.floor(Math.random() * (255 + 1));
    },
    // Trigonometric function angle calculation sineCosine(a, b, c) {
      this.sa = Math.sin(a * this.dtr);
      this.ca = Math.cos(a * this.dtr);
      this.sb = Math.sin(b * this.dtr);
      this.cb = Math.cos(b * this.dtr);
      this.sc = Math.sin(c * this.dtr);
      this.cc = Math.cos(c * this.dtr);
    },
    // Set the initial position positionAll() {
      this.$nextTick(() => { // Note: All methods executed in the onReady method require $nextTick to ensure that all labels have been rendered var phi = 0;
        var theta = 0;
        var max = this.mcList.length;
        var aTmp = [];
        var oFragment = document.createDocumentFragment();
        // Random sort for (let i = 0; i < this.tagList.length; i++) {
          aTmp.push(this.oA[i]);
        }
        aTmp.sort(() => {
          return Math.random() < 0.5 ? 1 : -1;
        });
        for (let i = 0; i < aTmp.length; i++) {
          oFragment.appendChild(aTmp[i]);
        }
        this.oList.appendChild(oFragment);
        for (let i = 1; i < max + 1; i++) {
          if (this.distr) {
            phi = Math.acos(-1 + (2 * i - 1) / max);
            theta = Math.sqrt(max * Math.PI) * phi;
          } else {
            phi = Math.random() * (Math.PI);
            theta = Math.random() * (2 * Math.PI);
          }
          // Coordinate transformation this.mcList[i - 1].cx = this.radius * Math.cos(theta) * Math.sin(phi);
          this.mcList[i - 1].cy = this.radius * Math.sin(theta) * Math.sin(phi);
          this.mcList[i - 1].cz = this.radius * Math.cos(phi);
          this.oA[i - 1].style.left = this.mcList[i - 1].cx + this.oList.offsetWidth / 2 - this.mcList[i - 1].offsetWidth / 2 + 'px';
          this.oA[i - 1].style.top = this.mcList[i - 1].cy + this.oList.offsetHeight / 2 - this.mcList[i - 1].offsetHeight / 2 + 'px';
        }
      })
    },
    // Update the coordinates to make the label move update() {
      this.$nextTick(() => { // Note: All methods executed in the onReady method require $nextTick to ensure that all labels have been rendered var a;
        var b;
        if (this.active) {
          a = (-Math.min(Math.max(-this.mouseY, -this.size), this.size) / this.radius) * this.tspeed;
          b = (Math.min(Math.max(-this.mouseX, -this.size), this.size) / this.radius) * this.tspeed;
        } else {
          a = this.lasta * 0.98;
          b = this.lastb * 0.98;
        }
        this.lasta = a;
        this.lastb = b;
        if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) {
          return
        }
        var c = 0;
        this.sineCosine(a, b, c);
        for (var j = 0; j < this.mcList.length; j++) {
          var rx1 = this.mcList[j].cx;
          var ry1 = this.mcList[j].cy * this.ca + this.mcList[j].cz * (-this.sa);
          var rz1 = this.mcList[j].cy * this.sa + this.mcList[j].cz * this.ca;
          var rx2 = rx1 * this.cb + rz1 * this.sb;
          var ry2 = ry1;
          var rz2 = rx1 * (-this.sb) + rz1 * this.cb;
          var rx3 = rx2 * this.cc + ry2 * (-this.sc);
          var ry3 = rx2 * this.sc + ry2 * this.cc;
          var rz3 = rz2;
          this.mcList[j].cx = rx3;
          this.mcList[j].cy = ry3;
          this.mcList[j].cz = rz3;
          var per = this.d / (this.d + rz3);
          this.mcList[j].x = (this.howElliptical * rx3 * per) - (this.howElliptical * 2);
          this.mcList[j].y = ry3 * per;
          this.mcList[j].scale = per;
          this.mcList[j].alpha = per;
          this.mcList[j].alpha = (this.mcList[j].alpha - 0.6) * (10 / 6);
        }
        this.doPosition();
        this.depthSort();
      })
    },
    //
    doPosition() {
      this.$nextTick(() => { // Note: All methods executed in the onReady method require $nextTick to ensure that all labels have been rendered var l = this.oList.offsetWidth / 2;
        var t = this.oList.offsetHeight / 2;
        for (var i = 0; i < this.mcList.length; i++) {
          this.oA[i].style.left = this.mcList[i].cx + l - this.mcList[i].offsetWidth / 2 + 'px';
          this.oA[i].style.top = this.mcList[i].cy + t - this.mcList[i].offsetHeight / 2 + 'px';
          this.oA[i].style.fontSize = Math.ceil(12 * this.mcList[i].scale / 2) + 8 + 'px';
          // this.oA[i].style.filter = "alpha(opacity=" + 100 * this.mcList[i].alpha + ")";
          this.oA[i].style.opacity = this.mcList[i].alpha;
        }
      })
    },
    //
    depthSort() {
      this.$nextTick(() => { // Note: All methods executed in the onReady method require $nextTick to ensure that all labels have been rendered var aTmp = [];
        for (let i = 0; i < this.oA.length; i++) {
          aTmp.push(this.oA[i]);
        }
        aTmp.sort(function (vItem1, vItem2) {
          if (vItem1.cz > vItem2.cz) {
            return -1;
          } else if (vItem1.cz < vItem2.cz) {
            return 1;
          } else {
            return 0;
          }
        });
        for (let i = 0; i < aTmp.length; i++) {
          aTmp[i].style.zIndex = i;
        }
      })
    },
    // Network request to get tagList
    query() {
      // Pretend to get the data from the interface let tagListOrg = [
        { name: 'Label 1', url: 'www.baidu.com' },
        { name: 'Label 2', url: 'www.baidu.com' },
        { name: 'Tag 3', url: 'www.baidu.com' },
        { name: 'Label 4', url: 'www.baidu.com' },
        { name: 'Tag 5', url: 'www.baidu.com' },
        { name: 'Tag 6', url: 'www.baidu.com' },
        { name: 'Tag 7', url: 'www.baidu.com' },
        { name: 'Label 8', url: 'www.baidu.com' },
        { name: 'Tag 9', url: 'www.baidu.com' },
        { name: 'Label 10', url: 'www.baidu.com' },
        { name: 'Label 11', url: 'www.baidu.com' },
        { name: 'Label 12', url: 'www.baidu.com' },
        { name: 'Tag 13', url: 'www.baidu.com' },
        { name: 'Tag 14', url: 'www.baidu.com' },
        { name: 'Tag 15', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 16', url: 'www.baidu.com' },
        { name: 'Tag 17', url: 'www.baidu.com' }
      ];
      // Add random colors to tagListtagListOrg.forEach(item => {
        item.color = "rgb(" + this.getRandomNum() + "," + this.getRandomNum() + "," + this.getRandomNum() + ")";
      })
      this.tagList = tagListOrg;
      this.onReady();
    },
    // Generate tag cloud onReady() {
      this.$nextTick(() => {
        this.oList = this.$refs.tagcloudall;
        this.oA = this.oList.getElementsByTagName('a')
        var oTag = null;
        for (var i = 0; i < this.oA.length; i++) {
          oTag = {};
          oTag.offsetWidth = this.oA[i].offsetWidth;
          oTag.offsetHeight = this.oA[i].offsetHeight;
          this.mcList.push(oTag);
        }
        this.sineCosine(0, 0, 0);
        this.positionAll();
        this.oList.onmouseover = () => {
          this.active = true;
        }
        this.oList.onmouseout = () => {
          this.active = false;
        }
        this.oList.onmousemove = (event) => {
          var oEvent = window.event || event;

          this.mouseX = oEvent.clientX - (this.oList.offsetLeft + this.oList.offsetWidth / 2);
          this.mouseY = oEvent.clientY - (this.oList.offsetTop + this.oList.offsetHeight / 2);
          this.mouseX /= 5;
          this.mouseY /= 5;
        }
        setInterval(() => {
          this.update()
        }, 30); // Timer execution cannot write setInterval(this.update(), 30)
      })
    }
  },
  created() {
    this.$nextTick(() => {
      this.query();
    })
  }
}

This is the end of this article about implementing 3D tag cloud in Vue. For more relevant Vue 3D tag cloud content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Example of implementing tag cloud effect with Vue
  • Detailed explanation of how to implement tag cloud effect in Vue
  • Vue page introduces three.js to realize 3D animation scene operation
  • VUE 3D carousel encapsulation implementation method
  • Example of using 3DES encryption in vue.js
  • How to draw 3d pie chart using highCharts in Vue

<<:  How to install MySQL 8.0 in Docker

>>:  Optimization analysis of Limit query in MySQL optimization techniques

Recommend

Nginx stream configuration proxy (Nginx TCP/UDP load balancing)

Prelude We all know that nginx is an excellent re...

MySQL MyISAM default storage engine implementation principle

By default, the MyISAM table will generate three ...

Detailed explanation of importing/exporting MySQL data in Docker container

Preface We all know that the import and export of...

Understanding Nginx Current Limitation in One Article (Simple Implementation)

Nginx is now one of the most popular load balance...

Pagination Examples and Good Practices

<br />Structure and hierarchy reduce complex...

How to generate mysql primary key id (self-increment, unique and irregular)

Table of contents 1. Use the uuid function to gen...

Detailed application of Vue dynamic form

Overview There are many form requirements in the ...

Detailed explanation of MySQL database paradigm

Preface: I have often heard about database paradi...

Summary of Linux sftp command usage

sftp is the abbreviation of Secure File Transfer ...

What is flex and a detailed tutorial on flex layout syntax

Flex Layout Flex is the abbreviation of Flexible ...

MYSQL slow query and log example explanation

1. Introduction By enabling the slow query log, M...