(function () { function Garden(canvas, vpx, vpy) { this.canvas = canvas; this.ctx = this.canvas.getContext('2d'); // 三维系在二维上的原点 this.vpx = vpx === undefined ? 250 : 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, 500, 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(); } }; $(function () { var canvas = document.getElementById('canvas'); 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 <= 90; i += 5) // for(var j = 90; j <= 90; j += 5) { // 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); }) })();
<canvas id='canvas' width=500 height=500 style='background-color:rgb(0,0,0)'> This browser does not support html5. </canvas>
body { background:#000; }