<html> <head> <title>HTML5实现3D球效果</title> <style type="text/css"> #box{ border:2px solid #f60; margin:0 auto; } </style> <script> var spaceX = 30; //X方向的密度 var spaceY = 30; //Y方向的密度 var PI = Math.PI; //数学角度π var radius = 200; //球的半径 var radian = PI / 180; //弧度 var speedX = 0; //X方向的速度 var speedY = 0; //Y方向的速度 var offsetX = 300; //X方向的偏移量相当于将球的中心X坐标移之到画布中央 var offsetY = 300; //Y方向的偏移量相当于将球的中心Y坐标移之到画布中央 var spheres = new Array(); //存储像素点 var canvas; //画布 var context; //上下文 var focalLength = 300; //控制球距离屏幕的距离 var start = true; //是否启动 var sx = 0; //sinx var cx = 0; //cosx var sy = 0; //siny var cy = 0; //cosy var sz = 0; //sinz var cz = 0; //cosz var innerStaColor = "GREEN"; //表示内部颜色 var outerStaColor = "RED"; //外部颜色 var objectRadius = 10; //绘制原点半径 var scaleRatio = 0; var cameraView = { x: 0, y: 0, z: 0, rotX: 0, rotY: 0, rotZ: 0 }; //视角角度 /** author:qingfeilee date:2012-03-28 description:初始化系统画布信息 **/ function initCanvas() { try{ canvas = document.getElementById("sphere"); context = canvas.getContext("2d"); }catch(e){ document.getElementById("tip_info").innerHTML = "您的浏览器不支持!"; } } /** author:qingfeilee date:2012-03-28 description:初始化小球实体 **/ function initSphere() { for (var i = spaceY; i < 180; i += spaceY) { for (var angle = 0; angle < 360; angle += spaceX) { var object = {}; var x = Math.sin(radian * i) * radius; object.x = Math.cos(angle * radian) * x; object.y = Math.cos(radian * i) * radius; object.z = Math.sin(angle * radian) * x; object.glow = .5; //亮度的范围 spheres.push(object); } } } /** author:qingfeilee date:2012-03-28 description:初始化系统函数 **/ function init() { initCanvas(); initSphere(); setInterval(this.update, 1000 / 60, this); setTimeout(function() { start = false; }, 1000); } /** author:qingfeilee date:2012-03-28 description:设置整个大球的运转速度 **/ function setSpeed(speedX, speedY) { this.speedX = speedX; this.speedY = speedY; } /** author:qingfeilee date:2012-03-28 description:更新整个球的状态以实现动态效果 **/ function update() { if (start) { setParam(); } } /** author:qingfeilee date:2012-03-28 description:设置各个小球的属性 **/ function setParam() { //根据速度大小计算出一次旋转的角度大小 var rotYstep = speedX / 10000; var rotXstep = speedY / 10000; cameraView.rotY = rotYstep; cameraView.rotX = -rotXstep; //计算出对应的cos和sin sx = Math.sin(cameraView.rotX); cx = Math.cos(cameraView.rotX); sy = Math.sin(cameraView.rotY); cy = Math.cos(cameraView.rotY); sz = Math.sin(cameraView.rotZ); cz = Math.cos(cameraView.rotZ); // 设置画布的效果 context.fillStyle = 'rgba(0,0,0,0.1)'; context.fillRect(0, 0, canvas.width, canvas.height); var l = spheres.length - 1; for (var i = l, obj; obj = spheres[i]; i--) { render(obj); } } /** author:qingfeilee date:2012-03-28 description:渲染整个画布 **/ function render(object) { var xy, xz, yx, yz, zx, zy; // 计算出物体的相对于照相机的位置 var x = object.x - cameraView.x; var y = object.y - cameraView.y; var z = object.z - cameraView.z; // 绕X轴旋转 xy = cx * y - sx * z; xz = sx * y + cx * z; // 绕Y轴旋转 yz = cy * xz - sy * x; yx = sy * xz + cy * x; // 绕Z轴旋转 zx = cz * yx - sz * xy; zy = sz * yx + cz * xy; //给各个球重新定位 object.x = zx; object.y = zy; object.z = yz; //根据z轴数据来缩放球 scaleRatio = focalLength / (focalLength + yz); scale = scaleRatio; if (object.glow > .5) { object.glow -= .02; } var sphereStyle = context.createRadialGradient(offsetX + object.x * scaleRatio, offsetY + object.y * scaleRatio, scaleRatio * .5, offsetX + object.x * scaleRatio, offsetY + object.y * scaleRatio, scaleRatio * objectRadius * .5); sphereStyle.addColorStop(0, innerStaColor); sphereStyle.addColorStop(object.glow, outerStaColor); sphereStyle.addColorStop(1, 'rgba(0,0,0,0)'); context.fillStyle = sphereStyle; context.fillRect(offsetX + object.x * scaleRatio - scaleRatio * objectRadius * .5, offsetY + object.y * scaleRatio - scaleRatio * objectRadius * .5, scaleRatio * objectRadius, scaleRatio * objectRadius); document.getElementById("tip_info").innerHTML = "当前速度:"+speedX+" "+ speedY+" 小球半径:"+objectRadius; } /** author:qingfeilee date:2012-03-28 description:冻结/激活真个大球状态 **/ function startOrPause() { if (start) { setTimeout(function() { start = false; }, 2000); document.getElementById("swi").innerHTML = "激活"; innerStaColor = "GREEN"; outerStaColor = "RED"; } else { start = true; document.getElementById("swi").innerHTML = "2秒后冻结"; innerStaColor = "RED"; outerStaColor = "GREEN"; } } function changeObjectRadius(val) { this.objectRadius = val; } window.addEventListener("load", init, true); </script> </head> <body> <div id="box" style="600px; height:600px"> <canvas id="sphere" width="600" height="600" style="background:#0066FF"> </canvas> <div align="center"> <button id="swi" onclick="startOrPause()">激活</button> <button onclick="setSpeed(-150,0)">向东</button> <button onclick="setSpeed(150,0)">向西</button> <button onclick="setSpeed(0,-150)">向南</button> <button onclick="setSpeed(0,150)">向北</button> 小球大小: <input type="range" min="10" max="30" value="10" step="2" onchange="changeObjectRadius(this.value)"/> </div> <div align="center"> <a id="tip_info"> </a> </div> </div> </body> </html>