プレゼンフレームワーク reveal.js にやっつけ chapter 機能をつける

概要

プレゼンするのに reveal.js を使ってみてよかったんですが、プレゼンの構成として、chapter があって、それに各スライドが所属している、って形にしたくて、やっつけで chapter 機能をつけてみた、という話です。

ここでいうところの chapter 機能

次の動画における、左上ににゅるっと出てくる「麦・大豆&野菜」とか「生物多様性」とかの部分。各スライドは chapter に所属していて、複数個の chapter でプレゼン資料が成り立っている、という構成です。

reveal_chapter3.gif

実装方針

  • 水呑百姓がきれいなコードを書いている暇はないのでやっつけ
    • reveal.js に手は入れない
    • とりあえず動けばよくて、プラグインとして整備したりしない
    • プレゼン資料を作るごとにコードに手を入れるのも持さない
  • 出先でのプレゼンなのでローカル WEB サーバは動かさない前提で

コード

javascript

ほんと、やっつけです。きれいに書き直し、自由に使ってください。
グローバル汚染上等。ES6 って何? おいしいの?

chapter.js
const Chapterion = {
  current: {
    c: 0
  },
  chapters: [],
};

Chapterion.Chapter = function(section, idx, elm) {
  this.section = section;
  section.dataset.chapterIndex = idx;
  this.elm = elm;
  elm.dataset.chapterIndex = idx;
  this.index = idx;
  let text = section.dataset.chapter;
  if (text) {
    elm.innerHTML = text;
    this.activity = true;
  } else {
    this.activity = false;
  }
};

Chapterion.init = function() {
  const self = this;
  const header = document.querySelector("header");

  document.querySelectorAll("div.reveal section").forEach(function(section, i) \
{
    let elm = document.createElement("div");
    self.chapters.push(new Chapterion.Chapter(section, i, elm));
    header.appendChild(elm);
  });
};

Chapterion.flip = function(event) {
  let newChapterIndex = event.currentSlide.dataset.chapterIndex;
  if (! newChapterIndex) {
    newChapterIndex = event.currentSlide.offsetParent.dataset.chapterIndex;
  }
  if (newChapterIndex == this.current.c) return;
  this.chapters.forEach(function(chapter) {
    const section = chapter.section;
    if (chapter.activity && chapter.index == newChapterIndex) {
      console.log('ADD', newChapterIndex, chapter.index);
      chapter.elm.classList.add('shown');
    } else {
      console.log('REM', newChapterIndex, chapter.index);
      chapter.elm.classList.remove('shown');
    }
  });
  this.current.c = newChapterIndex;
};

スタイルシート

スタイルはこんな感じで。チャプターは HTML 的には header 要素です。

chapter.css
header {
  clear: both;

  position: absolute;
  top: 5px;
  left: 5px;

  z-index: 20;
}

header div {
  text-align: center;

  color: #fff;

  transition: all 300ms 0s ease-in;

  font-family: "Source Sans Pro", Helvetica, sans-serif;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: normal;
  text-transform: uppercase;
  text-shadow: none;

  word-wrap: break-word;

  display: block;

  font-size: 0em;
}

header div.shown {
  font-size: 2.5em;

  margin: 0 auto;
  padding: 10px;

  box-shadow: 1px 2px 3px #000;
  border-radius: 15px;
  background-color: rgba(0, 255, 0, 0.3);
}

Markup/Markdown

プレゼンの html はこんな感じで。
chapter にしたい文字列を sectiondata-chapter 属性として書いときます。
この section 内では Markdown で複数のスライドを書きます。

index.html
    <section data-chapter="麦・大豆&野菜"
             data-markdown
             data-separator="^\n---\n$"
             data-separator-vertical="^\n>>>\n$">

あ、上記 css をリンクして、上記 js を読み込んでおくのは、もちろん忘れずに。
Chapterion.init(); で初期化して、あとは slidechagenged イベントを拾って Chapterion.flip() を呼ぶだけです。

index.html
 <script src="js/reveal.js"></script>
  <script src="js/echi5c.js"></script>

  <script>
   // More info about config & dependencies:
   // - https://github.com/hakimel/reveal.js#configuration
   // - https://github.com/hakimel/reveal.js#dependencies
   Reveal.initialize({
    dependencies: [
     { src: 'plugin/markdown/marked.js' },
     { src: 'plugin/markdown/markdown.js' },
     { src: 'plugin/notes/notes.js', async: true },
     { src: 'plugin/zoom-js/zoom.js', async: true },
    ],
    parallaxBackgroundImage: "mugi.jpg",
    parallaxBackgroundHorizontal: 220,
    parallaxBackgroundVertical: 100
   });

   Chapterion.init();

   Reveal.addEventListener('slidechanged', function(event) {
     Chapterion.flip(event);
   });
  </script>
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.