Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- initVideoScrollControl("YourRectangleAccessibilityText", "YourVideoAccessibilityText");
- /*
- VideoScrollTrigger v1.2.0
- Description: Allows scrubbing through videos using scroll, touch, or keyboard controls
- Usage: Replace "YourRectangleAccessibilityText" and "YourVideoAccessibilityText" with the
- accessibility text of the slide objects in Storyline. */
- function initVideoScrollControl(rectangleId, videoId, options = {}) {
- // Selectors
- var videoContainer = document.querySelector(`[data-acc-text="${rectangleId}"] div`);
- var video = document.querySelector(`[data-acc-text="${videoId}"] video`);
- // Error handling and fallbacks
- if (!videoContainer) {
- console.error(`VideoScrollTrigger: Container with data-acc-text="${rectangleId}" not found`);
- return;
- }
- if (!video) {
- console.error(`VideoScrollTrigger: Video with data-acc-text="${videoId}" not found`);
- return;
- }
- // Merged config with user options
- const config = {
- scrollSensitivity: 0.3,
- touchSensitivity: 0.2,
- frameRate: 1000 / 60,
- smoothingFactor: 0.8,
- momentumScrolling: true,
- momentumDecay: 0.95,
- allowHorizontalScroll: true,
- keyboardSensitivity: 5,
- enableKeyboard: true,
- ...options
- };
- // State variables
- let touchStartY = null;
- let touchStartX = null;
- let lastTouchY = null;
- let lastTouchX = null;
- let lastTime = video ? video.currentTime : 0;
- let targetTime = lastTime;
- let isAnimating = false;
- let lastScrollTime = Date.now();
- let scrollTimeout;
- let momentum = 0;
- let lastMomentumUpdate = Date.now();
- let isMomentumActive = false;
- // Apply momentum decay
- function applyMomentum() {
- if (!config.momentumScrolling || Math.abs(momentum) < 0.001) {
- isMomentumActive = false;
- return;
- }
- const now = Date.now();
- const elapsed = now - lastMomentumUpdate;
- lastMomentumUpdate = now;
- momentum *= Math.pow(config.momentumDecay, elapsed / 16);
- updateVideoTime(targetTime + momentum);
- requestAnimationFrame(applyMomentum);
- }
- function animateToTargetTime() {
- if (!video || !isAnimating) return;
- const diff = targetTime - lastTime;
- if (Math.abs(diff) < 0.01) {
- lastTime = targetTime;
- isAnimating = false;
- return;
- }
- lastTime += diff * config.smoothingFactor;
- video.currentTime = lastTime;
- requestAnimationFrame(animateToTargetTime);
- }
- function updateVideoTime(newTargetTime) {
- if (!video || isNaN(video.duration)) return;
- targetTime = Math.max(0, Math.min(video.duration, newTargetTime));
- if (!isAnimating) {
- isAnimating = true;
- animateToTargetTime();
- }
- }
- function handleScroll(event) {
- event.preventDefault();
- if (!video || isNaN(video.duration)) return;
- const now = Date.now();
- if (now - lastScrollTime < config.frameRate) return;
- lastScrollTime = now;
- // Calculate scroll amount based on primary scroll direction
- let scrollAmount;
- if (Math.abs(event.deltaY) >= Math.abs(event.deltaX) || !config.allowHorizontalScroll) {
- scrollAmount = event.deltaY * config.scrollSensitivity;
- } else {
- scrollAmount = event.deltaX * config.scrollSensitivity;
- }
- // Update momentum
- momentum = scrollAmount / 100;
- const newTime = targetTime + momentum;
- updateVideoTime(newTime);
- // Start momentum scrolling
- if (config.momentumScrolling && !isMomentumActive) {
- isMomentumActive = true;
- lastMomentumUpdate = now;
- requestAnimationFrame(applyMomentum);
- }
- clearTimeout(scrollTimeout);
- scrollTimeout = setTimeout(() => {
- isAnimating = false;
- }, 150);
- }
- function handleTouchStart(event) {
- if (event.touches.length !== 1) return;
- touchStartY = event.touches[0].clientY;
- touchStartX = event.touches[0].clientX;
- lastTouchY = touchStartY;
- lastTouchX = touchStartX;
- lastTime = video.currentTime;
- targetTime = lastTime;
- momentum = 0;
- isMomentumActive = false;
- event.preventDefault();
- }
- function handleTouchMove(event) {
- event.preventDefault();
- if (!video || isNaN(video.duration) || event.touches.length !== 1) return;
- const currentY = event.touches[0].clientY;
- const currentX = event.touches[0].clientX;
- // Determine primary direction of movement
- const deltaY = lastTouchY - currentY;
- const deltaX = lastTouchX - currentX;
- lastTouchY = currentY;
- lastTouchX = currentX;
- let delta;
- if (Math.abs(deltaY) >= Math.abs(deltaX) || !config.allowHorizontalScroll) {
- delta = deltaY;
- } else {
- delta = deltaX;
- }
- const direction = Math.sign(delta);
- const magnitude = Math.abs(delta);
- const scaledDelta = direction * Math.pow(magnitude, 1.5) * config.touchSensitivity;
- const timeAdjustment = scaledDelta / 100;
- momentum = timeAdjustment;
- const newTime = video.currentTime + timeAdjustment;
- updateVideoTime(newTime);
- }
- function handleTouchEnd(event) {
- event.preventDefault();
- // Start momentum effect
- if (config.momentumScrolling && Math.abs(momentum) > 0.001) {
- isMomentumActive = true;
- lastMomentumUpdate = Date.now();
- requestAnimationFrame(applyMomentum);
- }
- touchStartY = null;
- touchStartX = null;
- lastTouchY = null;
- lastTouchX = null;
- setTimeout(() => {
- isAnimating = false;
- }, 150);
- }
- function handleKeyDown(event) {
- if (!config.enableKeyboard || !video || isNaN(video.duration)) return;
- let timeAdjustment = 0;
- const step = config.keyboardSensitivity / 100;
- switch (event.key) {
- case 'ArrowUp':
- case 'ArrowLeft':
- timeAdjustment = -step;
- event.preventDefault();
- break;
- case 'ArrowDown':
- case 'ArrowRight':
- timeAdjustment = step;
- event.preventDefault();
- break;
- case 'Home':
- updateVideoTime(0);
- event.preventDefault();
- return;
- case 'End':
- updateVideoTime(video.duration);
- event.preventDefault();
- return;
- default:
- return;
- }
- updateVideoTime(video.currentTime + timeAdjustment);
- }
- // Clean up any existing event listeners before adding new ones
- function setupEventListeners() {
- // Remove any existing event listeners first
- videoContainer.removeEventListener('wheel', handleScroll, { passive: false, capture: true });
- videoContainer.removeEventListener('touchstart', handleTouchStart, { passive: false });
- videoContainer.removeEventListener('touchmove', handleTouchMove, { passive: false });
- videoContainer.removeEventListener('touchend', handleTouchEnd, { passive: false });
- document.removeEventListener('keydown', handleKeyDown);
- // Add new event listeners
- videoContainer.addEventListener('wheel', handleScroll, {
- passive: false,
- capture: true
- });
- videoContainer.addEventListener('touchstart', handleTouchStart, {
- passive: false
- });
- videoContainer.addEventListener('touchmove', handleTouchMove, {
- passive: false
- });
- videoContainer.addEventListener('touchend', handleTouchEnd, {
- passive: false
- });
- if (config.enableKeyboard) {
- document.addEventListener('keydown', handleKeyDown);
- }
- }
- // Initialize video
- video.pause();
- video.preload = 'auto';
- video.addEventListener('waiting', () => {
- isAnimating = false;
- });
- video.addEventListener('canplay', () => {
- if (targetTime !== lastTime) {
- isAnimating = true;
- animateToTargetTime();
- }
- });
- // Set up all event listeners
- setupEventListeners();
- // Return API for external control
- return {
- updateConfig: function(newOptions) {
- Object.assign(config, newOptions);
- setupEventListeners(); // Re-setup event listeners in case keyboard was enabled/disabled
- },
- seekTo: function(timePercentage) {
- if (!video || isNaN(video.duration)) return;
- const newTime = video.duration * Math.max(0, Math.min(1, timePercentage));
- updateVideoTime(newTime);
- }
- };
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement