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 相关文章推荐
XENON基于JSON变种
Jul 27 Javascript
基于jquery 的一个progressbar widge
Oct 29 Javascript
使用JS进行目录上传(相当于批量上传)
Dec 05 Javascript
js精美的幻灯片画集特效代码分享
Aug 29 Javascript
学习JavaScript设计模式之代理模式
Jan 12 Javascript
基于HTML5上使用iScroll实现下拉刷新,上拉加载更多
May 21 Javascript
20行js代码实现的贪吃蛇小游戏
Jun 20 Javascript
详解Angular 自定义结构指令
Jun 21 Javascript
新版vue-cli模板下本地开发环境使用node服务器跨域的方法
Apr 03 Javascript
vue2之简易的pc端短信验证码的问题及处理方法
Jun 03 Javascript
vue拖拽组件 vuedraggable API options实现盒子之间相互拖拽排序
Jul 08 Javascript
在vue中使用jsx语法的使用方法
Sep 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
实用PHP会员权限控制实现原理分析
2011/05/29 PHP
php实现多张图片上传加水印技巧
2013/04/18 PHP
php curl模拟post请求小实例
2013/11/13 PHP
利用php输出不同的心形图案
2016/04/22 PHP
PHP简单获取随机数的常用方法小结
2017/06/07 PHP
this和执行上下文实现代码
2010/07/01 Javascript
javascript操作referer详细解析
2014/03/10 Javascript
JS+CSS实现仿msn风格选项卡效果代码
2015/10/22 Javascript
超实用的JavaScript表单代码段
2016/02/26 Javascript
如何使用jquery修改css中带有!important的样式属性
2016/04/28 Javascript
又一枚精彩的弹幕效果jQuery实现
2016/07/25 Javascript
原生Javascript和jQuery做轮播图简单例子
2016/10/11 Javascript
JS中解决谷歌浏览器记住密码输入框颜色改变功能
2017/02/13 Javascript
Angular组件化管理实现方法分析
2017/03/17 Javascript
jQuery插件之validation插件
2017/03/29 jQuery
vue devtools的安装与使用教程
2018/08/08 Javascript
原生JS实现简单的倒计时功能示例
2018/08/30 Javascript
js实现前面自动补全位数的方法
2018/10/10 Javascript
Vue2.0实现组件之间数据交互和通信操作示例
2019/05/16 Javascript
vue2配置scss的方法步骤
2019/06/06 Javascript
python通过索引遍历列表的方法
2015/05/04 Python
Python实现字典的key和values的交换
2015/08/04 Python
python executemany的使用及注意事项
2017/03/13 Python
Python操作Excel之xlsx文件
2017/03/24 Python
Python with语句上下文管理器两种实现方法分析
2018/02/09 Python
python操作mysql代码总结
2018/06/01 Python
python画柱状图--不同颜色并显示数值的方法
2018/12/13 Python
CSS3 清除浮动的方法示例
2018/06/01 HTML / CSS
导出HTML5 Canvas图片并上传服务器功能
2019/08/16 HTML / CSS
Vans(范斯)德国官网:美国南加州的原创极限运动潮牌
2017/05/02 全球购物
党员自我评价分享
2013/12/13 职场文书
食品安全工作方案
2014/05/07 职场文书
统计学教授推荐信
2014/09/18 职场文书
个人遵守党的政治纪律情况对照检查材料思想汇报
2014/09/25 职场文书
狂人日记读书笔记
2015/06/30 职场文书
InterProcessMutex实现zookeeper分布式锁原理
2022/03/21 Java/Android