bs4Dash | Shiny 仪表盘框架

2020-11-11 16:27:00 浏览数 (1)

bs4Dash 是一款基于 AdminLTE3 的 Bootstrap 4 Shiny 仪表盘模板框架,这个前端界面简洁清爽,用起来也和 Shinydashboard 非常类似,也易于学习使用。

GitHub 地址:https://github.com/RinteRface/bs4Dash/ demo:https://dgranjon.shinyapps.io/bs4DashDemo/_w_84c16fa9/

安装

代码语言:javascript复制
# 从 CRAN 下载install.packages("bs4Dash")# 下载最新开发版devtools::install_github("RinteRface/bs4Dash")

基础教程

下面是 bs4Dash 结构的分步介绍。

1. 创建基本框架

以下是 bs4Dash 的模板:

代码语言:javascript复制
library(shiny)
library(bs4Dash)
shiny::shinyApp(
  ui = bs4DashPage(
    old_school = FALSE,
    sidebar_mini = TRUE,
    sidebar_collapsed = FALSE,
    controlbar_collapsed = FALSE,
    controlbar_overlay = TRUE,
    title = "Basic Dashboard",
    navbar = bs4DashNavbar(),
    sidebar = bs4DashSidebar(),
    controlbar = bs4DashControlbar(),
    footer = bs4DashFooter(),
    body = bs4DashBody()
  ),
  server = function(input, output) {}
)

bs4DashPage() 提供了许多参数,例如 old_school,默认情况下为 FALSE,若为 TRUE,则会更改网页风格。使用 sidebar_collapsed 参数可以控制启动应用程序时侧边栏 bs4DashSidebar() 的显示方式。同样, controlbar_collapsed 控制是否显示右侧边栏 bs4DashControlbar()。当 sidebar_mini 参数为 TRUE 时,即使折叠了侧边栏,侧边栏图标也可见。最后,您还可以为页面添加标题 title,设置网页名称。

接下来让我们一步步填充这个模板 ~

2. 设置侧边栏

bs4DashSidebar() 用于自定义侧边栏:

代码语言:javascript复制
bs4DashSidebar(
 skin = "light",
 status = "primary",
 title = "bs4Dash",
 brandColor = "primary",
 url = "https://www.google.fr",
 src = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg",
 elevation = 3,
 opacity = 0.8,
 bs4SidebarUserPanel(
  img = "https://image.flaticon.com/icons/svg/1149/1149168.svg",
  text = "Welcome Onboard!"
 ),
 bs4SidebarMenu(
   bs4SidebarHeader("Header 1"),
   bs4SidebarMenuItem(
     "Item 1",
     tabName = "item1",
     icon = "sliders" 
   ),
   bs4SidebarMenuItem(
     "Item 2",
     tabName = "item2",
     icon = "id-card"
   )
 )
)

填充 bs4DashSidebar() 后效果如下:

有很多选项可用:

skin 设置皮肤:lightdark;•status 设置侧边栏 bs4SidebarUserPanel 的颜色。提供 5 种颜色:蓝色 primary, 红色 danger, 黄色 warning, 绿色 success, 青色 info;•brandColor 设置 bs4SidebarMenuItem 的颜色。同样为上面 5 种;•src 设置侧边栏的头像图片,支持 SVG,JPEG,PNG 格式。

3. 设置导航栏

bs4DashNavbar() 用于自定义导航栏:

代码语言:javascript复制
bs4DashNavbar(
  skin = "light",
  status = "white",
  border = TRUE,
  sidebarIcon = "bars",
  controlbarIcon = "th",
  fixed = FALSE,
  leftUi = bs4DropdownMenu(
    show = TRUE,
    align = "left",
    status = "warning", # 角标的颜色,黄色
    menuIcon = "envelope-open",
    src = NULL
  ),
  rightUi = bs4DropdownMenu(
    show = FALSE,
    status = "danger", # 角标的颜色,红色
    src = "https://www.google.fr",
    bs4DropdownMenuItem(
      message = "message 1",
      from = "Divad Nojnarg",
      src = "https://adminlte.io/themes/v3/dist/img/user3-128x128.jpg",
      time = "today",
      status = "danger", # 星号的颜色,红色
      type = "message"
    ),
    bs4DropdownMenuItem(
      message = "message 2",
      from = "Nono Gueye",
      src = "https://adminlte.io/themes/v3/dist/img/user3-128x128.jpg",
      time = "yesterday",
      status = "success", # 星号的颜色,绿色
      type = "message"
    )
  )
)

填充 bs4DashNavbar() 后效果如下:

