From 6058358fe2f56901f2ef175fb74fa655e0b9793b Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Mon, 13 Jul 2020 16:28:24 -0400 Subject: [PATCH 001/200] Settable font options (#591) * Add parital implementation of custom font support * Add partial implementation of better font support * Add the `add` option to `opt_font()` * Make further refinements on expanded font support * Update google_fonts_process.R * Update google_fonts_process.R * Make modifications based on code review * Add `info_google_fonts()` information fcn * Change fcn name and add some testthat tests * Add more testthat tests * Update test-opt_functions.R * Put Google Fonts processing in sysdata pipeline * Add CSS builder functions and docs * Add documentation assets * Make changes based on code review * Reexport `css()` and update documentation * Update DESCRIPTION * Use correct dimension values in testthat test --- DESCRIPTION | 2 +- NAMESPACE | 7 + R/compile_scss.R | 21 +- R/dt_options.R | 13 +- R/helpers.R | 202 +- R/info_tables.R | 205 +- R/opts.R | 242 ++ R/reexports.R | 4 + R/sysdata.rda | Bin 117513 -> 191478 bytes R/tab_create_modify.R | 91 +- R/utils.R | 12 +- R/utils_render_html.R | 42 +- R/zzz.R | 10 + _pkgdown.yml | 8 +- data-raw/X04-palettes_strips.R | 5 + data-raw/X05-google_fonts.R | 140 + data-raw/zz_process_datasets_ext.R | 2 + inst/css/external.css | 11 + inst/css/gt_styles_default.scss | 2 + inst/extdata/google_axes_tbl.csv | 59 + inst/extdata/google_font_tbl.csv | 1008 +++++++ inst/extdata/google_styles_tbl.csv | 2683 +++++++++++++++++ man/adjust_luminance.Rd | 4 +- man/cell_borders.Rd | 2 + man/cell_fill.Rd | 2 + man/cell_text.Rd | 6 +- man/cells_body.Rd | 2 + man/cells_column_labels.Rd | 2 + man/cells_column_spanners.Rd | 2 + man/cells_grand_summary.Rd | 2 + man/cells_row_groups.Rd | 2 + man/cells_stub.Rd | 2 + man/cells_stubhead.Rd | 2 + man/cells_summary.Rd | 2 + man/cells_title.Rd | 2 + man/currency.Rd | 2 + man/default_fonts.Rd | 81 + man/escape_latex.Rd | 4 +- man/figures/man_cols_width_1.png | Bin 36577 -> 36577 bytes man/figures/man_default_fonts_1.png | Bin 0 -> 16127 bytes man/figures/man_google_font_1.png | Bin 0 -> 14827 bytes man/figures/man_google_font_2.png | Bin 0 -> 85656 bytes man/figures/man_info_google_fonts_1.png | Bin 0 -> 188535 bytes man/figures/man_opt_css_1.png | Bin 0 -> 25815 bytes man/figures/man_opt_table_font_1.png | Bin 0 -> 45023 bytes man/figures/man_opt_table_font_2.png | Bin 0 -> 18357 bytes man/figures/man_tab_style_3.png | Bin 0 -> 15895 bytes man/google_font.Rd | 113 + man/gt_latex_dependencies.Rd | 4 +- man/html.Rd | 2 + man/info_currencies.Rd | 8 +- man/info_date_style.Rd | 6 +- man/info_google_fonts.Rd | 43 + man/info_locales.Rd | 4 + man/info_paletteer.Rd | 4 + man/info_time_style.Rd | 6 +- man/md.Rd | 2 + man/opt_align_table_header.Rd | 2 + man/opt_all_caps.Rd | 2 + man/opt_css.Rd | 86 + man/opt_footnote_marks.Rd | 2 + man/opt_row_striping.Rd | 2 + man/opt_table_font.Rd | 120 + man/opt_table_lines.Rd | 2 + man/opt_table_outline.Rd | 2 + man/pct.Rd | 2 + man/px.Rd | 2 + man/random_id.Rd | 4 +- man/reexports.Rd | 3 + man/tab_options.Rd | 39 +- man/tab_style.Rd | 26 +- .../html-16-table_options_everywhere.R | 4 +- tests/testthat/helper-gt_attr_expectations.R | 2 +- tests/testthat/test-info_tables.R | 17 + tests/testthat/test-opt_functions.R | 111 + tests/testthat/test-tab_style.R | 40 + tests/testthat/test-util_functions.R | 5 +- 77 files changed, 5467 insertions(+), 86 deletions(-) create mode 100644 data-raw/X05-google_fonts.R create mode 100644 inst/css/external.css create mode 100644 inst/extdata/google_axes_tbl.csv create mode 100644 inst/extdata/google_font_tbl.csv create mode 100644 inst/extdata/google_styles_tbl.csv create mode 100644 man/default_fonts.Rd create mode 100644 man/figures/man_default_fonts_1.png create mode 100644 man/figures/man_google_font_1.png create mode 100644 man/figures/man_google_font_2.png create mode 100644 man/figures/man_info_google_fonts_1.png create mode 100644 man/figures/man_opt_css_1.png create mode 100644 man/figures/man_opt_table_font_1.png create mode 100644 man/figures/man_opt_table_font_2.png create mode 100644 man/figures/man_tab_style_3.png create mode 100644 man/google_font.Rd create mode 100644 man/info_google_fonts.Rd create mode 100644 man/opt_css.Rd create mode 100644 man/opt_table_font.Rd diff --git a/DESCRIPTION b/DESCRIPTION index eecbd6a18b..59157168f2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -23,7 +23,7 @@ BugReports: https://github.com/rstudio/gt/issues Encoding: UTF-8 LazyData: true ByteCompile: true -RoxygenNote: 7.1.0.9000 +RoxygenNote: 7.1.1 Depends: R (>= 3.2.0) Imports: diff --git a/NAMESPACE b/NAMESPACE index 854f0bbfad..067929eb03 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -32,8 +32,10 @@ export(cols_move_to_end) export(cols_move_to_start) export(cols_width) export(contains) +export(css) export(currency) export(data_color) +export(default_fonts) export(ends_with) export(escape_latex) export(everything) @@ -50,6 +52,7 @@ export(fmt_percent) export(fmt_scientific) export(fmt_time) export(ggplot_image) +export(google_font) export(grand_summary_rows) export(gt) export(gt_latex_dependencies) @@ -59,6 +62,7 @@ export(gtsave) export(html) export(info_currencies) export(info_date_style) +export(info_google_fonts) export(info_locales) export(info_paletteer) export(info_time_style) @@ -68,8 +72,10 @@ export(md) export(one_of) export(opt_align_table_header) export(opt_all_caps) +export(opt_css) export(opt_footnote_marks) export(opt_row_striping) +export(opt_table_font) export(opt_table_lines) export(opt_table_outline) export(pct) @@ -96,6 +102,7 @@ import(rlang) import(tidyselect) importFrom(dplyr,vars) importFrom(ggplot2,ggsave) +importFrom(htmltools,css) importFrom(magrittr,"%>%") importFrom(tidyselect,contains) importFrom(tidyselect,ends_with) diff --git a/R/compile_scss.R b/R/compile_scss.R index 5be69212a5..0499ddf480 100644 --- a/R/compile_scss.R +++ b/R/compile_scss.R @@ -9,6 +9,21 @@ compile_scss <- function(data, id = NULL) { has_id <- !is.null(id) + # Get the vector of fonts and transform to a `font-family` string + font_vec <- unique(dt_options_get_value(data = data, option = "table_font_names")) + font_family_attr <- as_css_font_family_attr(font_vec = font_vec) + + # Get any additional CSS statements + additional_css <- dt_options_get_value(data = data, option = "table_additional_css") + + # Determine if there are any additional CSS statements + has_additional_css <- any(nchar(additional_css) > 0) + + # Combine any additional CSS statements and separate with `\n` + if (has_additional_css) { + table_additional_css <- paste(additional_css, collapse = "\n") %>% paste_right("\n") + } + sass::sass( list( list(element_id = id), @@ -19,14 +34,14 @@ compile_scss <- function(data, id = NULL) { .open = "<<", .close = ">>", " <> { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', - Arial, sans-serif; + <> } <> @include gt_styles(); <> + + <> ") ) ) diff --git a/R/dt_options.R b/R/dt_options.R index dcf3a0064a..8be9d5e31d 100644 --- a/R/dt_options.R +++ b/R/dt_options.R @@ -36,6 +36,13 @@ dt_options_get_value <- function(data, option) { dt_options$value[[which(dt_options$parameter == option)]] } +default_fonts_vec <- + c( + "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", + "Oxygen", "Ubuntu", "Cantarell", "Helvetica Neue", "Fira Sans", + "Droid Sans", "Arial", "sans-serif" + ) + dt_options_tbl <- dplyr::tribble( ~parameter, ~scss, ~category, ~type, ~value, @@ -50,9 +57,13 @@ dt_options_tbl <- "table_margin_left", TRUE, "table", "px", "auto", "table_margin_right", TRUE, "table", "px", "auto", "table_background_color", TRUE, "table", "value", "#FFFFFF", + "table_additional_css", FALSE, "table", "values", character(0), + "table_font_names", FALSE, "table", "values", default_fonts_vec, + "table_font_size", TRUE, "table", "px", "16px", + "table_font_weight", TRUE, "table", "value", "normal", + "table_font_style", TRUE, "table", "value", "normal", "table_font_color", TRUE, "table", "value", "#333333", "table_font_color_light", TRUE, "table", "value", "#FFFFFF", - "table_font_size", TRUE, "table", "px", "16px", "table_border_top_include", FALSE, "table", "logical", TRUE, "table_border_top_style", TRUE, "table", "value", "solid", "table_border_top_width", TRUE, "table", "px", "2px", diff --git a/R/helpers.R b/R/helpers.R index 20ed61ca78..47dcbdfa14 100644 --- a/R/helpers.R +++ b/R/helpers.R @@ -1128,8 +1128,8 @@ currency <- function(..., #' function. We can also use one of the following absolute size keywords: #' `"xx-small"`, `"x-small"`, `"small"`, `"medium"`, `"large"`, `"x-large"`, #' or `"xx-large"`. -#' @param style The text style. Can be one of either `"center"`, `"normal"`, -#' `"italic"`, or `"oblique"`. +#' @param style The text style. Can be one of either `"normal"`, `"italic"`, or +#' `"oblique"`. #' @param weight The weight of the font. Can be a text-based keyword such as #' `"normal"`, `"bold"`, `"lighter"`, `"bolder"`, or, a numeric value between #' `1` and `1000`, inclusive. Note that only variable fonts may support the @@ -1219,43 +1219,52 @@ cell_text <- function(color = NULL, # validate_style_in( - style_vals, style_names, "align", - c("center", "left", "right", "justify") + style_vals, style_names, + arg_name = "align", + in_vector = c("center", "left", "right", "justify") ) validate_style_in( - style_vals, style_names, "v_align", - c("middle", "top", "bottom") + style_vals, style_names, + arg_name = "v_align", + in_vector = c("middle", "top", "bottom") ) validate_style_in( - style_vals, style_names, "style", - c("normal", "italic", "oblique") + style_vals, style_names, + arg_name = "style", + in_vector = c("normal", "italic", "oblique") ) validate_style_in( - style_vals, style_names, "weight", - c("normal", "bold", "lighter", "bolder") + style_vals, style_names, + arg_name = "weight", + in_vector = c("normal", "bold", "lighter", "bolder"), + with_pattern = "[1-9][0-9][0-9]" ) validate_style_in( - style_vals, style_names, "stretch", - c("ultra-condensed", "extra-condensed", "condensed", + style_vals, style_names, arg_name = "stretch", + in_vector = c( + "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", - "extra-expanded", "ultra-expanded") + "extra-expanded", "ultra-expanded" + ) ) validate_style_in( - style_vals, style_names, "decorate", - c("overline", "line-through", "underline", "underline overline") + style_vals, style_names, + arg_name = "decorate", + in_vector = c("overline", "line-through", "underline", "underline overline") ) validate_style_in( - style_vals, style_names, "transform", - c("uppercase", "lowercase", "capitalize") + style_vals, style_names, + arg_name = "transform", + in_vector = c("uppercase", "lowercase", "capitalize") ) - cell_style_structure("cell_text", style_vals) + cell_style_structure(name = "cell_text", obj = style_vals) } cell_style_to_html.cell_text <- function(style) { @@ -1544,6 +1553,155 @@ cell_style_structure <- function(name, obj, subclass = name) { style_obj } +#' Helper function for specifying a font from the Google Fonts service +#' +#' The `google_font()` helper function can be used wherever a font name should +#' be specified. There are two instances where this helper can be used: the +#' `name` argument in [opt_table_font()] (for setting a table font) and in that +#' of [cell_text()] (used with [tab_style()]). To get a helpful listing of fonts +#' that work well in tables, use the [info_google_fonts()] function. +#' +#' @param name The complete name of a font available in Google Fonts. +#' +#' @return An object of class `font_css`. +#' +#' @examples +#' if (interactive()) { +#' +#' # Use `exibble` to create a gt table of +#' # eight rows, replace missing values with +#' # em dashes; for text in the `time` column, +#' # we use the Google font 'IBM Plex Mono' +#' # and set up the `default_fonts()` as +#' # fallbacks (just in case the webfont is +#' # not accessible) +#' tab_1 <- +#' exibble %>% +#' dplyr::select(char, time) %>% +#' gt() %>% +#' fmt_missing(columns = everything()) %>% +#' tab_style( +#' style = cell_text( +#' font = c( +#' google_font(name = "IBM Plex Mono"), +#' default_fonts() +#' ) +#' ), +#' locations = cells_body(columns = vars(time)) +#' ) +#' +#' # Use `sp500` to create a small gt table, +#' # using `fmt_currency()` to provide a +#' # dollar sign for the first row of monetary +#' # values; then, set a larger font size for +#' # the table and use the 'Merriweather' font +#' # using the `google_font()` function (with +#' # two font fallbacks: 'Cochin' and the +#' # catchall 'Serif' group) +#' tab_2 <- +#' sp500 %>% +#' dplyr::slice(1:10) %>% +#' dplyr::select(-volume, -adj_close) %>% +#' gt() %>% +#' fmt_currency( +#' columns = 2:5, +#' rows = 1, +#' currency = "USD", +#' use_seps = FALSE +#' ) %>% +#' tab_options(table.font.size = px(20)) %>% +#' opt_table_font( +#' font = list( +#' google_font(name = "Merriweather"), +#' "Cochin", "Serif" +#' ) +#' ) +#' } +#' +#' @section Figures: +#' \if{html}{\figure{man_google_font_1.png}{options: width=100\%}} +#' +#' \if{html}{\figure{man_google_font_2.png}{options: width=100\%}} +#' +#' @family Helper Functions +#' @section Function ID: +#' 7-18 +#' +#' @export +google_font <- function(name) { + + import_stmt <- + name %>% tidy_gsub(" ", "+") %>% + paste_between( + c( + "@import url('https://fonts.googleapis.com/css2?family=", + ":ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');" + ) + ) + + font_list <- + list( + name = name, + import_stmt = import_stmt + ) + + class(font_list) <- "font_css" + font_list +} + +#' A vector of default fonts for use with **gt** tables +#' +#' The vector of fonts given by `default_fonts()` should be used with a **gt** +#' table that is rendered to HTML. We can specify additional fonts to use but +#' this default set should be placed after that to act as fallbacks. This is +#' useful when specifying `font` values in the [cell_text()] function (itself +#' used in the [tab_style()] function). If using [opt_table_font()] (which also +#' has a `font` argument) we probably don't need to specify this vector of fonts +#' since it is handled by its `add` option (which is `TRUE` by default). +#' +#' @return A character vector of font names. +#' +#' @examples +#' # Use `exibble` to create a gt table; +#' # attempting to modify the fonts used +#' # for the `time` column is much safer +#' # if `default_fonts()` is appended to +#' # the end of the `font` listing in the +#' # `cell_text()` call (the "Comic Sansa" +#' # and "Menloa" fonts don't exist, but, +#' # we'll get the first available font +#' # from the `default_fonts()` set) +#' tab_1 <- +#' exibble %>% +#' dplyr::select(char, time) %>% +#' gt() %>% +#' tab_style( +#' style = cell_text( +#' font = c( +#' "Comic Sansa", "Menloa", +#' default_fonts() +#' ) +#' ), +#' locations = cells_body(columns = vars(time)) +#' ) +#' +#' @section Figures: +#' \if{html}{\figure{man_default_fonts_1.png}{options: width=100\%}} +#' +#' @family Helper Functions +#' +#' @section Function ID: +#' 7-19 +#' +#' @export +default_fonts <- function() { + c( + "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", + "Oxygen", "Ubuntu", "Cantarell", "Helvetica Neue", "Fira Sans", + "Droid Sans", "Arial", "sans-serif" + ) +} + #' Adjust the luminance for a palette of colors #' #' This function can brighten or darken a palette of colors by an arbitrary @@ -1611,7 +1769,7 @@ cell_style_structure <- function(name, obj, subclass = name) { #' #' @family Helper Functions #' @section Function ID: -#' 7-18 +#' 7-20 #' #' @export adjust_luminance <- function(colors, @@ -1664,7 +1822,7 @@ adjust_luminance <- function(colors, #' #' @family Helper Functions #' @section Function ID: -#' 7-19 +#' 7-21 #' #' @export random_id <- function(n = 10) { @@ -1685,7 +1843,7 @@ random_id <- function(n = 10) { #' #' @family Helper Functions #' @section Function ID: -#' 7-20 +#' 7-22 #' #' @export escape_latex <- function(text) { @@ -1737,7 +1895,7 @@ escape_latex <- function(text) { #' #' @family Helper Functions #' @section Function ID: -#' 7-21 +#' 7-23 #' #' @export gt_latex_dependencies <- function() { diff --git a/R/info_tables.R b/R/info_tables.R index 6a422bdfd9..6dfef8687f 100644 --- a/R/info_tables.R +++ b/R/info_tables.R @@ -1,11 +1,13 @@ #' View a table with info on date styles #' -#' The `fmt_date()` function lets us format date-based values in a convenient +#' The [fmt_date()] function lets us format date-based values in a convenient #' manner using preset styles. The table generated by the `info_date_style()` #' function provides a quick reference to all 14 styles, with associated number #' codes, the format names, and example outputs using a fixed date #' (`2000-02-29`). #' +#' @return An object of class `gt_tbl`. +#' #' @examples #' # Get a table of info on the different #' # date-formatting styles (which are used @@ -62,12 +64,14 @@ info_date_style <- function() { #' View a table with info on time styles #' -#' The `fmt_time()` function lets us format time-based values in a convenient +#' The [fmt_time()] function lets us format time-based values in a convenient #' manner using preset styles. The table generated by the `info_time_style()` #' function provides a quick reference to all five styles, with associated #' number codes, the format names, and example outputs using a fixed time #' (`14:35`). #' +#' @return An object of class `gt_tbl`. +#' #' @examples #' # Get a table of info on the different #' # time-formatting styles (which are used @@ -112,8 +116,8 @@ info_time_style <- function() { #' View a table with info on supported currencies #' -#' The `fmt_currency()` function lets us format numeric values as currencies. -#' The table generated by the `info_currencies()` function provides a quick +#' The [fmt_currency()] function lets us format numeric values as currencies. +#' The table generated by the [info_currencies()] function provides a quick #' reference to all the available currencies. The currency identifiers are #' provided (name, 3-letter currency code, and 3-digit currency code) along with #' the each currency's exponent value (number of digits of the currency @@ -135,6 +139,8 @@ info_time_style <- function() { #' (`NULL`) will produce a table with all currencies displayed. This option #' only constrains the information table where `type == "code"`. #' +#' @return An object of class `gt_tbl`. +#' #' @examples #' # Get a table of info on all of #' # the currencies where the three- @@ -284,6 +290,8 @@ info_currencies <- function(type = c("code", "symbol"), #' those that begin with that letter in their base locale ID. The default #' (`NULL`) will produce a table with all locales displayed. #' +#' @return An object of class `gt_tbl`. +#' #' @examples #' # Get a table of info on all of #' # the locales where the base @@ -416,6 +424,9 @@ info_locales <- function(begins_with = NULL) { #' palettes should be displayed in the information table. If this is #' `NULL` (the default) then all of the discrete palettes from all of the #' color packages represented in **paletteer** will be displayed. +#' +#' @return An object of class `gt_tbl`. +#' #' @examples #' # Get a table of info on just the #' # `ggthemes` color palette (easily @@ -505,3 +516,189 @@ info_paletteer <- function(color_pkgs = NULL) { ) ) } + + +#' View a table on recommended Google Fonts +#' +#' The [google_font()] helper function can be used wherever a font name should +#' be specified. There are two instances where this helper can be used: the +#' `name` argument in [opt_table_font()] (for setting a table font) and in that +#' of [cell_text()] (used with [tab_style()]). Because there is an overwhelming +#' number of fonts available in the *Google Fonts* catalog, the +#' `info_google_fonts()` provides a table with a set of helpful font +#' recommendations. These fonts look great in the different parts of a **gt** +#' table. Why? For the most part they are suitable for body text, having large +#' counters, large x-height, reasonably low contrast, and open apertures. These +#' font features all make for high legibility at smaller sizes. +#' +#' @return An object of class `gt_tbl`. +#' +#' @examples +#' # Get a table of info on some of the +#' # recommended Google Fonts for tables +#' tab_1 <- info_google_fonts() +#' +#' @family Information Functions +#' @section Function ID: +#' 10-6 +#' +#' @export +info_google_fonts <- function() { + + # Recommended Fonts + recommended <- + c( + "Space Mono", + "Work Sans", + "Inter", + "Rubik", + "Libre Franklin", + "Comorant", + "Fira Sans", + "Fira Code", + "Eczar", + "Chivo", + "Inknut", + "Source Sans Pro", + "Source Serif Pro", + "Roboto", + "Roboto Slab", + "BioRhyme", + "Poppins", + "Archivo Narrow", + "Libre Baskerville", + "Playfair Display", + "Karla", + "Encode Sans", + "Lora", + "Proza Libre", + "Spectral", + "IBM Plex Sans", + "IBM Plex Mono", + "Crimson Text", + "Montserrat", + "PT Sans", + "PT Serif", + "Lato", + "Cardo", + "Open Sans", + "Inconsolata", + "Cabin", + "Raleway", + "Anonymous Pro", + "Merriweather", + "Exo 2", + "Public Sans", + "Muli" + ) + + styles_summary <- + google_styles_tbl %>% + dplyr::mutate(weight = as.integer(weight)) %>% + dplyr::filter(name %in% recommended) %>% + dplyr::group_by(name, style) %>% + dplyr::summarize(min_weight = min(weight), max_weight = max(weight)) %>% + dplyr::ungroup() %>% + dplyr::arrange(name, dplyr::desc(style)) %>% + dplyr::mutate(weight_range = dplyr::case_when( + style == "normal" & min_weight != max_weight ~ paste0("n ", min_weight, "‑", max_weight), + style == "normal" & min_weight == max_weight ~ paste0("n ", min_weight), + style == "italic" & min_weight != max_weight ~ paste0("*i* ", min_weight, "‑", max_weight), + style == "italic" & min_weight == max_weight ~ paste0("*i* ", min_weight) + )) %>% + dplyr::group_by(name) %>% + dplyr::summarize(weight_ranges = paste(weight_range, collapse = "
")) + + source_notes <- + google_styles_tbl %>% + dplyr::filter(name %in% recommended) %>% + dplyr::select(name, copyright) %>% + dplyr::distinct() %>% + dplyr::mutate(name = paste0("**", name, "** ")) %>% + dplyr::mutate(name_copy = paste0(name, copyright)) %>% + dplyr::pull(name_copy) %>% + paste(collapse = ". ") %>% + gsub("..", ".", ., fixed = TRUE) %>% + paste_right(".") + + google_font_tbl_int <- + google_font_tbl %>% + dplyr::filter(name %in% recommended) %>% + dplyr::left_join(styles_summary, by = "name") %>% + dplyr::mutate( + category = stringr::str_to_title(category) %>% + tidy_gsub("_", " ") %>% + tidy_gsub("serif", "Serif") + ) %>% + dplyr::select(-license, -date_added, -designer) %>% + dplyr::mutate(samp = paste0(LETTERS[1:13], letters[1:13], collapse = "")) + + google_font_tbl_gt <- + google_font_tbl_int %>% + dplyr::arrange(category) %>% + gt(rowname_col = "name", groupname_col = "category") %>% + fmt_markdown(columns = vars(weight_ranges)) %>% + tab_style( + style = list( + cell_text(size = px(8), font = "Courier"), + cell_fill(color = "#F7F7F7") + ), + locations = cells_body(columns = vars(weight_ranges)) + ) %>% + tab_style( + style = cell_text(size = px(24)), + locations = cells_title(groups = "title") + ) %>% + tab_style( + style = cell_text(size = px(18)), + locations = cells_title(groups = "subtitle") + ) %>% + tab_style( + style = cell_text(size = px(28), indent = px(5)), + locations = cells_body(columns = vars(samp)) + ) %>% + tab_style( + style = cell_text(size = px(14)), + locations = cells_stub() + ) %>% + tab_style( + style = cell_text(size = px(18), weight = "600"), + locations = cells_row_groups() + ) %>% + tab_header( + title = md("Recommended *Google Fonts* for **gt**"), + subtitle = md("Fonts like these can be accessed using the `google_font()` function.

") + ) %>% + opt_align_table_header("left") %>% + opt_table_lines("none") %>% + tab_options( + table.width = px(800), + column_labels.hidden = TRUE, + row_group.padding = px(12), + data_row.padding = px(4), + table_body.hlines.style = "solid", + table_body.hlines.width = px(1), + table_body.hlines.color = "#F7F7F7", + row_group.border.top.style = "solid", + row_group.border.top.width = px(1), + row_group.border.bottom.width = px(1), + table.border.bottom.style = "solid", + table.border.bottom.width = px(1), + table.border.bottom.color = "#F7F7F7", + source_notes.font.size = px(10), + source_notes.padding = px(6) + ) %>% + tab_source_note(md(source_notes)) + + for (i in seq(nrow(google_font_tbl_int))) { + + google_font_tbl_gt <- + google_font_tbl_gt %>% + tab_style( + style = cell_text(font = google_font(name = google_font_tbl_int$name[i])), + locations = cells_body(columns = vars(samp), rows = google_font_tbl_int$name[i]) + ) + } + + google_font_tbl_gt +} diff --git a/R/opts.R b/R/opts.R index 41b75bda12..79cb807763 100644 --- a/R/opts.R +++ b/R/opts.R @@ -497,6 +497,248 @@ opt_table_outline <- function(data, tab_options_multi(data, option_value_list) } + +#' Option to define a custom font for the table +#' +#' @description +#' The `opt_table_font()` function makes it possible to define a custom font for +#' the entire **gt** table. The standard fallback fonts are still set by default +#' but the font defined here will take precedence. You could still have +#' different fonts in select locations in the table, and for that you would need +#' to use [tab_style()] in conjunction with the [cell_text()] helper function. +#' +#' We have the option to supply either a system font for the `font_name`, or, a +#' font available at the Google Fonts service by use of the [google_font()] +#' helper function. +#' +#' @inheritParams fmt_number +#' @param font Either the name of a font available in the user system or a call +#' to [google_font()], which has a large selection of typefaces. +#' @param style The text style. Can be one of either `"normal"`, `"italic"`, or +#' `"oblique"`. +#' @param weight The weight of the font. Can be a text-based keyword such as +#' `"normal"`, `"bold"`, `"lighter"`, `"bolder"`, or, a numeric value between +#' `1` and `1000`, inclusive. Note that only variable fonts may support the +#' numeric mapping of weight. +#' @param add Should this font be added to the front of the already-defined +#' fonts for the table? By default, this is `TRUE` and is recommended since +#' the list serves as fallbacks when certain fonts are not available. +#' +#' @return An object of class `gt_tbl`. +#' +#' @examples +#' if (interactive()) { +#' +#' # Use `sp500` to create a small gt table, +#' # using `fmt_currency()` to provide a +#' # dollar sign for the first row of monetary +#' # values; then, set a larger font size for +#' # the table and use the 'Merriweather' font +#' # (from Google Fonts, via `google_font()`) +#' # with two font fallbacks ('Cochin' and the +#' # catchall 'Serif' group) +#' tab_1 <- +#' sp500 %>% +#' dplyr::slice(1:10) %>% +#' dplyr::select(-volume, -adj_close) %>% +#' gt() %>% +#' fmt_currency( +#' columns = 2:5, +#' rows = 1, +#' currency = "USD", +#' use_seps = FALSE +#' ) %>% +#' tab_options(table.font.size = px(18)) %>% +#' opt_table_font( +#' font = list( +#' google_font(name = "Merriweather"), +#' "Cochin", "Serif" +#' ) +#' ) +#' +#' # Use `sza` to create an eleven-row table; +#' # within `opt_table_font()`, set up a +#' # preferred list of sans-serif fonts that +#' # are commonly available in macOS (using +#' # part of the `default_fonts()` vector as +#' # a fallback) +#' # and Windows 10 +#' tab_2 <- +#' sza %>% +#' dplyr::filter( +#' latitude == 20 & +#' month == "jan" & +#' !is.na(sza) +#' ) %>% +#' dplyr::select(-latitude, -month) %>% +#' gt() %>% +#' opt_table_font( +#' font = c( +#' "Helvetica Neue", "Segoe UI", +#' default_fonts()[-c(1:3)] +#' ) +#' ) %>% +#' opt_all_caps() +#' +#' } +#' +#' @section Figures: +#' \if{html}{\figure{man_opt_table_font_1.png}{options: width=100\%}} +#' +#' \if{html}{\figure{man_opt_table_font_2.png}{options: width=100\%}} +#' +#' @family Table Option Functions +#' @section Function ID: +#' 9-7 +#' +#' @export +opt_table_font <- function(data, + font, + weight = NULL, + style = NULL, + add = TRUE) { + + existing_fonts <- dt_options_get_value(data = data, option = "table_font_names") + existing_additional_css <- dt_options_get_value(data = data, option = "table_additional_css") + + font <- normalize_font_input(font_input = font) + + additional_css <- c(font$import_stmt, existing_additional_css) + + data <- tab_options(data = data, table.font.names = c(font$name, if (add) existing_fonts)) + data <- tab_options(data = data, table.additional_css = additional_css) + + if (!is.null(weight)) { + + if (is.numeric(weight)) weight <- as.character(weight) + + data <- tab_options(data = data, table.font.weight = weight) + data <- tab_options(data = data, column_labels.font.weight = weight) + } + + if (!is.null(style)) { + data <- tab_options(data = data, table.font.style = style) + } + + data +} + +#' Option to add custom CSS for the table +#' +#' The `opt_css()` function makes it possible to add CSS to a **gt** table. This +#' CSS will be added after the compiled CSS that **gt** generates automatically +#' when the object is transformed to an HTML output table. You can supply `css` +#' as a vector of lines or as a single string. +#' +#' @inheritParams fmt_number +#' @param css The CSS to include as part of the rendered table's `