[Partial solution] Different background videos on different breakpoints?

I wrote a code snippet that allows you to use the bricks custom attributes in the editor to set background images. It works on the principles of the previous solution by @UbuntuProductions but aims to be more dynamic in how it treats the breakpoints.

All you need to do is add the dynamic video breakpoint as an attribute using the data-video-src-{breakpoint} on the section containing a background video:
image

If all goes well the video should update based on the screen resize.

Here is the code snippet:

    const VERBOSE = false; // Debugging
    const videoWrappers = document.getElementsByClassName('has-bg-video');
    const activeVideos = new Map();

    function setBreakpoints() {
        Array.from(videoWrappers).forEach((wrapper, index) => {
            const attributes = wrapper.dataset;
            const videoSources = Object.keys(attributes).filter(key => key.includes("videoSrc-"));

            const breakpoints = new Map();
            videoSources.forEach(key => {
                const breakpoint = parseInt(key.slice(key.lastIndexOf('-') + 1));
                const src = attributes[key];
                breakpoints.set(breakpoint, src);
                const video = wrapper.querySelector('video');
                if (!video) return;
                video.setAttribute('data-video-id', index);
            });
            activeVideos.set(index, breakpoints);
        });
    }

    function switchVideoSource() {
    const screenWidth = window.innerWidth;
    const videos = document.querySelectorAll('[data-video-id]');
    videos.forEach((video) => {
        try {
            const videoId = parseInt(video.getAttribute('data-video-id'));
            const breakpoints = activeVideos.get(videoId);
            if (!breakpoints) return;

            let activeBreakpoint;
            let activeSource;
            let smallestDifference;
            for (const [breakpoint, source] of breakpoints) {
                let difference = breakpoint - screenWidth;
                if (VERBOSE){
                    console.log('bp:', breakpoint, 'sw:', screenWidth, 'diff:', difference, 'sd:', smallestDifference)
                }

                // Set smallest if not exist
                if ( difference >= 0 && (!smallestDifference || difference < smallestDifference)) smallestDifference = difference;

                if (screenWidth < breakpoint && difference === smallestDifference) {
                    activeBreakpoint = breakpoint;
                    activeSource = source;
                } else if (screenWidth > breakpoint && !smallestDifference){
                    activeBreakpoint = breakpoint;
                    activeSource = source;
                }
            }
        
            // Update video source if it's different
            if (video.src !== activeSource && activeSource !== '') {
                // const wasPlaying = !video.paused;
                video.src = activeSource;
                video.load();
                video.setAttribute('data-active-breakpoint', activeBreakpoint.toString());
                // if (wasPlaying) {
                //     video.play().catch(e => console.error('Error playing video:', e));
                // }
                if (VERBOSE) {
                    console.log(`Updated video ${videoId} to breakpoint ${activeBreakpoint} with source ${activeSource}`);
                }
            }
        } catch (error) {
            console.error('Error switching video source:', error);
        }
    });
}

    // Cleanup function
    function cleanup() {
        activeVideos.clear();
        // Remove event listeners
        window.removeEventListener('resize', handleResize);
        window.removeEventListener('unload', cleanup);
    }

    // Use requestAnimationFrame for smoother resize handling
    let resizeTimer;
    function handleResize() {
        cancelAnimationFrame(resizeTimer);
        resizeTimer = requestAnimationFrame(() => {
            switchVideoSource();
        });
    }

    // Initial call
    window.addEventListener('load', function() {
        setBreakpoints();
        switchVideoSource(); 
        
        window.addEventListener('resize', handleResize);
        window.addEventListener('unload', cleanup);
    });

PS: This was a proof of concept and I am sure it could be optimized

I would love to see this kind of implementation to the native breakpoints in bricks as the functionality is not too difficult really.

1 Like