UNPKG

move.gl

Version:

Motion and Animation Library for Stylescape.

206 lines (178 loc) 6 kB
// ============================================================================ // move.gl | Video Overlay // ============================================================================ // Copyright 2025 Scape Agency BV // Licensed under MIT License // ============================================================================ /** * Video overlay options */ export interface VideoOverlayOptions { /** Fade transition duration in milliseconds */ fadeTransitionDuration?: number; /** Whether to loop the video */ loop?: boolean; /** Initial video source URL */ initialSource?: string; } /** * Transparent Video Overlay Handler * * Manages a transparent video overlay, controlling its visibility, * playback, and effects. * * @example * ```typescript * const overlay = new TransparentVideoOverlay('myVideo', { * fadeTransitionDuration: 500, * loop: true * }); * overlay.showOverlay(); * ``` */ export class TransparentVideoOverlay { private videoElement: HTMLVideoElement | null = null; private isVisible: boolean = false; private fadeTransitionDuration: number; private loop: boolean; /** * Creates a new TransparentVideoOverlay instance. * @param videoElementId - The ID of the video element to manage. * @param options - Optional configuration options. */ constructor(videoElementId: string, options: VideoOverlayOptions = {}) { const element = document.getElementById(videoElementId); if (element instanceof HTMLVideoElement) { this.videoElement = element; } else { console.warn(`Element with id "${videoElementId}" is not a video element`); } this.fadeTransitionDuration = options.fadeTransitionDuration ?? 500; this.loop = options.loop ?? true; if (this.videoElement) { this.setupVideo(); if (options.initialSource) { this.changeVideoSource(options.initialSource, false); } } } /** * Initializes video settings and event listeners. */ private setupVideo(): void { if (!this.videoElement) return; if (this.loop) { this.videoElement.addEventListener('ended', () => { this.videoElement?.play(); }); } this.videoElement.addEventListener('loadeddata', () => { console.log('Video loaded successfully.'); }); this.videoElement.addEventListener('error', (e) => { console.error('Error loading video:', e); }); // Set initial style for smooth transitions this.videoElement.style.transition = `opacity ${this.fadeTransitionDuration}ms ease`; } /** * Shows the video overlay with a fade-in effect. */ public showOverlay(): void { if (!this.videoElement) return; this.videoElement.style.display = 'block'; this.videoElement.style.opacity = '0'; // Use requestAnimationFrame for smoother transition requestAnimationFrame(() => { if (this.videoElement) { this.videoElement.style.opacity = '1'; this.videoElement.play().catch(err => { console.warn('Auto-play prevented:', err); }); } }); this.isVisible = true; } /** * Hides the video overlay with a fade-out effect. */ public hideOverlay(): void { if (!this.videoElement) return; this.videoElement.style.opacity = '0'; setTimeout(() => { if (this.videoElement) { this.videoElement.style.display = 'none'; this.videoElement.pause(); } }, this.fadeTransitionDuration); this.isVisible = false; } /** * Toggles the visibility of the video overlay. */ public toggleOverlay(): void { if (this.isVisible) { this.hideOverlay(); } else { this.showOverlay(); } } /** * Changes the video source and optionally plays it immediately. * @param videoUrl - The URL of the new video source. * @param autoPlay - Whether the video should play immediately after loading. */ public changeVideoSource(videoUrl: string, autoPlay: boolean = true): void { if (!this.videoElement) return; this.videoElement.src = videoUrl; this.videoElement.load(); if (autoPlay) { this.showOverlay(); } } /** * Gets the visibility state of the overlay. */ public getIsVisible(): boolean { return this.isVisible; } /** * Cleans up the video overlay instance. */ public destroy(): void { if (this.videoElement) { this.videoElement.pause(); this.videoElement.src = ''; this.videoElement = null; } } } /** * Checks if the browser supports HEVC alpha channel videos. * This is primarily supported in Safari. * @returns Whether HEVC alpha is supported. */ export function supportsHEVCAlpha(): boolean { const navigator = window.navigator; const ua = navigator.userAgent.toLowerCase(); const hasMediaCapabilities = !!( navigator.mediaCapabilities && navigator.mediaCapabilities.decodingInfo ); const isSafari = ( ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1 && ua.indexOf('version/') !== -1 ); return isSafari && hasMediaCapabilities; } /** * Gets the appropriate video source based on browser support. * @param hevcSource - The HEVC/MOV source for Safari. * @param webmSource - The WebM source for other browsers. * @returns The appropriate video source URL. */ export function getOptimalVideoSource(hevcSource: string, webmSource: string): string { return supportsHEVCAlpha() ? hevcSource : webmSource; } export default TransparentVideoOverlay;