-
Notifications
You must be signed in to change notification settings - Fork 30
/
server.R
214 lines (195 loc) · 7.72 KB
/
server.R
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
210
211
212
213
server <- function(input, output, session) {
# Add pdf folder as ResourcePath
addResourcePath(prefix = "pdf", directoryPath = file.path("images", "pdf"))
# Filter keyboard options based on filter options
observe({
keyboardNames <- getFilteredKeyboardNames(input, keyboards)
updatePrettyCheckboxGroup(
session = session,
inputId = "keyboard",
choices = keyboardNames,
prettyOptions = list(shape = "curve", outline = TRUE, animation = "pulse")
)
})
# Set initial starting layout based on url parameter
observeEvent("",
{
query <- parseQueryString(session$clientData$url_search)
keyboardQuery <- query[["keyboards"]]
if (is.null(keyboardQuery)) {
keyboardNames <- "kyria"
} else if (grepl(";", keyboardQuery)) {
keyboardNames <- strsplit(keyboardQuery, ";")[[1]]
} else {
keyboardNames <- keyboardQuery
}
updatePrettyCheckboxGroup(
session = session,
inputId = "keyboard",
choices = keyboards$nameKeys,
selected = keyboards$nameKeys[which(keyboards$id %in% keyboardNames)],
prettyOptions = list(shape = "curve", outline = TRUE, animation = "pulse")
)
},
once = TRUE
)
# Render keyboard table on "Keyboards" page
output$keyboardsDT <- DT::renderDataTable({
DT::datatable(
keyboardsDT,
escape = FALSE,
style = "bootstrap",
rownames = FALSE,
options = list(pageLength = 50)
)
})
# Control reset button
observeEvent(input$reset,
{
updateSliderInput(
session = session,
inputId = "numKeys",
value = c(min(keyboards$nKeysMin), max(keyboards$nKeysMax))
)
updateSliderInput(
session = session,
inputId = "numRows",
value = c(min(keyboards$numRows), max(keyboards$numRows))
)
updatePrettyCheckboxGroup(
session = session,
inputId = "keyboard",
choices = keyboards$nameKeys
)
pickerIds <- c(
"hasNumRow", "colStagger", "rowStagger", "rotaryEncoder",
"wireless", "onePiece", "availability", "switchType",
"openSource"
)
for (id in pickerIds) {
updatePickerInput(
session = session,
inputId = id,
selected = character(0)
)
}
},
ignoreInit = TRUE
)
# Control Select All button
observeEvent(
input$selectAll,
{
# Select all displayed (filtered) keyboards
# Identical to filtering step but also set selected=`choices list`.
keyboardNames <- getFilteredKeyboardNames(input, keyboards)
updatePrettyCheckboxGroup(
session = session,
inputId = "keyboard",
choices = keyboardNames,
selected = keyboardNames,
prettyOptions = list(shape = "curve", outline = TRUE, animation = "pulse")
)
},
ignoreInit = TRUE
)
selectedIDs <- reactive({
return(keyboards[which(keyboards$nameKeys %in% input$keyboard), ]$id)
})
# Create joint overlay image
# If IDs isn't given, then uses the usual all-selected But can also get just
# a subset of (selected) keyboards
makeImageOverlay <- function(images, palette, color = FALSE, IDs = selectedIDs()) {
if (length(IDs) > 0) {
if (color) {
return(getImageOverlayColor(IDs, images, palette))
} else {
return(getImageOverlay(IDs, images))
}
}
return(images$scale_black)
}
# Render overlay image
output$layout <- renderImage(
{
# Create the color image overlay
overlayColor <- makeImageOverlay(images, palette, color = TRUE)
# Mirror when left half is selected.
if (input$keyboardHalf == "Left (mirrored)") {
overlayColor <- image_flop(overlayColor)
}
# Define the path to the image
tmpImagePathColor <- overlayColor %>%
image_write(tempfile(fileext = "png"), format = "png")
# Render the file
return(
list(
src = tmpImagePathColor,
width = 700,
alt = "Keyboard layout",
contentType = "image/png"
)
)
},
deleteFile = TRUE
)
# Download overlay images
output$printFile <- downloadHandler(
filename = function() {
selectedIDs_filename <- paste(selectedIDs(), collapse = "_")
# Magic number but avoid crazily long output filename if many
# keyboards. Could probably be set even smaller
if (length(selectedIDs()) > 5) selectedIDs_filename <- "many"
paste0("compare_", selectedIDs_filename, "_", input$printSize, ".pdf")
},
content = function(file) {
# Copy the file to a temporary directory before processing it,
# in case we don't have write permissions to the current dir
# (which can happen when deployed).
tempReport <- file.path(tempdir(), "print.Rmd")
file.copy(
file.path("code", paste0("print", input$printSize, ".Rmd")),
tempReport,
overwrite = TRUE
)
# Want to support one-page all-overlapping visualization as well
# as single keyboards. So pass a list of {keyboard groups} where
# a keyboard group can have any number of keyboards
# Default is one big group so one list of list
# If only one selected, all overlay = separate page anyway,
# so don't print redundant page even if sepPages is set
if (input$printSepPages == FALSE || length(selectedIDs()) == 1) {
id_groups <- list(selectedIDs())
} else {
# First page is all overlay like normal
# Then subsequent pages is each keyb individually
id_groups <- c(list(selectedIDs()), selectedIDs())
}
# Hold path to the image generated for each id_group
id_group_paths <- c()
for (gp in id_groups) {
# Create the black and white image overlay
overlayBw <- makeImageOverlay(images, palette, color = FALSE, IDs = gp)
# Mirror when left half is selected.
if (input$keyboardHalf == "Left (mirrored)") {
overlayBw <- image_flop(overlayBw)
}
# Define the path to the image
tmpImagePathBw <- overlayBw %>%
image_write(tempfile(fileext = ".png"), format = "png")
id_group_paths <- c(id_group_paths, tmpImagePathBw)
}
# Prepare the path to be passed to the Rmd file
params <- list(path = id_group_paths)
# Knit the document, passing in the `params` list, and eval it
# in a child of the global environment (this isolates the code
# in the document from the code in this app).
rmarkdown::render(
tempReport,
output_file = file,
params = params,
envir = new.env(parent = globalenv())
)
}
)
}