35

I Would like to determine the size of the browser window in Shiny to help me layout my plot divs better. Specifically I would like to determine the aspect ratio of the window to see how many divs I should spread across the screen and it still look nice. My initial thought would be that the number of plots would be floor(width/(height-navbar_height)).

I did some looking for this and I am currently unable to locate a possible solution and am currently lead to believe that this feature is simply not present in the clientData structure. Any thoughts?

Justace Clutter
  • 2,097
  • 3
  • 18
  • 31

3 Answers3

39

See the example below. It uses Javascript to detect the browser window size (initial size and any resize), and use Shiny.onInputChange to send the data to the server code for processing. It uses shiny:connected event to get the initial window size, as Shiny.onInputChange is not ready for use until shiny is connected.

library(shiny)

# Define UI for application that draws a histogram
ui <- shinyUI(fluidPage(

   # Application title
   titlePanel("Old Faithful Geyser Data"),

   # Sidebar with a slider input for number of bins 
   sidebarLayout(
      sidebarPanel(
         tags$head(tags$script('
                                var dimension = [0, 0];
                                $(document).on("shiny:connected", function(e) {
                                    dimension[0] = window.innerWidth;
                                    dimension[1] = window.innerHeight;
                                    Shiny.onInputChange("dimension", dimension);
                                });
                                $(window).resize(function(e) {
                                    dimension[0] = window.innerWidth;
                                    dimension[1] = window.innerHeight;
                                    Shiny.onInputChange("dimension", dimension);
                                });
                            ')),
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30)
      ),

      # Show a plot of the generated distribution
      mainPanel(
         verbatimTextOutput("dimension_display"),
         plotOutput("distPlot")
      )
   )
))

# Define server logic required to draw a histogram
server <- shinyServer(function(input, output) {
   output$dimension_display <- renderText({
       paste(input$dimension[1], input$dimension[2], input$dimension[2]/input$dimension[1])
   })

   output$distPlot <- renderPlot({
      # generate bins based on input$bins from ui.R
      x    <- faithful[, 2] 
      bins <- seq(min(x), max(x), length.out = input$bins + 1)

      # draw the histogram with the specified number of bins
      hist(x, breaks = bins, col = 'darkgray', border = 'white')
   })
})

# Run the application 
shinyApp(ui = ui, server = server)
Xiongbing Jin
  • 11,779
  • 3
  • 47
  • 41
  • Thanks for this. Sorry it took so long to check. It seems though that there would be a better place to add this outside of the sidebarPanel. For instance, right after the fluidPage call. – Justace Clutter May 08 '16 at 04:52
  • It does not matter where you add the Javascript though, as the Javascript will appear in the `head` section of the HTML regardless (as we used `tags$head`). You can verify the source code of the html page. – Xiongbing Jin May 08 '16 at 20:30
  • This javascript snippet gives me the following error: "Warning: Error in if: argument is of length zero" – rcorty Oct 14 '20 at 14:38
3

There is a new and much simpler way to do this since 2021: using the {shinybrowser} package. Example:

library(shiny)

ui <- fluidPage(
  shinybrowser::detect(),
  "Window size:",
  textOutput("size")
)

server <- function(input, output, session) {
  output$size <- renderText({
    paste(
      shinybrowser::get_width(),
      "x",
      shinybrowser::get_height()
    )
  })
}

shinyApp(ui, server)

Note that {shinybrowser} is currently on GitHub only and not yet on CRAN (should be in the near future). Note also that {shinybrowser} only gives you the initial dimensions, but will not update if the browser is resized.

DeanAttali
  • 25,268
  • 10
  • 92
  • 118
  • Yes that's correct. The question did not mention if this needs to be re-calculated on browser resize or if just once. I'll add a comment to my answer to mention this drawback. – DeanAttali May 27 '21 at 07:56
  • 1
    It's not yet, I want to get more people testing it before. But I did open a github issue based on this discussion to look into making the dimensions truly reactive – DeanAttali May 27 '21 at 19:24
-2

Shorter version for getting window dimensions in shiny with JS from package htmlwidgets:

window_height <- JS('window.innerHeight')
window_width <- JS('window.innerWidth')
JaKu
  • 1,096
  • 16
  • 29