diff options
author | Adam Spiers <github@adamspiers.org> | 2016-04-16 15:43:44 +0100 |
---|---|---|
committer | Adam Spiers <github@adamspiers.org> | 2017-04-20 16:11:10 +0100 |
commit | 715cf0ba11db0f913cfd2edb56a2c66aed57b505 (patch) | |
tree | 34931979c899769e2ed3ed9dd79f6917e0c84529 /plugin | |
parent | 921a605567e8c08409fefa2cea75f66c851de748 (diff) | |
download | fosdem-2018-presentation-715cf0ba11db0f913cfd2edb56a2c66aed57b505.tar fosdem-2018-presentation-715cf0ba11db0f913cfd2edb56a2c66aed57b505.tar.gz |
optionally display pacing advice based on slide timings
Add an option to display advice on whether the current pace of the
presentation is on track for the right timing (shown as green), and if
not, whether the presenter should speed up (shown as red) or has the
luxury of slowing down (blue).
The pacing timer can be enabled by configuring by the `defaultTiming`
parameter in the `Reveal` configuration block, which specifies the
number of seconds per slide. 120 can be a reasonable rule of thumb.
Timings can also be given per slide `<section>` by setting the
`data-timing` attribute. Both values are in numbers of seconds.
When the option is enabled, clicking on the timers will reset the timer
to the beginning of the current slide, i.e. as if pacing was perfectly
on track, not to zero as if the presentation had just begun.
Diffstat (limited to 'plugin')
-rw-r--r-- | plugin/notes/notes.html | 140 |
1 files changed, 129 insertions, 11 deletions
diff --git a/plugin/notes/notes.html b/plugin/notes/notes.html index df55e79..c339d58 100644 --- a/plugin/notes/notes.html +++ b/plugin/notes/notes.html @@ -82,6 +82,7 @@ } .speaker-controls-time .label, + .speaker-controls-pace .label, .speaker-controls-notes .label { text-transform: uppercase; font-weight: normal; @@ -90,7 +91,7 @@ margin: 0; } - .speaker-controls-time { + .speaker-controls-time, .speaker-controls-pace { border-bottom: 1px solid rgba( 200, 200, 200, 0.5 ); margin-bottom: 10px; padding: 10px 16px; @@ -111,6 +112,13 @@ .speaker-controls-time .timer, .speaker-controls-time .clock { width: 50%; + } + + .speaker-controls-time .timer, + .speaker-controls-time .clock, + .speaker-controls-time .pacing .hours-value, + .speaker-controls-time .pacing .minutes-value, + .speaker-controls-time .pacing .seconds-value { font-size: 1.9em; } @@ -127,6 +135,18 @@ opacity: 0.3; } + .speaker-controls-time .pacing.ahead { + color: blue; + } + + .speaker-controls-time .pacing.on-track { + color: green; + } + + .speaker-controls-time .pacing.behind { + color: red; + } + .speaker-controls-notes { padding: 10px 16px; } @@ -276,6 +296,12 @@ <span class="hours-value">00</span><span class="minutes-value">:00</span><span class="seconds-value">:00</span> </div> <div class="clear"></div> + + <h4 class="label pacing-title" style="display: none">Pacing</h4> + <div class="pacing" style="display: none"> + <span class="hours-value">00</span><span class="minutes-value">:00</span><span class="seconds-value">:00</span> + to finish current slide + </div> </div> <div class="speaker-controls-notes hidden"> @@ -450,6 +476,47 @@ } + function getTimings() { + + var slides = Reveal.getSlides(); + var defaultTiming = Reveal.getConfig().defaultTiming; + if (defaultTiming == null) { + return null; + } + var timings = []; + for ( var i in slides ) { + var slide = slides[i]; + var timing = defaultTiming; + if( slide.hasAttribute( 'data-timing' )) { + var t = slide.getAttribute( 'data-timing' ); + timing = parseInt(t); + if( isNaN(timing) ) { + console.warn("Could not parse timing '" + t + "' of slide " + i + "; using default of " + defaultTiming); + timing = defaultTiming; + } + } + timings.push(timing); + } + return timings; + + } + + /** + * Return the number of seconds allocated for presenting + * all slides up to and including this one. + */ + function getTimeAllocated(timings) { + + var slides = Reveal.getSlides(); + var allocated = 0; + var currentSlide = Reveal.getSlidePastCount(); + for (var i in slides.slice(0, currentSlide + 1)) { + allocated += timings[i]; + } + return allocated; + + } + /** * Create the timer and clock and start updating them * at an interval. @@ -457,18 +524,30 @@ function setupTimer() { var start = new Date(), - timeEl = document.querySelector( '.speaker-controls-time' ), - clockEl = timeEl.querySelector( '.clock-value' ), - hoursEl = timeEl.querySelector( '.hours-value' ), - minutesEl = timeEl.querySelector( '.minutes-value' ), - secondsEl = timeEl.querySelector( '.seconds-value' ); + timeEl = document.querySelector( '.speaker-controls-time' ), + clockEl = timeEl.querySelector( '.clock-value' ), + hoursEl = timeEl.querySelector( '.hours-value' ), + minutesEl = timeEl.querySelector( '.minutes-value' ), + secondsEl = timeEl.querySelector( '.seconds-value' ), + pacingTitleEl = timeEl.querySelector( '.pacing-title' ), + pacingEl = timeEl.querySelector( '.pacing' ), + pacingHoursEl = pacingEl.querySelector( '.hours-value' ), + pacingMinutesEl = pacingEl.querySelector( '.minutes-value' ), + pacingSecondsEl = pacingEl.querySelector( '.seconds-value' ); + + var timings = getTimings(); + if (timings !== null) { + pacingTitleEl.style.removeProperty('display'); + pacingEl.style.removeProperty('display'); + } function _displayTime( hrEl, minEl, secEl, time) { + var sign = Math.sign(time) == -1 ? "-" : ""; time = Math.abs(Math.round(time / 1000)); var seconds = time % 60; - var minutes = ( time / 60 ) % 60 ; - var hours = time / ( 60 * 60 ) ; + var minutes = Math.floor( time / 60 ) % 60 ; + var hours = Math.floor( time / ( 60 * 60 )) ; hrEl.innerHTML = sign + zeroPadInteger( hours ); if (hours == 0) { hrEl.classList.add( 'mute' ); @@ -489,12 +568,34 @@ function _updateTimer() { var diff, hours, minutes, seconds, - now = new Date(); + now = new Date(); diff = now.getTime() - start.getTime(); clockEl.innerHTML = now.toLocaleTimeString( 'en-US', { hour12: true, hour: '2-digit', minute:'2-digit' } ); _displayTime( hoursEl, minutesEl, secondsEl, diff ); + if (timings !== null) { + _updatePacing(diff); + } + + } + + function _updatePacing(diff) { + + var slideEndTiming = getTimeAllocated(timings) * 1000; + var currentSlide = Reveal.getSlidePastCount(); + var currentSlideTiming = timings[currentSlide] * 1000; + var timeLeftCurrentSlide = slideEndTiming - diff; + if (timeLeftCurrentSlide < 0) { + pacingEl.className = 'pacing behind'; + } + else if (timeLeftCurrentSlide < currentSlideTiming) { + pacingEl.className = 'pacing on-track'; + } + else { + pacingEl.className = 'pacing ahead'; + } + _displayTime( pacingHoursEl, pacingMinutesEl, pacingSecondsEl, timeLeftCurrentSlide ); } @@ -504,9 +605,26 @@ // Then update every second setInterval( _updateTimer, 1000 ); - timeEl.addEventListener( 'click', function() { - start = new Date(); + function _resetTimer() { + + if (timings == null) { + start = new Date(); + } + else { + // Reset timer to beginning of current slide + var slideEndTiming = getTimeAllocated(timings) * 1000; + var currentSlide = Reveal.getSlidePastCount(); + var currentSlideTiming = timings[currentSlide] * 1000; + var previousSlidesTiming = slideEndTiming - currentSlideTiming; + var now = new Date(); + start = new Date(now.getTime() - previousSlidesTiming); + } _updateTimer(); + + } + + timeEl.addEventListener( 'click', function() { + _resetTimer(); return false; } ); |