码迷,mamicode.com
首页 > 其他好文 > 详细

rotate 3d II

时间:2015-01-24 11:25:01      阅读:356      评论:0      收藏:0      [点我收藏+]

标签:

  第二篇来学习如何用canvas打造3d标签云。

  demo -> 3d标签云

  参考资料:

前面我们已经构造了一个三维空间旋转的模板(其实Ball类初始化时有bug...),如何构造一个标签云?思考ing...

其实就是构造一个球体,标签放在球体上,然后每个标签旋转即可。也就是说,我们可以把每个粒子当做是一个标签。

怎样构造球体?前面一篇中我用确定z参数,然后枚举x获取y的方法获得球面坐标,其实有更好的方法:

技术分享

不懂数学,试了下觉得角度的取值有两种方法:

  1. (0 <= θ <= PI && 0 <= Φ <= 2 * PI)
  2. (0 <= θ <= 2 * PI && 0 <= Φ <= PI)

可以验证x*x+y*y+z*z确实等于R*R。

有了公式,我们可以枚举角度获得坐标。

如果有n个点,我需要平均分配在球面上,怎么做?我们引入第二个公式:

技术分享

var all = 100;
for(var i = 1; i <= all; i++) {
  var a1 = Math.acos(1 - (2 * i) / all);
  var a2 = a1 * Math.sqrt(all * Math.PI);
  var x = 150 * Math.sin(a1) * Math.cos(a2);
  var y = 150 * Math.sin(a1) * Math.sin(a2);
  var z = 150 * Math.cos(a1);
  garden.createBall(x, y, z);
}

  然后就差不多了,以前的demo我都是代码自己控制旋转角度,加个事件的监听:

document.addEventListener("mousemove" , function(event){
  var x = event.clientX - garden.vpx;
  var y = event.clientY - garden.vpy;

  garden.angleY = -x * 0.0001;
  garden.angleX = y * 0.0001;
});

  不考虑兼容...仅在chrome下测试。然后每帧绘制的时候,前面的demo是绘制小球,现在就是fillText,根据scale改变text的大小、透明度等。其实应该是个“标签”,应该有点击跳转的功能,无奈我的css能力为0...

