App-revealup

 view release on metacpan or  search on metacpan

share/revealjs/js/controllers/backgrounds.js  view on Meta::CPAN

import { colorToRgb, colorBrightness } from '../utils/color.js'

/**
 * Creates and updates slide backgrounds.
 */
export default class Backgrounds {

	constructor( Reveal ) {

		this.Reveal = Reveal;

	}

	render() {

		this.element = document.createElement( 'div' );
		this.element.className = 'backgrounds';
		this.Reveal.getRevealElement().appendChild( this.element );

	}

	/**
	 * Creates the slide background elements and appends them
	 * to the background container. One element is created per
	 * slide no matter if the given slide has visible background.
	 */
	create() {

		// Clear prior backgrounds
		this.element.innerHTML = '';
		this.element.classList.add( 'no-transition' );

		// Iterate over all horizontal slides
		this.Reveal.getHorizontalSlides().forEach( slideh => {

			let backgroundStack = this.createBackground( slideh, this.element );

			// Iterate over all vertical slides
			queryAll( slideh, 'section' ).forEach( slidev => {

				this.createBackground( slidev, backgroundStack );

				backgroundStack.classList.add( 'stack' );

			} );

		} );

		// Add parallax background if specified
		if( this.Reveal.getConfig().parallaxBackgroundImage ) {

			this.element.style.backgroundImage = 'url("' + this.Reveal.getConfig().parallaxBackgroundImage + '")';
			this.element.style.backgroundSize = this.Reveal.getConfig().parallaxBackgroundSize;
			this.element.style.backgroundRepeat = this.Reveal.getConfig().parallaxBackgroundRepeat;
			this.element.style.backgroundPosition = this.Reveal.getConfig().parallaxBackgroundPosition;

			// Make sure the below properties are set on the element - these properties are
			// needed for proper transitions to be set on the element via CSS. To remove
			// annoying background slide-in effect when the presentation starts, apply
			// these properties after short time delay
			setTimeout( () => {
				this.Reveal.getRevealElement().classList.add( 'has-parallax-background' );
			}, 1 );

		}
		else {

			this.element.style.backgroundImage = '';
			this.Reveal.getRevealElement().classList.remove( 'has-parallax-background' );

		}

	}

	/**
	 * Creates a background for the given slide.
	 *
	 * @param {HTMLElement} slide
	 * @param {HTMLElement} container The element that the background
	 * should be appended to
	 * @return {HTMLElement} New background div
	 */
	createBackground( slide, container ) {

		// Main slide background element
		let element = document.createElement( 'div' );
		element.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' );

		// Inner background element that wraps images/videos/iframes
		let contentElement = document.createElement( 'div' );
		contentElement.className = 'slide-background-content';

		element.appendChild( contentElement );
		container.appendChild( element );

		slide.slideBackgroundElement = element;
		slide.slideBackgroundContentElement = contentElement;

		// Syncs the background to reflect all current background settings
		this.sync( slide );

		return element;

	}

