0

I build a dynamic UI and want to position an element (say, a button) on the screen, based on some data available at runtime.

for example, if the value of input$x is F then put the button at 90% of the window width and 50% of window height (e.g. middle right of the visible window), but if input$x is T then put the same button somewhere else say bottom-right corner).

For this I might also need to extract information on the window itself.

Any ideas how this can be done?

amit
  • 3,332
  • 6
  • 24
  • 32
  • Have you tried `conditionalPanel`? – amrrs Feb 16 '18 at 09:06
  • I need to do it in a uiOutput for other reaons. regardless, how this would have solved my problem? I think the main challenge (for me, at least) is the ability to put an element in an absolute/relative position on the window, regardless of the other elements put on it – amit Feb 16 '18 at 09:12

1 Answers1

1

You can get the dimensions of the window as input using some JavaScript. (Related SO question)

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);
      });
  '))

After including this script, you can access input$dimensions, as a 2 element vector in shiny (containing width and height).

So you can introduce an observer that uses input$dimension, and create custom CSS based on that:

observe( {
    if (input$slt == "TRUE") {
      # put the button at bottom right corner
      output$ui <- renderUI( {
        margin_left <- input$dimension[1] * 0.8  # 80% off left
        margin_top <- input$dimension[2] * 0.8   # 80% off top
        actionButton("btn", "Moving button at bottom",
                     style = sprintf("position: absolute; left: %spx; top: %spx;", margin_left, margin_top))
      })
    } else {
      # put the button at middle right
      output$ui <- renderUI( {
        margin_left <- input$dimension[1] * 0.8  # 80% off left
        margin_top <- input$dimension[2] * 0.5   # 50% off top
        actionButton("btn", "Moving button at middle",
                     style = sprintf("position: absolute; left: %spx; top: %spx;", margin_left, margin_top))
      })
    }
  })

Not sure how useful it is though. For example when placing an element at the far right it's better to use something like: "right: 0px;".

GyD
  • 3,902
  • 2
  • 18
  • 28