canvasframework 0.3.6
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 +554 -0
- package/components/Accordion.js +252 -0
- package/components/AndroidDatePickerDialog.js +398 -0
- package/components/AppBar.js +225 -0
- package/components/Avatar.js +202 -0
- package/components/BottomNavigationBar.js +205 -0
- package/components/BottomSheet.js +374 -0
- package/components/Button.js +225 -0
- package/components/Card.js +193 -0
- package/components/Checkbox.js +180 -0
- package/components/Chip.js +212 -0
- package/components/CircularProgress.js +143 -0
- package/components/ContextMenu.js +116 -0
- package/components/DatePicker.js +257 -0
- package/components/Dialog.js +367 -0
- package/components/Divider.js +125 -0
- package/components/Drawer.js +261 -0
- package/components/FAB.js +270 -0
- package/components/FileUpload.js +315 -0
- package/components/IOSDatePickerWheel.js +268 -0
- package/components/ImageCarousel.js +193 -0
- package/components/ImageComponent.js +223 -0
- package/components/Input.js +309 -0
- package/components/List.js +94 -0
- package/components/ListItem.js +223 -0
- package/components/Modal.js +364 -0
- package/components/MultiSelectDialog.js +206 -0
- package/components/NumberInput.js +271 -0
- package/components/ProgressBar.js +88 -0
- package/components/RadioButton.js +142 -0
- package/components/SearchInput.js +315 -0
- package/components/SegmentedControl.js +202 -0
- package/components/Select.js +199 -0
- package/components/SelectDialog.js +255 -0
- package/components/Slider.js +113 -0
- package/components/Snackbar.js +243 -0
- package/components/Stepper.js +281 -0
- package/components/SwipeableListItem.js +179 -0
- package/components/Switch.js +147 -0
- package/components/Table.js +492 -0
- package/components/Tabs.js +125 -0
- package/components/Text.js +141 -0
- package/components/TextField.js +331 -0
- package/components/Toast.js +236 -0
- package/components/TreeView.js +420 -0
- package/components/Video.js +397 -0
- package/components/View.js +140 -0
- package/components/VirtualList.js +120 -0
- package/core/CanvasFramework.js +1271 -0
- package/core/CanvasWork.js +32 -0
- package/core/Component.js +153 -0
- package/core/LogicWorker.js +25 -0
- package/core/WebGLCanvasAdapter.js +1369 -0
- package/features/Column.js +43 -0
- package/features/Grid.js +47 -0
- package/features/LayoutComponent.js +43 -0
- package/features/OpenStreetMap.js +310 -0
- package/features/Positioned.js +33 -0
- package/features/PullToRefresh.js +328 -0
- package/features/Row.js +40 -0
- package/features/SignaturePad.js +257 -0
- package/features/Skeleton.js +84 -0
- package/features/Stack.js +21 -0
- package/index.js +101 -0
- package/manager/AccessibilityManager.js +107 -0
- package/manager/ErrorHandler.js +59 -0
- package/manager/FeatureFlags.js +60 -0
- package/manager/MemoryManager.js +107 -0
- package/manager/PerformanceMonitor.js +84 -0
- package/manager/SecurityManager.js +54 -0
- package/package.json +28 -0
- package/utils/AnimationEngine.js +428 -0
- package/utils/DataStore.js +403 -0
- package/utils/EventBus.js +407 -0
- package/utils/FetchClient.js +74 -0
- package/utils/FormValidator.js +355 -0
- package/utils/GeoLocationService.js +62 -0
- package/utils/I18n.js +207 -0
- package/utils/IndexedDBManager.js +273 -0
- package/utils/OfflineSyncManager.js +342 -0
- package/utils/QueryBuilder.js +478 -0
- package/utils/SafeArea.js +64 -0
- package/utils/SecureStorage.js +289 -0
- package/utils/StateManager.js +207 -0
- package/utils/WebSocketClient.js +66 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Moteur d'animation pour composants Canvas
|
|
3
|
+
* Permet d'animer n'importe quelle propriété d'un composant sans le modifier
|
|
4
|
+
* @class
|
|
5
|
+
* @property {Map} animations - Liste des animations actives
|
|
6
|
+
* @property {boolean} isRunning - Indique si le moteur tourne
|
|
7
|
+
*/
|
|
8
|
+
class AnimationEngine {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.animations = new Map();
|
|
11
|
+
this.isRunning = false;
|
|
12
|
+
this.animationFrameId = null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Anime une propriété d'un composant
|
|
17
|
+
* @param {Component} component - Composant à animer
|
|
18
|
+
* @param {Object} options - Options d'animation
|
|
19
|
+
* @param {Object} options.from - Valeurs de départ {x: 0, y: 0, ...}
|
|
20
|
+
* @param {Object} options.to - Valeurs d'arrivée {x: 100, y: 200, ...}
|
|
21
|
+
* @param {number} options.duration - Durée en ms (défaut: 300)
|
|
22
|
+
* @param {string} options.easing - Fonction d'easing (défaut: 'easeInOutQuad')
|
|
23
|
+
* @param {number} options.delay - Délai avant démarrage en ms (défaut: 0)
|
|
24
|
+
* @param {Function} options.onUpdate - Callback à chaque frame
|
|
25
|
+
* @param {Function} options.onComplete - Callback à la fin
|
|
26
|
+
* @param {boolean} options.loop - Boucler l'animation (défaut: false)
|
|
27
|
+
* @param {boolean} options.yoyo - Retour inverse (défaut: false)
|
|
28
|
+
* @returns {string} ID de l'animation
|
|
29
|
+
*/
|
|
30
|
+
animate(component, options = {}) {
|
|
31
|
+
const animationId = this.generateId();
|
|
32
|
+
|
|
33
|
+
const animation = {
|
|
34
|
+
id: animationId,
|
|
35
|
+
component,
|
|
36
|
+
from: options.from || {},
|
|
37
|
+
to: options.to || {},
|
|
38
|
+
duration: options.duration || 300,
|
|
39
|
+
easing: options.easing || 'easeInOutQuad',
|
|
40
|
+
delay: options.delay || 0,
|
|
41
|
+
onUpdate: options.onUpdate,
|
|
42
|
+
onComplete: options.onComplete,
|
|
43
|
+
loop: options.loop || false,
|
|
44
|
+
yoyo: options.yoyo || false,
|
|
45
|
+
|
|
46
|
+
// État interne
|
|
47
|
+
startTime: null,
|
|
48
|
+
delayStartTime: null,
|
|
49
|
+
progress: 0,
|
|
50
|
+
isDelaying: options.delay > 0,
|
|
51
|
+
isReversed: false,
|
|
52
|
+
originalValues: {}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Sauvegarder les valeurs originales
|
|
56
|
+
for (let prop in animation.to) {
|
|
57
|
+
if (animation.from[prop] === undefined) {
|
|
58
|
+
animation.from[prop] = component[prop];
|
|
59
|
+
}
|
|
60
|
+
animation.originalValues[prop] = component[prop];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.animations.set(animationId, animation);
|
|
64
|
+
|
|
65
|
+
if (!this.isRunning) {
|
|
66
|
+
this.start();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return animationId;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Anime plusieurs propriétés en séquence
|
|
74
|
+
* @param {Component} component - Composant à animer
|
|
75
|
+
* @param {Array} sequence - Tableau d'options d'animation
|
|
76
|
+
* @returns {Promise} Promesse résolue à la fin de la séquence
|
|
77
|
+
*/
|
|
78
|
+
async animateSequence(component, sequence) {
|
|
79
|
+
for (let options of sequence) {
|
|
80
|
+
await new Promise(resolve => {
|
|
81
|
+
this.animate(component, {
|
|
82
|
+
...options,
|
|
83
|
+
onComplete: () => {
|
|
84
|
+
if (options.onComplete) options.onComplete();
|
|
85
|
+
resolve();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Anime plusieurs composants en parallèle
|
|
94
|
+
* @param {Array} animations - Tableau de {component, options}
|
|
95
|
+
* @returns {Promise} Promesse résolue quand toutes sont finies
|
|
96
|
+
*/
|
|
97
|
+
async animateParallel(animations) {
|
|
98
|
+
const promises = animations.map(({component, options}) => {
|
|
99
|
+
return new Promise(resolve => {
|
|
100
|
+
this.animate(component, {
|
|
101
|
+
...options,
|
|
102
|
+
onComplete: () => {
|
|
103
|
+
if (options.onComplete) options.onComplete();
|
|
104
|
+
resolve();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return Promise.all(promises);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Crée une animation de rebond
|
|
115
|
+
* @param {Component} component - Composant
|
|
116
|
+
* @param {Object} options - Options
|
|
117
|
+
*/
|
|
118
|
+
bounce(component, options = {}) {
|
|
119
|
+
const originalY = component.y;
|
|
120
|
+
const height = options.height || 50;
|
|
121
|
+
|
|
122
|
+
return this.animate(component, {
|
|
123
|
+
from: { y: originalY },
|
|
124
|
+
to: { y: originalY - height },
|
|
125
|
+
duration: options.duration || 400,
|
|
126
|
+
easing: 'easeOutQuad',
|
|
127
|
+
yoyo: true,
|
|
128
|
+
onComplete: options.onComplete
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Crée une animation de shake (tremblement)
|
|
134
|
+
* @param {Component} component - Composant
|
|
135
|
+
* @param {Object} options - Options
|
|
136
|
+
*/
|
|
137
|
+
shake(component, options = {}) {
|
|
138
|
+
const originalX = component.x;
|
|
139
|
+
const intensity = options.intensity || 10;
|
|
140
|
+
const shakes = options.shakes || 4;
|
|
141
|
+
const duration = options.duration || 400;
|
|
142
|
+
|
|
143
|
+
const sequence = [];
|
|
144
|
+
for (let i = 0; i < shakes; i++) {
|
|
145
|
+
sequence.push({
|
|
146
|
+
to: { x: originalX + (i % 2 === 0 ? intensity : -intensity) },
|
|
147
|
+
duration: duration / (shakes * 2),
|
|
148
|
+
easing: 'linear'
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
sequence.push({
|
|
152
|
+
to: { x: originalX },
|
|
153
|
+
duration: duration / (shakes * 2),
|
|
154
|
+
easing: 'linear',
|
|
155
|
+
onComplete: options.onComplete
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return this.animateSequence(component, sequence);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Crée une animation de pulsation (scale)
|
|
163
|
+
* @param {Component} component - Composant
|
|
164
|
+
* @param {Object} options - Options
|
|
165
|
+
*/
|
|
166
|
+
pulse(component, options = {}) {
|
|
167
|
+
const originalWidth = component.width;
|
|
168
|
+
const originalHeight = component.height;
|
|
169
|
+
const scale = options.scale || 1.1;
|
|
170
|
+
|
|
171
|
+
return this.animate(component, {
|
|
172
|
+
from: {
|
|
173
|
+
width: originalWidth,
|
|
174
|
+
height: originalHeight
|
|
175
|
+
},
|
|
176
|
+
to: {
|
|
177
|
+
width: originalWidth * scale,
|
|
178
|
+
height: originalHeight * scale
|
|
179
|
+
},
|
|
180
|
+
duration: options.duration || 300,
|
|
181
|
+
easing: 'easeInOutQuad',
|
|
182
|
+
yoyo: true,
|
|
183
|
+
loop: options.loop || false,
|
|
184
|
+
onComplete: options.onComplete
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Crée une animation de fade (opacité)
|
|
190
|
+
* @param {Component} component - Composant
|
|
191
|
+
* @param {Object} options - Options
|
|
192
|
+
*/
|
|
193
|
+
fade(component, options = {}) {
|
|
194
|
+
// Ajouter une propriété opacity si elle n'existe pas
|
|
195
|
+
if (component.opacity === undefined) {
|
|
196
|
+
component.opacity = 1;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return this.animate(component, {
|
|
200
|
+
from: { opacity: options.from !== undefined ? options.from : component.opacity },
|
|
201
|
+
to: { opacity: options.to !== undefined ? options.to : 0 },
|
|
202
|
+
duration: options.duration || 300,
|
|
203
|
+
easing: options.easing || 'linear',
|
|
204
|
+
onComplete: options.onComplete
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Crée une animation de slide (glissement)
|
|
210
|
+
* @param {Component} component - Composant
|
|
211
|
+
* @param {Object} options - Options
|
|
212
|
+
*/
|
|
213
|
+
slide(component, options = {}) {
|
|
214
|
+
return this.animate(component, {
|
|
215
|
+
from: options.from || { x: component.x, y: component.y },
|
|
216
|
+
to: options.to || { x: component.x + 100, y: component.y },
|
|
217
|
+
duration: options.duration || 400,
|
|
218
|
+
easing: options.easing || 'easeOutQuad',
|
|
219
|
+
onComplete: options.onComplete
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Crée une animation de rotation
|
|
225
|
+
* @param {Component} component - Composant
|
|
226
|
+
* @param {Object} options - Options
|
|
227
|
+
*/
|
|
228
|
+
rotate(component, options = {}) {
|
|
229
|
+
if (component.rotation === undefined) {
|
|
230
|
+
component.rotation = 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return this.animate(component, {
|
|
234
|
+
from: { rotation: options.from !== undefined ? options.from : component.rotation },
|
|
235
|
+
to: { rotation: options.to !== undefined ? options.to : 360 },
|
|
236
|
+
duration: options.duration || 1000,
|
|
237
|
+
easing: options.easing || 'linear',
|
|
238
|
+
loop: options.loop || false,
|
|
239
|
+
onComplete: options.onComplete
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Arrête une animation
|
|
245
|
+
* @param {string} animationId - ID de l'animation
|
|
246
|
+
*/
|
|
247
|
+
stop(animationId) {
|
|
248
|
+
this.animations.delete(animationId);
|
|
249
|
+
|
|
250
|
+
if (this.animations.size === 0) {
|
|
251
|
+
this.isRunning = false;
|
|
252
|
+
if (this.animationFrameId) {
|
|
253
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
254
|
+
this.animationFrameId = null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Arrête toutes les animations d'un composant
|
|
261
|
+
* @param {Component} component - Composant
|
|
262
|
+
*/
|
|
263
|
+
stopAll(component) {
|
|
264
|
+
const toDelete = [];
|
|
265
|
+
|
|
266
|
+
for (let [id, anim] of this.animations) {
|
|
267
|
+
if (anim.component === component) {
|
|
268
|
+
toDelete.push(id);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
toDelete.forEach(id => this.stop(id));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Démarre le moteur d'animation
|
|
277
|
+
* @private
|
|
278
|
+
*/
|
|
279
|
+
start() {
|
|
280
|
+
this.isRunning = true;
|
|
281
|
+
this.lastTime = performance.now();
|
|
282
|
+
this.update();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Met à jour toutes les animations
|
|
287
|
+
* @private
|
|
288
|
+
*/
|
|
289
|
+
update() {
|
|
290
|
+
const currentTime = performance.now();
|
|
291
|
+
const toDelete = [];
|
|
292
|
+
|
|
293
|
+
for (let [id, anim] of this.animations) {
|
|
294
|
+
// Gérer le délai
|
|
295
|
+
if (anim.isDelaying) {
|
|
296
|
+
if (!anim.delayStartTime) {
|
|
297
|
+
anim.delayStartTime = currentTime;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (currentTime - anim.delayStartTime >= anim.delay) {
|
|
301
|
+
anim.isDelaying = false;
|
|
302
|
+
anim.startTime = currentTime;
|
|
303
|
+
}
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Initialiser le temps de départ
|
|
308
|
+
if (!anim.startTime) {
|
|
309
|
+
anim.startTime = currentTime;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Calculer la progression
|
|
313
|
+
const elapsed = currentTime - anim.startTime;
|
|
314
|
+
let progress = Math.min(elapsed / anim.duration, 1);
|
|
315
|
+
|
|
316
|
+
// Appliquer l'easing
|
|
317
|
+
const easedProgress = this.applyEasing(progress, anim.easing);
|
|
318
|
+
|
|
319
|
+
// Inverser si yoyo
|
|
320
|
+
const actualProgress = anim.isReversed ? 1 - easedProgress : easedProgress;
|
|
321
|
+
|
|
322
|
+
// Mettre à jour les propriétés du composant
|
|
323
|
+
for (let prop in anim.to) {
|
|
324
|
+
const from = anim.from[prop];
|
|
325
|
+
const to = anim.to[prop];
|
|
326
|
+
const value = from + (to - from) * actualProgress;
|
|
327
|
+
anim.component[prop] = value;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Callback onUpdate
|
|
331
|
+
if (anim.onUpdate) {
|
|
332
|
+
anim.onUpdate(actualProgress);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Animation terminée
|
|
336
|
+
if (progress >= 1) {
|
|
337
|
+
if (anim.yoyo && !anim.isReversed) {
|
|
338
|
+
// Inverser pour le yoyo
|
|
339
|
+
anim.isReversed = true;
|
|
340
|
+
anim.startTime = currentTime;
|
|
341
|
+
} else if (anim.loop) {
|
|
342
|
+
// Recommencer
|
|
343
|
+
anim.startTime = currentTime;
|
|
344
|
+
anim.isReversed = false;
|
|
345
|
+
} else {
|
|
346
|
+
// Terminer
|
|
347
|
+
if (anim.onComplete) {
|
|
348
|
+
anim.onComplete();
|
|
349
|
+
}
|
|
350
|
+
toDelete.push(id);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Nettoyer les animations terminées
|
|
356
|
+
toDelete.forEach(id => this.stop(id));
|
|
357
|
+
|
|
358
|
+
// Continuer l'animation
|
|
359
|
+
if (this.animations.size > 0) {
|
|
360
|
+
this.animationFrameId = requestAnimationFrame(() => this.update());
|
|
361
|
+
} else {
|
|
362
|
+
this.isRunning = false;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Applique une fonction d'easing
|
|
368
|
+
* @param {number} t - Progression (0-1)
|
|
369
|
+
* @param {string} easingName - Nom de l'easing
|
|
370
|
+
* @returns {number} Valeur easée
|
|
371
|
+
* @private
|
|
372
|
+
*/
|
|
373
|
+
applyEasing(t, easingName) {
|
|
374
|
+
const easings = {
|
|
375
|
+
linear: t => t,
|
|
376
|
+
easeInQuad: t => t * t,
|
|
377
|
+
easeOutQuad: t => t * (2 - t),
|
|
378
|
+
easeInOutQuad: t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
|
|
379
|
+
easeInCubic: t => t * t * t,
|
|
380
|
+
easeOutCubic: t => (--t) * t * t + 1,
|
|
381
|
+
easeInOutCubic: t => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
|
|
382
|
+
easeInQuart: t => t * t * t * t,
|
|
383
|
+
easeOutQuart: t => 1 - (--t) * t * t * t,
|
|
384
|
+
easeInOutQuart: t => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t,
|
|
385
|
+
easeInElastic: t => {
|
|
386
|
+
const c4 = (2 * Math.PI) / 3;
|
|
387
|
+
return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4);
|
|
388
|
+
},
|
|
389
|
+
easeOutElastic: t => {
|
|
390
|
+
const c4 = (2 * Math.PI) / 3;
|
|
391
|
+
return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
|
|
392
|
+
},
|
|
393
|
+
easeOutBounce: t => {
|
|
394
|
+
const n1 = 7.5625;
|
|
395
|
+
const d1 = 2.75;
|
|
396
|
+
if (t < 1 / d1) return n1 * t * t;
|
|
397
|
+
else if (t < 2 / d1) return n1 * (t -= 1.5 / d1) * t + 0.75;
|
|
398
|
+
else if (t < 2.5 / d1) return n1 * (t -= 2.25 / d1) * t + 0.9375;
|
|
399
|
+
else return n1 * (t -= 2.625 / d1) * t + 0.984375;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
return (easings[easingName] || easings.linear)(t);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Génère un ID unique
|
|
408
|
+
* @returns {string} ID unique
|
|
409
|
+
* @private
|
|
410
|
+
*/
|
|
411
|
+
generateId() {
|
|
412
|
+
return `anim_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Nettoie toutes les animations
|
|
417
|
+
*/
|
|
418
|
+
clear() {
|
|
419
|
+
this.animations.clear();
|
|
420
|
+
this.isRunning = false;
|
|
421
|
+
if (this.animationFrameId) {
|
|
422
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
423
|
+
this.animationFrameId = null;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export default AnimationEngine;
|