import { animation } from "./library.js";Scrawl-canvas runs a single, centralized requestAnimationFrame (RAF) function - animationLoop - for all animation objects.
Animation objects are Scrawl-canvas objects with a fn attribute - a function which returns a Promise; all Animation objects contained in the animate array will be invoked as part of a Promise.all action. Once the Promise.all resolves, animationLoop is invoked again.
The RAF function is first invoked as part of Scrawl-canvas initialization when it loads into a web page, and continues to run while the doAnimation flag remains true.
To stop the RAF:
scrawl.stopCoreAnimationLoop()
To restart the RAF after it has been stopped:
scrawl.startCoreAnimationLoop()
… Functionality tested in Demo DOM-009
As part of initialization, two animation objects are created and added to the animate array:
Additional animations can be created via a number of ‘make’ functions:
These objects can be added to the animate Array by invoking their run function, and removed by invoking their halt function.
The order in which animations objects run during each RAF cycle (= Display cycle) can be (partly) determined by the objects’ order attribute: those with a lower order value will be invoked before those with a higher value.
Note that ticker/tween animations will all run before other animations (order differences between tickers/tween objects will be respected).
import { animation } from "./library.js";Local variables
let doAnimation = false,
resortBatchAnimations = true,
animate_sorted = [];Exported array (to modules). The animate array, which holds handles to all animation objects due to be run at the next RAF invocation, is exported to other modules so code can add/remove animation objects as required.
let animate = [];Exported function (to modules). Force the animation objects to be sorted at the start of the next RAF invocation
const resortAnimations = function () {
resortBatchAnimations = true;
};Scrawl-canvas animation sorter uses a ‘bucket sort’ algorithm
const sortAnimations = function () {
if (resortBatchAnimations) {
resortBatchAnimations = false;
let floor = Math.floor,
buckets = [],
obj, order;
animate.forEach(name => {
obj = animation[name];
if (obj) {
order = floor(obj.order) || 0;
if (!buckets[order]) buckets[order] = [];
buckets[order].push(obj);
}
});
animate_sorted = buckets.reduce((a, v) => a.concat(v), []);
}
};The requestAnimationFrame function
const animationLoop = function () {
let promises = [];
if (resortBatchAnimations) sortAnimations();
animate_sorted.forEach(item => {
if (item && item.fn) promises.push(item.fn());
});
Promise.all(promises)
.then(() => {
if (doAnimation) window.requestAnimationFrame(() => animationLoop());
})
.catch(err => console.log('animationLoop error: ', err));
};Exported function (modules and scrawl object). Start the RAF function running
const startCoreAnimationLoop = function () {
doAnimation = true;
animationLoop();
};Exported function (modules and scrawl object). Halt the RAF function
const stopCoreAnimationLoop = function () {
doAnimation = false;
};export {
animate,
resortAnimations,
startCoreAnimationLoop,
stopCoreAnimationLoop,
};