2022-11-25

原起

目录

1.丰富数据元素

往表格里插入 Unicode 字符、图片、超链接、字体图标(icon)、迷你图(sparkline)等。

2.丰富表格元素

多行表头、表格标题、表格脚注。

3.设置静态样式

自定义样式、formatStyle 函数、引入 JS。

DT 的基本样式

library(DT)

set.seed(2022)

data <- data.frame(
  type1 = sort(rep(LETTERS[1:20], 2)), 
  type2 = rep(c('NO', 'YES'), 20),
  value1 = sample(200:2000, 40),
  value2 = sample(200:2000, 40),
  level = sample(1:5, 40, replace = TRUE)
)

# 设置全局选项
options(DT.options = list(dom = 'lftp'))

datatable(data)

1.丰富数据元素

插入Unicode 字符、图片、超链接、字体图标、迷你图

1.1.插入 Unicode 字符

  • 填入适于 JS 的Unicode 编码,详细参数介绍见备注(按 P 键)。
datatable(data) |>
  formatCurrency(
    columns = c('value1', 'value2'),
    currency = '\u2714', # 代表 ✔
    before = FALSE,
    digits = 2,
    rows = c(1:2)) |>
  formatString(
    columns = 2,
    prefix = '¥',
    suffix = '\u2716', # 代表 ✖
    rows = seq(
      from = 1,
      to = nrow(data),
      by = 2))

1.2.插入图片

  • <img class="自定义 css 样式" src="图片链接" alt="图片alt">
# 图片名字
imgvalue <- c(rep('China', 2), rep('USA', 2)) 
imgdata <- cbind(data, imgvalue)

