|
| 1 | +# This demonstrates how to use fewer than 12 columns in gridstackr, |
| 2 | +# some basic card styling, and how to use grab handles for position |
| 3 | +# control instead of making the whole div grabbable.. |
| 4 | + |
| 5 | +library(shiny) |
| 6 | +library(bslib) |
| 7 | +library(ggplot2) |
| 8 | +library(gridstackr) |
| 9 | + |
| 10 | + |
| 11 | +full_screen_toggle <- function(id_controls) { |
| 12 | + tooltip( |
| 13 | + tags$button( |
| 14 | + class = "bslib-full-screen-enter", |
| 15 | + "aria-expanded" = "false", |
| 16 | + "aria-controls" = id_controls, |
| 17 | + "aria-label" = "Expand card", |
| 18 | + full_screen_toggle_icon() |
| 19 | + ), |
| 20 | + "Expand" |
| 21 | + ) |
| 22 | +} |
| 23 | + |
| 24 | +window_move_handle <- function() { |
| 25 | + htmltools::tags$div( |
| 26 | + class = "card-handle card-handle-button", |
| 27 | + shiny::icon("up-down-left-right", class = "fa-solid", lib = "font-awesome") |
| 28 | + ) |
| 29 | +} |
| 30 | + |
| 31 | +ui <- bslib::page_fluid( |
| 32 | + tags$h2("GridStack card example"), |
| 33 | + theme = bslib::bs_theme(preset = "shiny"), |
| 34 | + shiny::tags$head( |
| 35 | + shiny::tags$style(" |
| 36 | + .card-handle { |
| 37 | + cursor: move; |
| 38 | + } |
| 39 | + .card-handle:hover { |
| 40 | + background-color: rgba(0,0,0,0.1); |
| 41 | + } |
| 42 | + .card-handle-button { |
| 43 | + position: absolute; |
| 44 | + right: 25px; /* sets it in top right of parent container */ |
| 45 | + top: 25px; |
| 46 | + height: 50px; |
| 47 | + width: 50px; |
| 48 | + border-radius: 50px; /* gives it the circular button shape */ |
| 49 | + text-align: center; /* puts the icon in the middle horizontally */ |
| 50 | + } |
| 51 | + .card-handle-button i { /* Applies this style to any <i> tags within the container */ |
| 52 | + position: relative; |
| 53 | + top: calc(50% - 12.5px); |
| 54 | + } |
| 55 | +
|
| 56 | + .card-handle-header-button { |
| 57 | + float: right; |
| 58 | + height: 25px; |
| 59 | + width: 25px; |
| 60 | + border-radius: 50px; |
| 61 | + text-align: center; |
| 62 | + } |
| 63 | +
|
| 64 | + /* Applies this style to any <i> tags within the container. |
| 65 | + In this case it isn't super necessary because the icon is nearly the same |
| 66 | + size as the circle. */ |
| 67 | + .card-handle-header-button i { |
| 68 | + position: relative; |
| 69 | + top: calc(50% - 12.5px); |
| 70 | + } |
| 71 | + ") |
| 72 | + ), |
| 73 | + gridstack( |
| 74 | + margin = "10px", |
| 75 | + cellHeight = "140px", |
| 76 | + float = FALSE, # Set to true if you want to be able to keep spaces in the middle of the page |
| 77 | + column = 6, |
| 78 | + options = list(handle = ".card-handle"), # Necessary to set the grab handle element |
| 79 | + gs_item( # If a gard doesn't have an element with class .card-handle the whole thing will be grabbable |
| 80 | + class = "card", |
| 81 | + shiny::plotOutput("plot1", height = "100%"), |
| 82 | + w = 3, |
| 83 | + h = 2 |
| 84 | + ), |
| 85 | + gs_item( |
| 86 | + class = "card", |
| 87 | + bslib::card_body(paste( |
| 88 | + "Notice that we only have 6 columns because we set column=6.", |
| 89 | + "This gives it a blockier feel, and can make things align and resize a", |
| 90 | + "bit more cleanly depending on what you're after." |
| 91 | + )), |
| 92 | + w = 3, |
| 93 | + h = 2 |
| 94 | + ), |
| 95 | + gs_item( # Setting an element with class .card-handle means that only that element will be grabbable |
| 96 | + class = "card", |
| 97 | + window_move_handle(), |
| 98 | + shiny::plotOutput("plot2", height = "100%"), |
| 99 | + class_content = "p-2", # Gives it a bit of padding on the inside. CF plot 1 |
| 100 | + w = 6, |
| 101 | + h = 2 |
| 102 | + ), |
| 103 | + gs_item( |
| 104 | + class = "card", |
| 105 | + bslib::card_header( |
| 106 | + "Plot 3", |
| 107 | + htmltools::tags$div( |
| 108 | + class = "card-handle-header-button card-handle", |
| 109 | + shiny::icon("up-down-left-right", class = "fa-solid", lib = "font-awesome") |
| 110 | + ) |
| 111 | + ), |
| 112 | + bslib::card_body( # You could use bslib instead of class_content |
| 113 | + id = "test", |
| 114 | + plotOutput("plot3") |
| 115 | + ), |
| 116 | + w = 4, |
| 117 | + h = 2 |
| 118 | + ), |
| 119 | + gs_item( # You could also just set the whole header to be grabbable. |
| 120 | + class = "card", |
| 121 | + bslib::card_header( |
| 122 | + class = "card-handle", |
| 123 | + "Plot 4" |
| 124 | + ), |
| 125 | + shiny::plotOutput("plot4", height = "100%"), |
| 126 | + w = 2, |
| 127 | + h = 2 |
| 128 | + ) |
| 129 | + ) |
| 130 | +) |
| 131 | + |
| 132 | +server <- function(input, output, session) { |
| 133 | + |
| 134 | + output$plot1 <- renderPlot({ |
| 135 | + ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear)) + ggtitle("Plot 1") |
| 136 | + }) |
| 137 | + output$plot2 <- renderPlot({ |
| 138 | + ggplot(mtcars) + geom_point(aes(mpg, disp)) + ggtitle("Plot 2") |
| 139 | + }) |
| 140 | + output$plot3 <- renderPlot({ |
| 141 | + ggplot(mtcars) + geom_smooth(aes(disp, qsec)) |
| 142 | + }) |
| 143 | + output$plot4 <- renderPlot({ |
| 144 | + ggplot(mtcars) + geom_bar(aes(carb)) |
| 145 | + }) |
| 146 | + |
| 147 | +} |
| 148 | + |
| 149 | +if (interactive()) |
| 150 | + shinyApp(ui, server) |
0 commit comments