1. 程式人生 > 實用技巧 >tagCould3d 移動端優化版

tagCould3d 移動端優化版

class TagCould {
    mcList = [];
    active = false;  // 事件控制
    lasta = 1;
    lastb = 1;
    distr = true;
    mouseX = 0;
    mouseY = 0;
    aA = null;
    oDiv = null;

    _now = 0;
    _then = Date.now();
    _delta = 0;

    isStart = false;
    defaultOptions = {
        dtr: Math.PI / 180,
        d: 
500, tspeed: 5, size: 250, howElliptical: 1, fps: 30 }; radius = (window.innerWidth + 25) / 2 > 300 ? 300 : (window.innerWidth + 25) / 2; constructor(container, tags = [], options = {}) { this.container = container; this.tags = tags; options
= Object.assign(this.defaultOptions, options); for (var p in options) { this[p] = options[p]; } this._interval = 1000 / this.fps; window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame; this.init(); } init() { this.createTag(); this.setOffset(); this.sineCosine(0, 0, 0); this.positionAll(); this.tick(); this.bindEvent(); } start() { this.isStart = true; } pause() { this.isStart = false; } createTag() { this.oDiv = typeof this.container == 'string' ? document.getElementById(this.container) : this.container; for (let i = 0; i < this.tags.length; i++) { const item = this.tags[i]; let aElE = document.createElement('a'); aElE.innerHTML = item.text; aElE.classList.add(`tag${i}`); aElE.classList.add(`tag`); item.className && aElE.classList.add(item.className); aElE.setAttribute('href', item.url || 'javascript:;'); this.oDiv.appendChild(aElE); } } setOffset() { this.oDiv = typeof this.container == 'string' ? document.getElementById(this.container) : this.container; let i = 0, oTag = null; this.aA = this.oDiv.getElementsByTagName('a'); for (i = 0; i < this.aA.length; i++) { oTag = {}; oTag.offsetWidth = this.aA[i].offsetWidth; oTag.offsetHeight = this.aA[i].offsetHeight; this.mcList.push(oTag); } } bindEvent() { let self = this; document.addEventListener( 'mouseover', function() { self.active = true; }, false ); document.addEventListener( 'mouseout', function() { self.active = false; }, false ); document.addEventListener( 'mousemove', function(evt) { //var oEvent=window.event || evt; self.onmove(window.event || evt); }, false ); document.addEventListener( 'touchstart', function() { self.active = true; }, false ); document.addEventListener( 'touchmove', function(evt) { self.onmove(window.event || evt); }, false ); document.addEventListener( 'touchend', function() { self.active = false; }, false ); } tick() { if (window.requestAnimationFrame) { window.requestAnimationFrame(this.tick.bind(this)); this._now = Date.now(); this._delta = this._now - this._then; if (this._delta > this._interval) { // 這裡不能簡單then=now,否則還會出現上邊簡單做法的細微時間差問題。例如fps=10,每幀100ms,而現在每16ms(60fps)執行一次draw。16*7=112>100,需要7次才實際繪製一次。這個情況下,實際10幀需要112*10=1120ms>1000ms才繪製完成。 this._then = this._now - this._delta % this._interval; this.update(); // ... Code for Drawing the Frame ... } } else { setTimeout(this._tick, this._interval); this.update(); } } onmove(oEvent) { oEvent.preventDefault(); if (oEvent.touches && oEvent.touches.length > 0) { oEvent.clientX = oEvent.touches[0].clientX; oEvent.clientY = oEvent.touches[0].clientY; } this.mouseX = oEvent.clientX - (this.oDiv.offsetLeft + this.oDiv.offsetWidth / 2); this.mouseY = oEvent.clientY - (this.oDiv.offsetTop + this.oDiv.offsetHeight / 2); this.mouseX /= 5; this.mouseY /= 5; } update() { if (!this.isStart) { return false; } var a, b; if (this.active) { a = -Math.min(Math.max(-this.mouseY, -this.size), this.size) / this.radius * this.tspeed; b = Math.min(Math.max(-this.mouseX, -this.size), this.size) / this.radius * this.tspeed; } else { a = this.lasta * 0.999; b = this.lastb * 0.999; } this.lasta = a; this.lastb = b; if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) { return; } var c = 0; this.sineCosine(a, b, c); for (var j = 0; j < this.mcList.length; j++) { var rx1 = this.mcList[j].cx, ry1 = this.mcList[j].cy * this.ca + this.mcList[j].cz * -this.sa, rz1 = this.mcList[j].cy * this.sa + this.mcList[j].cz * this.ca, rx2 = rx1 * this.cb + rz1 * this.sb, ry2 = ry1, rz2 = rx1 * -this.sb + rz1 * this.cb, rx3 = rx2 * this.cc + ry2 * -this.sc, ry3 = rx2 * this.sc + ry2 * this.cc, rz3 = rz2; this.mcList[j].cx = rx3; this.mcList[j].cy = ry3; this.mcList[j].cz = rz3; var per = this.d / (this.d + rz3); this.mcList[j].x = this.howElliptical * rx3 * per - this.howElliptical * 2; this.mcList[j].y = ry3 * per; this.mcList[j].scale = per; this.mcList[j].alpha = per; this.mcList[j].alpha = (this.mcList[j].alpha - 0.6) * (10 / 6); } this.doPosition(); this.depthSort(); } depthSort() { var i = 0, aTmp = []; for (i = 0; i < this.aA.length; i++) { aTmp.push(this.aA[i]); } aTmp.sort(function(vItem1, vItem2) { if (vItem1.cz > vItem2.cz) { return -1; } else if (vItem1.cz < vItem2.cz) { return 1; } else { return 0; } }); for (i = 0; i < aTmp.length; i++) { aTmp[i].style.zIndex = i; } } positionAll() { var phi = 0, theta = 0, max = this.mcList.length, i = 0, aTmp = [], oFragment = document.createDocumentFragment(); //隨機排序 for (i = 0; i < this.aA.length; i++) { aTmp.push(this.aA[i]); } aTmp.sort(function() { return Math.random() < 0.5 ? 1 : -1; }); for (i = 0; i < aTmp.length; i++) { oFragment.appendChild(aTmp[i]); } this.oDiv.appendChild(oFragment); for (var i = 1; i < max + 1; i++) { if (this.distr) { phi = Math.acos(-1 + (2 * i - 1) / max); theta = Math.sqrt(max * Math.PI) * phi; } else { phi = Math.random() * Math.PI; theta = Math.random() * (2 * Math.PI); } //座標變換 this.mcList[i - 1].cx = this.radius * Math.cos(theta) * Math.sin(phi); this.mcList[i - 1].cy = this.radius * Math.sin(theta) * Math.sin(phi); this.mcList[i - 1].cz = this.radius * Math.cos(phi); this.aA[i - 1].style.webkitTransform = `translate(${this.mcList[i - 1].cx + this.oDiv.offsetWidth / 2 - this.mcList[i - 1].offsetWidth / 2 + 'px'},${this.mcList[i - 1].cy + this.oDiv.offsetHeight / 2 - this.mcList[i - 1].offsetHeight / 2 + 'px'}) scale(${this.mcList[i - 1].scale || 1})`; } } doPosition() { var l = this.oDiv.offsetWidth / 2, t = this.oDiv.offsetHeight / 2; for (var i = 0; i < this.mcList.length; i++) { this.aA[i].style.webkitTransform = `translate(${this.mcList[i].cx + l - this.mcList[i].offsetWidth / 2 + 'px'},${this.mcList[i].cy + t - this.mcList[i].offsetHeight / 2 + 'px'}) scale(${this.mcList[i] .scale})`; this.aA[i].style.opacity = this.mcList[i].alpha; } } sineCosine(a, b, c) { this.sa = Math.sin(a * this.dtr); this.ca = Math.cos(a * this.dtr); this.sb = Math.sin(b * this.dtr); this.cb = Math.cos(b * this.dtr); this.sc = Math.sin(c * this.dtr); this.cc = Math.cos(c * this.dtr); } } export default TagCould;

classTagCould{ mcList=[]; active=false;//事件控制 lasta=1; lastb=1; distr=true; mouseX=0; mouseY=0; aA=null; oDiv=null;
_now=0; _then=Date.now(); _delta=0;
isStart=false; defaultOptions={ dtr:Math.PI/180, d:500, tspeed:5, size:250, howElliptical:1, fps:30 }; radius=(window.innerWidth+25)/2>300?300:(window.innerWidth+25)/2; constructor(container,tags=[],options={}){ this.container=container; this.tags=tags; options=Object.assign(this.defaultOptions,options); for(varpinoptions){ this[p]=options[p]; } this._interval=1000/this.fps; window.requestAnimationFrame= window.requestAnimationFrame|| window.mozRequestAnimationFrame|| window.webkitRequestAnimationFrame|| window.msRequestAnimationFrame;
this.init(); }
init(){ this.createTag(); this.setOffset(); this.sineCosine(0,0,0); this.positionAll(); this.tick(); this.bindEvent(); } start(){ this.isStart=true; } pause(){ this.isStart=false; } createTag(){ this.oDiv=typeofthis.container=='string'?document.getElementById(this.container):this.container; for(leti=0;i<this.tags.length;i++){ constitem=this.tags[i]; letaElE=document.createElement('a'); aElE.innerHTML=item.text; aElE.classList.add(`tag${i}`); aElE.classList.add(`tag`); item.className&&aElE.classList.add(item.className); aElE.setAttribute('href',item.url||'javascript:;'); this.oDiv.appendChild(aElE); } } setOffset(){ this.oDiv=typeofthis.container=='string'?document.getElementById(this.container):this.container; leti=0, oTag=null; this.aA=this.oDiv.getElementsByTagName('a'); for(i=0;i<this.aA.length;i++){ oTag={}; oTag.offsetWidth=this.aA[i].offsetWidth; oTag.offsetHeight=this.aA[i].offsetHeight; this.mcList.push(oTag); } } bindEvent(){ letself=this; document.addEventListener( 'mouseover', function(){ self.active=true; }, false );
document.addEventListener( 'mouseout', function(){ self.active=false; }, false );
document.addEventListener( 'mousemove', function(evt){ //varoEvent=window.event||evt; self.onmove(window.event||evt); }, false );
document.addEventListener( 'touchstart', function(){ self.active=true; }, false ); document.addEventListener( 'touchmove', function(evt){ self.onmove(window.event||evt); }, false ); document.addEventListener( 'touchend', function(){ self.active=false; }, false ); } tick(){ if(window.requestAnimationFrame){ window.requestAnimationFrame(this.tick.bind(this)); this._now=Date.now(); this._delta=this._now-this._then; if(this._delta>this._interval){ //這裡不能簡單then=now,否則還會出現上邊簡單做法的細微時間差問題。例如fps=10,每幀100ms,而現在每16ms(60fps)執行一次draw。16*7=112>100,需要7次才實際繪製一次。這個情況下,實際10幀需要112*10=1120ms>1000ms才繪製完成。 this._then=this._now-this._delta%this._interval; this.update();//...CodeforDrawingtheFrame... } }else{ setTimeout(this._tick,this._interval); this.update(); } } onmove(oEvent){ oEvent.preventDefault();
if(oEvent.touches&&oEvent.touches.length>0){ oEvent.clientX=oEvent.touches[0].clientX; oEvent.clientY=oEvent.touches[0].clientY; }
this.mouseX=oEvent.clientX-(this.oDiv.offsetLeft+this.oDiv.offsetWidth/2); this.mouseY=oEvent.clientY-(this.oDiv.offsetTop+this.oDiv.offsetHeight/2);
this.mouseX/=5; this.mouseY/=5; } update(){ if(!this.isStart){ returnfalse; } vara,b; if(this.active){ a=-Math.min(Math.max(-this.mouseY,-this.size),this.size)/this.radius*this.tspeed; b=Math.min(Math.max(-this.mouseX,-this.size),this.size)/this.radius*this.tspeed; }else{ a=this.lasta*0.999; b=this.lastb*0.999; }
this.lasta=a; this.lastb=b;
if(Math.abs(a)<=0.01&&Math.abs(b)<=0.01){ return; }
varc=0; this.sineCosine(a,b,c); for(varj=0;j<this.mcList.length;j++){ varrx1=this.mcList[j].cx, ry1=this.mcList[j].cy*this.ca+this.mcList[j].cz*-this.sa, rz1=this.mcList[j].cy*this.sa+this.mcList[j].cz*this.ca, rx2=rx1*this.cb+rz1*this.sb, ry2=ry1, rz2=rx1*-this.sb+rz1*this.cb, rx3=rx2*this.cc+ry2*-this.sc, ry3=rx2*this.sc+ry2*this.cc, rz3=rz2;
this.mcList[j].cx=rx3; this.mcList[j].cy=ry3; this.mcList[j].cz=rz3;
varper=this.d/(this.d+rz3);
this.mcList[j].x=this.howElliptical*rx3*per-this.howElliptical*2; this.mcList[j].y=ry3*per; this.mcList[j].scale=per; this.mcList[j].alpha=per;
this.mcList[j].alpha=(this.mcList[j].alpha-0.6)*(10/6); }
this.doPosition(); this.depthSort(); } depthSort(){ vari=0, aTmp=[];
for(i=0;i<this.aA.length;i++){ aTmp.push(this.aA[i]); }
aTmp.sort(function(vItem1,vItem2){ if(vItem1.cz>vItem2.cz){ return-1; }elseif(vItem1.cz<vItem2.cz){ return1; }else{ return0; } });
for(i=0;i<aTmp.length;i++){ aTmp[i].style.zIndex=i; } } positionAll(){ varphi=0, theta=0, max=this.mcList.length, i=0, aTmp=[], oFragment=document.createDocumentFragment();
//隨機排序 for(i=0;i<this.aA.length;i++){ aTmp.push(this.aA[i]); }
aTmp.sort(function(){ returnMath.random()<0.5?1:-1; });
for(i=0;i<aTmp.length;i++){ oFragment.appendChild(aTmp[i]); }
this.oDiv.appendChild(oFragment);
for(vari=1;i<max+1;i++){ if(this.distr){ phi=Math.acos(-1+(2*i-1)/max); theta=Math.sqrt(max*Math.PI)*phi; }else{ phi=Math.random()*Math.PI; theta=Math.random()*(2*Math.PI); } //座標變換 this.mcList[i-1].cx=this.radius*Math.cos(theta)*Math.sin(phi); this.mcList[i-1].cy=this.radius*Math.sin(theta)*Math.sin(phi); this.mcList[i-1].cz=this.radius*Math.cos(phi); this.aA[i-1].style.webkitTransform=`translate(${this.mcList[i-1].cx+ this.oDiv.offsetWidth/2- this.mcList[i-1].offsetWidth/2+ 'px'},${this.mcList[i-1].cy+ this.oDiv.offsetHeight/2- this.mcList[i-1].offsetHeight/2+ 'px'})scale(${this.mcList[i-1].scale||1})`; } } doPosition(){ varl=this.oDiv.offsetWidth/2, t=this.oDiv.offsetHeight/2; for(vari=0;i<this.mcList.length;i++){ this.aA[i].style.webkitTransform=`translate(${this.mcList[i].cx+ l- this.mcList[i].offsetWidth/2+ 'px'},${this.mcList[i].cy+t-this.mcList[i].offsetHeight/2+'px'})scale(${this.mcList[i] .scale})`; this.aA[i].style.opacity=this.mcList[i].alpha; } } sineCosine(a,b,c){ this.sa=Math.sin(a*this.dtr); this.ca=Math.cos(a*this.dtr); this.sb=Math.sin(b*this.dtr); this.cb=Math.cos(b*this.dtr); this.sc=Math.sin(c*this.dtr); this.cc=Math.cos(c*this.dtr); } } iENV.Emitter.mixTo(TagCould); exportdefaultTagCould;