	/**
	 * Renders all of the visual properties of a slide background
	 * based on the various background attributes.
	 *
	 * @param {HTMLElement} slide
	 */
	sync( slide ) {

		const element = slide.slideBackgroundElement,
			contentElement = slide.slideBackgroundContentElement;

		const data = {
			background: slide.getAttribute( 'data-background' ),
			backgroundSize: slide.getAttribute( 'data-background-size' ),
			backgroundImage: slide.getAttribute( 'data-background-image' ),
			backgroundVideo: slide.getAttribute( 'data-background-video' ),

share/revealjs/js/controllers/backgrounds.js  view on Meta::CPAN

						if( h === indices.h ) currentBackground = backgroundv;
					}

				} );
			}

		} );

		// Stop content inside of previous backgrounds
		if( this.previousBackground ) {

			this.Reveal.slideContent.stopEmbeddedContent( this.previousBackground, { unloadIframes: !this.Reveal.slideContent.shouldPreload( this.previousBackground ) } );

		}

		// Start content in the current background
		if( currentBackground ) {

			this.Reveal.slideContent.startEmbeddedContent( currentBackground );

			let currentBackgroundContent = currentBackground.querySelector( '.slide-background-content' );
			if( currentBackgroundContent ) {

				let backgroundImageURL = currentBackgroundContent.style.backgroundImage || '';

				// Restart GIFs (doesn't work in Firefox)
				if( /\.gif/i.test( backgroundImageURL ) ) {
					currentBackgroundContent.style.backgroundImage = '';
					window.getComputedStyle( currentBackgroundContent ).opacity;
					currentBackgroundContent.style.backgroundImage = backgroundImageURL;
				}

			}

			// Don't transition between identical backgrounds. This
			// prevents unwanted flicker.
			let previousBackgroundHash = this.previousBackground ? this.previousBackground.getAttribute( 'data-background-hash' ) : null;
			let currentBackgroundHash = currentBackground.getAttribute( 'data-background-hash' );
			if( currentBackgroundHash && currentBackgroundHash === previousBackgroundHash && currentBackground !== this.previousBackground ) {
				this.element.classList.add( 'no-transition' );
			}

			this.previousBackground = currentBackground;

		}

		// If there's a background brightness flag for this slide,
		// bubble it to the .reveal container
		if( currentSlide ) {
			[ 'has-light-background', 'has-dark-background' ].forEach( classToBubble => {
				if( currentSlide.classList.contains( classToBubble ) ) {
					this.Reveal.getRevealElement().classList.add( classToBubble );
				}
				else {
					this.Reveal.getRevealElement().classList.remove( classToBubble );
				}
			}, this );
		}

		// Allow the first background to apply without transition
		setTimeout( () => {
			this.element.classList.remove( 'no-transition' );
		}, 1 );

	}

	/**
	 * Updates the position of the parallax background based
	 * on the current slide index.
	 */
	updateParallax() {

		let indices = this.Reveal.getIndices();

		if( this.Reveal.getConfig().parallaxBackgroundImage ) {

			let horizontalSlides = this.Reveal.getHorizontalSlides(),
				verticalSlides = this.Reveal.getVerticalSlides();

			let backgroundSize = this.element.style.backgroundSize.split( ' ' ),
				backgroundWidth, backgroundHeight;

			if( backgroundSize.length === 1 ) {
				backgroundWidth = backgroundHeight = parseInt( backgroundSize[0], 10 );
			}
			else {
				backgroundWidth = parseInt( backgroundSize[0], 10 );
				backgroundHeight = parseInt( backgroundSize[1], 10 );
			}

			let slideWidth = this.element.offsetWidth,
				horizontalSlideCount = horizontalSlides.length,
				horizontalOffsetMultiplier,
				horizontalOffset;

			if( typeof this.Reveal.getConfig().parallaxBackgroundHorizontal === 'number' ) {
				horizontalOffsetMultiplier = this.Reveal.getConfig().parallaxBackgroundHorizontal;
			}
			else {
				horizontalOffsetMultiplier = horizontalSlideCount > 1 ? ( backgroundWidth - slideWidth ) / ( horizontalSlideCount-1 ) : 0;
			}

			horizontalOffset = horizontalOffsetMultiplier * indices.h * -1;

			let slideHeight = this.element.offsetHeight,
				verticalSlideCount = verticalSlides.length,
				verticalOffsetMultiplier,
				verticalOffset;

			if( typeof this.Reveal.getConfig().parallaxBackgroundVertical === 'number' ) {
				verticalOffsetMultiplier = this.Reveal.getConfig().parallaxBackgroundVertical;
			}
			else {
				verticalOffsetMultiplier = ( backgroundHeight - slideHeight ) / ( verticalSlideCount-1 );
			}

			verticalOffset = verticalSlideCount > 0 ?  verticalOffsetMultiplier * indices.v : 0;

			this.element.style.backgroundPosition = horizontalOffset + 'px ' + -verticalOffset + 'px';

		}



( run in 0.475 second using v1.01-cache-2.11-cpan-fe3c2283af0 )