var ElapsedTimeBar = { // default value barColor: 'rgb(200,0,0)', pausedBarColor: 'rgba(200,0,0,.6)', isPaused: false, isFinished: false, allottedTime: null, timeProgressBar: null, startTime: null, pauseTime: null, pauseTimeDuration: 0, /** * initialize elements */ handleReady() { var config = Reveal.getConfig(); // activate this plugin if config.allottedTime exists. if (!config.allottedTime) { console.warn('Failed to start ElapsedTimeBar plugin. "allottedTime" property is required.'); return; } // set configurations this.barColor = config.barColor || this.barColor; this.pausedBarColor = config.pausedBarColor || this.pausedBarColor; // calc barHeight from config.barHeight or page-progress container var barHeight; var pageProgressContainer = document.querySelector('.progress'); if (config.progressBarHeight) { barHeight = parseInt(config.progressBarHeight, 10) + 'px'; // override height of page-progress container pageProgressContainer && (pageProgressContainer.style.height = barHeight); } else if (config.progress && pageProgressContainer) { // get height from page-progress container barHeight = pageProgressContainer.getBoundingClientRect().height + 'px'; } else { // default barHeight = '3px'; } // create container of time-progress var timeProgressContainer = document.createElement('div'); timeProgressContainer.classList.add('progress'); Object.entries({ display: 'block', position: 'fixed', bottom: config.progress ? barHeight : 0, width: '100%', height: barHeight }).forEach(([k, v]) => { timeProgressContainer.style[k] = v; }); document.querySelector('.reveal').appendChild(timeProgressContainer); // create content of time-progress this.timeProgressBar = document.createElement('div'); Object.entries({ height: '100%', willChange: 'width' }).forEach(([k, v]) => { this.timeProgressBar.style[k] = v; }); timeProgressContainer.appendChild(this.timeProgressBar); // start timer this.start(config.allottedTime); }, /** * update repeatedly using requestAnimationFrame. */ loop() { if (this.isPaused) return; var now = +new Date(); var elapsedTime = now - this.startTime - this.pauseTimeDuration; if (elapsedTime > this.allottedTime) { this.timeProgressBar.style.width = '100%'; this.isFinished = true; } else { this.timeProgressBar.style.width = elapsedTime / this.allottedTime * 100 + '%'; requestAnimationFrame(this.loop.bind(this)); } }, /** * set color of progress bar */ setBarColor() { if (this.isPaused) { this.timeProgressBar.style.backgroundColor = this.pausedBarColor; } else { this.timeProgressBar.style.backgroundColor = this.barColor; } }, /** * start(reset) timer with new allotted time. * @param {number} allottedTime * @param {number} [elapsedTime=0] */ start(allottedTime, elapsedTime = 0) { this.isFinished = false; this.isPaused = false; this.allottedTime = allottedTime; this.startTime = +new Date() - elapsedTime; this.pauseTimeDuration = 0; this.setBarColor(); this.loop(); }, reset() { this.start(this.allottedTime); }, pause() { if (this.isPaused) return; this.isPaused = true; this.pauseTime = +new Date(); this.setBarColor(); }, resume() { if (!this.isPaused) return; // add paused time duration this.isPaused = false; this.pauseTimeDuration += new Date() - this.pauseTime; this.pauseTime = null; this.setBarColor(); this.loop(); } }; if (Reveal.isReady()) { ElapsedTimeBar.handleReady(); } else { Reveal.addEventListener('ready', () => ElapsedTimeBar.handleReady()); }