vue实现标签云效果的示例


Posted in Javascript onNovember 09, 2020

闲扯两句

最近想给自己的博客上加上一个3D标签云的效果,用来表示自己博客文章的分组,网上找到了canvas实现的,还有a元素实现的解析3D标签云,我想让标签可以选择和点击,又不想在标签数量较多时操作a标签导致性能问题,于是svg就成了一个不错的选择。

标签初始化

这里实现的核心主要是参考了前面的那篇解析3D标签云的文章,作者给出了源码,讲解也比较通俗易懂。大体来说,整个代码分三步:

  • 根据标签的数量,算出每个标签在球面上分布的x,y,z坐标
  • 根据标签的坐标,将标签绘制出来,x,y坐标通过标签的位置来表示,z坐标通过标签字体的大小和透明度来表示
  • 通过函数根据球的旋转角速度不断计算标签新的x,y坐标,制造出旋转效果
  • 通过mousemove事件,根据鼠标坐标值,改变球旋转的角速度,做出交互效果

贴上代码:

<div id='app' >
    <svg :width='width' :height='height' @mousemove='listener($event)'>
      <a :href="tag.href" rel="external nofollow" v-for='tag in tags'>
        <text :x='tag.x' :y='tag.y' :font-size='20 * (600/(600-tag.z))' :fill-opacity='((400+tag.z)/600)'>{{tag.text}}</text>
      </a>
    </svg>
  </div>

在模板中,借用指令v-for来渲染标签,每个标签上绑定了x,y,font-size(用来表现z轴),fill-opacity(都是与z坐标有关的表达式,用来表现z轴),及text;

data: {
   width:700,//svg宽度
   height:700,//svg高度
   tagsNum:20,//标签数量
   RADIUS:200,//球的半径
   speedX:Math.PI/360,//球一帧绕x轴旋转的角度
   speedY:Math.PI/360,//球-帧绕y轴旋转的角度
   tags: []
 }
 computed:{
   CX(){//球心x坐标
     return this.width/2;
   },
   CY(){//球心y坐标
     return this.height/2;
   }
 },

做好了上面的基础,下面我们来初始化标签数据:

created(){//初始化标签位置
   let tags=[];
   for(let i = 0; i < this.tagsNum; i++){
     let tag = {};
     let k = -1 + (2 * (i + 1) - 1) / this.tagsNum;
     let a = Math.acos(k);
     let b = a * Math.sqrt(this.tagsNum * Math.PI)//计算标签相对于球心的角度
     tag.text = i + 'tag';
     tag.x = this.CX + this.RADIUS * Math.sin(a) * Math.cos(b);//根据标签角度求出标签的x,y,z坐标
     tag.y = this.CY + this.RADIUS * Math.sin(a) * Math.sin(b); 
     tag.z = this.RADIUS * Math.cos(a);
     tag.href = 'https://imgss.github.io';//给标签添加链接
     tags.push(tag);
   }
   this.tags = tags;//让vue替我们完成视图更新
 },

到了这里,我们就算了算坐标,vue完成了视图更新的工作,这时基本上就可以得到一副静态的图像了:

vue实现标签云效果的示例

下面就是通过改变每一个tag的x,y的值来使球旋转起来;实现方法是rotateX,rotateY函数:

rotateX(angleX){
    var cos = Math.cos(angleX);
    var sin = Math.sin(angleX);
    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;
    }
  },
  rotateY(angleY){
    var cos = Math.cos(angleY);
    var sin = Math.sin(angleY);
    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;
    }
  },

这两个函数就是根据标签原来的坐标和球旋转的角度算出新的坐标,最后在mounted钩子下面,写一个animate函数,不断调用这两个函数,实现旋转动画

mounted(){//使球开始旋转
    setInterval(() => {
      this.rotateX(this.speedX);
      this.rotateY(this.speedY);
    }, 17)
  },

全部代码如下:

<script>
    var app = new Vue({
      el: '#app',
      data: {
        width:700,
        height:700,
        tagsNum:20,
        RADIUS:200,
        speedX:Math.PI/360,
        speedY:Math.PI/360,
        tags: []
      },
      computed:{
        CX(){
          return this.width/2;
        },
        CY(){
          return this.height/2;
        }
      },
      created(){//初始化标签位置
        let tags=[];
        for(let i = 0; i < this.tagsNum; i++){
          let tag = {};
          let k = -1 + (2 * (i + 1) - 1) / this.tagsNum;
          let a = Math.acos(k);
          let b = a * Math.sqrt(this.tagsNum * Math.PI);
          tag.text = i + 'tag';
          tag.x = this.CX + this.RADIUS * Math.sin(a) * Math.cos(b);
          tag.y = this.CY + this.RADIUS * Math.sin(a) * Math.sin(b); 
          tag.z = this.RADIUS * Math.cos(a);
          tag.href = 'https://imgss.github.io';
          tags.push(tag);
        }
        this.tags = tags;
      },
      mounted(){//使球开始旋转
        setInterval(() => {
          this.rotateX(this.speedX);
          this.rotateY(this.speedY);
        }, 17)
      },
      methods: {
        rotateX(angleX){
          var cos = Math.cos(angleX);
          var sin = Math.sin(angleX);
          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;
          } 
        },
        rotateY(angleY){
          var cos = Math.cos(angleY);
          var sin = Math.sin(angleY);
          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.RADIUS*0.00002, x*0.0001) : Math.max(-this.RADIUS*0.00002, x*0.0001);
          this.speedY = y*0.0001>0 ? Math.min(this.RADIUS*0.00002, y*0.0001) : Math.max(-this.RADIUS*0.00002, y*0.0001); 
        }
       }
     })
  </script>

