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

Detailed summary of web form submission methods

Let's first look at several ways to submit a ...

Linux redis-Sentinel configuration details

download Download address: https://redis.io/downl...

How to publish static resources in nginx

step Place the prepared static resource files in ...

A brief introduction to the usage of decimal type in MySQL

The floating-point types supported in MySQL are F...

CSS realizes the scene analysis of semi-transparent border and multiple border

Scenario 1: To achieve a semi-transparent border:...

Using vsftp to build an FTP server under Linux (with parameter description)

introduce This chapter mainly introduces the proc...

Detailed explanation of the relationship between React and Redux

Table of contents 1. The relationship between red...

How to split data in MySQL table and database

Table of contents 1. Vertical (longitudinal) slic...

MySQL 8.0.20 installation and configuration tutorial under Win10

MySQL 8.0.20 installation and configuration super...

How to install and configure SSH service in Ubuntu 18.04

Install ssh tool 1. Open the terminal and type th...

Implementation of Docker CPU Limit

1. --cpu=<value> 1) Specify how much availa...

Solution to slow network request in docker container

Several problems were discovered during the use o...