rintrojsでShinyアプリにヒント表示を追加する


R Shiny Advent Calendar 2018 3日目の記事[『rintrojsでShinyアプリにチュートリアル機能を追加する』](https://qiita.com/terashim/items/94e05ec181b7870129ce) に引き続き、[rintrojs](https://cran.r-project.org/web/packages/rintrojs/)パッケージを利用してShinyアプリのUIにヒント表示を加える方法を紹介します。

## デモ

こちらに [デモアプリ](https://terashim.shinyapps.io/shiny-example-hintjs/) を用意しました。

### 画面の動き

![ヒント表示ボタンが追加された画面](https://qiita-image-store.s3.amazonaws.com/0/78813/ae351966-cc87-1871-9463-6d1e47101f06.png)

UIの各部に丸い形のヒント表示ボタンがあります。

![ヒント表示の様子](https://qiita-image-store.s3.amazonaws.com/0/78813/01bb1d9c-b736-23b2-c8be-a2bbdbe5cef2.png)

ヒント表示ボタンをクリックするとふきだしが現れてヒントの内容が表示されます。
注意点として、**ふきだしの中にある「了解」ボタンをクリックすると、ふきだしが閉じるだけでなくヒント表示ボタンも消えてしまい、ふたたび表示させることができなくなってしまいます**。

![ヒント表示ボタンを消したところ](https://qiita-image-store.s3.amazonaws.com/0/78813/b7b1cc4d-f6b3-cd41-4fc1-de75f806a0d8.png)

ヒント表示ボタンが消えてしまうと同じ説明をもう一度見たいと思っても見ることができなくなってしまう（ブラウザで再読み込みすれば復活しますが）ので、このヒント機能は一度ユーザーの目に触れれば十分というような軽い説明に使うと良いでしょう。

## サンプルコード

デモアプリのソースコードは以下のようになっています

### app.R

```r
library(shiny)
library(rintrojs)

# アプリケーションのUIを定義
ui <- fluidPage(
  
  introjsUI(), # これをUI定義のどこかに含める
  
  # アプリケーションのタイトル
  titlePanel("ヒント表示を追加"),
  
  sidebarLayout(
    # サイドバー
    sidebarPanel(
      introBox( # ヒント表示を追加したい要素を囲む
        # スライダー
        sliderInput("bins", "ビンの数:", min = 1, max = 50, value = 30), # ヒントが追加される要素
        data.hint = "このスライダーを動かしてビンの数を変更してください" # ヒントのメッセージ
      )
    ),
    
    # メインパネル
    mainPanel(
      introBox( # ヒント表示を追加したい要素を囲む
        plotOutput("distPlot"), # ヒントが追加される要素
        data.hint = "スライダーの値に合わせてこのヒストグラムが変化します" # ヒントのメッセージ
      )
    )
  )
)

# サーバー側ロジックを定義
server <- function(input, output, session) {
  
  output$distPlot <- renderPlot({
    # ui.Rから来た input$bins に基づいてビンを生成
    x    <- faithful[, 2] 
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    
    # 指定のビン数でヒストグラムを描画
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
  
  # ヒント表示を有効化
  hintjs(
    session,
    # オプション設定
    options = list(
      hintPosition = "top-left", # ヒントの表示位置
      hintButtonLabel = "了解" # ボタンのラベル
    )
  )
}

# アプリケーションを起動する
shinyApp(ui = ui, server = server)
```

これを起動すると[デモ](https://terashim.shinyapps.io/shiny-example-hintjs/)と同じものが開始します。

### ポイント

ヒントを付けたいUI要素を `introBox()` で囲み、引数 `data.hint` にヒントのメッセージを与えます。

```ｒ
      introBox( # ヒント表示を追加したい要素を囲む
        plotOutput("distPlot"), # ヒントが追加される要素
        data.hint = "スライダーの値に合わせてこのヒストグラムが変化します" # ヒントのメッセージ
      )
```

サーバー側では、 `hintjs()`関数を加えます。このとき`session`を引数に与える必要があります。

```r
server <- function(input, output, session) {
  
  # ...省略...
  
  # ヒント表示を有効化
  hintjs(
    session,
    # オプション設定
    options = list(
      hintPosition = "top-left", # ヒントの表示位置
      hintButtonLabel = "了解" # ボタンのラベル
    )
  )
}
```

オプションについては[intro.jsの公式ドキュメント](https://introjs.com/docs/hints/options/)を参照ください。

-----

以上、rintrojsパッケージを利用してShinyアプリにヒント表示を追加する方法についてご紹介しました。
サンプルコードはGitHub [terashim/shiny-example-hintjs](https://github.com/terashim/shiny-example-hintjs) でも公開しています。

### 蛇足

前述のように、`rintrojs`パッケージと`hintjs()`関数を利用した方法で実装したヒントは一度消してしまうと再表示できなくなってしまうので、繰り返し見られるようにしたい場合には不便です。
そこで、マウスオーバーでツールチップが表示できるような方法がないかと調査していたところ [tippy](https://tippy.john-coene.com/) というパッケージを発見しました。こちらを利用すればShinyやR Markdownでツールチップが利用できるようになるとのことです。これについてはまた別記事にまとめる予定です。

12/9 追記: [こちら](https://qiita.com/terashim/items/78ca99ed45113f7598e2) にまとめました。