【问题标题】:Neatly display images of different sizes sequentially in the same UI element在同一个 UI 元素中顺序整齐地显示不同大小的图像
【发布时间】:2021-02-02 18:10:11
【问题描述】:

在我的应用程序中,我需要在其他 UI 元素中显示单个预渲染图像。我希望其他元素紧紧地包裹在图像的顶部和底部。显示的图像取决于应用的状态,并且图像的大小可能不同。

This question 解决了类似的问题,但似乎不同之处在于需要同时显示许多不同大小的图像。

这是显示问题的 MWE。您可以提供自己的图像,也可以将它们与我的 RStudio 项目 here 的其余部分一起下载。

library(shiny)
library(png)

ui <- fluidPage(
  tags$head(tags$link(rel="stylesheet", type="text/css", href="stylesheet.css")),
  selectInput("size", label="Size:", choices=c("small", "large")),
  imageOutput("image"),
  # uiOutput("imageUI"),
  textOutput("info")
)

# Define server logic required to draw a histogram
server <- function(input, output) {
  imgFileName <- reactive({
    paste0("./www/", input$size, ".png")
  })
  
  imgFile <- reactive({
    readPNG(imgFileName(), info=TRUE)
  })
  
  imgSize <- reactive({
    info <- unlist(stringr::str_split(attr(imgFile(), "info")$dim, stringr::fixed(" ")))
    info <- paste0(info, "px")
    names(info) <- c("width", "height")
    info <- as.list(info)
    info
  })
  
  output$info <- renderText({
    paste0("Height: ", imgSize()$height, "; Width: ", imgSize()$width)
  })
  
  output$image <- renderImage({
    list(
       src=imgFileName(),
       contentType="image/png",
       width=imgSize()$width,
       height=imgSize()$height,
       alt=paste0("A ", input$size, " image"),
       class="myImageClass"
    )
  })

  # output$imageUI <- renderUI({
  #   tagList(plotOutput("image"))
  # })
}

shinyApp(ui, server)

如果你运行MWE,你会看到当select输入的值为small时图像和文本输出之间有很大的差距,而当select输入为@时图像与文本输出重叠987654331@.

这些屏幕截图显示了所需的行为。

检查底层 HTML(在 Firefox 中,右键单击图像上的任意位置并选择“检查元素”),问题似乎是由包裹图像的 div 引起的:

img 已正确获取图像的大小,但周围的元素被周围的 div 的内联 height 属性保持在原位。为了证明这是问题所在,我可以在 Firefox 的检查器中禁用有问题的高度属性:

这给了我想要的行为。

如果问题是由 div 中引用的 CSS 类之一引起的,我可以通过覆盖应用程序样式表中的类定义来解决问题。但是有问题的属性是内联的,所以这不是一个选项。

如何修改包装显示图像的imgdiv 的属性?

【问题讨论】:

    标签: css r shiny


    【解决方案1】:

    您与uiOutput() 非常亲近,这是必要的,因为您希望 UI 的布局发生变化。而您未注释的内容只会交换图像,但会保持 UI 布局不变。

    library(shiny)
    library(png)
    
    ui <- fluidPage(
      tags$head(tags$link(rel="stylesheet", type="text/css", href="stylesheet.css")),
      selectInput("size", label="Size:", choices=c("small", "large")),
      
      # don't use imageOutput() here because the UI will not be able to change
      #imageOutput("image"),
      # instead use uiOutput() which will allow you to update the UI itself
      # that is, you will be able to update the height of the image div reactively
      uiOutput("imageUI"),
      textOutput("info")
    )
    
    server <- function(input, output) {
      imgFileName <- reactive({
        paste0("./www/", input$size, ".png")
      })
      
      imgFile <- reactive({
        readPNG(imgFileName(), info=TRUE)
      })
      
      imgSize <- reactive({
        info <- unlist(stringr::str_split(attr(imgFile(), "info")$dim, stringr::fixed(" ")))
        info <- paste0(info, "px")
        names(info) <- c("width", "height")
        info <- as.list(info)
        info
      })
      
      output$info <- renderText({
        paste0("Height: ", imgSize()$height, "; Width: ", imgSize()$width)
      })
      
      output$image <- renderImage({
        list(
           src=imgFileName(),
           contentType="image/png",
           width=imgSize()$width,
           height=imgSize()$height,
           alt=paste0("A ", input$size, " image"),
           class="myImageClass"
        )
      })
    
      # update the UI here by changing the height of the image div
      output$imageUI <- renderUI({
        imageOutput("image", height = imgSize()$height)
      })
    }
    
    shinyApp(ui, server)
    

    【讨论】:

    • 太好了。谢谢你。正如您所推测的那样,我用renderUI 尝试了各种方法,但显然我错过了一个解决方案。这正是我想要的。
    猜你喜欢
    • 2019-10-22
    • 2018-12-03
    • 2012-10-10
    • 1970-01-01
    • 2020-11-07
    • 2022-12-13
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多