Nothing
suppressPackageStartupMessages({
library(shiny)
library(shinyjs)
library(shinydashboard)
library(shinyWidgets)
library(DT)
library(dplyr)
library(webmorphR)
})
imgdir <- getShinyOption("imgdir")
# tabs ----
## main_tab ----
main_tab <- tabItem(
tabName = "main_tab",
textOutput("quickhelp"),
#fluidRow(
#column(width = 6,
#actionButton("delin_clear", "Clear Points"),
actionButton("delin_reload", NULL, icon = icon("redo")),
actionButton("prev_img", NULL, icon = icon("step-backward")),
actionButton("delin_save", "Save", icon = icon("save")),
actionButton("next_img", NULL, icon = icon("step-forward")),
#),
#column(width = 6,
sliderTextInput("img_size", NULL,
selected = 100,
grid = FALSE,
post = "%",
choices = c(seq(10,100, 10), seq(200, 1000, 100))),
#)
#),
tags$div(id = "delin_box_box",
tags$div(id = "delin_box", imageOutput("delin_img", ))
)
)
# UI ----
ui <- dashboardPage(
skin = "blue",
dashboardHeader(title = "WebmorphR"),
dashboardSidebar(
sidebarMenu(
id = "tabs",
#menuItem("QuickDelin", tabName = "main_tab"),
hidden(downloadButton("tem_dl", "Templates")),
actionButton("delin_finish", "Save and Back to R"),
actionButton("delin_cancel", "Cancel without Saving"),
fileInput("finder_load", "Load Files", multiple = TRUE,
width = "100%", accept = c("image/*", ".tem")),
DTOutput("finder_table")
)
),
dashboardBody(
useShinyjs(),
tags$head(
tags$link(rel = "stylesheet", type = "text/css", href = "custom.css"),
tags$script(src= "https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"),
tags$script(src = "keycodes.js"),
tags$script(src = "custom.js")
),
#tabItems(
main_tab
#)
)
)
# server ----
server <- function(input, output, session) {
v <- reactiveValues()
if (!is.null(imgdir)) {
output$quickhelp <- renderText("Loading stimuli from webmorphR")
runjs("delin_clear();")
v$stimuli <- read_stim(imgdir)
v$delin_current <- 1
output$quickhelp <- renderText({
sprintf("%d images loaded", length(v$stimuli))
})
# hide desktop use functions
hide("finder_load")
hide("tem_dl")
}
## finder_load ----
observeEvent(input$finder_load, { debug_msg("finder_load")
# rename files to original names in tempdir
tdir <- dirname(input$finder_load$datapath[[1]])
file.rename(input$finder_load$datapath,
file.path(tdir, input$finder_load$name))
# load as stimlist
runjs("delin_clear();")
v$stimuli <- webmorphR::read_stim(tdir)
v$delin_current <- 1
show("tem_dl")
}, ignoreNULL = TRUE)
## finder_table ----
output$finder_table <- renderDT({
req(v$stimuli)
df <- data.frame(
file = names(v$stimuli)
)
# my_col <- rep('black', nrow(df))
# my_col[v$delin_current] <- 'white'
# my_bg <- rep('white', nrow(df))
# my_bg[v$delin_current] <- '#204969'
datatable(df, escape = TRUE,
rownames = FALSE,
selection = 'single',
options = dt_options()) #|>
# formatStyle(1, target = 'row',
# color = styleEqual(df$file, my_col),
# backgroundColor = styleEqual(df$file, my_bg))
})
## finder_table_rows_selected ----
observeEvent(input$finder_table_rows_selected, {
debug_msg("finder_table_rows_selected")
idx <- input$finder_table_rows_selected
if (length(idx) == 0) { return() }
v$delin_current <- idx
updateTabItems(session, "tabs", selected = "delin_tab")
})
## img_size ----
observeEvent(input$img_size, {
sprintf("resize = %f; delin_resize();",
input$img_size) |>
runjs()
})
# update save button on template change ----
observeEvent(input$pts, { debug_msg("pts change")
req(v$stimuli)
img <- v$stimuli[[v$delin_current]]
# check if same as delin
needs_saved <- TRUE
if (!is.null(img$points)) {
saved_pts <- apply(img$points, 2, c) |> c() |> round(1)
needs_saved <- !all(round(input$pts, 1) == saved_pts)
# debug_msg("input: ", str(input$pts))
# debug_msg("saved: ", str(saved_pts))
}
shinyjs::toggleClass("delin_save", "btn-danger", needs_saved)
})
## delin_img ----
output$delin_img <- renderImage({ debug_msg("delin_img")
req(v$stimuli)
img <- v$stimuli[[v$delin_current]]
# update size
w <- img$width * input$img_size/100
h <- img$height * input$img_size/100
js <- sprintf("$('#delin_img, #delin_box').css('width', %d).css('height', %d)", w, h)
runjs(js)
list(src = img$imgpath,
alt = "Image failed to render",
draggable = "false",
width = w,
height = h)
}, deleteFile = FALSE)
# draw tem points -----
observeEvent(v$delin_current, {
req(v$stimuli)
img <- v$stimuli[[v$delin_current]]
runjs("delin_clear();")
if (is.null(img$points)) {
output$quickhelp <- renderText("Hold down cmd/ctrl and shift to add points")
} else {
# add points with js
apply(img$points, 2, function(pt) {
sprintf("new_pt({originalEvent: {layerX: %f, layerY: %f}});",
pt[["x"]] * input$img_size / 100,
pt[["y"]] * input$img_size / 100) |>
runjs()
})
}
})
## delin_reload ----
observeEvent(input$delin_reload, {
req(v$stimuli)
img <- v$stimuli[[v$delin_current]]
runjs("delin_clear();")
# add points with js
if (!is.null(img$points)) {
apply(img$points, 2, function(pt) {
sprintf("new_pt({originalEvent: {layerX: %f, layerY: %f}});",
pt[["x"]] * input$img_size / 100,
pt[["y"]] * input$img_size / 100) |>
runjs()
})
}
})
## delin_clear ----
observeEvent(input$delin_clear, {
runjs("delin_clear();")
})
# next_img ----
next_img <- function() {
# increment image
if (v$delin_current >= length(v$stimuli)) {
v$delin_current <- 1
} else {
v$delin_current <- v$delin_current + 1
}
}
observeEvent(input$next_img, { next_img() })
# prev_img ----
observeEvent(input$prev_img, {
if (v$delin_current == 1) {
v$delin_current <- length(v$stimuli)
} else {
v$delin_current <- v$delin_current - 1
}
})
# delin_save ----
observeEvent(input$delin_save, {
# add delin to v$stimuli
v$stimuli[[v$delin_current]]$points <-
matrix(input$pts, 2, dimnames = list(c("x", "y")))
next_img()
})
## tem_dl ----
output$tem_dl <- downloadHandler(
filename = function() {
debug_msg("tem_dl")
"tems.zip"
},
content = function(file) {
tryCatch({
# change wd to tempdir for zipping
oldwd <- getwd()
on.exit(setwd(oldwd))
tdir <- tempfile()
write_stim(v$stimuli, tdir, overwrite = TRUE)
setwd(tdir)
utils::zip(file, list.files(pattern = "\\.tem$"))
}, error = function(e) {
alert(e)
})
},
contentType = "application/zip"
)
# delin_finish ----
observeEvent(input$delin_finish, {
if (!is.null(imgdir)) {
debug_msg("writing stimuli to ", imgdir)
write_stim(v$stimuli, imgdir, overwrite = TRUE)
}
# clean up and signal done
hide("delin_img")
runjs("delin_clear();")
showModal(modalDialog(title = "Images saved and returning to R",
"You can close this app now."))
stopApp()
})
# delin_cancel ----
modal_quit_confirm <- modalDialog(
"This will not save any changes you made to the delineations.",
title = "Cancel without Saving",
footer = tagList(
actionButton("quit_cancel", "Return to Delineator"),
actionButton("quit_ok", "Cancel without Saving", class = "btn btn-danger")
)
)
observeEvent(input$delin_cancel, { showModal(modal_quit_confirm) })
observeEvent(input$quit_cancel, removeModal())
observeEvent(input$quit_ok, {
removeModal()
stopApp()
})
} # end server()
shinyApp(ui, server)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.