针对https://github.com/bitjjj/JS-3D-TagCloud这个版本的做了移动端性能优化(使用transform做偏移及缩放,优化帧)。基本原理一致。
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;