这里的3D标签云是以球体为基础的标签云。
实现效果:
- 标签云呈现球体效果
- 自动旋转
- 鼠标hover可控制旋转方向。
基本公式
1、在空间直角坐标系中,以坐标原点为球心,半径为r
的球面的参数方程为:
x = r * sinφ * cosθ; y = r * sinΦ * sinθ; z = r * cosΦ;
|
- 球体旋转公式
详细步骤
计算各个标签的位置
- 各个标签均相对于父元素绝对定位
- 标签需要均匀分布在球体上,避免分布太过集中或重叠。用到的公式:
Φ = 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();
|
参考文章:
- 解析3D标签云,其实很简单
- 3D标签云