@houstonp/rubiks-cube 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/index.js +40 -84
- package/package.json +1 -1
- package/src/cube/cube.js +104 -28
- package/src/cube/cubeRotation.js +7 -7
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This package is a rubiks cube web component built with threejs. Camera animation smoothing is done with the tweenjs package.
|
|
4
4
|
|
|
5
|
+

|
|
6
|
+
|
|
5
7
|
## Adding the component
|
|
6
8
|
|
|
7
9
|
You can add the component to a webpage by adding an import statement in the index.js file. And then
|
|
@@ -19,7 +21,7 @@ import '@houstonp/rubiks-cube';
|
|
|
19
21
|
<meta charset="utf-8" />
|
|
20
22
|
</head>
|
|
21
23
|
<body>
|
|
22
|
-
<rubiks-cube animation-speed="1000" animation-style="exponential" gap="1.04"> </rubiks-cube>
|
|
24
|
+
<rubiks-cube animation-speed="1000" animation-style="exponential" piece-gap="1.04"> </rubiks-cube>
|
|
23
25
|
<script type="module" src="index.js"></script>
|
|
24
26
|
</body>
|
|
25
27
|
</html>
|
|
@@ -27,11 +29,11 @@ import '@houstonp/rubiks-cube';
|
|
|
27
29
|
|
|
28
30
|
## component attributes
|
|
29
31
|
|
|
30
|
-
| attribute | accepted values
|
|
31
|
-
| --------------- |
|
|
32
|
-
| animation-speed | integer greater than 0
|
|
33
|
-
| animation-style | "exponetial", "next", "fixed" | fixed: fixed animation lengths, next: skips to next animation, exponential: speeds up successive animations |
|
|
34
|
-
| gap
|
|
32
|
+
| attribute | accepted values | Description |
|
|
33
|
+
| --------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| animation-speed | integer greater than 0 | sets the speed of the animations in milliseconds |
|
|
35
|
+
| animation-style | "exponetial", "next", "fixed", "match" | fixed: fixed animation lengths, next: skips to next animation, exponential: speeds up successive animations, match: matches the speed the frequency of events |
|
|
36
|
+
| piece-gap | greater than 1 | sets the gap between rubiks cube pieces |
|
|
35
37
|
|
|
36
38
|
## state of the component
|
|
37
39
|
|
package/index.js
CHANGED
|
@@ -6,8 +6,9 @@ import getRotationDetailsFromNotation from './src/utils/rotation';
|
|
|
6
6
|
import { debounce } from './src/utils/debouncer';
|
|
7
7
|
|
|
8
8
|
const defaultAnimationSpeed = 100;
|
|
9
|
-
const defaultAnimationStyle = '
|
|
9
|
+
const defaultAnimationStyle = 'fixed';
|
|
10
10
|
const defaultGap = 1.04;
|
|
11
|
+
const minimumGap = 1;
|
|
11
12
|
|
|
12
13
|
class RubiksCube extends HTMLElement {
|
|
13
14
|
constructor() {
|
|
@@ -19,27 +20,29 @@ class RubiksCube extends HTMLElement {
|
|
|
19
20
|
this.attachShadow({ mode: 'open' });
|
|
20
21
|
this.shadowRoot.innerHTML = `<canvas id="cube-canvas" style="display:block;"></canvas>`;
|
|
21
22
|
this.canvas = this.shadowRoot.getElementById('cube-canvas');
|
|
22
|
-
/** @type {{
|
|
23
|
+
/** @type {{animationStyle: "exponential" | "next" | "fixed" | "match", animationSpeed: number, gap: number}} */
|
|
23
24
|
this.settings = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
gap: this.getAttribute('gap') || defaultGap,
|
|
25
|
+
animationSpeed: this.getAttribute('animation-speed') || defaultAnimationSpeed,
|
|
26
|
+
animationStyle: this.getAttribute('animation-style') || defaultAnimationStyle,
|
|
27
|
+
gap: this.getAttribute('piece-gap') || defaultGap,
|
|
27
28
|
};
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
static get observedAttributes() {
|
|
31
|
-
return ['animation-style', 'animation-speed'];
|
|
32
|
+
return ['animation-style', 'animation-speed', 'piece-gap'];
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
35
36
|
if (name === 'animation-style') {
|
|
36
|
-
this.settings.
|
|
37
|
+
this.settings.animationStyle = newVal;
|
|
37
38
|
}
|
|
38
39
|
if (name === 'animation-speed') {
|
|
39
|
-
|
|
40
|
+
var speed = Number(newVal);
|
|
41
|
+
this.settings.animationSpeed = speed > 0 ? speed : 0;
|
|
40
42
|
}
|
|
41
|
-
if (name === 'gap') {
|
|
42
|
-
|
|
43
|
+
if (name === 'piece-gap') {
|
|
44
|
+
var gap = Number(newVal);
|
|
45
|
+
this.settings.gap = gap < minimumGap ? minimumGap : gap;
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
48
|
connectedCallback() {
|
|
@@ -71,6 +74,8 @@ class RubiksCube extends HTMLElement {
|
|
|
71
74
|
|
|
72
75
|
// add camera
|
|
73
76
|
const camera = new PerspectiveCamera(75, this.clientWidth / this.clientHeight, 0.1, 1000);
|
|
77
|
+
/** @type {{Up: boolean, Right: boolean, UpDistance: number, RightDistance: number}} */
|
|
78
|
+
const cameraState = { Up: true, Right: true, UpDistance: 2.5, RightDistance: 2.5 };
|
|
74
79
|
camera.position.z = 4;
|
|
75
80
|
camera.position.y = 3;
|
|
76
81
|
camera.position.x = 0;
|
|
@@ -115,102 +120,53 @@ class RubiksCube extends HTMLElement {
|
|
|
115
120
|
function animate() {
|
|
116
121
|
cameraAnimationGroup.update();
|
|
117
122
|
controls.update();
|
|
118
|
-
|
|
123
|
+
|
|
124
|
+
var cubeState = cube.update();
|
|
125
|
+
if (cubeState) {
|
|
126
|
+
sendState();
|
|
127
|
+
}
|
|
119
128
|
renderer.render(scene, camera);
|
|
120
129
|
}
|
|
121
130
|
|
|
131
|
+
// add event listeners for rotation and camera controls
|
|
122
132
|
this.addEventListener('reset', () => {
|
|
123
133
|
cube.reset();
|
|
124
134
|
sendState();
|
|
125
135
|
});
|
|
126
136
|
|
|
127
|
-
// add event listeners for rotation and camera controls
|
|
128
137
|
this.addEventListener('rotate', (e) => {
|
|
129
138
|
const action = getRotationDetailsFromNotation(e.detail.action);
|
|
130
139
|
if (action !== undefined) {
|
|
131
140
|
cube.rotate(action);
|
|
132
141
|
}
|
|
133
142
|
});
|
|
143
|
+
|
|
134
144
|
this.addEventListener('camera', (e) => {
|
|
135
145
|
if (e.detail.action === 'peek-toggle-horizontal') {
|
|
136
|
-
|
|
137
|
-
new Tween(camera.position)
|
|
138
|
-
.to(
|
|
139
|
-
{
|
|
140
|
-
x: camera.position.x > 0 ? -2.5 : 2.5,
|
|
141
|
-
y: camera.position.y > 0 ? 2.5 : -2.5,
|
|
142
|
-
z: 4,
|
|
143
|
-
},
|
|
144
|
-
200,
|
|
145
|
-
)
|
|
146
|
-
.start(),
|
|
147
|
-
);
|
|
146
|
+
cameraState.Right = !cameraState.Right;
|
|
148
147
|
} else if (e.detail.action === 'peek-toggle-vertical') {
|
|
149
|
-
|
|
150
|
-
new Tween(camera.position)
|
|
151
|
-
.to(
|
|
152
|
-
{
|
|
153
|
-
x: camera.position.x > 0 ? 2.5 : -2.5,
|
|
154
|
-
y: camera.position.y > 0 ? -2.5 : 2.5,
|
|
155
|
-
z: 4,
|
|
156
|
-
},
|
|
157
|
-
200,
|
|
158
|
-
)
|
|
159
|
-
.start(),
|
|
160
|
-
);
|
|
148
|
+
cameraState.Up = !cameraState.Up;
|
|
161
149
|
} else if (e.detail.action === 'peek-right') {
|
|
162
|
-
|
|
163
|
-
new Tween(camera.position)
|
|
164
|
-
.to(
|
|
165
|
-
{
|
|
166
|
-
x: 2.5,
|
|
167
|
-
y: camera.position.y > 0 ? 2.5 : -2.5,
|
|
168
|
-
z: 4,
|
|
169
|
-
},
|
|
170
|
-
200,
|
|
171
|
-
)
|
|
172
|
-
.start(),
|
|
173
|
-
);
|
|
150
|
+
cameraState.Right = true;
|
|
174
151
|
} else if (e.detail.action === 'peek-left') {
|
|
175
|
-
|
|
176
|
-
new Tween(camera.position)
|
|
177
|
-
.to(
|
|
178
|
-
{
|
|
179
|
-
x: -2.5,
|
|
180
|
-
y: camera.position.y > 0 ? 2.5 : -2.5,
|
|
181
|
-
z: 4,
|
|
182
|
-
},
|
|
183
|
-
200,
|
|
184
|
-
)
|
|
185
|
-
.start(),
|
|
186
|
-
);
|
|
152
|
+
cameraState.Right = false;
|
|
187
153
|
} else if (e.detail.action === 'peek-up') {
|
|
188
|
-
|
|
189
|
-
new Tween(camera.position)
|
|
190
|
-
.to(
|
|
191
|
-
{
|
|
192
|
-
x: camera.position.x > 0 ? 2.5 : -2.5,
|
|
193
|
-
y: 2.5,
|
|
194
|
-
z: 4,
|
|
195
|
-
},
|
|
196
|
-
200,
|
|
197
|
-
)
|
|
198
|
-
.start(),
|
|
199
|
-
);
|
|
154
|
+
cameraState.Up = true;
|
|
200
155
|
} else if (e.detail.action === 'peek-down') {
|
|
201
|
-
|
|
202
|
-
new Tween(camera.position)
|
|
203
|
-
.to(
|
|
204
|
-
{
|
|
205
|
-
x: camera.position.x > 0 ? 2.5 : -2.5,
|
|
206
|
-
y: -2.5,
|
|
207
|
-
z: 4,
|
|
208
|
-
},
|
|
209
|
-
200,
|
|
210
|
-
)
|
|
211
|
-
.start(),
|
|
212
|
-
);
|
|
156
|
+
cameraState.Up = false;
|
|
213
157
|
}
|
|
158
|
+
cameraAnimationGroup.add(
|
|
159
|
+
new Tween(camera.position)
|
|
160
|
+
.to(
|
|
161
|
+
{
|
|
162
|
+
x: cameraState.Right ? cameraState.RightDistance : -cameraState.RightDistance,
|
|
163
|
+
y: cameraState.Up ? cameraState.UpDistance : -cameraState.UpDistance,
|
|
164
|
+
z: 4,
|
|
165
|
+
},
|
|
166
|
+
200,
|
|
167
|
+
)
|
|
168
|
+
.start(),
|
|
169
|
+
);
|
|
214
170
|
});
|
|
215
171
|
}
|
|
216
172
|
}
|
package/package.json
CHANGED
package/src/cube/cube.js
CHANGED
|
@@ -3,28 +3,34 @@ import { createCoreMesh } from '../threejs/pieces';
|
|
|
3
3
|
import { createCubeState } from './cubeState';
|
|
4
4
|
import { CubeRotation } from './cubeRotation';
|
|
5
5
|
|
|
6
|
-
const minimumGap = 1;
|
|
7
|
-
|
|
8
6
|
export default class Cube {
|
|
9
7
|
/**
|
|
10
|
-
* @param {{style: "exponential" | "next" | "fixed", speed: number, gap: number}}
|
|
8
|
+
* @param {{style: "exponential" | "next" | "fixed", speed: number, gap: number}} settings
|
|
11
9
|
*/
|
|
12
|
-
constructor(
|
|
13
|
-
/** @type {number} */
|
|
14
|
-
this.
|
|
10
|
+
constructor(settings) {
|
|
11
|
+
/** @type {{animationStyle: "match" | "exponential" | "next" | "fixed", animationSpeed: number, gap: number}} */
|
|
12
|
+
this.settings = settings;
|
|
15
13
|
/** @type {Group} */
|
|
16
|
-
this.group =
|
|
14
|
+
this.group = this.createCubeGroup();
|
|
17
15
|
/** @type {Group} */
|
|
18
16
|
this.rotationGroup = new Group();
|
|
19
17
|
/** @type {CubeRotation[]} */
|
|
20
18
|
this.rotationQueue = [];
|
|
21
19
|
/** @type {CubeRotation | undefined} */
|
|
22
20
|
this.currentRotation = undefined;
|
|
21
|
+
/** @type {number | undefined} */
|
|
22
|
+
this._matchSpeed = undefined;
|
|
23
23
|
/** @type {number} */
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
this.animationStyle = style;
|
|
24
|
+
this._lastGap = settings.gap;
|
|
25
|
+
}
|
|
27
26
|
|
|
27
|
+
/**
|
|
28
|
+
* creates a ThreeJS group with all the required pieces for a cube
|
|
29
|
+
* @param {Group} group
|
|
30
|
+
* @returns {Group}
|
|
31
|
+
*/
|
|
32
|
+
createCubeGroup(group) {
|
|
33
|
+
var group = new Group();
|
|
28
34
|
const core = createCoreMesh();
|
|
29
35
|
core.userData = {
|
|
30
36
|
position: { x: 0, y: 0, z: 0 },
|
|
@@ -33,11 +39,11 @@ export default class Cube {
|
|
|
33
39
|
initialRotation: { x: 0, y: 0, z: 0 },
|
|
34
40
|
type: 'core',
|
|
35
41
|
};
|
|
36
|
-
|
|
42
|
+
group.add(core);
|
|
37
43
|
|
|
38
44
|
for (const piece of createCubeState()) {
|
|
39
45
|
var pieceGroup = piece.group;
|
|
40
|
-
pieceGroup.position.set(piece.position.x * this.gap, piece.position.y * this.gap, piece.position.z * this.gap);
|
|
46
|
+
pieceGroup.position.set(piece.position.x * this.settings.gap, piece.position.y * this.settings.gap, piece.position.z * this.settings.gap);
|
|
41
47
|
pieceGroup.rotation.set(piece.rotation.x, piece.rotation.y, piece.rotation.z);
|
|
42
48
|
pieceGroup.userData = {
|
|
43
49
|
position: Object.assign({}, piece.position),
|
|
@@ -46,52 +52,111 @@ export default class Cube {
|
|
|
46
52
|
initialRotation: Object.assign({}, piece.rotation),
|
|
47
53
|
type: piece.type,
|
|
48
54
|
};
|
|
49
|
-
|
|
55
|
+
group.add(pieceGroup);
|
|
50
56
|
}
|
|
57
|
+
return group;
|
|
51
58
|
}
|
|
52
59
|
|
|
60
|
+
/**
|
|
61
|
+
* update the cube and continue any rotations
|
|
62
|
+
* @returns {{ up: string[][], down: string[][], front: string[][], back: string[][], left: string[][], right: string[][] } | undefined }
|
|
63
|
+
*/
|
|
53
64
|
update() {
|
|
54
65
|
if (this.currentRotation === undefined) {
|
|
66
|
+
if (this._lastGap !== this.settings.gap) {
|
|
67
|
+
this.updateGap();
|
|
68
|
+
}
|
|
55
69
|
this.currentRotation = this.rotationQueue.shift();
|
|
56
|
-
if (this.currentRotation === undefined)
|
|
70
|
+
if (this.currentRotation === undefined) {
|
|
71
|
+
this._matchSpeed = undefined; // reset speed for the match animation options
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (this.currentRotation.status === 'pending') {
|
|
57
76
|
this.rotationGroup.add(...this.getRotationLayer(this.currentRotation.rotation));
|
|
58
77
|
this.currentRotation.initialise();
|
|
59
78
|
}
|
|
60
|
-
|
|
79
|
+
if (this.currentRotation.status === 'initialised') {
|
|
80
|
+
var speed = this.getRotationSpeed();
|
|
81
|
+
this.currentRotation.update(this.rotationGroup, speed);
|
|
82
|
+
}
|
|
61
83
|
if (this.currentRotation.status === 'complete') {
|
|
62
84
|
this.clearRotationGroup();
|
|
63
|
-
this.currentRotation
|
|
64
|
-
|
|
65
|
-
if (this.currentRotation === undefined) return;
|
|
66
|
-
this.rotationGroup.add(...this.getRotationLayer(this.currentRotation.rotation));
|
|
67
|
-
this.currentRotation.initialise();
|
|
85
|
+
this.currentRotation = undefined;
|
|
86
|
+
return this.getStickerState();
|
|
68
87
|
}
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
69
90
|
|
|
70
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Updates the gap of the pieces. To be used when the cube is not rotating
|
|
93
|
+
* @returns {void}
|
|
94
|
+
*/
|
|
95
|
+
updateGap() {
|
|
96
|
+
if (this.currentRotation === undefined) {
|
|
97
|
+
this.group.children.forEach((piece) => {
|
|
98
|
+
var { x, y, z } = piece.userData.position;
|
|
99
|
+
piece.position.set(x * this.settings.gap, y * this.settings.gap, z * this.settings.gap);
|
|
100
|
+
});
|
|
101
|
+
this._lastGap = this.settings.gap;
|
|
102
|
+
}
|
|
71
103
|
}
|
|
72
104
|
|
|
105
|
+
/**
|
|
106
|
+
*
|
|
107
|
+
* calculates the current speed of the current rotation in ms.
|
|
108
|
+
* calculation is dependent on animation style and animation speed settings
|
|
109
|
+
* - exponential: speeds up rotations depending on the queue length
|
|
110
|
+
* - next: an animation speed of 0 when there is another animation in the queue
|
|
111
|
+
* - match: will match the speed of rotations to the frequency of key presses.
|
|
112
|
+
* - fixed: will return a constant value
|
|
113
|
+
* @returns {number}
|
|
114
|
+
*/
|
|
73
115
|
getRotationSpeed() {
|
|
74
|
-
if (this.animationStyle
|
|
75
|
-
return this.animationSpeed / 2 ** this.rotationQueue.length;
|
|
116
|
+
if (this.settings.animationStyle === 'exponential') {
|
|
117
|
+
return this.settings.animationSpeed / 2 ** this.rotationQueue.length;
|
|
118
|
+
}
|
|
119
|
+
if (this.settings.animationStyle === 'next') {
|
|
120
|
+
return this.rotationQueue.length > 0 ? 0 : this.settings.animationSpeed;
|
|
121
|
+
}
|
|
122
|
+
if (this.settings.animationStyle === 'match') {
|
|
123
|
+
if (this.rotationQueue.length > 0) {
|
|
124
|
+
var lastTimeStamp = this.currentRotation.timestampMs;
|
|
125
|
+
var minGap = this._matchSpeed ?? this.settings.animationSpeed;
|
|
126
|
+
for (var i = 0; i < this.rotationQueue.length; i++) {
|
|
127
|
+
var gap = this.rotationQueue[i].timestampMs - lastTimeStamp;
|
|
128
|
+
if (gap < minGap) {
|
|
129
|
+
minGap = gap;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this._matchSpeed = minGap;
|
|
133
|
+
}
|
|
134
|
+
if (this._matchSpeed !== undefined) {
|
|
135
|
+
return this._matchSpeed;
|
|
136
|
+
}
|
|
137
|
+
return this.settings.animationSpeed;
|
|
76
138
|
}
|
|
77
|
-
if (this.animationStyle
|
|
78
|
-
return this.
|
|
139
|
+
if (this.settings.animationStyle === 'fixed') {
|
|
140
|
+
return this.settings.animationSpeed;
|
|
79
141
|
}
|
|
80
|
-
return this.animationSpeed;
|
|
142
|
+
return this.settings.animationSpeed;
|
|
81
143
|
}
|
|
82
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Complete the current rotation and reset the cube
|
|
147
|
+
* @returns {void}
|
|
148
|
+
*/
|
|
83
149
|
reset() {
|
|
84
150
|
this.rotationQueue = [];
|
|
85
151
|
if (this.currentRotation) {
|
|
86
152
|
this.currentRotation.update(this.rotationGroup, 0);
|
|
87
153
|
this.clearRotationGroup();
|
|
88
|
-
this.currentRotation.dispose();
|
|
89
154
|
this.currentRotation = undefined;
|
|
90
155
|
}
|
|
91
156
|
this.group.children.forEach((piece) => {
|
|
92
157
|
const { x, y, z } = piece.userData.initialPosition;
|
|
93
158
|
const { x: u, y: v, z: w } = piece.userData.initialRotation;
|
|
94
|
-
piece.position.set(x * this.gap, y * this.gap, z * this.gap);
|
|
159
|
+
piece.position.set(x * this.settings.gap, y * this.settings.gap, z * this.settings.gap);
|
|
95
160
|
piece.rotation.set(u, v, w);
|
|
96
161
|
piece.userData.position.x = x;
|
|
97
162
|
piece.userData.position.y = y;
|
|
@@ -102,6 +167,10 @@ export default class Cube {
|
|
|
102
167
|
});
|
|
103
168
|
}
|
|
104
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Adds pieces in the rotationGroup back into the main group.
|
|
172
|
+
* @returns {void}
|
|
173
|
+
*/
|
|
105
174
|
clearRotationGroup() {
|
|
106
175
|
if (this.currentRotation.status != 'complete') {
|
|
107
176
|
throw Error('cannot clear rotation group while rotating');
|
|
@@ -121,12 +190,16 @@ export default class Cube {
|
|
|
121
190
|
});
|
|
122
191
|
this.group.add(...this.rotationGroup.children);
|
|
123
192
|
this.rotationGroup.rotation.set(0, 0, 0);
|
|
193
|
+
this.currentRotation.status = 'disposed';
|
|
124
194
|
}
|
|
125
195
|
|
|
126
196
|
/**
|
|
127
197
|
* @param {{axis: "x"|"y"|"z", layers: (-1|0|1)[], direction: 1|-1|2|-2}} input
|
|
128
198
|
*/
|
|
129
199
|
rotate(input) {
|
|
200
|
+
var queueLength = this.rotationQueue.length;
|
|
201
|
+
if (queueLength > 0 && this.rotationQueue[queueLength - 1].rotation.axis === input.axis) {
|
|
202
|
+
}
|
|
130
203
|
this.rotationQueue.push(new CubeRotation(input));
|
|
131
204
|
}
|
|
132
205
|
|
|
@@ -150,6 +223,9 @@ export default class Cube {
|
|
|
150
223
|
});
|
|
151
224
|
}
|
|
152
225
|
|
|
226
|
+
/**
|
|
227
|
+
* @returns {{ up: string[][], down: string[][], front: string[][], back: string[][], left: string[][], right: string[][] }}
|
|
228
|
+
*/
|
|
153
229
|
getStickerState() {
|
|
154
230
|
const state = {
|
|
155
231
|
up: [[], [], []],
|
package/src/cube/cubeRotation.js
CHANGED
|
@@ -10,22 +10,18 @@ export class CubeRotation {
|
|
|
10
10
|
/** @type {"pending" | "initialised" | "complete" | "disposed"} */
|
|
11
11
|
this.status = 'pending';
|
|
12
12
|
/** @type {number} */
|
|
13
|
+
this.timestampMs = performance.now();
|
|
14
|
+
/** @type {number} */
|
|
13
15
|
this._lastUpdatedTimeMs = undefined;
|
|
14
|
-
this._startTimeMs = undefined;
|
|
15
16
|
/** @type {number} */
|
|
16
17
|
this._rotationPercentage = 0;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
initialise() {
|
|
20
21
|
this._lastUpdatedTimeMs = performance.now();
|
|
21
|
-
this._startTimeMs = this._lastUpdatedTimeMs;
|
|
22
22
|
this.status = 'initialised';
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
dispose() {
|
|
26
|
-
this.status = 'disposed';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
25
|
/**
|
|
30
26
|
*
|
|
31
27
|
* @param {Group} rotationGroup
|
|
@@ -53,8 +49,12 @@ export class CubeRotation {
|
|
|
53
49
|
rotationIncrement,
|
|
54
50
|
);
|
|
55
51
|
|
|
56
|
-
if (this._rotationPercentage
|
|
52
|
+
if (this._rotationPercentage === 100) {
|
|
57
53
|
this.status = 'complete';
|
|
58
54
|
}
|
|
55
|
+
|
|
56
|
+
if (this._rotationPercentage > 100) {
|
|
57
|
+
throw new Error('rotation percentage > 100');
|
|
58
|
+
}
|
|
59
59
|
}
|
|
60
60
|
}
|