こういう機能が欲しかったので作ってみた。
R Markdownが読み込んでいるもの
R Markdownの基本outputであるhtml_documentには、Bootstrapというデザインワークフレームが組み込まれています。その関係で、jQueryも合わせて読み込まれています。したがって、意図的に除去しない限りはこれら2つは標準で利用可能となっています。
これら2つが使えるということは、Webにおけるいろいろな要素を簡単に組み込むことができます。そこで今回は、Webでもよく見かける「あるエリアの表示/非表示をボタンで切り替える」というのを実装します。
目標
- ボタンをクリックすると、狙ったエリアが表示/非表示される
- 表示/非表示の状態にあわせてボタンのテキストも変化
- 表示/非表示エリアがページ内に複数あっても対応可能
- 汎用性が高い(他のRmdでもコピペですぐ使える)コード
- 極力Rmdファイル内にhtmlタグを使用しない
なんかハードル高いですが、やるからには…
実装
できました。サンプルとして、以下の内容を含むRmdファイルを準備すればいけます:
## エクササイズ
### 問題1
irisの先頭から3行分を出力せよ。
<button type="button" class="btn btn-primary ansBtn"></button>
### 問題1の解答例 {.ans}
````{r}
head(iris, 3)
```
### 問題2
irisの末尾から3行分を出力せよ。
<button type="button" class="btn btn-primary ansBtn"></button>
### 問題2の解答例 {.ans}
```{r}
tail(iris, 3)
```
## 仕込んだjsコード
```{js}
$(function(){
$(".ans").hide();
$(".ansBtn").text("答えを表示");
$(".ansBtn").click(function(){
var index = $(".ansBtn").index(this);
if($(".ans").eq(index).is(":visible")){
$(".ans").eq(index).hide();
$(".ansBtn").eq(index).text("答えを表示");
}else{
$(".ans").eq(index).show();
$(".ansBtn").eq(index).text("答えを隠す");
};
});
});
```
以下のような感じになります:
検証してもらえるとわかるのですが、先ほどの条件は全てクリアしています。
実装手順
以下の手順でやればOKです。
切り替えるターゲット用のclass属性とボタンのclass属性を決める
まず、この2つを決定します。今回の実装方法では、表示/非表示を切り替えるエリアには統一したclass属性を付与させる必要があります。今回はいわゆるエクササイズの解答エリアを表示/非表示にしたかったという設定なので、.ans
という属性にしてみました。
また、ボタンにも統一したclass属性を付与させる必要があります。今回は解答エリアのボタンということで、.ansBtn
としました。
切り替えるターゲットの見出しにクラスを付与
これはPandocの機能を活用しています。PandocはR Markdownでmdから各種出力形式へとドキュメントを変換するソフトウェアです。rmarkdownはこれを使ってドキュメントを生成しています。
さて、Pandoc拡張Markdownには、heading(#とか##とか)の行末に{.ans}
のように{}
をつけると、それがそのブロックを覆うdivエリアにclass属性を付与します。詳しくは以下の記事などを眺めてください:
- R Markdownで使えるMarkdown記法 - Qiita
- RStudioの"knit HTML"でPandocに送っている内容 - Qiita
- R MarkdownでBootstrapのグリッドシステムを利用する - Qiita
というわけで、今回の例の設定では「解答エリアをターゲットにしたい」わけなので、以下のようにしました:
### 問題1の解答例 {.ans}
(以下ターゲットの内容)
こうすることでターゲットとして設定することができます。
ボタン用htmlタグを準備
表示/非表示を切り替えるためのボタンを設置します。R MarkdownはBootstrapが組み込まれているので、ボタンも簡単に実装できます:
<button type="button" class="btn btn-primary ansBtn"></button>
これを、隠すエリアの直前に差しこめばOKです。なおclass
属性のbtn btn-primary
についてはBootstrapでのボタン実装に関するところなので、詳しく知りたい方はBootstrap関連のドキュメントを検索してください。
jsコードを準備
以上でドキュメント側の準備ができたので、jQueryのスクリプトをドキュメントの最後に記述します。通常なら<script>
タグを使って記述するところですが、せっかくのRmdファイルなのでjsチャンクでやりました。
このjQueryのコードについての解説は省きます。なにせjQueryというかJavaScript自体もまともに書けない人間なので…。
留意点
いくつかあります。
ボタンと切り替えのターゲットは必ず1対1にする
今回の実装では、「上から何番目のボタンが押されたか」という番号を元に、「表示/非表示を切り替える対象のindex」を指定しています。なので、ボタン設置し忘れや入れるはずの領域に該当クラスが付与されてない場合はずれてしまいます。自分の能力不足で、現状このあたりまででした。。
jsコードの仕込み方
実際にやるなら、jsの部分は見えないようにしたほうがいいと思います。
一番いいのは、その該当箇所を別ファイル(html)で切り出し、その中で<script>
タグで挟み込んだものを準備し、それをRmdのyaml front matterでhtmlファイルをincludesで指定する方法です。この方法なら、他のドキュメントへの使い回しも簡単ですし、コストがぐっと下がります。
このあたりについては、R Markdownの公式サイトを検索してください。
雑感
自分の中で模索してたエクササイズ用のドキュメント作りが、これである程度落ち着きそうです。あと個人的に、もうちょっとR Markdownの潜在能力を引き出せたらなぁと思ってます。ぼちぼちやっていきます。
Enjoy!