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()
用于自定义侧边栏:
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
设置皮肤:light
或 dark
;•status
设置侧边栏 bs4SidebarUserPanel
的颜色。提供 5 种颜色:蓝色 primary
, 红色 danger
, 黄色 warning
, 绿色 success
, 青色 info
;•brandColor
设置 bs4SidebarMenuItem
的颜色。同样为上面 5 种;•src
设置侧边栏的头像图片,支持 SVG,JPEG,PNG 格式。
3. 设置导航栏
bs4DashNavbar()
用于自定义导航栏:
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 个容器:leftUi
和 rightUi
分别负责嵌入左右 UI 元素,在他们中间我们还可以添加任意内容。
4. 设置右侧边栏
bs4DashControlbar()
用于自定义右侧边栏:
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()
用于自定义页脚:
bs4DashFooter(
copyrights = a(
href = "https://twitter.com/divadnojnarg",
target = "_blank", "@DivadNojnarg"
),
right_text = "2018"
)
填充 bs4DashFooter()
后效果如下:
6. 设置网页主体内容
bs4DashBody()
用于自定义网页主体内容:
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()
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()
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()
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()
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()
。
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