bs4DashNavbar() 可以更改侧边栏 bs4DashSidebar() 的切换图标以及右侧边栏 bs4DashControlbar() 的图标。导航栏共包含 3 个容器:leftUirightUi 分别负责嵌入左右 UI 元素,在他们中间我们还可以添加任意内容。

4. 设置右侧边栏

bs4DashControlbar() 用于自定义右侧边栏:

代码语言:javascript复制
bs4DashControlbar(
 skin = "light",
 title = "My right sidebar",
 sliderInput(
   inputId = "obs",
   label = "Number of observations:",
   min = 0,
   max = 1000,
   value = 500
 ),
 column(
   width = 12,
   align = "center",
   radioButtons(
     inputId = "dist",
     label = "Distribution type:",
     c("Normal" = "norm",
       "Uniform" = "unif",
       "Log-normal" = "lnorm",
       "Exponential" = "exp")
   )
 )
)

填充 bs4DashControlbar() 后效果如下:

建议不要在右侧边栏中添加过多元素。bs4DashPage()中的 controlbar_overlay 参数控制展开时侧边栏是否覆盖内容,若为 False 则 body 区的内容会随着侧边栏的展开而被压缩。

5. 设置页脚

bs4DashFooter() 用于自定义页脚:

代码语言:javascript复制
bs4DashFooter(
 copyrights = a(
   href = "https://twitter.com/divadnojnarg",
   target = "_blank", "@DivadNojnarg"
 ),
 right_text = "2018"
)

填充 bs4DashFooter() 后效果如下:

6. 设置网页主体内容

bs4DashBody() 用于自定义网页主体内容:

代码语言:javascript复制
bs4DashBody(
 bs4TabItems(
   bs4TabItem(
    tabName = "item1",
    fluidRow(
      lapply(1:3, FUN = function(i) {
        bs4Sortable(
          width = 4,
          p(class = "text-center", paste("Column", i)),
          lapply(1:2, FUN = function(j) {
            bs4Card(
              title = paste0("I am the ", j,"-th card of the ", i, "-th column"),
              width = 12,
              "Click on my header"
            )
          })
        )
      })
    )
   ),
   bs4TabItem(
     tabName = "item2",
     bs4Card(
       title = "Card with messages",
       width = 9,
       userMessages(
         width = 12,
         status = "success",
         userMessage(
           author = "Alexander Pierce",
           date = "20 Jan 2:00 pm",
           src = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg",
           side = NULL,
           "Is this template really for free? That's unbelievable!"
         ),
         userMessage(
           author = "Dana Pierce",
           date = "21 Jan 4:00 pm",
           src = "https://adminlte.io/themes/AdminLTE/dist/img/user5-128x128.jpg",
           side = "right",
           "Indeed, that's unbelievable!"
         )
       )
     )
   )
 )
)

填充 bs4DashBody() 后效果如下:

7. 组装代码

最后,把上面每一个部分的代码套到框架里就得到了这个 bs4Dash 应用的完整代码:

代码语言:javascript复制
library(shiny)
library(bs4Dash)
shiny::shinyApp(
  ui = bs4DashPage(
    old_school = FALSE,
    sidebar_collapsed = TRUE,
    controlbar_collapsed = TRUE,
    title = "Basic Dashboard",
    navbar = bs4DashNavbar(
      skin = "light",
      status = "white",
      border = TRUE,
      sidebarIcon = "bars",
      controlbarIcon = "th",
      fixed = FALSE,
      leftUi = bs4DropdownMenu(
        show = TRUE,
        align = "left",
        status = "warning",
        menuIcon = "envelope-open",
        src = NULL
      ),
      rightUi = bs4DropdownMenu(
        show = FALSE,
        status = "danger",
        src = "https://www.google.fr",
        bs4DropdownMenuItem(
          message = "message 1",
          from = "Divad Nojnarg",
          src = "https://adminlte.io/themes/v3/dist/img/user3-128x128.jpg",
          time = "today",
          status = "danger",
          type = "message"
        ),
        bs4DropdownMenuItem(
          message = "message 2",
          from = "Nono Gueye",
          src = "https://adminlte.io/themes/v3/dist/img/user3-128x128.jpg",
          time = "yesterday",
          status = "success",
          type = "message"
        )
      )
    ),
    sidebar = bs4DashSidebar(
      skin = "light",
      status = "primary",
      title = "bs4Dash",
      brandColor = "primary",
      url = "https://www.google.fr",
      src = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg",
      elevation = 3,
      opacity = 0.8,
      bs4SidebarUserPanel(
        img = "https://image.flaticon.com/icons/svg/1149/1149168.svg",
        text = "Welcome Onboard!"
      ),
      bs4SidebarMenu(
        bs4SidebarHeader("Header 1"),
        bs4SidebarMenuItem(
          "Item 1",
          tabName = "item1",
          icon = "sliders"
        ),
        bs4SidebarMenuItem(
          "Item 2",
          tabName = "item2",
          icon = "id-card"
        )
      )
    ),
    controlbar = bs4DashControlbar(
      skin = "light",
      title = "My right sidebar",
      sliderInput(
        inputId = "obs",
        label = "Number of observations:",
        min = 0,
        max = 1000,
        value = 500
      ),
      column(
        width = 12,
        align = "center",
        radioButtons(
          inputId = "dist",
          label = "Distribution type:",
          c("Normal" = "norm",
            "Uniform" = "unif",
            "Log-normal" = "lnorm",
            "Exponential" = "exp")
        )
      )
    ),
    footer = bs4DashFooter(
      copyrights = a(
        href = "https://twitter.com/divadnojnarg",
        target = "_blank", "@DivadNojnarg"
      ),
      right_text = "2018"
    ),
    body = bs4DashBody(
      bs4TabItems(
        bs4TabItem(
          tabName = "item1",
          fluidRow(
            lapply(1:3, FUN = function(i) {
              bs4Sortable(
                width = 4,
                p(class = "text-center", paste("Column", i)),
                lapply(1:2, FUN = function(j) {
                  bs4Card(
                    title = paste0("I am the ", j,"-th card of the ", i, "-th column"),
                    width = 12,
                    "Click on my header"
                  )
                })
              )
            })
          )
        ),
        bs4TabItem(
          tabName = "item2",
          bs4Card(
            title = "Card with messages",
            width = 9,
            userMessages(
              width = 12,
              status = "success",
              userMessage(
                author = "Alexander Pierce",
                date = "20 Jan 2:00 pm",
                src = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg",
                side = NULL,
                "Is this template really for free? That's unbelievable!"
              ),
              userMessage(
                author = "Dana Pierce",
                date = "21 Jan 4:00 pm",
                src = "https://adminlte.io/themes/AdminLTE/dist/img/user5-128x128.jpg",
                side = "right",
                "Indeed, that's unbelievable!"
              )
            )
          )
        )
      )
    )
  ),
  server = function(input, output) {}
)

进阶

bootstrap 4 卡片

bs4Dash 也带来了许多 bootstrap 4 卡片特性。

Classic Cards

bs4Card()

代码语言:javascript复制
fluidRow(
    bs4Card(
      title = "Closable card with dropdown",
      closable = TRUE,
      width = 6,
      status = "warning",
      solidHeader = FALSE,
      collapsible = TRUE,
      label = bs4CardLabel(
        text = 1,
        status = "danger",
        tooltip = "Hello!"
      ),
      dropdownMenu = dropdownItemList(
        dropdownItem(url = "https://www.google.com", name = "Link to google"),
        dropdownItem(url = "#", name = "item 2"),
        dropdownDivider(),
        dropdownItem(url = "#", name = "item 3")
      ),
      plotOutput("plot")
    ),
    bs4Card(
      title = "Closable card with gradient",
      closable = TRUE,
      width = 6,
      status = "warning",
      solidHeader = FALSE,
      gradientColor = "success",
      collapsible = TRUE,
      plotOutput("distPlot")
    ),
    bs4Card(
      title = "Card with solidHeader and elevation",
      elevation = 4,
      closable = TRUE,
      width = 6,
      solidHeader = TRUE,
      status = "primary",
      collapsible = TRUE,
      plot_ly(z = ~volcano) %>% add_surface()
    )
  )
Social Cards

bs4UserCard()bs4SocialCard()

