-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcat.js
154 lines (138 loc) · 5.52 KB
/
cat.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
export default class Cat {
constructor(locationX) {
this.root = document.querySelector('#root');
this.maxHeight = document.querySelector('#root').clientHeight;
this.imgSize = 50;
this.caching = {};
this.createCat(locationX);
this.render();
}
/**
* This function creates a node that moves up and down within the viewport.
* The node's class and locationX are randomly choosen.
* All location infromation is cached.
* @param {Number} locationX - Indicates the horizontal X coordinate where the node will be placed.
*/
createCat(locationX) {
const { maxHeight, imgSize, caching } = this;
const movingState = Math.random() > 0.5 ? 'up' : 'down';
const node = document.createElement('img');
const locationY = Math.max(Math.random() * maxHeight - imgSize, 0);
node.src = './imgs/cat.gif';
node.className = `cat ${movingState}`;
node.style.cssText = `left: ${locationX}px; top: ${locationY}px; transform : translateY(0px);`;
caching.curTop = locationY;
caching.curTranslateY = 0;
caching.curLocation = locationY - 0;
this.node = node;
}
render() {
const { node, root } = this;
root.appendChild(node);
}
/**
* Parsing the style.transform text to calculate the translateY value
* @constant {number} start - index of character follwing '('
* @constant {number} end - index of character preceding 'px'
* @returns {number} - The current translateY value of the node.
*/
translateParsing = () => {
const { node } = this;
const translateText = node.style.transform;
const start = translateText.indexOf('(') + 1;
const end = translateText.indexOf('px');
return parseInt(translateText.slice(start, end));
};
/**
*
* @param {boolean} isCaching - Indicates whether to use cached location values
* @returns {Object} - infromation of the location of the node.
* @property {number} curTop - The current top position of the node.
* @property {number} curTranslateY - The current translateY value of the node.
* @property {number} curLocation - The current calculated location of the node
*
*/
getLocation = (isCaching) => {
const { node, caching } = this;
const { translateParsing } = this;
const amountTranslate = translateParsing();
if (isCaching) return caching;
return {
curTop: node.offsetTop,
curTranslateY: amountTranslate,
curLocation: node.offsetTop + amountTranslate,
};
};
/**
* Calculate the offset to going next step depending on whether it is cached or not
* offset is the distance to move depending on the current location
* if the distnace after moving by offset is beyond the viewport , the offset is adjusted to the
* distance from the current position to viewport.
* @param {boolean} isCaching - Indicates whether caching for animation if enabled.
* @returns {number} - Indicates the distance the node will move next.
*/
calcaulateOffset = (isGoingUp, isCaching) => {
const { maxHeight, imgSize } = this;
const { getLocation } = this;
const { curLocation } = getLocation(isCaching);
const offset = isGoingUp ? -3 : 3;
const nextLocation = curLocation + offset;
if (isGoingUp && nextLocation <= 0) return -curLocation;
if (!isGoingUp && nextLocation >= maxHeight - imgSize)
return maxHeight - imgSize - curLocation;
return offset;
};
/**
* function to change the node's class based on the next direction to move,
* wheter the next direction to go is up or down
* this is depending on nextLocation is beyond the viewport
* @param {boolean} isGoingUp - Indicates the node's class contains up
* @param {boolean} nextLocation - Indicates the location where the next node will be placed
*/
changeState = (isGoingUp, nextLocation) => {
const { node, maxHeight, imgSize } = this;
if (nextLocation !== 0 && nextLocation !== maxHeight - imgSize) return;
if (isGoingUp) {
node.classList.remove('up');
node.classList.add('down');
} else {
node.classList.remove('down');
node.classList.add('up');
}
};
/**
* This function update the caching data using Object spread syntax
* @param {Object} newData - The Object used to update the caching.
*/
updateCache = (newData) => {
this.caching = { ...this.caching, ...newData };
};
/**
* This function makes the node movable within the viewport.
* This calculates the offset indicating next step using calculateOffset function ,
* changes the style of node depending on isTranslate.
* and this function updates caching data if isCaching is true
* @param {Object} optimizeState
* @property {boolean} isCaching - Indicates whether to use cached location values
* @property {boolean} isTranslate - Indicates whether to use translateY or not
*/
move = (optimizeState) => {
const { isCaching, isTranslate } = optimizeState;
const { node } = this;
const { getLocation, calcaulateOffset, changeState, updateCache } = this;
const isGoingUp = node.classList.contains('up');
let { curTop, curTranslateY, curLocation } = getLocation(isCaching);
const offset = calcaulateOffset(isGoingUp, isCaching);
const nextLocation = curLocation + offset;
if (isTranslate) {
node.style.transform = `translateY(${curTranslateY + offset}px)`;
curTranslateY += offset;
} else {
node.style.top = `${curTop + offset}px`;
curTop += offset;
}
curLocation += offset;
updateCache({ curTop, curTranslateY, curLocation });
changeState(isGoingUp, nextLocation);
};
}