完整demo

vue

 no vue

vue实现标签云效果的示例

总结

vue的数据绑定可以减少我们对dom的操作,而将关注点放在逻辑上面,vue构造函数提供的几个选项可以帮助我们更好的组织代码

以上就是vue实现标签云效果的示例的详细内容,更多关于vue 标签云的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JS中style属性
Oct 11 Javascript
用javascript实现给出的盒子的序列是否可连为一矩型
Aug 30 Javascript
jqGrid随窗口大小变化自适应大小的示例代码
Dec 28 Javascript
在Google 地图上实现做的标记相连接
Jan 05 Javascript
一个超简单的jQuery回调函数例子(分享)
Aug 08 Javascript
vue自定义指令实现v-tap插件
Nov 03 Javascript
js的OOP继承实现(必看篇)
Feb 18 Javascript
基于 Immutable.js 实现撤销重做功能的实例代码
Mar 01 Javascript
JS构造一个html文本内容成文件流形式发送到后台
Jul 31 Javascript
Vue 莹石摄像头直播视频实例代码
Aug 31 Javascript
使用vue开发移动端管理后台的注意事项
Mar 07 Javascript
vue中格式化时间过滤器代码实例
Apr 17 Javascript
写一个Vue loading 插件
Nov 09 #Javascript
解决Vue大括号字符换行踩的坑
Nov 09 #Javascript
vue data有值,但是页面{{}} 取不到值的解决
Nov 09 #Javascript
vue 防止页面加载时看到花括号的解决操作
Nov 09 #Javascript
Webpack的Loader和Plugin的区别
Nov 09 #Javascript
解决vue初始化项目一直停在downloading template的问题
Nov 09 #Javascript
在VUE中使用lodash的debounce和throttle操作
Nov 09 #Javascript
You might like
使用PHP Socket 编程模拟Http post和get请求
2014/11/25 PHP
php判断表是否存在的方法
2015/06/18 PHP
php使用文本统计访问量的方法
2016/05/12 PHP
Laravel5.1 框架控制器基础用法实例分析
2020/01/04 PHP
Javascript动态绑定事件的简单实现代码
2010/12/25 Javascript
11个用于提高排版水平的基于jquery的文字效果插件
2012/09/14 Javascript
JavaScript设计模式之外观模式实例
2014/10/10 Javascript
JQuery选中checkbox方法代码实例(全选、反选、全不选)
2015/04/27 Javascript
easyui Draggable组件实现拖动效果
2015/08/19 Javascript
Angularjs CURD 详解及实例代码
2016/09/14 Javascript
利用vue写todolist单页应用
2016/12/15 Javascript
Vue实例简单方法介绍
2017/01/20 Javascript
Angular 2父子组件之间共享服务通信的实现
2017/07/04 Javascript
详解利用jsx写vue组件的方法示例
2017/07/17 Javascript
Vue源码解析之数据响应系统的使用
2019/04/24 Javascript
Javascript摸拟自由落体与上抛运动原理与实现方法详解
2020/04/08 Javascript
微信小程序实现电影App导航和轮播
2020/11/30 Javascript
[44:33]EG vs Liquid 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python操作xml文件详细介绍
2014/06/09 Python
利用python发送和接收邮件
2016/09/27 Python
python 按不同维度求和,最值,均值的实例
2018/06/28 Python
Python3 实现爬取网站下所有URL方式
2020/01/16 Python
解决python对齐错误的方法
2020/07/16 Python
如何在python中处理配置文件代码实例
2020/09/27 Python
详解python的变量缓存机制
2021/01/24 Python
英国日常交易网站:Wowcher
2018/09/04 全球购物
一份婚庆公司创业计划书
2014/01/11 职场文书
求职意向书
2014/04/01 职场文书
村创先争优活动总结
2014/08/28 职场文书
教书育人演讲稿
2014/09/11 职场文书
Python机器学习之逻辑回归
2021/05/11 Python
利用Sharding-Jdbc进行分库分表的操作代码
2022/01/22 Java/Android
漫画「日和酱的要求是绝对的」第3卷封面公开
2022/03/21 日漫
MySQL数据库 安全管理
2022/05/06 MySQL
MySQL自定义函数及触发器
2022/08/05 MySQL
JavaScript实现简单的音乐播放器
2022/08/14 Javascript