Expand/Collapse shiny box on header click - r

I have developed a shiny app, where we are using various box object in the ui. Currently the boxes expand/Collapse by clicking on the "+/-" sign on the right of the box header, but we need the expand/collapse on click on the header (anywhere on the box header).
Below code (sample code)
If you look at the box with chart, I want the expansion & collapse to be performed on clicking the header i.e. "Histogram box title" and not just the "+/-" sign on right side of the header:
## Only run this example in interactive R sessions
if (interactive()) {
library(shiny)
# A dashboard body with a row of infoBoxes and valueBoxes, and two rows of boxes
body <- dashboardBody(
# Boxes
fluidRow(
box(title = "Histogram box title",
status = "warning", solidHeader = TRUE, collapsible = TRUE,
plotOutput("plot", height = 250)
)
)
)
server <- function(input, output) {
output$plot <- renderPlot({
hist(rnorm(50))
})
}
shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
body
),
server = server
)
}

This is easily achievable using javascript. You just have to create a javascript function and call the same in your header code. Refer to below code for better understanding. I have provided 3 options, let me know if this works for you.
## Only run this example in interactive R sessions
if (interactive()) {
library(shiny)
# javascript code to collapse box
jscode <- "
shinyjs.collapse = function(boxid) {
$('#' + boxid).closest('.box').find('[data-widget=collapse]').click();
}
"
# A dashboard body with a row of infoBoxes and valueBoxes, and two rows of boxes
body <- dashboardBody(
# Including Javascript
useShinyjs(),
extendShinyjs(text = jscode),
# Boxes
fluidRow(
box(id="box1",title = actionLink("titleId", "Histogram box title",icon =icon("arrow-circle-up")),
status = "warning", solidHeader = TRUE, collapsible = T,
plotOutput("plot", height = 250)
),
box(id="box2",title = p("Histogram box title",
actionButton("titleBtId", "", icon = icon("arrow-circle-up"),
class = "btn-xs", title = "Update")),
status = "warning", solidHeader = TRUE, collapsible = T,
plotOutput("plot1", height = 250)
),
box(id="box3",title = actionButton("titleboxId", "Histogram box title",icon =icon("arrow-circle-up")),
status = "warning", solidHeader = TRUE, collapsible = T,
plotOutput("plot2", height = 250)
)
)
)
server <- function(input, output) {
output$plot <- renderPlot({
hist(rnorm(50))
})
output$plot1 <- renderPlot({
hist(rnorm(50))
})
output$plot2 <- renderPlot({
hist(rnorm(50))
})
observeEvent(input$titleId, {
js$collapse("box1")
})
observeEvent(input$titleBtId, {
js$collapse("box2")
})
observeEvent(input$titleboxId, {
js$collapse("box3")
})
}
shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
body
),
server = server
)
}

You can do this for all boxes in an app with a few lines of external css and javascript.
The JS triggers a click on the widget when you click on the header title. It has to be the h3 element because the widget is inside .box-header, which would cause infinite recursion.
$('.box').on('click', '.box-header h3', function() {
$(this).closest('.box')
.find('[data-widget=collapse]')
.click();
});
But then we need to make the h3 element fill the full .box-header, so get rid of the header padding (except on the right), add it to the h3, and make the h3 fill 100% of the width of the box.
.box-header {
padding: 0 10px 0 0;
}
.box-header h3 {
width: 100%;
padding: 10px;
}