# 由于图片名字在表中第6列,所以列渲染时写row[6]
datatable(imgdata,
          options = list(
            pageLength = 5,
            columnDefs = list(
              list(targets = 1,
                   render = JS("
    function(data, type, row, meta) {return  
'<img src=\"https://yuanfan.rbind.io/images/' 
             + row[6] + '.png\" />' 
             + data}")), 
     list(targets = 6, visible = FALSE))))
  • <img src="https://yuanfan.rbind.io/images/imgvalue.png">

1.2.插入图片 –> 改变图片样式

  • 所引入的 css 样式 team-flag、team-name、team-record 见备注(按P键)。
datatable(imgdata,
          options = list(
            columnDefs = list(
              list(targets = 1,
                   render = JS("
function(data, type, row, meta) {return 
'<img class=\"team-flag\" 
        src=\"https://yuanfan.rbind.io/images/' 
         + row[6] + '.png\" />'
         +'<span class=\"team-name\">'+data
         +'<span/><span class=\"team-record\">' 
         + row[5] + 'level'+'<span/>' }")), 
      list(targets = 6, visible = FALSE))))
  • 这段代码直接复制粘贴不可用,因为<img>元素里有多余空格。
  • <img class = "team-flag" src = "https://yuanfan.rbind.io/images/imgvalue.png">
  • <span class = "team-name"> type1 </span>
  • <span class = "team-record"> level 'level'</span>

1.3.插入超链接

  • <a class="自定义 css 样式" href="超链接地址">超链接显示名</a>
hrefvalue = c(rep("https://yufree.cn/cn/", 2),
   rep("https://xiangyun.rbind.io/post/", 2)) 
hrefdata <- cbind(data, hrefvalue) 

datatable(hrefdata,
          options = list(columnDefs = list(
            list(
              targets = 2,
              render = JS(
    "function(data, type, row, meta) {
return  '<a href=' + row[6] + '>' 
          + data + '</a>'}")),
    list(targets = 6, visible = FALSE) 
          )))
  • row[6]表示取数据中第6列中的值。

1.4.插入字体图标 –> 插入一个小图标

  • shiny 包中有个函数icon()可以方便地从字体图标库 Font AwesomeBootstrap Glyphicons 引入小图标。其中,Font Awesome 库在 R 中也有对应的 R 包 fontawesome。
library(fontawesome)
library(data.table)

icon1data <- as.data.table(data)

icon1data <- icon1data[, ':='(icon1 = ifelse(
  type2 == "YES",
  fontawesome::fa(name = "thumbs-up"),
  fontawesome::fa(name = "thumbs-down")
))]

datatable(icon1data, escape = FALSE)

1.4.插入字体图标 –> 插入多个小图标

  • 插入多个小图标就是把单个小图标拼接在一起。
icon2data <- as.data.table(data)

# icon2data$level <- sapply(icon2data$level ,
# function(level) {
#   paste(
#    rep(fontawesome::fa(name = "heart"),level), 
#    collapse = "")
# })

icon2data$level <-
  strrep(fontawesome::fa(name = "heart"), 
             icon2data$level)

datatable(icon2data, escape = FALSE)

1.5.插入迷你图 –> 基本方法

library(sparkline)
dt <- as.data.table(data)
spark_html <- function(...) {
  as.character(htmltools::as.tags(sparkline(..., height = 100, width=100)))}

dt.DT1 <- dt[, .( # 部分参数含义见备注(按P键)。
  '面积图' = spark_html(value1, type = "line"),
  '柱状图' = spark_html(value1, type = "bar"),
  '折线图' = spark_html(value1, type = "line", lineColor = "red", fillColor = FALSE),
  '柱状图2' = spark_html(value1, type = "bar", barColor = "green"),
  '箱图' = spark_html(value1, type = "box") ), keyby = .(type2)]

datatable(dt.DT1,  escape = FALSE, options = list(dom = 't')) |> spk_add_deps()

1.5.插入迷你图 –> 分页重新渲染

dt.DT2 <- dt[, .('饼图' = spark_html(value1, type = "pie", sliceColors = c("red", "green"), 
                  offset = 90)),  keyby = .(type1)]

datatable(dt.DT2,
          escape = FALSE,
          options = list(pageLength=2, dom = 'tp',
            # 每次分页重新渲染,不加这个的话只有第一页有图
            drawCallback = JS('function(s) { HTMLWidgets.staticRender(); }') 
          )) |> spk_add_deps()
  • 部分参数含义见备注(按P键)。

1.5.插入迷你图 –> 组合多个迷你图

dt.DT <- dt[, .(
"两条折线" = as.character(htmltools::as.tags(spk_composite(
  sparkline(value1, type = "line", fillColor = FALSE, lineColor = 'red', width = 300, height = 100),
  sparkline(value2, type = "line", fillColor = FALSE, lineColor = 'green', width = 300, height = 100))))
  ), keyby = .(type2)]

datatable(dt.DT, escape = FALSE, options = list(dom = 't')) |> spk_add_deps()
  • 基本方法就是把多个单独的 sparkline() 一起写入 spk_composite() 中。

2.丰富表格元素

标题、脚注、多行表头

2.1.设置标题、脚注 –> 用标题(caption)参数

datatable(data, caption = '一个表格的标题')

datatable(
  data,
  options = list(dom = 'tp', pageLength = 3),
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: center;',
    htmltools::h5(class = 'font-size:24px;', '标题1:这是表格的主标题'),
    htmltools::h6(class = 'font-size:18px;', '标题2:这是表格的副标题')
  )
)

2.1.设置标题、脚注 –> 用表格容器(container)

.top{caption-side: top; text-align:left;}
.bottom{caption-side: bottom; text-align:left; line-height:90%;}
sketch1 = htmltools::withTags(table(
  caption(class = 'top', h4('主标题:这里写主标题'), h5('副标题:这里写副标题')),
  caption(class = 'bottom', h6('注1:数据来源'), h6('注2:其他说明')),
  thead(tr(th('客户范围'), th('有无'), th('留存人数'), th('流失人数'), th('等级')))))

datatable(data, container = sketch1, rownames = FALSE, 
  options = list(dom = 'tp', pageLength = 3))

2.1.设置标题、脚注 –> 把表格放在 div 框中

主标题:这是表格的副标题

副标题:这是表格的副标题
注1:数据来源
注2:其他说明
tbl <- datatable(data,
                 options = list(dom = 'tp', pageLength = 3))

htmltools::div(
  htmltools::div(
    htmltools::h4("主标题:这是表格的副标题"),
    htmltools::h5("副标题:这是表格的副标题")
  ),
  tbl,
  htmltools::div(htmltools::h6("注1:数据来源"), htmltools::h6("注2:其他说明"))
)

2.2.多行表头

sketch2 = htmltools::withTags(table(
  thead(tr(class = 'firstHead',
    th(rowspan = 2, colspan = 1, '客户范围'),
    th(rowspan = 2, colspan = 1, '有无'),
    th(rowspan = 1, colspan = 2, '总客户数'),
    th(rowspan = 2, colspan = 1, '等级')),
  tr(class = 'secondHead',
    th(rowspan = 1, colspan = 1, '留存人数'),
    th(rowspan = 1, colspan = 1, '流失人数')))))

datatable(
  data, container = sketch2, options = list(dom = 'tp', pageLength = 3),
  rownames = FALSE, escape = FALSE)
  • 具体 css 样式设置内容见备注(按P键)。

3.设置静态样式

字体(字体大小、字体颜色、字体粗细、对齐方式)、边框、背景(背景颜色、背景填充)

3.1.自定义样式

  • 具体的 css 样式设置见备注(按P键)。
  • 一般,此方法会同时改变目标列的表头和表格主体的样式,更多css 背景形状
datatable(data, options = list(
 pageLength = 5,
columnDefs = list(
# 引入自定义的 css 样式  
  list(targets = 1, 
       class = 'dt-center ring'),
  list(targets = 2, 
       class = 'dt-center className1'),
  list(targets = c(3, 4), class = 'className2'),
# 如'dt-[head|body]-center'等官方定义的样式
# 可分别定义表头和表格主体的文本对齐方式
  list(targets = 5,
      className = 'dt-head-right dt-body-left')
  )))
  • DT 包对表格的文本居中方式有默认样式,CSS 优先级问题可参考此贴

3.2.formatStyle 函数 –> 为列

  • 通过formatStyle()函数设定的样式只对目标列的表格主体起作用。

  • list(targets = '_all', className = 'dt-head-center')表示设置所有列的表格表头居中。

datatable(data, options = list(pageLength = 5,
  columnDefs = list(
    list(targets = '_all', className = 'dt-head-center')))) |> 
  formatStyle(
    columns = 1,
    'display' = 'flex',
    'align-items' = 'center',
    'justify-content' = 'center',
    'margin' = 'auto',
    'width' = '1.875rem',
    'height' = '1.875rem',
    'border' = '0.5px solid #555',
    'border-radius' = '50%',
    'color' = '#000',
    'font-size' = '0.8125rem',
    'letter-spacing' = '-1px') |>
  formatStyle(
    columns = 2, 'font-size' = '18px',
    'color' = 'red', 'font-weight' = 'bold',
    'text-align' = 'center',
    'border-right' = '1px solid #555',
    'background-color' = 'lightgrey') |>
  formatStyle(
    columns = c(3, 4), 'min-width' = '100px',
    'text-align' = 'center') |>
  formatStyle(columns = 5, 'text-align' = 'center')

3.2.formatStyle 函数 –> 为行

  • 为不同行填充不同 css 属性的函数的介绍见备注(按P键)。
#为目标列'value1'准备填充渐变颜色所需的分段向量、颜色向量
brks <- quantile(data$value1, 
    probs = seq(.05, .95, .05), na.rm = TRUE)
clrs <- 
  colorRampPalette(c("white", "red"))(length(brks) + 1)

datatable(data, options = list(pageLength = 5,
  columnDefs = list(
list(targets = '_all', className = 'dt-head-center')))) |>
  formatStyle(
    columns = 1,
    valueColumns = 'value1',
'background-color' = 
       styleInterval(cuts = brks, values = clrs),
    'display' = 'flex', 'margin' = 'auto',
    'align-items' = 'center', 'justify-content' = 'center',
    'width' = '1.875rem', 'height' = '1.875rem',
    'border' = '0.5px solid rgb(0,0,0,0.1)',
    'border-radius' = '50%', 'color' = '#000',
    'font-size' = '0.8125rem', 'letter-spacing' = '-1px')|>
  formatStyle(columns = 2,
'color' = styleEqual(levels = c('YES', 'NO'), 
                  values = c('green', 'red'))) |>
  formatStyle(columns = 3,
background = styleColorBar(data$value1, 'steelblue'),
              textAlign='right')

3.3.引入 JS –> 全表的表头与表格主体

  • 在 initComplete 初始化回调函数里引入 JS 函数,调用 Data API 分别为整个表格的表头 table().header()和表格主体tables().body()设置 css 样式。大括号里本来能够以逗号分隔的形式写入多个 css 样式,但是生成 isolides 幻灯片后有问题,所以只写了一个。
datatable(data, options = list(
  initComplete = JS(
    "function(settings, json) {
    $(this.api().table().header()).css({
       'background-color': 'lightblue'});
    $(this.api().tables().body()).css({
       'background-color': 'lightgrey'});
    }")
))

3.3.引入 JS –> 单列的表头与表格主体

  • column(3).header()表示第三列的表头,column(3).nodes()表示第三列的表格主体。
datatable(data,
          options = list(
            pageLength = 5,
            initComplete = JS(
              "function(settings, json) {
    $(this.api().column(3).header()).css({
      'color': 'green','font-size':'24px'});
    $(this.api().column(3).nodes()).css({
      'display': 'flex',
      'align-items': 'center',
      'justify-content': 'center',
      'margin': 'auto',
      'width': '1.875rem',
      'height': '1.875rem',
      'border': '1px solid #555',
      'border-radius': '50%',
      'color': '#000',
      'font-size': '0.8125rem',
      'letter-spacing': '-1px'}); }"
            )
          ))

3.4.样式冲突

1.class/className:先定义好 css 样式和样式名,通过class='样式名'引入样式,一般情况下会对表格表头和表格主体同时起作用,仅对齐方式如className = 'dt-[head|body]-center'可分别对表头或表格主体进行设置。

2.formatStyle():在formatStyle()函数中直接写入需要设置的各样式属性和具体属性值,可对表格的列或行进行设置,可应用styleInterval()等函数为不同行设置不同样式。

3.initComplete = JS():通过调用 DataTables API 对全表或单独一列的表头或表格主体设置样式。

4.如第一章改变图片样式时,单独对一列插入图片且设定了样式。同理,可对单独一列或多列如此设定样式。

datatable(
  data,
  options = list(columnDefs = list(list(
    targets = columns,
    render = JS("function(data, type, row, meta){
              return '<div class=\"className\">' + data + '</div>'
              }"))

5.在设定表格标题、脚注或多行表头时,也可设置样式。

完结https://yuanfan.rbind.io/slides/dt-r15

✿✿ヽ(°▽°)ノ✿ ✿✿ヽ(°▽°)ノ✿ ✿✿ヽ(°▽°)ノ✿