1

Using a Shiny app, I would like to implement a slider with slickR to switch from one image to the other.

I managed to implement the slider but I'm having trouble in displaying the images correctly because of their different sizes. In the following example, the stackexchange logo is way bigger than the stackoverflow logo. When displaying them with slickR(), the bigger logo makes inroads into the first one like this:

enter image description here

I would also like to have the size of the pictures relative to the size of the screen.

Here is a reproducible example of the Shiny app used to generate the above image:

library(shiny)
library(slickR)

# User interface ----
ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      
    ),
    
    mainPanel(
      slickROutput("slickr", width = "auto")
    )
  )
)

# Server ----
server <- function(input, output) {
  
  imgs_links <- list(
    "https://upload.wikimedia.org/wikipedia/fr/9/95/Stack_Overflow_website_logo.png",
    "https://upload.wikimedia.org/wikipedia/commons/6/6f/Stack_Exchange_Logo.png")
  
  output$slickr <- renderSlickR({
    
    photo_list <- lapply(imgs_links, function(x){
      tags$div(
        tags$img(src = x, width = "10%", height = "10%")
      )
    })
    
    imgs <- do.call(tagList, photo_list)
    slickR(imgs)
  })
}

# Run the application ----
shinyApp(ui = ui, server = server)

What would be the correct way to have each image resized according the size of the screen?

ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
P. Denelle
  • 790
  • 10
  • 24

1 Answers1

0

I don't manage to get it with the 'slickR' package. Here is a solution which doesn't use this package, it uses the 'slick' JavaScript library. You have to download the library files and put them in the www/slick-1.8.1/slick folder.

library(shiny)

ui <- fluidPage(
  tags$head(
    tags$link(rel="stylesheet", type="text/css",
              href="slick-1.8.1/slick/slick-theme.css"),
    tags$link(rel="stylesheet", type="text/css",
              href="slick-1.8.1/slick/slick.css"),
    tags$script(type="text/javascript", 
                src="slick-1.8.1/slick/slick.js"),
    tags$script(HTML(
      "$(document).ready(function(){
  $('#images').slick({
    arrows: true,
    dots:true
  });
});")),
    tags$style(HTML(
      "#images .slick-prev {
    position:absolute;
  top:65px; 
  left:-50px;
}
#images .slick-next {
  position:absolute;
  top:95px; 
  left:-50px;
}
.slick-prev:before, .slick-next:before { 
    color:red !important;
    font-size: 30px;
}
.content {
    margin: auto;
    padding: 2px;
    width: 90%;
}"))
  ),
  
  sidebarLayout(
    
    sidebarPanel(
      ####
    ),
    
    mainPanel(
      tags$div(
        class = "content",
        tags$div(
          id = "images", 
          tags$img(
            src = "https://upload.wikimedia.org/wikipedia/fr/9/95/Stack_Overflow_website_logo.png",
            width = "50vw"
          ),
          tags$img(
            src = "https://upload.wikimedia.org/wikipedia/commons/6/6f/Stack_Exchange_Logo.png",
            width = "50vw"
          )
        )
      )
    )
  )
)

server <- function(input, output) {
  
}

# Run the application 
shinyApp(ui = ui, server = server)

enter image description here


EDIT: dynamic number of images

library(shiny)

ui <- fluidPage(
  tags$head(
    tags$link(rel="stylesheet", type="text/css",
              href="slick-1.8.1/slick/slick-theme.css"),
    tags$link(rel="stylesheet", type="text/css",
              href="slick-1.8.1/slick/slick.css"),
    tags$script(type="text/javascript", 
                src="slick-1.8.1/slick/slick.js"),
    tags$style(HTML(
      "#carousel .slick-prev {
    position:absolute;
  top:65px; 
  left:-50px;
}
#carousel .slick-next {
  position:absolute;
  top:95px; 
  left:-50px;
}
.slick-prev:before, .slick-next:before { 
    color:red !important;
    font-size: 30px;
}
.content {
    margin: auto;
    padding: 2px;
    width: 90%;
}"))
  ),
  
  sidebarLayout(
    
    sidebarPanel(
      checkboxGroupInput(
        "images",
        "Select images",
        choiceNames = c("Stackoverflow", "Stackexchange", "Asymptote"),
        choiceValues = c(
          "https://upload.wikimedia.org/wikipedia/fr/9/95/Stack_Overflow_website_logo.png",
          "https://upload.wikimedia.org/wikipedia/commons/6/6f/Stack_Exchange_Logo.png",
          "https://www.clipartmax.com/png/small/203-2038151_asymptote-vector-graphics-language-wikipedia-rh-en-asymptote.png"
        )
      )
    ),
    
    mainPanel(
      tags$div(
        class = "content",
        uiOutput("carousel-ui"),
      )
    )
  )
)

server <- function(input, output) {
  
  output[["carousel-ui"]] <- renderUI({
    imgs <- lapply(input[["images"]], function(x){
      tags$img(src = x, width = "50vw")
    })
    imgs_div <- do.call(function(...) div(id = "carousel", ...), imgs)
    script <- tags$script(HTML(
    "$('#carousel').slick({
      arrows: true,
      dots:true
    });"))
    do.call(tagList, list(imgs_div, script))
  })
  
}

# Run the application 
shinyApp(ui = ui, server = server)

enter image description here

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • Thanks the codes does work but in the app I'm making, I never know how much images I have (their numbers depend on another variable). Would it be possible to adapt the part in `ui.R` when you call the source of each image (`tags$img(src = "blabla", width = "50vw")`) so you don't have to specify the name of each figure? – P. Denelle Jan 19 '21 at 14:05
  • I just validated your answer. Thank you also for the edit. It's not exactly what I envisioned since you still specify the names of each image. In my app, I never know how many images I get. I have something like this in `server.R` :`output$selected_sp_photo <- renderSlickR({ photo_list <- lapply(sp_infos$images, function(x){ tags$div(tags$img(src = x, width = "20%", height = "20%")) }) imgs <- do.call(tagList, photo_list) slickR(imgs) }) ` and in `ui.R` `slickROutput("selected_sp_photo", width = "400")` – P. Denelle Jan 21 '21 at 08:13