代码语言:javascript复制
fluidRow(
    bs4UserCard(
      src = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg",
      status = "info",
      title = "User card type 1",
      subtitle = "a subtitle here",
      elevation = 4,
      "Any content here"
    ),
    bs4UserCard(
      type = 2,
      src = "https://adminlte.io/themes/AdminLTE/dist/img/user7-128x128.jpg",
      status = "success",
      imageElevation = 4,
      title = "User card type 2",
      subtitle = "a subtitle here",
      bs4ProgressBar(
        value = 5,
        striped = FALSE,
        status = "info"
      ),
      bs4ProgressBar(
        value = 5,
        striped = TRUE,
        status = "warning",
        width = "20%"
      )
    )
  ),
  fluidRow(
    bs4SocialCard(
      title = "Social Card",
      subtitle = "example-01.05.2018",
      src = "https://adminlte.io/themes/AdminLTE/dist/img/user4-128x128.jpg",
      "Some text here!",
      comments = tagList(
        lapply(X = 1:10, FUN = function(i) {
          cardComment(
            src = "https://adminlte.io/themes/AdminLTE/dist/img/user3-128x128.jpg",
            title = paste("Comment", i),
            date = "01.05.2018",
            paste0("The ", i, "-th comment")
          )
        })
      ),
      footer = "The footer here!"
    ),
    bs4Card(
      title = "Box with user comment",
      status = "primary",
      userPost(
        id = 1,
        src = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg",
        author = "Jonathan Burke Jr.",
        description = "Shared publicly - 7:30 PM today",
        "Lorem ipsum represents a long-held tradition for designers, 
       typographers and the like. Some people hate it and argue for 
       its demise, but others ignore the hate as they create awesome 
       tools to help create filler text for everyone from bacon 
       lovers to Charlie Sheen fans.",
        userPostTagItems(
          userPostTagItem(bs4Badge("item 1", status = "warning")),
          userPostTagItem(bs4Badge("item 2", status = "danger"))
        )
      ),
      userPost(
        id = 2,
        src = "https://adminlte.io/themes/AdminLTE/dist/img/user6-128x128.jpg",
        author = "Adam Jones",
        description = "Shared publicly - 5 days ago",
        userPostMedia(src = "https://adminlte.io/themes/AdminLTE/dist/img/photo2.png"),
        userPostTagItems(
          userPostTagItem(bs4Badge("item 1", status = "info")),
          userPostTagItem(bs4Badge("item 2", status = "danger"))
        )
      )
    )
  ),
  fluidRow(
    bs4Card(
      status = "primary",
      width = 3,
      solidHeader = TRUE,
      cardProfile(
        src = "https://adminlte.io/themes/AdminLTE/dist/img/user4-128x128.jpg",
        title = "Nina Mcintire",
        subtitle = "Software Engineer",
        cardProfileItemList(
          bordered = TRUE,
          cardProfileItem(
            title = "Followers",
            description = 1322
          ),
          cardProfileItem(
            title = "Following",
            description = 543
          ),
          cardProfileItem(
            title = "Friends",
            description = 13287
          )
        )
      )
    ),
    bs4Card(
      title = "Card with messages",
      width = 9,
      userMessages(
        width = 12,
        status = "success",
        userMessage(
          author = "Alexander Pierce",
          date = "20 Jan 2:00 pm",
          src = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg",
          side = NULL,
          "Is this template really for free? That's unbelievable!"
        ),
        userMessage(
          author = "Dana Pierce",
          date = "21 Jan 4:00 pm",
          src = "https://adminlte.io/themes/AdminLTE/dist/img/user5-128x128.jpg",
          side = "right",
          "Indeed, that's unbelievable!"
        )
      )
    )
  )
Tab Cards

bs4TabCard()

