我在面板中有一些情节。当窗口宽度很小时,我想将它们更改为 self.session.sessionPreset = .medium
。是否有任何方法可以确定浏览器的窗口宽度。例如,在以下示例中,当窗口宽度足够大时,如何将tabsetpanel
从uiOutput
切换到plotPanel1
。
plotPanel2
答案 0 :(得分:1)
由于Shiny
生成一堆HTML,您可以使用media-query
,或者另一种可能性是使用javaScript
并获取窗口的宽度。 css
解决方案遇到了一些麻烦,但我会告诉你们两个:
使用javaScript
,您可以根据窗口的width
定义输入元素:
tags$head(tags$script('
var width = 0;
$(document).on("shiny:connected", function(e) {
width = window.innerWidth;
Shiny.onInputChange("width", width);
});
$(window).resize(function(e) {
width = window.innerWidth;
Shiny.onInputChange("width", width);
});
'))
如果此脚本包含在UI
中,您可以访问input$width
以获取窗口的宽度。 (免责声明:我在以下SO topic中使用了接受的答案作为JS代码。)
我添加了observer
来检查宽度。如果它低于/高于某个阈值,则显示/隐藏元素。
observe( {
req(input$width)
if(input$width < 800) {
shinyjs::show("plotPanel1")
shinyjs::hide("plotPanel2")
} else {
shinyjs::hide("plotPanel1")
shinyjs::show("plotPanel2")
}
})
完整代码:
library(shinyjs)
library(ggplot2)
ui <- fluidPage(
useShinyjs(),
title = "TestApp",
h1("Test Application"),
sidebarLayout(
sidebarPanel(
sliderInput("bins", "Bins", 2, 20, 1, value = 10)
),
mainPanel(
fluidRow(
div(id="p1", uiOutput("plotPanel1")),
div(id="p2", uiOutput("plotPanel2"))
)
)
),
tags$head(tags$script('
var width = 0;
$(document).on("shiny:connected", function(e) {
width = window.innerWidth;
Shiny.onInputChange("width", width);
});
$(window).resize(function(e) {
width = window.innerWidth;
Shiny.onInputChange("width", width);
});
'))
)
server <- function(input, output, session){
plot1 <- reactive({
ggplot(lm(mpg ~ ., data = mtcars), aes(.resid)) +
geom_histogram(bins = input$bins)
})
plot2 <- reactive({
ggplot(lm(UrbanPop ~ ., data = USArrests), aes(.resid)) +
geom_histogram(bins = input$bins)
})
plot3 <- reactive({
ggplot(lm(uptake ~ ., data = CO2), aes(.resid)) +
geom_histogram(bins = input$bins)
})
output$plotPanel1 <- renderUI({
tagList(
tabsetPanel(
tabPanel(
"plot1",
renderPlot(plot1())
),
tabPanel(
"plot2",
renderPlot(plot2())
),
tabPanel(
"plot3",
renderPlot(plot3())
)
)
)
})
output$plotPanel2 <- renderUI({
tagList(
fluidRow(
column(
4,
renderPlot(plot1())
),
column(
4,
renderPlot(plot2())
),
column(
4,
renderPlot(plot3())
)
)
)
})
observe( {
req(input$width)
if(input$width < 800) {
shinyjs::show("plotPanel1")
shinyjs::hide("plotPanel2")
} else {
shinyjs::hide("plotPanel1")
shinyjs::show("plotPanel2")
}
})
}
runApp(shinyApp(ui, server))
在我看来,这不是一个完美的解决方案,因为我们每次都会渲染两次,但是你可以在此基础上进行构建。
您可以在display
的{{1}}内控制media-query
属性。它适用于任何元素,但我发现它与tags$head
不兼容。
带UIOutput
的简单div
的工作示例:
text
不适用ui <- fluidPage(
tags$head(
tags$style(HTML("
@media screen and (min-width: 1000px) {
#p1 {
display: none;
}
#p2 {
display: block;
}
}
@media screen and (max-width: 1000px) {
#p1 {
display: block;
}
#p2 {
display: none;
}
}
"
))
),
div(id="p1", "First element"),
div(id="p2", "Second element")
)
的示例:
UIOutput