animejs
Version:
JavaScript animation engine
121 lines (115 loc) • 4.42 kB
JavaScript
/**
* Anime.js - utils - ESM
* @version v4.3.6
* @license MIT
* @copyright 2026 - Julian Garnier
*/
import { unitsExecRgx, emptyString } from '../core/consts.js';
import { isUnd, parseNumber, isFnc, abs, floor, sqrt, round, isArr, isNum, isStr, max } from '../core/helpers.js';
import { parseEase } from '../easings/eases/parser.js';
import { parseTimelinePosition } from '../timeline/position.js';
import { getOriginalAnimatableValue } from '../core/values.js';
import { registerTargets } from '../core/targets.js';
import { shuffle } from './random.js';
/**
* @import {
* StaggerParams,
* StaggerFunction,
* } from '../types/index.js'
*/
/**
* @import {
* Spring,
* } from '../easings/spring/index.js'
*/
/**
* @overload
* @param {Number} val
* @param {StaggerParams} [params]
* @return {StaggerFunction<Number>}
*/
/**
* @overload
* @param {String} val
* @param {StaggerParams} [params]
* @return {StaggerFunction<String>}
*/
/**
* @overload
* @param {[Number, Number]} val
* @param {StaggerParams} [params]
* @return {StaggerFunction<Number>}
*/
/**
* @overload
* @param {[String, String]} val
* @param {StaggerParams} [params]
* @return {StaggerFunction<String>}
*/
/**
* @param {Number|String|[Number, Number]|[String, String]} val The staggered value or range
* @param {StaggerParams} [params] The stagger parameters
* @return {StaggerFunction<Number|String>}
*/
const stagger = (val, params = {}) => {
let values = [];
let maxValue = 0;
const from = params.from;
const reversed = params.reversed;
const ease = params.ease;
const hasEasing = !isUnd(ease);
const hasSpring = hasEasing && !isUnd(/** @type {Spring} */(ease).ease);
const staggerEase = hasSpring ? /** @type {Spring} */(ease).ease : hasEasing ? parseEase(ease) : null;
const grid = params.grid;
const axis = params.axis;
const customTotal = params.total;
const fromFirst = isUnd(from) || from === 0 || from === 'first';
const fromCenter = from === 'center';
const fromLast = from === 'last';
const fromRandom = from === 'random';
const isRange = isArr(val);
const useProp = params.use;
const val1 = isRange ? parseNumber(val[0]) : parseNumber(val);
const val2 = isRange ? parseNumber(val[1]) : 0;
const unitMatch = unitsExecRgx.exec((isRange ? val[1] : val) + emptyString);
const start = params.start || 0 + (isRange ? val1 : 0);
let fromIndex = fromFirst ? 0 : isNum(from) ? from : 0;
return (target, i, t, tl) => {
const [ registeredTarget ] = registerTargets(target);
const total = isUnd(customTotal) ? t : customTotal;
const customIndex = !isUnd(useProp) ? isFnc(useProp) ? useProp(registeredTarget, i, total) : getOriginalAnimatableValue(registeredTarget, useProp) : false;
const staggerIndex = isNum(customIndex) || isStr(customIndex) && isNum(+customIndex) ? +customIndex : i;
if (fromCenter) fromIndex = (total - 1) / 2;
if (fromLast) fromIndex = total - 1;
if (!values.length) {
for (let index = 0; index < total; index++) {
if (!grid) {
values.push(abs(fromIndex - index));
} else {
const fromX = !fromCenter ? fromIndex % grid[0] : (grid[0] - 1) / 2;
const fromY = !fromCenter ? floor(fromIndex / grid[0]) : (grid[1] - 1) / 2;
const toX = index % grid[0];
const toY = floor(index / grid[0]);
const distanceX = fromX - toX;
const distanceY = fromY - toY;
let value = sqrt(distanceX * distanceX + distanceY * distanceY);
if (axis === 'x') value = -distanceX;
if (axis === 'y') value = -distanceY;
values.push(value);
}
maxValue = max(...values);
}
if (staggerEase) values = values.map(val => staggerEase(val / maxValue) * maxValue);
if (reversed) values = values.map(val => axis ? (val < 0) ? val * -1 : -val : abs(maxValue - val));
if (fromRandom) values = shuffle(values);
}
const spacing = isRange ? (val2 - val1) / maxValue : val1;
const offset = tl ? parseTimelinePosition(tl, isUnd(params.start) ? tl.iterationDuration : start) : /** @type {Number} */(start);
/** @type {String|Number} */
let output = offset + ((spacing * round(values[staggerIndex], 2)) || 0);
if (params.modifier) output = params.modifier(output);
if (unitMatch) output = `${output}${unitMatch[2]}`;
return output;
}
};
export { stagger };