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 相关文章推荐
Javascript与vbscript数据共享
Jan 09 Javascript
Use Word to Search for Files
Jun 15 Javascript
jQuery数组处理方法汇总
Jun 20 Javascript
js判断页面中是否有指定控件的简单实例
Mar 04 Javascript
深入探密Javascript数组方法
Jan 08 Javascript
js+html5实现canvas绘制镂空字体文本的方法
Jun 05 Javascript
JavaScript实现点击按钮直接打印
Jan 06 Javascript
教你JS中的运算符乘方、开方及变量格式转换
Aug 09 Javascript
JS实现多级菜单中当前菜单不随页面跳转样式而发生变化
May 30 Javascript
关于ES6箭头函数中的this问题
Feb 27 Javascript
浅谈vue-router路由切换 组件重用挖下的坑
Nov 01 Javascript
vue 使用class创建和清除水印的示例代码
Dec 25 Vue.js
写一个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连接数据库实现注册页面的增删改查操作
2016/03/27 PHP
php实现统计二进制中1的个数算法示例
2018/01/23 PHP
JS之小练习代码
2008/10/12 Javascript
JavaScript 学习笔记二 字符串拼接
2010/03/28 Javascript
JQuery中对服务器控件 DropdownList, RadioButtonList, CheckboxList的操作总结
2011/06/28 Javascript
多浏览器兼容性比较好的复制到剪贴板的js代码
2011/10/09 Javascript
JQuery设置文本框和密码框得到焦点时的样式
2013/08/30 Javascript
Knockout visible绑定使用方法
2013/11/15 Javascript
js中document.write使用过程中的一点疑问解答
2014/03/20 Javascript
JS实现控制表格只显示行边框或者只显示列边框的方法
2015/03/31 Javascript
js实现的后台左侧管理菜单代码
2015/09/11 Javascript
使用jquery插件qrcode生成二维码
2015/10/22 Javascript
javascript跨域总结之window.name实现的跨域数据传输
2015/11/01 Javascript
JavaScript代码里的判断小结
2016/08/22 Javascript
学习JavaScript图片预加载模块
2016/11/07 Javascript
JavaScript无阻塞加载和defer、async详解
2017/02/26 Javascript
微信小程序如何获知用户运行小程序的场景教程
2017/05/17 Javascript
jQuery实现仿京东防抖动菜单效果示例
2018/07/06 jQuery
JS实现数组的增删改查操作示例
2018/08/29 Javascript
微信小程序webview与h5通过postMessage实现实时通讯的实现
2019/08/20 Javascript
nodejs制作小爬虫功能示例
2020/02/24 NodeJs
Python使用Beautiful Soup包编写爬虫时的一些关键点
2016/01/20 Python
Python变量和字符串详解
2017/04/29 Python
python timestamp和datetime之间转换详解
2017/12/11 Python
利用python的socket发送http(s)请求方法示例
2018/05/07 Python
Python中的异常处理try/except/finally/raise用法分析
2019/02/28 Python
Python3网络爬虫开发实战之极验滑动验证码的识别
2019/08/02 Python
如何基于Python和Flask编写Prometheus监控
2020/11/25 Python
如何利用cmp命令比较文件
2013/09/23 面试题
工厂厂长的职责
2013/12/12 职场文书
党的群众路线教育实践活动批评与自我批评
2014/02/16 职场文书
原料仓管员岗位职责
2014/04/12 职场文书
2014年个人工作总结报告
2014/11/27 职场文书
学习弘扬焦裕禄精神心得体会
2016/01/23 职场文书
2019年大学生职业生涯规划书
2019/03/25 职场文书
Python中json.load()和json.loads()有哪些区别
2021/06/07 Python