完整代码:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title> rotate 3d</title>
    <script>
      window.onload = function() {
        var canvas = document.getElementById(‘canvas‘);
        var ctx = canvas.getContext(‘2d‘);
        var garden = new Garden(canvas);

        // x=r*sinθ*cosΦ   y=r*sinθ*sinΦ   z=r*cosθ;
        // θ = arccos((2*num-1)/all - 1);
        // Φ = θ*sqrt(all * π);

        // for(var i = 0; i <= 180; i += 10)
        //   for(var j = 0; j <= 360; j += 10) {
        //     var a1 = Math.PI / 180 * i;
        //     var a2 = Math.PI / 180 * j;
        //     var x = 150 * Math.sin(a1) * Math.cos(a2);
        //     var y = 150 * Math.sin(a1) * Math.sin(a2);
        //     var z = 150 * Math.cos(a1);
        //     garden.createBall(x, y, z);
        //   }
          
        var all = 30;
        for(var i = 1; i <= all; i++) {
          var a1 = Math.acos(1- (2 * i) / all);
          var a2 = a1 * Math.sqrt(all * Math.PI);
          var x = 150 * Math.sin(a1) * Math.cos(a2);
          var y = 150 * Math.sin(a1) * Math.sin(a2);
          var z = 150 * Math.cos(a1);
          garden.createBall(x, y, z);
        }

        document.addEventListener("mousemove" , function(event){
          var x = event.clientX - garden.vpx;
          var y = event.clientY - garden.vpy;
      
          garden.angleY = -x * 0.0001;
          garden.angleX = y * 0.0001;
        });

        setInterval(function() {garden.render();}, 1000/60); 
      };

      function Garden(canvas, vpx, vpy) {
        this.canvas = canvas;
        this.ctx = this.canvas.getContext(‘2d‘);

        // 三维系在二维上的原点
        this.vpx = vpx === undefined? 500: vpx;
        this.vpy = vpy === undefined? 250: vpy;
        this.balls = [];
        this.angleY = 0;
        this.angleX = 0;
      }

      Garden.prototype = {
        createBall: function(x, y, z) {
          this.balls.push(new Ball(this, x, y, z));
        },

        render: function() {
          this.ctx.clearRect(0,0,1000,500)
          this.balls.sort(function (a, b) {return b.z-a.z })
          for(var i = 0; i < this.balls.length; i++) {
            this.balls[i].rotateY();
            this.balls[i].rotateX();
            this.balls[i].draw();
          }
        }
      };

      function Ball(garden, x, y, z, angleX, angleY, ballR) {
        this.garden = garden;

        // 三维下坐标
        this.x = x === undefined? Math.random() * 200 - 100: x;
        this.y = y === undefined? Math.random() * 200 - 100: y;
        this.z = z === undefined? Math.random() * 200 - 100: z;

        this.r = Math.floor(Math.random() * 255);
        this.g = Math.floor(Math.random() * 255);
        this.b = Math.floor(Math.random() * 255);

        this.fontSize = (10 + 10 * Math.random());

        // this.angleX = 0;
        // this.angleX = angleX || Math.PI / 200;

        // this.angleY = angleY === undefined? Math.PI / 100: angleY;

        // 三维上半径
        this.ballR = 1;

        // 二维上半径
        this.radius = undefined;

        // 二维上坐标
        this.x2 = undefined;
        this.y2 = undefined;
      }

      
      Ball.prototype = {
        // 绕y轴变化,得出新的x,z坐标
        rotateY: function() {
          var cosy = Math.cos(this.garden.angleY);
          var siny = Math.sin(this.garden.angleY);
          var x1 = this.z * siny + this.x * cosy;
          var z1 = this.z * cosy - this.x * siny;

          this.x = x1;
          this.z = z1;

        },

        // 绕x轴变化,得出新的y,z坐标
        rotateX: function() {
          var cosx = Math.cos(this.garden.angleX);
          var sinx = Math.sin(this.garden.angleX);
          var y1 = this.y * cosx - this.z * sinx;
          var z1 = this.y * sinx + this.z * cosx;

          this.y = y1;
          this.z = z1;
        },

        draw: function() {
          // focalLength 表示当前焦距,一般可设为一个常量
          var focalLength = 300;
          
          // 把z方向扁平化
          var scale = focalLength / (focalLength + this.z);
          this.x2 = this.garden.vpx + this.x * scale;
          this.y2 = this.garden.vpy + this.y * scale;
          this.radius = this.ballR * scale;

          this.garden.ctx.beginPath();
          this.garden.ctx.fillStyle = ‘rgba(‘+this.r+‘,‘+this.g+‘,‘+this.b+‘,‘+ Math.min(1, scale)+‘)‘;
          // this.garden.ctx.arc(this.x2, this.y2, this.radius, 0, Math.PI * 2 , true);
          this.garden.ctx.font = ‘bold ‘ + this.fontSize * scale+ ‘px serif‘;
          this.garden.ctx.textAlign = "left";
          this.garden.ctx.textBaseline = "top";
          this.garden.ctx.fillText(‘博客园‘, this.x2, this.y2);
          this.garden.ctx.fill();
        }
      }
    </script>
  </head>
  <body bgcolor=‘#000‘> 
    <canvas id=‘canvas‘ width=1000 height=500 style=‘background-color:rgb(0,0,0)‘>
      This browser does not support html5.
    </canvas>
  </body>
</html>

  其实用封装好的3d标签云插件的实现也大同小异,无非是用div代替canvas,然后设置原点为div的中心,原html里写好链接,然后监听,实现a标签的位置变化...不会css是硬伤...

rotate 3d II

标签:

原文地址:http://www.cnblogs.com/zichi/p/4245494.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!