I think Lisa DeBruine answer is the better one since you can click the whole header and not just the title.
Pasted it into a small example:
if (interactive()) {
body <- dashboardBody(
useShinyjs(),
tags$style(HTML("
.box-header {
padding: 0 10px 0 0;
}
.box-header h3 {
width: 100%;
padding: 10px;
}")),
fluidRow(
box(id="box1", title = "Histogram box title",
status = "warning", solidHeader = TRUE, collapsible = T,
plotOutput("plot", height = 250)
)
)
)
server <- function(input, output) {
output$plot <- renderPlot({
hist(rnorm(50))
})
runjs("
$('.box').on('click', '.box-header h3', function() {
$(this).closest('.box')
.find('[data-widget=collapse]')
.click();
});")
}
shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(),
body
),
server = server
)
}

Related

How to render an image in shiny box and fix the width and height? R

I have this shiny app I am making. My goal is to have a fluid row that has an image and some inputs
# Test Version with google logo
library(shinydashboard)
library(shiny)
ui <- dashboardPage(
dashboardHeader(title = "Dashbaord"),
dashboardSidebar(
sidebarMenuOutput("menu")
),
dashboardBody(
fluidRow(
box(
title = "Image Goes Here",
img(src='https://cdn.vox-cdn.com/thumbor/ULiGDiA4_u4SaK-xexvmJVYUNY0=/0x0:640x427/1400x1050/filters:focal(0x0:640x427):format(jpeg)/cdn.vox-cdn.com/assets/3218223/google.jpg',
align = "center",
width = "100%",
style="height: 50px")), #I'm trying to change the size here but it doesn't work
box(align = "center",
title = "Select Inputs",status = "warning", solidHeader = F,
selectInput("dropdown1", "Select Drilldown:", c(50,100,200))
)
)
)
)
server <- function(input, output) {
}
shinyApp(ui, server)
Technically this code works, but I don't like how the box with the image changes based off the monitor/view. I would like for both boxes to be the same height and remain uniformed. I posted some screen shots below.
Full Screen
Half Screen
Desire Output (row is the same height no matter what).
Edit:
box_height = "20em"
plot_height = "16em"
ui <- dashboardPage(
dashboardHeader(title = "Box alignmnent test"),
dashboardSidebar(),
dashboardBody(
# Put boxes in a row
fluidRow(
box(
title = "Image Goes Here",
img(src='https://cdn.vox-cdn.com/thumbor/ULiGDiA4_u4SaK-xexvmJVYUNY0=/0x0:640x427/1400x1050/filters:focal(0x0:640x427):format(jpeg)/cdn.vox-cdn.com/assets/3218223/google.jpg',
align = "center",
width = "100%"),
height = box_height),
box(plotOutput("speed_distbn",height = plot_height), height = box_height)
)
)
)
server <- function(input, output) {
}
shinyApp(ui, server)
Boxes stay the same height but the image overlaps the box
How about this
library(shinydashboard)
library(shiny)
my_height = "30em"
ui <- dashboardPage(
dashboardHeader(title = "Box alignmnent test"),
dashboardSidebar(),
dashboardBody(
# Put boxes in a row
fluidRow(
box(
title = "Image Goes Here",
img(src='https://cdn.vox-cdn.com/thumbor/ULiGDiA4_u4SaK-xexvmJVYUNY0=/0x0:640x427/1400x1050/filters:focal(0x0:640x427):format(jpeg)/cdn.vox-cdn.com/assets/3218223/google.jpg',
align = "center", style = paste0("width: 100%; height: ", my_height, ";"))
),
box(title = "Plot", plotOutput("speed_distbn", height = my_height))
)
)
)
server <- function(input, output) {
output$speed_distbn <- renderPlot(plot(1))
}
shinyApp(ui, server)
In your first case, if you want to use other random tags on the right side. In order to have the right the same height as left, we can use spsComps::heightMatcher. We can use this function to dynamically match the height of the right side to the left side.
library(shinydashboard)
library(shiny)
my_height = "30em"
ui <- dashboardPage(
dashboardHeader(title = "Box alignmnent test"),
dashboardSidebar(),
dashboardBody(
# Put boxes in a row
fluidRow(
box(
title = "Image Goes Here",
id= "box_l",
img(src='https://cdn.vox-cdn.com/thumbor/ULiGDiA4_u4SaK-xexvmJVYUNY0=/0x0:640x427/1400x1050/filters:focal(0x0:640x427):format(jpeg)/cdn.vox-cdn.com/assets/3218223/google.jpg',
align = "center", style = paste0("width: 100%; height: ", my_height, ";"))
),
box(
title = "Select inputs",
id= "box_r",
selectInput("dropdown1", "Select Drilldown:", c(50,100,200))
),
spsComps::heightMatcher("box_r", "box_l")
)
)
)
server <- function(input, output) {
}
shinyApp(ui, server)
In your case, the height on left is fixed, but heightMatcher can do it even with dynamically changed height. try click on spsComps shiny demo and go to the Misc tab and see the dynamic heightMatcher example.

Adding action button (icon) on top right corner of the shiny dashboard box

I would require an action button icon on the top right corner of the shiny dashboard box. The below code appends the icons 'refresh' and 'plus' adjacent to the 'Title1'. However, I would require the icons to be placed at the right side end of the header bar (Similar to the positions of minimize, restore and close button in windows application).
library(shiny)
library(shinydashboard)
body <- dashboardBody(
fluidRow(
box(
title = p("Title 1",
actionButton("titleBtId", "", icon = icon("refresh"),
class = "btn-xs", title = "Update"),
actionButton('titleBtid2', '', icon = icon('plus'),
class='btn-xs', title = 'update')
),
width = 4, solidHeader = TRUE, status = "warning",
uiOutput("boxContentUI2")
)
)
)
ui <- dashboardPage(
dashboardHeader(title = "Row layout"),
dashboardSidebar(),
body
)
server = function(input, output, session) {
output$boxContentUI2 <- renderUI({
input$titleBtId
pre(paste(sample(LETTERS,10), collapse = ", "))
})
}
shinyApp(ui = ui, server = server)
Add a style declaration with absolute positioning to your action buttons.
library(shiny)
library(shinydashboard)
body <- dashboardBody(
fluidRow(
box(
title = p("Title 1",
actionButton("titleBtId", "", icon = icon("refresh"),
class = "btn-xs", title = "Update", style = "position: absolute; right: 40px"),
actionButton('titleBtid2', '', icon = icon('plus'),
class = 'btn-xs', title = 'update', style = "position: absolute; right: 10px")
),
width = 4, solidHeader = TRUE, status = "warning",
uiOutput("boxContentUI2")
)
)
)
ui <- dashboardPage(
dashboardHeader(title = "Row layout"),
dashboardSidebar(),
body
)
server = function(input, output, session) {
output$boxContentUI2 <- renderUI({
input$titleBtId
pre(paste(sample(LETTERS,10), collapse = ", "))
})
}
shinyApp(ui = ui, server = server)

How to get a notification icon on a tab in shiny

I have a tabpanelSet in a shiny application. One of the tabs contains a datatable. Id like the number of rows in the datatable to show in a nice circular icon next to the the tab header text so the user can see see the number in the datatable within the tab before clicking on the tab.
Here is the basic app. Its the 'Details' tab that I would like the circular notification icon library
library(shiny)
library(DT)
library(data.table)
ui <- fluidPage(
# Application title
titlePanel("Circular notification icon app"),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Empty"),
tabPanel("Details",
DT::dataTableOutput("iris"))
)
)
)
server <- function(input, output) {
output$iris = DT::renderDT({
datatable(iris,class = "display wrap",selection = "single",
options = list(
scrollX = TRUE,
scrollY = TRUE,
pageLength = 15,
select = "api",
dom = 'Bfrtip')
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Like this?
library(shiny)
library(DT)
library(shinyjs)
CSS <- "
#tabHeader {
display: inline-block;
}
.circle {
display: inline-block;
width: 25px;
height: 25px;
border-radius: 50%;
font-size: 12px;
color: #fff;
line-height: 25px;
text-align: center;
background: #000
}"
js <- function(nrows){
sprintf("$('#tabHeader .circle').html('%s');", nrows)
}
ui <- fluidPage(
useShinyjs(),
tags$head(
tags$style(HTML(CSS))
),
# Application title
titlePanel("Circular notification icon app"),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Empty"),
tabPanel(div(id = "tabHeader", span("Details"),
div(class = "circle")),
DTOutput("iris"))
)
)
)
server <- function(input, output) {
runjs(js(nrow(iris)))
output$iris = renderDT({
datatable(iris, class = "display wrap", selection = "single",
options = list(
scrollX = TRUE,
scrollY = TRUE,
pageLength = 15,
select = "api",
dom = 'Bfrtip')
)
})
}
# Run the application
shinyApp(ui = ui, server = server)

How to show embedded tweet in R shiny app?

I'm finishing up my dashboard atm, and I'm trying to show a tweet on my page. I'm using the tweetrmd package to do this, but it doesn't seem to work
here is part of my UI code
library(tidyverse)
library(shiny)
library(rtweet)
library(tweetrmd)
screenshot <- tweet_screenshot(tweet_url("Metro", "1251153881209307136"))
# UI
list(
ui <- tagList(
includeCSS("style.css"),
navbarPage("#Corona",
windowTitle = "#Corona",
tabPanel("Twitter",
sidebarLayout(
sidebarPanel(
h2("Algemene twitter data", align = "left"),
),
mainPanel(
tabsetPanel(
id = "Tabs",
tabPanel(
title = "Kranten",
h3("Frequentie tweets over corona door populaire kranten", align = "center"),
plotOutput("plot1")%>% withSpinner(color="#dca108"),
div(img(src= screenshot, align = "center"), style="text-align: center;", id= "screenshot"),
), )
)
)
))
)
)
Question is: can I make the tweet_screenshot function work in a shiny app (default is rmarkdown) and how?
If I check out the screenshot object it shows this:
(screenshot <- tweet_screenshot(tweet_url("Metro", "1251153881209307136")))
file://C:\Users\jolien\AppData\Local\Temp\RtmpKeTPxU\file47383c65585c.html screenshot completed
Thanks in advance
A solution using twitframe.com:
library(shiny)
tweet <- "https://twitter.com/Twitter/status/1144673160777912322"
url <- URLencode(tweet, reserved = TRUE)
src <- paste0("https://twitframe.com/show?url=", url)
js <- '
$(window).on("message", function(e) {
var oe = e.originalEvent;
if (oe.origin !== "https://twitframe.com")
return;
if (oe.data.height && oe.data.element.id === "tweet"){
$("#tweet").css("height", parseInt(oe.data.height) + "px");
}
});'
ui <- fluidPage(
fluidRow(
tags$head(
tags$script(HTML(js)),
tags$style(HTML(
"
.content {
margin: auto;
padding: 20px;
width: 60%;
}"))
),
uiOutput("frame")
)
)
server <- function(input, output, session) {
output[["frame"]] <- renderUI({
tagList(
tags$div(
class = "content",
tags$div(tags$iframe(
id = "tweet",
border=0, frameborder=0, height=50, width=550,
src = src
))
),
singleton(tags$script(HTML(
"$(document).ready(function(){
$('iframe#tweet').on('load', function() {
this.contentWindow.postMessage(
{ element: {id:this.id}, query: 'height' },
'https://twitframe.com');
});
});")))
)
})
}
shinyApp(ui, server)

Adjust the height of infoBox in shiny dashboard

I have a very basic infoBox like this, and want to adjust the height as the current height is just way too much for what I am incorporating.
Any idea how I can do it? I tried what was suggested here: r shinydashboard - change height of valueBox. But, that is not having any change.
sidebar <- dashboardSidebar(
sidebarMenu(id = 'sidebarmenu',
menuItem('About', tabName = 'about'))
)
about <- tabItem('about', fluidPage(
fluidRow(
infoBoxOutput('age')
)
)
)
body <- dashboardBody(
tabItems(
about
)
)
ui <- dashboardPage(
dashboardHeader(
title = 'My App'
),
sidebar = sidebar,
body = body
)
server <- function(input, output) {
output$age <- renderInfoBox({
infoBox('Age: ', 50, icon = icon('list'), width = 6)
})
}
shinyApp(ui = ui, server = server)
You need to apply some CSS rules.
body <- dashboardBody(
tags$head(tags$style(HTML('.info-box {min-height: 45px;} .info-box-icon {height: 45px; line-height: 45px;} .info-box-content {padding-top: 0px; padding-bottom: 0px;}'))),
tabItems(
about
)
)

Resources