先看效果:
静态html部分代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" >
<title>3D标签云</title>
<style type="text/css">
.tagBall{
width:500px;
height: 500px;
margin: 50px auto;
position: relative;
border: 1px solid red;
}
.tag{
display:block;
position: absolute;
left:0;
top:0px;
color: #000;
text-decoration: none;
font-size:15px;
font-family: "微软雅黑";
font-weight: bold;
}
.tag:hover{
border:1px solid #666;
}
</style>
</head>
<body>
<div class="tagBall">
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">WAXES</a>
<a class="tag" href="#">3D标签云</a>
</div>
接下来是动态js部分:
主要分为三个部分:
分别是:
- 画标签:innit() , tag对象
- 写标签动画 animate(),rotateX(),rotateY()
- 标签跟随鼠标移动变化事件 mousemove事件
<script>
var canvas = document.getElementById("cas"),
ctx = canvas.getContext("2d"),
vpx = canvas.width/2,
vpy = canvas.height/2,
Radius = 150,
balls = [],
angleX = Math.PI/100,
angleY = Math.PI/100;
window.addEventListener("mousemove" , function(event){
var x = event.clientX - canvas.offsetLeft - vpx - document.body.scrollLeft - document.documentElement.scrollLeft;
var y = event.clientY - canvas.offsetTop - vpy - document.body.scrollTop - document.documentElement.scrollTop;
angleY = -x*0.0001;
angleX = -y*0.0001;
});
var Animation = function(){
this.init();
};
Animation.prototype = {
isrunning:false,
init:function(){
balls = [];
var num = 1000;
for(var i=0;i<=num;i++){
var k = -1+(2*(i+1)-1)/num;
var a = Math.acos(k);
var b = a*Math.sqrt(num*Math.PI);
var x = Radius*Math.sin(a)*Math.cos(b);
var y = Radius*Math.sin(a)*Math.sin(b);
var z = Radius*Math.cos(a);
var b = new ball(x , y , z , 1.5);
balls.push(b);
b.paint();
}
},
start:function(){
this.isrunning = true;
animate();
},
stop:function(){
this.isrunning = false;
}
}
function animate(){
ctx.clearRect(0,0,canvas.width , canvas.height);
rotateX();
rotateY();
balls.sort(function(a , b){
return b.z-a.z;
})
for(var i=0;i<balls.length;i++){
balls[i].paint();
}
if(animation.isrunning) {
if("requestAnimationFrame" in window){
requestAnimationFrame(animate);
}
else if("webkitRequestAnimationFrame" in window){
webkitRequestAnimationFrame(animate);
}
else if("msRequestAnimationFrame" in window){
msRequestAnimationFrame(animate);
}
else if("mozRequestAnimationFrame" in window){
mozRequestAnimationFrame(animate);
}
}
}
function rotateX(){
var cos = Math.cos(angleX);
var sin = Math.sin(angleX);
for(var i=0;i<balls.length;i++){
var y1 = balls[i].y * cos - balls[i].z * sin;
var z1 = balls[i].z * cos + balls[i].y * sin;
balls[i].y = y1;
balls[i].z = z1;
}
}
function rotateY(){
var cos = Math.cos(angleY);
var sin = Math.sin(angleY);
for(var i=0;i<balls.length;i++){
var x1 = balls[i].x * cos - balls[i].z * sin;
var z1 = balls[i].z * cos + balls[i].x * sin;
balls[i].x = x1;
balls[i].z = z1;
}
}
var ball = function(x , y , z , r){
this.x = x;
this.y = y;
this.z = z;
this.r = r;
this.width = 2*r;
}
ball.prototype = {
paint:function(){
var fl = 450 //焦距
ctx.save();
ctx.beginPath();
var scale = fl / (fl - this.z);
var alpha = (this.z+Radius)/(2*Radius);
ctx.arc(vpx + this.x, vpy + this.y, this.r*scale , 0 , 2*Math.PI , true);
ctx.fillStyle = "rgba(255,255,255,"+(alpha+0.5)+")"
ctx.fill();
ctx.restore();
}
}
var animation = new Animation();
animation.start();
document.getElementById("controlBtn").onclick = function(){
this.innerText === "开始" ? this.innerText="停止" : this.innerText="开始";
this.innerText === "开始" ? animation.stop() : animation.start();;
}
</script>