bathyscapher
bathyscapher

Reputation: 2319

Leaflet map as background behind fluidRows

I'm developing a R Shiny app that is composed of two fluidRows holding some content. One of them contains a Leaflet map spanning some columns. So far, so good. Now, the idea was to extend the map in the background to the other columns and also to the upper fluidRow. In the end, the map could be seen across the whole website: without opacity in its columns and semitransparently in the other columns and the upper fluidRow.

This is how the app looks so far: enter image description here

And this is how I ideally want it to look: enter image description here

And here is the code for the app:

library(leaflet)
library(shiny)
library(shinythemes)


ui <- navbarPage(
  title = "The app",
  tabPanel("Reproducible examples are great :)",
           fluidPage(
             fluidRow(
               column(2,
                      selectInput("city", "Select city:",
                                  c("Beirut", "Cairo", "Bagdad"),
                                  selected = "Beirut"
                      ),
                      actionButton("start", "Start",
                                   style = "color: black;
                                           background-color: #ffcc00;")
                      ),
               column(5,
                      "Content is here ...",
                      br(),
                      sliderInput("slider1", "",
                                  min = 1,
                                  max = 100,
                                  value = 30,
                                  ticks = TRUE)
                     ),
               column(5,
                      "... and there and ...",
                      br(),
                      sliderInput("slider2", "",
                                  min = 1,
                                  max = 100,
                                  value = 30,
                                  ticks = TRUE)
                      ),
             ),
             fluidRow(
               column(7,
                      leafletOutput("map",
                                    height = "67vh"
                      )
               ),
               column(5,
                      "... also here ...",
                      br(),
                      sliderInput("slider3", "",
                                  min = 1,
                                  max = 500,
                                  value = 30,
                                  ticks = TRUE),
                      "... and even down there",
                      br(),
                      sliderInput("slider4", "",
                                  min = 1,
                                  max = 500,
                                  value = 30,
                                  ticks = TRUE)
                     )
             )
           )
           ),
  theme = shinytheme("cosmo")
  )

server <- function(input, output) {
  output$map <- renderLeaflet({
    leaflet(data = NULL,
            options = leafletOptions(zoomControl = FALSE,
                                     dragging = TRUE)) |>
      addTiles(
        options = providerTileOptions(noWrap = TRUE)) |>
      setView(lng = 35.5051, lat = 33.889, zoom = 14) |>
      addScaleBar(position = "bottomleft")
  })
  }

shinyApp(ui, server)

I tried to look for a solution online, but failed badly without even finding a real inspiration. So, I am even more curious if any of you knows a solution or hint!

Upvotes: 0

Views: 562

Answers (1)

lz100
lz100

Reputation: 7350

tada :)

library(leaflet)
library(shiny)
library(shinythemes)


