Spaces:
Running
Running
| function setMessagePosition(message, x, y) { | |
| message.style.left = `${x}px`; | |
| message.style.top = `${y}px`; | |
| } | |
| function animateMessageBetween(message, fromX, fromY, toX, toY, duration, callback) { | |
| const startTime = performance.now(); | |
| function step(currentTime) { | |
| const elapsed = currentTime - startTime; | |
| const progress = Math.min(elapsed / duration, 1); | |
| const eased = 1 - Math.pow(1 - progress, 3); | |
| setMessagePosition( | |
| message, | |
| fromX + (toX - fromX) * eased, | |
| fromY + (toY - fromY) * eased | |
| ); | |
| if (progress < 1) { | |
| requestAnimationFrame(step); | |
| } else if (callback) { | |
| callback(); | |
| } | |
| } | |
| requestAnimationFrame(step); | |
| } | |
| function animatePathBetween(message, waypoints, totalDuration, callback) { | |
| if (waypoints.length < 2) { | |
| if (callback) { | |
| callback(); | |
| } | |
| return; | |
| } | |
| let totalDist = 0; | |
| for (let i = 0; i < waypoints.length - 1; i++) { | |
| const dx = waypoints[i + 1].x - waypoints[i].x; | |
| const dy = waypoints[i + 1].y - waypoints[i].y; | |
| totalDist += Math.sqrt(dx * dx + dy * dy); | |
| } | |
| const durations = []; | |
| for (let i = 0; i < waypoints.length - 1; i++) { | |
| const dx = waypoints[i + 1].x - waypoints[i].x; | |
| const dy = waypoints[i + 1].y - waypoints[i].y; | |
| const legDist = Math.sqrt(dx * dx + dy * dy); | |
| durations.push((legDist / totalDist) * totalDuration); | |
| } | |
| let i = 0; | |
| function nextLeg() { | |
| if (i < waypoints.length - 1) { | |
| animateMessageBetween( | |
| message, | |
| waypoints[i].x, waypoints[i].y, | |
| waypoints[i + 1].x, waypoints[i + 1].y, | |
| durations[i], | |
| () => { | |
| i++; | |
| nextLeg(); | |
| } | |
| ); | |
| } else if (callback) { | |
| callback(); | |
| } | |
| } | |
| nextLeg(); | |
| } | |
| function configureMessage(elements, { | |
| type, | |
| arrow, | |
| method, | |
| detail, | |
| sessionText, | |
| sessionError = false, | |
| direction = 'right', | |
| } = {}) { | |
| const container = elements.container; | |
| const header = elements.header || container.querySelector('.message-header'); | |
| container.className = `message ${type} visible`; | |
| elements.type.textContent = method; | |
| elements.arrow.textContent = arrow; | |
| elements.detail.textContent = detail; | |
| if (elements.session) { | |
| if (sessionText) { | |
| elements.session.innerHTML = sessionText; | |
| elements.session.style.display = 'block'; | |
| elements.session.className = 'message-session' + (sessionError ? ' error' : ''); | |
| } else { | |
| elements.session.style.display = 'none'; | |
| } | |
| } | |
| if (header) { | |
| header.style.flexDirection = direction === 'left' ? 'row-reverse' : 'row'; | |
| } | |
| } | |
| function runStepSequence(steps, { initialDelay = 100, stepPause, startOnLoad = true } = {}) { | |
| if (!steps || steps.length === 0) { | |
| return; | |
| } | |
| const pause = stepPause ?? (typeof ANIMATION !== 'undefined' ? ANIMATION.STEP_PAUSE : 1500); | |
| let currentStep = 0; | |
| let animationTimer = null; | |
| let runId = 0; | |
| function runStep(activeRunId) { | |
| if (activeRunId !== runId) { | |
| return; | |
| } | |
| if (currentStep >= steps.length) { | |
| currentStep = 0; | |
| } | |
| const step = steps[currentStep]; | |
| step.setup(); | |
| animationTimer = setTimeout(() => { | |
| if (activeRunId !== runId) { | |
| return; | |
| } | |
| step.animate(() => { | |
| if (activeRunId !== runId) { | |
| return; | |
| } | |
| if (step.after) { | |
| step.after(); | |
| } | |
| currentStep++; | |
| animationTimer = setTimeout(() => runStep(activeRunId), pause); | |
| }); | |
| }, initialDelay); | |
| } | |
| const start = () => { | |
| runId++; | |
| if (animationTimer) { | |
| clearTimeout(animationTimer); | |
| animationTimer = null; | |
| } | |
| currentStep = 0; | |
| runStep(runId); | |
| }; | |
| if (startOnLoad) { | |
| if (document.readyState === 'complete') { | |
| start(); | |
| } else { | |
| window.addEventListener('load', start, { once: true }); | |
| } | |
| // Restart only for bfcache restores to avoid duplicate starts. | |
| window.addEventListener('pageshow', (event) => { | |
| if (event.persisted) { | |
| start(); | |
| } | |
| }); | |
| } else { | |
| start(); | |
| } | |
| } | |