-
Notifications
You must be signed in to change notification settings - Fork 29
/
understanding_sortable_js.Rmd
209 lines (152 loc) · 5.26 KB
/
understanding_sortable_js.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
---
title: "Understanding the interface to sortable.js"
author: "Andrie de Vries and Kenton Russell"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
description: >
Understanding the key idea of `sortable.js` will help you to write your own custom sortable widgets.
vignette: >
%\VignetteIndexEntry{Understanding the interface to sortable.js}
%\VignetteEngine{knitr::rmarkdown}
%\usepackage[utf8]{inputenc}
---
```{r, echo = FALSE}
## get knitr just the way we like it
knitr::opts_chunk$set(
message = FALSE,
warning = FALSE,
error = FALSE,
tidy = FALSE,
cache = FALSE
)
```
```{css, echo=FALSE}
pre {
max-height: 20em;
overflow-y: auto;
}
pre[class] {
max-height: 20em;
}
```
With the `sortable` [`htmlwidget`](http://www.htmlwidgets.org) you can use powerful, dependency-free interactivity from [`SortableJS`](https://sortablejs.github.io/Sortable/) in the browser, RStudio Viewer, or Shiny apps.
```{r}
library(sortable)
library(htmltools)
```
## The central idea
The key idea to understand about `sortable`, and `SortableJS` in particular, is that the JavaScript will manipulate an HTML object based on it's CSS `id`.
Using `sortable` in markdown is a little tricky since markdown does not provide an easy way to provide an `id` that we'll need. We can overcome this by using bare `HTML` or using `htmltools::tags`. Let's make a simple `ul` list. Note, however, that `sortable` works with nearly any `HTML` element, such as `div`.
### An example using raw HTML
The following example uses HTML to construct an unordered list (`<ul>`), and then uses `sortable_js()` to link the JavaScript required to create interactivity.
Note:
1. The HTML `id` matches the `css_id` argument of `sortable_js()`.
2. You can drag and drop the list entries. Try it!
```html
<p>You can drag and drop these items in any order (try it!):</p>
<ul id = "example01">
<li>Move</li>
<li>Or drag</li>
<li>Each of the items</li>
<li>To different positions</li>
</ul>
```
````r
```{r}`r ''`
sortable_js(css_id = "example01")
```
````
<p>You can drag and drop these items in any order (try it!):</p>
<ul id = "example01">
<li>Move</li>
<li>Or drag</li>
<li>Each of the items</li>
<li>To different positions</li>
</ul>
```{r, echo=FALSE}
sortable_js(css_id = "example01")
```
### Use a tag list to achieve the same, but from R
You can use the functions `tags()` and `tagList()`, both from the `htmltools` package, to create HTML.
This means you can construct the sortable list using:
<!-- the following chunk fails to build on CRAN, so use raw code instead -->
```{r}
library(htmltools)
tagList(
tags$ul(
id = "example02",
tags$li("drag me"),
tags$li("sort me"),
tags$li("any way you like")
),
sortable_js("example02")
)
```
### Little harder but better example
The `SortableJS` functionality works with any HTML object, not just lists.
In this next example, you can see how to drag and drop images (`<img>`). To embed the plots on the page, you can use the `base64::img()` function to encode the png images into a format that HTML understands.
```{r}
library(base64enc)
library(withr)
# create two plots for demo purposes
pngfile_1 <- tempfile(fileext = ".png")
with_png(pngfile_1, width = 300, height = 200,{
plot(1:100, rnorm(100), pch = 21, bg = "red")
title(main = "Moves Like Jagger")
})
pngfile_2 <- tempfile(fileext = ".png")
with_png(pngfile_2, width = 300, height = 200,{
barplot(1:9, col = blues9)
title(main = "I Like the Way You Move")
})
```
Again, notice that the HTML `id` matches the `css_id`.
```{r}
tagList(
tags$div(
id = "example03",
tags$image(src = base64enc::dataURI(file = pngfile_1, mime = "image/png")),
tags$image(src = base64enc::dataURI(file = pngfile_2, mime = "image/png"))
),
sortable_js(css_id = "example03")
)
```
## The power of groups
Looking at the [`SortableJS`](https://github.com/SortableJS/Sortable#options) excites me about the potential to use `sortable` as an important UI element in both a Shiny and non-Shiny context. We could potentially demo a plot builder with something like this example. You'll notice that it doesn't really do anything, but I hope the intent and direction is clear.
```{r shiny-drag-vars-to-plot, eval=FALSE}
knitr::read_chunk(
system.file("shiny/drag_vars_to_plot/app.R", package = "sortable")
)
```
![](figures/drag_vars_to_plot.gif)
## Dragging and dropping shiny tabs
The `sortable` JS library allows movable tabs inside a Shiny (and also not Shiny) app.
By adding just one line of code and an `id` to this RStudio
[Tabset example](https://github.com/rstudio/shiny/tree/master/006-tabsets),
you get tabs that the user can re-arrange.
You can copy and paste to see it for yourself, or `runGist("2dbe45f77b65e28acab9")`.
The modified code snippet is:
```r
# Show a tabset that includes a plot, summary, and table view
# of the generated distribution
mainPanel(
tabsetPanel(
type = "tabs",
id = "sortTab",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
),
sortable_js("sortTab")
```
And the full code:
```{r echo=FALSE, cache=FALSE}
knitr::read_chunk(
system.file("shiny/shiny_tabset/app.R", package = "sortable")
)
```
```{r shiny-tabset-app, eval=FALSE}
```
![](figures/sortable_tabs.gif)