ui <- navbarPage(
    title = "The app",
    tabPanel("Reproducible examples are great :)",
             div(
                 absolutePanel(
                     top = "50px", left = 0, right = 0, height = "125px",
                     style = "opacity: 0.6; background-color: white; z-index: 1",
                     column(2, 
                            selectInput("city", "Select city:",
                                        c("Beirut", "Cairo", "Bagdad"),
                                        selected = "Beirut"
                            ),
                            actionButton("start", "Start",
                                         style = "color: black;
                                           background-color: #ffcc00;")
                     ),
                     column(5,
                            "Content is here ...",
                            br(),
                            sliderInput("slider1", "",
                                        min = 1,
                                        max = 100,
                                        value = 30,
                                        ticks = TRUE)
                     ),
                     column(5,
                            "... and there and ...",
                            br(),
                            sliderInput("slider2", "",
                                        min = 1,
                                        max = 100,
                                        value = 30,
                                        ticks = TRUE)
                     )
                 ),
                 absolutePanel(
                     top = "50px", left = 0, right = 0, bottom = 0,
                     fixed = TRUE, cursor = "default",
                     style = "z-index: 0",
                     leafletOutput("map", height = "calc(100vh - 50px)")
                 ),
                 absolutePanel(
                     right = 0, top = "175px", width = "40vw",
                     "... also here ...",
                     style = "opacity: 0.6; background-color: white; height: calc(100vh - 175px);",
                     br(),
                     sliderInput("slider3", "",
                                 min = 1,
                                 max = 500,
                                 value = 30,
                                 ticks = TRUE),
                     "... and even down there",
                     br(),
                     sliderInput("slider4", "",
                                 min = 1,
                                 max = 500,
                                 value = 30,
                                 ticks = TRUE)
                 )
             )
    ),
    theme = shinytheme("cosmo")
)

server <- function(input, output) {
    output$map <- renderLeaflet({
        leaflet(data = NULL,
                options = leafletOptions(zoomControl = FALSE,
                                         dragging = TRUE)) |>
            addTiles(
                options = providerTileOptions(noWrap = TRUE)) |>
            setView(lng = 35.5051, lat = 33.889, zoom = 14) |>
            addScaleBar(position = "bottomleft")
    })
}

shinyApp(ui, server)

To be responsive on smaller screens:

library(leaflet)
library(shiny)
library(shinythemes)


ui <- navbarPage(
    title = "The app",
    tabPanel("Reproducible examples are great :)",
             div(
                 style = "margin-top: -70px;",
                 tags$style(
                     '
                     .top-panel {
                        position: relative;
                        width: 50%;
                        display: inline-block;
                        margin-top: 52px;
                     }
                     .right-panel {
                        position: relative;
                        width: 50%;
                        display: inline-block;
                        margin-top: 52px;
                        margin-left: -3px;
                        vertical-align: top;
                     }
                     .panels {
                        opacity: 0.6; 
                        background-color: white;
                        z-index: 1;
                     }
                     .panel-map {
                        position: absolute;
                        top: 50px;
                        left: 0;
                        right: 0; 
                        bottom: 0;
                        z-index: 0;
                     }
                    @media (min-width: 750px) {
                        .top-panel {
                            position: absolute;
                            top: 0px;
                            left: 0;
                            right: 0;
                            height: 125px;
                            width: 100%
                        }
                         .right-panel {
                            position: absolute;
                            top: 125px;
                            right: 0;
                            width: 40vw;
                            height: calc(100vh - 175px);
                            z-index: 1
                         }
                    }
                    '
                 ),
                 div(
                     class = "top-panel panels",
                     column(2, 
                            selectInput("city", "Select city:",
                                        c("Beirut", "Cairo", "Bagdad"),
                                        selected = "Beirut"
                            ),
                            actionButton("start", "Start",
                                         style = "color: black;
                                           background-color: #ffcc00;")
                     ),
                     column(5,
                            "Content is here ...",
                            br(),
                            sliderInput("slider1", "",
                                        min = 1,
                                        max = 100,
                                        value = 30,
                                        ticks = TRUE)
                     ),
                     column(5,
                            "... and there and ...",
                            br(),
                            sliderInput("slider2", "",
                                        min = 1,
                                        max = 100,
                                        value = 30,
                                        ticks = TRUE)
                     )
                 ),
                 div(
                     class = "panel-map",
                     top = "50px", left = 0, right = 0, bottom = 0,
                     fixed = TRUE, cursor = "default",
                     style = "z-index: 0",
                     leafletOutput("map", height = "calc(100vh - 50px)")
                 ),
                 div(
                     "... also here ...",
                     class = "right-panel panels",
                     br(),
                     sliderInput("slider3", "",
                                 min = 1,
                                 max = 500,
                                 value = 30,
                                 ticks = TRUE),
                     "... and even down there",
                     br(),
                     sliderInput("slider4", "",
                                 min = 1,
                                 max = 500,
                                 value = 30,
                                 ticks = TRUE)
                 )
             )
    ),
    theme = shinytheme("cosmo")
)

server <- function(input, output) {
    output$map <- renderLeaflet({
        leaflet(data = NULL,
                options = leafletOptions(zoomControl = FALSE,
                                         dragging = TRUE)) |>
            addTiles(
                options = providerTileOptions(noWrap = TRUE)) |>
            setView(lng = 35.5051, lat = 33.889, zoom = 14) |>
            addScaleBar(position = "bottomleft")
    })
}

shinyApp(ui, server)

Too many details, you need to learn some CSS. I'm not gonna explain all of them. The key here is the @media query, which makes it use a different set of CSS inside once the screen size is reached/below certain values.

enter image description here

When it is on small screen:

enter image description here

Upvotes: 3

Related Questions