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 相关文章推荐
jQuery EasyUI 的EasyLoader功能介绍
Sep 12 Javascript
jQuery页面滚动浮动层智能定位实例代码
Aug 23 Javascript
IE6、IE7中setAttribute不支持class/for/rowspan/colspan等属性
Aug 28 Javascript
Javascript 闭包引起的IE内存泄露分析
May 23 Javascript
JavaScript中的匀速运动和变速(缓冲)运动详细介绍
Nov 11 Javascript
js验证是否为数字的总结
Apr 14 Javascript
javascript中this指向详解
Apr 23 Javascript
最原始的jQuery注册验证方式
Oct 11 Javascript
详解基于javascript实现的苹果系统底部菜单
Dec 02 Javascript
微信小程序本地缓存数据增删改查实例详解
May 24 Javascript
微信小程序动态显示项目倒计时效果
Jun 13 Javascript
vue中的mescroll搜索运用及各种填坑处理
Oct 30 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
一个ftp类(ini.php)
2006/10/09 PHP
PHP文件上传操作实例详解
2016/09/27 PHP
Laravel框架路由设置与使用示例
2018/06/12 PHP
在php的yii2框架中整合hbase库的方法
2018/09/20 PHP
脚本收藏iframe
2006/07/21 Javascript
关于setInterval、setTimeout在jQuery中的使用注意事项
2011/09/28 Javascript
JQuery操作表格(隔行着色,高亮显示,筛选数据)
2012/02/23 Javascript
jQuery实现点击标题输入详细信息
2013/04/16 Javascript
jquery动态添加删除div 具体实现
2013/07/20 Javascript
淘宝网提供的国内NPM镜像简介和使用方法
2014/04/17 Javascript
javascript如何使用bind指定接收者
2014/05/04 Javascript
深入理解JavaScript系列(43):设计模式之状态模式详解
2015/03/04 Javascript
JS读取XML文件数据并以table形式显示数据的方法(兼容IE与火狐)
2016/06/02 Javascript
Jquery循环截取字符串的方法(多出的字符串处理成&quot;...&quot;)
2016/11/28 Javascript
angularjs $http实现form表单提交示例
2017/06/09 Javascript
详解Vue路由开启keep-alive时的注意点
2017/06/20 Javascript
详解webpack性能优化——DLL
2017/10/20 Javascript
javascript实现电脑和手机版样式切换
2017/11/10 Javascript
详解vue.js下引入百度地图jsApi的两种方法
2018/07/27 Javascript
vue-cli脚手架搭建的项目去除eslint验证的方法
2018/09/29 Javascript
Angular 多级路由实现登录页面跳转(小白教程)
2019/11/19 Javascript
Angular+Ionic使用queryParams实现跳转页传值的方法
2020/09/05 Javascript
Vue封装全局过滤器Filters的步骤
2020/09/16 Javascript
详解vue中在父组件点击按钮触发子组件的事件
2020/11/13 Javascript
python通过apply使用元祖和列表调用函数实例
2015/05/26 Python
Nginx搭建HTTPS服务器和强制使用HTTPS访问的方法
2015/08/16 Python
Python更新数据库脚本两种方法及对比介绍
2017/07/27 Python
python进行参数传递的方法
2020/05/12 Python
英国票务网站:Ticketmaster英国
2018/08/27 全球购物
干部现实表现材料
2014/02/13 职场文书
2014年妇幼保健工作总结
2014/12/08 职场文书
文明礼仪主题班会
2015/08/13 职场文书
调研报告的主要写法
2019/04/18 职场文书
大学生暑期实践报告之企业经营管理
2019/08/08 职场文书
Golang 如何实现函数的任意类型传参
2021/04/29 Golang
Python爬虫基础之初次使用scrapy爬虫实例
2021/06/26 Python