0

Is there a way (in pure Shiny) to check if an element is visible on screen (display : block), in the same way JScript does with "is.visible" ?

Here is a reproductible example of my problem :

library(shiny)
library(leaflet)
library(leaflet.extras)
library(tidyverse)
library(sf)
library(shinyjs)


#Create T0New data
lat <- c(49.823, 49.823, 58.478, 57.478, 45.823)
lng <- c(-10.854,-14.854,-10.854,2.02,2.02)
date <- c(123,125,135,168,149)
cat <-c("A","A","A","B","B")
type <- c("x","x","y","z","w")
col <- c("red","red","purple","green","turquoise")
T0New <- data.frame(lat,lng,date,cat,type,col)



ui <- fluidPage(
  useShinyjs(),

  tags$style("
             p{
             display:contents 
             }
             .show{
             display: block 
             }
             .hide{
             display: none !important
             }
             "),


      column(width = 3,
             HTML(' 
                  <div class="attr-col shiny-input-radiogroup" id="conf">

                      <input type="radio" id="A" name="conf" value="A" checked= "checked"/>
                      <label for="A">A</label>
                          <svg height="10" width="10">
                          <polygon points="0 0, 10 0, 10 10, 0 10" id="AToggle" />
                          </svg>
                      <br/>

                      <div id = "ALegend" class style = " display: none;" >
                          <svg height="10" width="10"><circle cx="5" cy="5" r="5" fill="red" /></svg>
                          <p>x </p>
                          </br>
                          <svg height="10" width="10"><circle cx="5" cy="5" r="5" fill="purple" /></svg>
                          <p> y </p>
                      </div>

                      <div id = "ALegendBoxes" class style = " display: none;" >
                          <input type="checkbox" id="x" name="x" checked>
                          <svg height="10" width="10"><circle cx="5" cy="5" r="5" fill="red" /></svg> 
                          <label for="x">x</label>
                          </br>
                          <input type="checkbox" id="y" name="y" checked>
                          <svg height="10" width="10"><circle cx="5" cy="5" r="5" fill="purple" /></svg>
                          <label for="Séculier">y</label>
                      </div>

                      <input type="radio" id="B" name="conf" value="B"  />
                      <label for="B">B</label>
                          <svg height="10" width="10">
                          <polygon points="0 0, 10 0, 10 10, 0 10" id="BToggle" />
                          </svg>
                      <br/>

                      <div id = "BLegend" class style = " display: none;" >
                          <svg height="10" width="10"><circle cx="5" cy="5" r="5" fill="green" /></svg>
                          <p> z </p>
                          </br>
                          <svg height="10" width="10"><circle cx="5" cy="5" r="5" fill="turquoise" /></svg>
                          <p> w </p>
                      </div>

                      <div id = "BLegendBoxes" class style = " display: none;" >
                          <input type="checkbox" id="z" name="z"checked>
                          <svg height="10" width="10"><circle cx="5" cy="5" r="5" fill="green" /></svg>
                          <label for="z">z</label>
                          </br>
                          <input type="checkbox" id="w" name="w"checked>
                          <svg height="10" width="10"><circle cx="5" cy="5" r="5" fill="turquoise" /></svg>
                          <label for="w">w</label>
                      </div>
                  </div>

                  ')
      ),
      column(width = 9, 
             leafletOutput("map", height = "45vh"),
             plotOutput("distribPlot", height = "40vh",
                        brush = brushOpts(id = "distribPlot_brush", direction = "x", resetOnNew = FALSE))
             )
  # )
)


server <- function(input, output, session) {

  filteredData <- reactive({

    if (input$x == TRUE) xV <- "x" else xV <- ""
    if (input$y == TRUE) yV <- "y" else yV <- ""

    if (input$z == TRUE) zV <- "z" else zV <- ""
    if (input$w == TRUE) wV <- "w" else wV <- ""

    currentlyFiltered <- filter(T0New, type %in% c(xV,yV,zV,wV))

    currentlyFiltered <- filter(currentlyFiltered, cat %in% input$conf)

    if(!is.null(input$distribPlot_brush)){
      thisSel <- input$distribPlot_brush
      currentlyFiltered <- currentlyFiltered %>% 
        filter(date >= thisSel$xmin, date <= thisSel$xmax)
    }


    return(currentlyFiltered)
  })

  #Sortie map
  output$map <- renderLeaflet({
    leaflet()%>%
      addProviderTiles(providers$OpenTopoMap) 
  })

  observe({
      mapData <- filteredData()
      mapProxy <- leafletProxy("map", session = session, data = mapData)
      mapProxy %>%
        clearGroup('1') %>% 
        addCircleMarkers(
          data = mapData,
          lat = mapData$lat,
          lng = mapData$lng,
          radius = 4,
          color = 'white',
          opacity = 1,
          fillColor = ~col,
          stroke = T,
          weight = 1,
          fillOpacity = 1,
          group='1'
        )
  })

  #Sortie graph
  output$distribPlot <- renderPlot({

    distribPlot <- ggplot(T0New,aes(date)) +
      geom_density(col = "#053144", fill = "#43a2ca", alpha = 0.3, adjust = 0.75)

    return(distribPlot)
  })



    onclick(id = "AToggle", c(toggleClass(id = "ALegend", class = "show")), add = FALSE)

    observe({
      toggleClass(id = "ALegend", class = "hide",
                  condition = input$conf=="A")
      toggleClass(id = "ALegendBoxes", class = "show",
                  condition = input$conf=="A")
    })

    onclick(id = "BToggle", c(toggleClass(id = "BLegend", class = "show")), add = FALSE)

    observe({
      toggleClass(id = "BLegend", class = "hide",
                  condition = input$conf=="B")
      toggleClass(id = "BLegendBoxes", class = "show",
                  condition = input$conf=="B")
    })

}

# Create Shiny app ----
shinyApp(ui = ui, server = server)

For now, interraction-based, this code does exactly what I want to do : By clicking on the square next to the radio button, if it's checkboxes are not visible yet, you can set visible it's legend without the checkboxes. If it's legend with checkboxes is already visible it won't set the legend without checkboxes visible.

But i want to enhance this functionnality by replacing the square with arrows, pointing the radiobutton if none of it's legend is visible and pointing down if any legend is visible.

For now i'm playing with "on click" (line 169 & 178), radiobutton selection (line 171 to 176 & 180 to 185) and the "!important" class "hide" (line 30) but to do what I want to do these condition aren't enough, so I was wandering if there where any "is.visible" condition in Shiny to play with

Oscar Jnn
  • 154
  • 1
  • 19
  • 1
    It's easier to help you if you include a simple [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input and desired output that can be used to test and verify possible solutions. How are you controlling the visibility in the first place? Are you running your own javascript? – MrFlick Nov 14 '19 at 19:16
  • I've added a reproductible example, I didn't want to in the first place, 'cause it adds a lot more complexity, and just wanted to know if there where an is.visible condition in Shiny. But if there is no other solution than adding JScript to my code, i'll do that – Oscar Jnn Nov 15 '19 at 11:49

0 Answers0