代码语言:javascript复制
fluidRow(
    column(
      width = 6,
      bs4TabCard(
        id = "tabcard1",
        title = "A card with tabs",
        elevation = 2,
        width = 12,
        bs4TabPanel(
          tabName = "Tab 1",
          active = FALSE,
          "A wonderful serenity has taken possession of my entire soul,
          like these sweet mornings of spring which I enjoy with my
          whole heart. I am alone, and feel the charm of existence in
          this spot, which was created for the bliss of souls like mine.
          I am so happy, my dear friend, so absorbed in the exquisite sense
          of mere tranquil existence, that I neglect my talents. I should be
          incapable of drawing a single stroke at the present moment; and yet
          I feel that I never was a greater artist than now"
        ),
        bs4TabPanel(
          tabName = "Tab 2",
          active = TRUE,
          "The European languages are members of the same family.
          Their separate existence is a myth. For science, music,
          sport, etc, Europe uses the same vocabulary. The languages
          only differ in their grammar, their pronunciation and their
          most common words. Everyone realizes why a new common
          language would be desirable: one could refuse to pay expensive
          translators. To achieve this, it would be necessary to have
          uniform grammar, pronunciation and more common words. If several
          languages coalesce, the grammar of the resulting language is
          more simple and regular than that of the individual languages."
        ),
        bs4TabPanel(
          tabName = "Tab 3",
          active = FALSE,
          "Lorem Ipsum is simply dummy text of the printing and
          typesetting industry. Lorem Ipsum has been the industry's
          standard dummy text ever since the 1500s, when an unknown
          printer took a galley of type and scrambled it to make a
          type specimen book. It has survived not only five centuries,
          but also the leap into electronic typesetting, remaining
          essentially unchanged. It was popularised in the 1960s with
          the release of Letraset sheets containing Lorem Ipsum passages,
          and more recently with desktop publishing software like Aldus
          PageMaker including versions of Lorem Ipsum."
        )
      )
    ),
    column(
      width = 6,
      bs4TabCard(
        id = "tabcard2",
        title = "A card with tabs",
        side = "right",
        elevation = 2,
        width = 12,
        bs4TabPanel(
          tabName = "Tab 4",
          active = FALSE,
          "A wonderful serenity has taken possession of my entire soul,
          like these sweet mornings of spring which I enjoy with my
          whole heart. I am alone, and feel the charm of existence in
          this spot, which was created for the bliss of souls like mine.
          I am so happy, my dear friend, so absorbed in the exquisite sense
          of mere tranquil existence, that I neglect my talents. I should be
          incapable of drawing a single stroke at the present moment; and yet
          I feel that I never was a greater artist than now"
        ),
        bs4TabPanel(
          tabName = "Tab 5",
          active = TRUE,
          "The European languages are members of the same family.
          Their separate existence is a myth. For science, music,
          sport, etc, Europe uses the same vocabulary. The languages
          only differ in their grammar, their pronunciation and their
          most common words. Everyone realizes why a new common
          language would be desirable: one could refuse to pay expensive
          translators. To achieve this, it would be necessary to have
          uniform grammar, pronunciation and more common words. If several
          languages coalesce, the grammar of the resulting language is
          more simple and regular than that of the individual languages."
        ),
        bs4TabPanel(
          tabName = "Tab 6",
          active = FALSE,
          "Lorem Ipsum is simply dummy text of the printing and
          typesetting industry. Lorem Ipsum has been the industry's
          standard dummy text ever since the 1500s, when an unknown
          printer took a galley of type and scrambled it to make a
          type specimen book. It has survived not only five centuries,
          but also the leap into electronic typesetting, remaining
          essentially unchanged. It was popularised in the 1960s with
          the release of Letraset sheets containing Lorem Ipsum passages,
          and more recently with desktop publishing software like Aldus
          PageMaker including versions of Lorem Ipsum."
        )
      )
    )
  )
Boxes

bs4Box()

代码语言:javascript复制
fluidRow(
    bs4Box(
      height = "600px",
      title = "Box 1",
      plotlyOutput("plot2")
    ),
    bs4Box(
      height = "600px",
      title = "Box 2",
      plotlyOutput("plot3")
    )
  )
Value and Info Boxes

包括 renderbs4InfoBox()renderbs4ValueBox()infoBoxOutput()valueBoxOutput()

代码语言:javascript复制
h4("Value Boxes"),
  fluidRow(
    bs4ValueBox(
      value = 150,
      subtitle = "New orders",
      status = "primary",
      icon = "shopping-cart",
      href = "#"
    ),
    bs4ValueBox(
      elevation = 4,
      value = "53%",
      subtitle = "New orders",
      status = "danger",
      icon = "cogs"
    ),
    bs4ValueBox(
      value = "44",
      subtitle = "User Registrations",
      status = "warning",
      icon = "sliders"
    ),
    bs4ValueBox(
      value = "53%",
      subtitle = "Bounce rate",
      status = "success",
      icon = "database"
    )
  ),
  h4("Info Boxes"),
  fluidRow(
    bs4InfoBox(
      title = "Messages",
      value = 1410,
      icon = "envelope"
    ),
    bs4InfoBox(
      title = "Bookmarks",
      status = "info",
      value = 240,
      icon = "bookmark"
    ),
    bs4InfoBox(
      title = "Comments",
      gradientColor = "danger",
      value = 41410,
      icon = "comments"
    )
  )

Sortable Containers

代码语言:javascript复制
library(shiny)
 library(bs4Dash)
 shiny::shinyApp(
  ui = bs4DashPage(
    navbar = bs4DashNavbar(),
    sidebar = bs4DashSidebar(),
    controlbar = bs4DashControlbar(),
    footer = bs4DashFooter(),
    title = "test",
    body = bs4DashBody(
      bs4TabItems(
        bs4TabItem(
          tabName = "sortabled",
          fluidRow(
            lapply(1:3, FUN = function(i) {
              bs4Sortable(
                width = 4,
                p(class = "text-center", paste("Column", i)),
                lapply(1:2, FUN = function(j) {
                  bs4Card(
                    title = paste0("I am the ", j,"-th card of the ", i, "-th column"),
                    width = 12,
                    "Click on my header"
                  )
                })
              )
            })
          )
        )
      )
    )
  ),
  server = function(input, output) {}
 )

参考

https://rinterface.github.io/bs4Dash/articles/index.html

0 人点赞