mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 17:26:01 +08:00
[ts][webcomponents] Add holdDurationLastAnimation to animations attribute.
This commit is contained in:
parent
ebaf15d9de
commit
680fa631d6
@ -765,10 +765,11 @@
|
|||||||
<li><code>mixDuration</code>: the mix duration between this animation and the previous one (not used for the first animation on a track)</li>
|
<li><code>mixDuration</code>: the mix duration between this animation and the previous one (not used for the first animation on a track)</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<p>To loop a track once it reaches the end, add the special group <code>[loop, trackNumber]</code>, where:</p>
|
<p>To loop a track once it reaches the end, add the special group <code>[loop, trackNumber, holdDurationLastAnimation]</code>, where:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>loop</code>: identifies this as a loop instruction</li>
|
<li><code>loop</code>: identifies this as a loop instruction</li>
|
||||||
<li><code>trackNumber</code>: the number of the track to loop</li>
|
<li><code>trackNumber</code>: the number of the track to loop</li>
|
||||||
|
<li><code>holdDurationLastAnimation</code>: the number of seconds to wait after the last animation is completed before repeating the loop</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>The parameters of the first group on each track are passed to the <code>setAnimation</code> method, while the remaining groups use <code>addAnimation</code>.</p>
|
<p>The parameters of the first group on each track are passed to the <code>setAnimation</code> method, while the remaining groups use <code>addAnimation</code>.</p>
|
||||||
|
|||||||
@ -58,7 +58,11 @@ type UpdateSpineWidgetFunction = (delta: number, skeleton: Skeleton, state: Anim
|
|||||||
export type OffScreenUpdateBehaviourType = "pause" | "update" | "pose";
|
export type OffScreenUpdateBehaviourType = "pause" | "update" | "pose";
|
||||||
export type ModeType = "inside" | "origin";
|
export type ModeType = "inside" | "origin";
|
||||||
export type FitType = "fill" | "width" | "height" | "contain" | "cover" | "none" | "scaleDown";
|
export type FitType = "fill" | "width" | "height" | "contain" | "cover" | "none" | "scaleDown";
|
||||||
export type AnimationsInfo = Record<string, { cycle?: boolean, animations: Array<AnimationsType> }>;
|
export type AnimationsInfo = Record<string, {
|
||||||
|
cycle?: boolean,
|
||||||
|
holdDurationLastAnimation?: number;
|
||||||
|
animations: Array<AnimationsType>
|
||||||
|
}>;
|
||||||
export type AnimationsType = { animationName: string | "#EMPTY#", loop?: boolean, delay?: number, mixDuration?: number };
|
export type AnimationsType = { animationName: string | "#EMPTY#", loop?: boolean, delay?: number, mixDuration?: number };
|
||||||
export type CursorEventType = "down" | "up" | "enter" | "leave" | "move" | "drag";
|
export type CursorEventType = "down" | "up" | "enter" | "leave" | "move" | "drag";
|
||||||
export type CursorEventTypesInput = Exclude<CursorEventType, "enter" | "leave">;
|
export type CursorEventTypesInput = Exclude<CursorEventType, "enter" | "leave">;
|
||||||
@ -1028,7 +1032,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
|||||||
state.data.defaultMix = defaultMix;
|
state.data.defaultMix = defaultMix;
|
||||||
|
|
||||||
if (animationsInfo) {
|
if (animationsInfo) {
|
||||||
for (const [trackIndexString, { cycle, animations }] of Object.entries(animationsInfo)) {
|
for (const [trackIndexString, { cycle, animations, holdDurationLastAnimation }] of Object.entries(animationsInfo)) {
|
||||||
const cycleFn = () => {
|
const cycleFn = () => {
|
||||||
const trackIndex = Number(trackIndexString);
|
const trackIndex = Number(trackIndexString);
|
||||||
for (const [index, { animationName, delay, loop, mixDuration }] of animations.entries()) {
|
for (const [index, { animationName, delay, loop, mixDuration }] of animations.entries()) {
|
||||||
@ -1050,7 +1054,15 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
|||||||
if (mixDuration) track.mixDuration = mixDuration;
|
if (mixDuration) track.mixDuration = mixDuration;
|
||||||
|
|
||||||
if (cycle && index === animations.length - 1) {
|
if (cycle && index === animations.length - 1) {
|
||||||
track.listener = { complete: () => cycleFn() };
|
track.listener = {
|
||||||
|
complete: () => {
|
||||||
|
if (holdDurationLastAnimation)
|
||||||
|
setTimeout(() => cycleFn(), 1000 * holdDurationLastAnimation);
|
||||||
|
else
|
||||||
|
cycleFn();
|
||||||
|
delete track.listener?.complete;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,7 +104,7 @@ function castToAnimationsInfo (value: string | null): AnimationsInfo | undefined
|
|||||||
if (!matches) return undefined;
|
if (!matches) return undefined;
|
||||||
|
|
||||||
return matches.reduce((obj, group) => {
|
return matches.reduce((obj, group) => {
|
||||||
const [trackIndexStringOrLoopDefinition, animationNameOrTrackIndexStringCycle, loop, delayString, mixDurationString] = group.slice(1, -1).split(',').map(v => v.trim());
|
const [trackIndexStringOrLoopDefinition, animationNameOrTrackIndexStringCycle, loopOrHoldDurationLastAnimation, delayString, mixDurationString] = group.slice(1, -1).split(',').map(v => v.trim());
|
||||||
|
|
||||||
if (trackIndexStringOrLoopDefinition === "loop") {
|
if (trackIndexStringOrLoopDefinition === "loop") {
|
||||||
if (!Number.isInteger(Number(animationNameOrTrackIndexStringCycle))) {
|
if (!Number.isInteger(Number(animationNameOrTrackIndexStringCycle))) {
|
||||||
@ -112,6 +112,15 @@ function castToAnimationsInfo (value: string | null): AnimationsInfo | undefined
|
|||||||
}
|
}
|
||||||
const animationInfoObject = obj[animationNameOrTrackIndexStringCycle] ||= { animations: [] };
|
const animationInfoObject = obj[animationNameOrTrackIndexStringCycle] ||= { animations: [] };
|
||||||
animationInfoObject.cycle = true;
|
animationInfoObject.cycle = true;
|
||||||
|
|
||||||
|
if (loopOrHoldDurationLastAnimation !== undefined) {
|
||||||
|
const holdDurationLastAnimation = Number(loopOrHoldDurationLastAnimation);
|
||||||
|
if (Number.isNaN(holdDurationLastAnimation)) {
|
||||||
|
throw new Error(`If present, duration of last animation of cycle in ${group} must be a positive integer number, instead it is ${loopOrHoldDurationLastAnimation}. Original value: ${value}`);
|
||||||
|
}
|
||||||
|
animationInfoObject.holdDurationLastAnimation = holdDurationLastAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +148,7 @@ function castToAnimationsInfo (value: string | null): AnimationsInfo | undefined
|
|||||||
const animationInfoObject = obj[trackIndexStringOrLoopDefinition] ||= { animations: [] };
|
const animationInfoObject = obj[trackIndexStringOrLoopDefinition] ||= { animations: [] };
|
||||||
animationInfoObject.animations.push({
|
animationInfoObject.animations.push({
|
||||||
animationName: animationNameOrTrackIndexStringCycle,
|
animationName: animationNameOrTrackIndexStringCycle,
|
||||||
loop: loop.trim().toLowerCase() === "true",
|
loop: loopOrHoldDurationLastAnimation.trim().toLowerCase() === "true",
|
||||||
delay,
|
delay,
|
||||||
mixDuration,
|
mixDuration,
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user