3D标签云的简单实现

作者 Simmin 日期 2017-04-12
3D标签云的简单实现

这里的3D标签云是以球体为基础的标签云。

实现效果:

  1. 标签云呈现球体效果
  2. 自动旋转
  3. 鼠标hover可控制旋转方向。

基本公式

1、在空间直角坐标系中,以坐标原点为球心,半径为r的球面的参数方程为:

x = r * sinφ * cosθ;
y = r * sinΦ * sinθ;
z = r * cosΦ;

image

  1. 球体旋转公式

image

详细步骤

计算各个标签的位置

  1. 各个标签均相对于父元素绝对定位
  2. 标签需要均匀分布在球体上,避免分布太过集中或重叠。用到的公式:
Φ = arccos(((2 * i) - 1) / len - 1);
θ = Φ * sqrt(len * π);

其中i表示第几个标签(i > 0),((2 * i) - 1) / len - 1其实是一个[-1,1]区间上关于0对称分布的等差数列。

//根据标签数量和半径计算标签的分布
var tagCloud = {};
tagCloud.item = getClassElements('tag-item');
tagCloud.radius = 250;
tagCloud.initItemLocate = function(){
var that = this;
var itemLen = this.item.length;
return [].slice.call(this.item).map(function(item,index){
var a , b;
var k = -1 + (2 * (index + 1) - 1) / itemLen;
var a = Math.acos(k);
var b = a * Math.sqrt(itemLen * Math.PI);
var x = that.radius * Math.sin(a) * Math.cos(b);
var y = that.radius * Math.sin(a) * Math.sin(b);
var z = that.radius * Math.cos(a);
return {item : item, x : x, y : y, z : z}
})
};

绘制到页面中

tagCloud.fallLength = 500;
tagCloud.draw = function(){
var that = this;
this.itemLocate.map(function(item){
var left = item.x + that.radius + 'px';
var top = item.y + that.radius + 'px';
var scale = that.fallLength / (that.fallLength - item.z);
var alpha = (item.z + that.radius)/(2 * that.radius);
var fontSize = 15 * scale + "px";
var opacity = alpha + 0.5;
var filter = "alpha(opacity = " + (alpha + 0.5) * 100 +")";
var zIndex = parseInt(scale*100);
item.item.style.cssText += "left:"+ left + "; top:" + top + ";font-size" + fontSize +";opacity:" + opacity + ";filter:"+filter+";z-index:"+zIndex+";";
})
}

这里注意:对于屏幕而言,横向为x轴,纵向为y轴,与屏幕垂直为z轴。

定时旋转

tagCloud.angleX = Math.PI / 2000; //设置每次旋转的角度
tagCloud.angleY = Math.PI / 2000; //设置每次旋转的角度
tagCloud.animation = function(){
var that = this;
setInterval(function(){
that.rotateX();
that.rotateY();
that.draw();
} , 17)
}
tagCloud.rotateX = function(){
var angleX = this.angleX;
this.itemLocate.map(function(item){
var yy = item.y * Math.cos(angleX) - item.z * Math.sin(angleX);
var zz = item.z * Math.cos(angleX) + item.y * Math.sin(angleX);
item.y = yy;
item.z = zz;
})
};
tagCloud.rotateY = function(){
var angleY = this.angleY;
this.itemLocate.map(function(item){
var xx = item.x * Math.cos(angleY) - item.z * Math.sin(angleY);
var zz = item.z * Math.cos(angleY) + item.x * Math.sin(angleY);
item.x = xx;
item.z = zz;
})
}

绑定鼠标事件

tagCloud.onmouseover = function(){
var that = this;
this.tag.addEventListener("mouseover",function(e){
that.angleY = (Math.abs(e.offsetX) - that.radius) * 0.00003; //根据鼠标的位置更改旋转角度(这里减去半径是因为之前为各标签定位时加了半径,主要是对坐标原点的控制)
that.angleX = (Math.abs(e.offsetY) - that.radius) * 0.00003;
})
};
tagCloud.onmouseout = function(){
var that = this;
this.tag.addEventListener("mouseout",function(e){
that.angleX = Math.PI / 2000; // 鼠标移走后恢复原旋转角度
that.angleY = Math.PI / 2000;
})
}

注意:旋转角度的正负控制旋转方向,大小控制转速。

最后的调用函数

tagCloud.init = function(){
this.itemLocate = this.initItemLocate();
this.animation();
this.onmouseover();
this.onmouseout();
}
tagCloud.init();

参考文章:

  1. 解析3D标签云,其实很简单
  2. 3D标签云