针对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;