Align outro animations at slide end
This commit is contained in:
1 parent
8ee59e97d3
commit
24a566a1a4
7 files changed
+88
-49
No files matched your search
@@ -5,6 +5,7 @@ var slideTransitionRequestId = 0;
|
||||
var playerWatchdogTimer = null;
|
||||
var playerLastProgressAt = Date.now();
|
||||
var playerWatchdogRecoveryKey = 'pulse-signage-player-watchdog-recoveries';
|
||||
var slideOutroFrameBufferMs = 50;
|
||||
|
||||
function markPlayerPlaybackProgress() {
|
||||
playerLastProgressAt = Date.now();
|
||||
@@ -89,18 +90,22 @@ function scheduleSlideOutro(holdDelayMs) {
|
||||
|
||||
var currentRoot = getCurrentSlideRoot();
|
||||
if (!currentRoot || typeof getRegionAnimationPhaseTimings !== 'function' || typeof playRegionAnimation !== 'function') {
|
||||
return;
|
||||
return Math.max(1, Math.round(Number(holdDelayMs || 0)));
|
||||
}
|
||||
|
||||
var regionTimings = getRegionAnimationPhaseTimings(currentRoot, 'outro');
|
||||
if (!regionTimings.length) {
|
||||
return;
|
||||
return Math.max(1, Math.round(Number(holdDelayMs || 0)));
|
||||
}
|
||||
|
||||
var slideDurationMs = Math.max(1, Math.round(Number(holdDelayMs || 0)));
|
||||
var longestTimingMs = regionTimings.reduce(function (longest, entry) {
|
||||
return Math.max(longest, Math.max(0, Math.round(Number(entry && entry.timingMs || 0))));
|
||||
}, 0);
|
||||
var transitionDelayMs = Math.max(slideDurationMs, longestTimingMs + slideOutroFrameBufferMs);
|
||||
slideOutroTimers = regionTimings.map(function (entry) {
|
||||
var timingMs = Math.max(0, Math.round(Number(entry && entry.timingMs || 0)));
|
||||
var triggerDelayMs = Math.max(0, slideDurationMs - timingMs);
|
||||
var triggerDelayMs = Math.max(0, transitionDelayMs - timingMs - slideOutroFrameBufferMs);
|
||||
return window.setTimeout(function () {
|
||||
if (!entry || !entry.element || !entry.element.isConnected) {
|
||||
return;
|
||||
@@ -108,14 +113,15 @@ function scheduleSlideOutro(holdDelayMs) {
|
||||
playRegionAnimation(entry.element, 'outro');
|
||||
}, triggerDelayMs);
|
||||
});
|
||||
return transitionDelayMs;
|
||||
}
|
||||
|
||||
// Schedule the next slide transition.
|
||||
function scheduleSlideAdvance(delayMs) {
|
||||
clearSlideTimer();
|
||||
var holdDelayMs = Math.max(1, Number(delayMs || 0));
|
||||
holdDelayMs = scheduleSlideOutro(holdDelayMs);
|
||||
slideExpiresAt = Date.now() + holdDelayMs;
|
||||
scheduleSlideOutro(holdDelayMs);
|
||||
timer = window.setTimeout(function () {
|
||||
timer = null;
|
||||
slideExpiresAt = null;
|
||||
|
||||
@@ -179,6 +179,7 @@ export function createSlideAnimationEditor(options) {
|
||||
previewMode = mode;
|
||||
var token = previewToken;
|
||||
var longest = 0;
|
||||
var pending = [];
|
||||
getPreviewElements().forEach(function (element) {
|
||||
var config = window.templateDesignerUtils.normalizeAnimationConfig(getConfig(element.dataset.regionKey));
|
||||
var step = config[mode] || {};
|
||||
@@ -196,7 +197,19 @@ export function createSlideAnimationEditor(options) {
|
||||
void element.offsetWidth;
|
||||
element.classList.add('animate__animated', 'animate__' + preset);
|
||||
if (mode === 'loop') element.classList.add('animate__repeat-1');
|
||||
longest = Math.max(longest, delay + getAnimationDurationMs(element, duration) * iterations);
|
||||
var runtime = getAnimationDurationMs(element, duration) * iterations;
|
||||
pending.push({ element: element, delay: delay, runtime: runtime });
|
||||
longest = Math.max(longest, delay + runtime);
|
||||
});
|
||||
pending.forEach(function (entry) {
|
||||
var delay = mode === 'outro' ? longest - entry.runtime : entry.delay;
|
||||
if (delay > 0) {
|
||||
entry.element.style.setProperty('--animate-delay', delay + 'ms');
|
||||
entry.element.style.setProperty('animation-delay', delay + 'ms');
|
||||
} else {
|
||||
entry.element.style.setProperty('--animate-delay', '0ms');
|
||||
entry.element.style.setProperty('animation-delay', '0ms');
|
||||
}
|
||||
});
|
||||
updatePreviewButtons();
|
||||
previewTimer = window.setTimeout(function () {
|
||||
|
||||
@@ -364,6 +364,7 @@
|
||||
rect.style.removeProperty('--animate-delay');
|
||||
rect.style.removeProperty('--animate-repeat');
|
||||
rect.style.removeProperty('animation-delay');
|
||||
rect.style.removeProperty('animation-play-state');
|
||||
rect.style.opacity = '';
|
||||
rect.style.transform = '';
|
||||
rect.style.filter = '';
|
||||
@@ -469,30 +470,15 @@
|
||||
|
||||
var MAX_ANIMATION_REPEAT_COUNT = 999;
|
||||
|
||||
function getPreviewAnimationStepTimingMs(step, mode, animateCssMode) {
|
||||
var normalizedMode = String(mode || '').trim().toLowerCase();
|
||||
var durationMs = Number(step && step.duration_ms);
|
||||
var delayMs = Number(step && step.delay_ms);
|
||||
var iterations = Number(step && step.iterations);
|
||||
|
||||
if (!Number.isFinite(durationMs) || durationMs <= 0) {
|
||||
durationMs = animateCssMode ? 1000 : 900;
|
||||
}
|
||||
if (!Number.isFinite(delayMs) || delayMs < 0) {
|
||||
delayMs = 0;
|
||||
}
|
||||
if (normalizedMode === 'out') {
|
||||
delayMs = 0;
|
||||
}
|
||||
if (!Number.isFinite(iterations) || iterations < 1) {
|
||||
iterations = 1;
|
||||
}
|
||||
|
||||
if (normalizedMode === 'continuous') {
|
||||
return delayMs + (durationMs * iterations);
|
||||
}
|
||||
|
||||
return delayMs + durationMs;
|
||||
function getComputedAnimationDurationMs(element, fallbackDurationMs) {
|
||||
if (typeof window.getComputedStyle !== 'function') return fallbackDurationMs;
|
||||
var durations = String(window.getComputedStyle(element).animationDuration || '').split(',');
|
||||
return durations.reduce(function (longest, value) {
|
||||
var match = value.trim().match(/^([\d.]+)\s*(ms|s)$/i);
|
||||
if (!match) return longest;
|
||||
var duration = Number(match[1]) * (match[2].toLowerCase() === 's' ? 1000 : 1);
|
||||
return Number.isFinite(duration) ? Math.max(longest, duration) : longest;
|
||||
}, 0) || fallbackDurationMs;
|
||||
}
|
||||
|
||||
function normalizeAnimationStep(value, fallbackPreset) {
|
||||
@@ -708,42 +694,55 @@
|
||||
function animatePreviewRects(mode, regions) {
|
||||
var rects = getPreviewRects();
|
||||
var token = previewState.token;
|
||||
var duration = 900;
|
||||
var fallbackDuration = 900;
|
||||
var overlayRect = getOverlayRect();
|
||||
var canvasMovement = Math.max(12, Math.round(overlayRect.height * 0.02));
|
||||
var longestTimingMs = 0;
|
||||
var pending = [];
|
||||
|
||||
previewState.animations = [];
|
||||
|
||||
rects.forEach(function (rect) {
|
||||
var region = regions && regions[index] ? regions[index] : null;
|
||||
var regionIndex = Number(rect.getAttribute('data-index'));
|
||||
var region = regions && Number.isInteger(regionIndex) ? regions[regionIndex] : null;
|
||||
var step = getPreviewRegionAnimationStep(region, mode);
|
||||
var preset = normalizePreviewAnimation(step && step.preset);
|
||||
if (preset === 'none') return;
|
||||
var delay = mode === 'out' ? 0 : Math.max(0, Number(step && step.delay_ms) || 0);
|
||||
var animation = null;
|
||||
var animateCssMode = isAnimateCssPreset(preset);
|
||||
var timingMs = delay + getPreviewAnimationStepTimingMs(step, mode, animateCssMode);
|
||||
var durationMs = Number(step && step.duration_ms);
|
||||
if (!Number.isFinite(durationMs) || durationMs <= 0) durationMs = animateCssMode ? 1000 : fallbackDuration;
|
||||
var iterations = String(mode || '').trim().toLowerCase() === 'continuous'
|
||||
? Math.max(1, Number(step && step.iterations) || 1) : 1;
|
||||
var runtimeMs = durationMs * iterations;
|
||||
|
||||
rect.style.willChange = 'transform, opacity, filter';
|
||||
|
||||
if (timingMs > longestTimingMs) {
|
||||
longestTimingMs = timingMs;
|
||||
}
|
||||
|
||||
if (preset === 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (animateCssMode) {
|
||||
rect.style.setProperty('animation-play-state', 'paused');
|
||||
applyAnimateCssPreview(rect, preset, step, mode);
|
||||
runtimeMs = getComputedAnimationDurationMs(rect, durationMs) * iterations;
|
||||
}
|
||||
pending.push({ rect: rect, mode: mode, preset: preset, delay: delay, runtimeMs: runtimeMs, animateCssMode: animateCssMode });
|
||||
longestTimingMs = Math.max(longestTimingMs, delay + runtimeMs);
|
||||
});
|
||||
|
||||
pending.forEach(function (entry) {
|
||||
var rect = entry.rect;
|
||||
var delay = mode === 'out' ? Math.max(0, longestTimingMs - entry.runtimeMs) : entry.delay;
|
||||
if (entry.animateCssMode) {
|
||||
rect.style.setProperty('--animate-delay', delay + 'ms');
|
||||
rect.style.setProperty('animation-delay', delay + 'ms');
|
||||
rect.style.removeProperty('animation-play-state');
|
||||
return;
|
||||
}
|
||||
|
||||
var animation = null;
|
||||
if (mode === 'intro') {
|
||||
animation = rect.animate([
|
||||
{ opacity: 0, transform: 'translate3d(0, ' + canvasMovement + 'px, 0) scale(0.96)', filter: 'blur(1px)' },
|
||||
{ opacity: 1, transform: 'translate3d(0, 0, 0) scale(1)', filter: 'blur(0)' }
|
||||
], {
|
||||
duration: duration,
|
||||
duration: entry.runtimeMs,
|
||||
delay: delay,
|
||||
easing: 'cubic-bezier(0.22, 1, 0.36, 1)',
|
||||
fill: 'both'
|
||||
@@ -753,7 +752,7 @@
|
||||
{ opacity: 1, transform: 'translate3d(0, 0, 0) scale(1)', filter: 'blur(0)' },
|
||||
{ opacity: 0, transform: 'translate3d(0, -' + canvasMovement + 'px, 0) scale(0.96)', filter: 'blur(1px)' }
|
||||
], {
|
||||
duration: duration,
|
||||
duration: entry.runtimeMs,
|
||||
delay: delay,
|
||||
easing: 'cubic-bezier(0.4, 0, 1, 1)',
|
||||
fill: 'both'
|
||||
|
||||
Reference in new issue
Block a user