😎 Give your xaringan slides some style
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

165 lines
5.6KB

  1. #' @title Generate lighter or darker version of a color
  2. #' @description Produces a linear blend of the color with white or black.
  3. #' @param color_hex A character string representing a hex color
  4. #' @param strength The "strength" of the blend with white or black,
  5. #' where 0 is entirely the original color and 1 is entirely white
  6. #' (`lighten_color()`) or black (`darken_color()`).
  7. #' @examples
  8. #' blue <- "#0e6ba8"
  9. #' blue_light <- lighten_color(blue, strength = 0.33)
  10. #' blue_dark <- darken_color(blue, strength = 0.33)
  11. #'
  12. #' if (requireNamespace("scales", quietly = TRUE)) {
  13. #' scales::show_col(c(blue_light, blue, blue_dark))
  14. #' }
  15. #' @return A character string with the lightened or darkened color in
  16. #' hexadecimal format.
  17. #' @name lighten_darken_color
  18. NULL
  19. #' @rdname lighten_darken_color
  20. #' @export
  21. lighten_color <- function(color_hex, strength = 0.7) {
  22. stopifnot(strength >= 0 && strength <= 1)
  23. color_rgb <- col2rgb(color_hex)[, 1]
  24. color_rgb <- (1 - strength) * color_rgb + strength * 255
  25. rgb(color_rgb[1], color_rgb[2], color_rgb[3], maxColorValue = 255)
  26. }
  27. #' @rdname lighten_darken_color
  28. #' @export
  29. darken_color <- function(color_hex, strength = 0.8) {
  30. stopifnot(strength >= 0 && strength <= 1)
  31. color_rgb <- col2rgb(color_hex)[, 1]
  32. color_rgb <- (1 - strength) * color_rgb
  33. rgb(color_rgb[1], color_rgb[2], color_rgb[3], maxColorValue = 255)
  34. }
  35. #' @title Add alpha to hex color
  36. #' @description Applies alpha (or opacity) to a color in hexadecimal form by
  37. #' converting opacity in the `[0, 1]` range to hex in the `[0, 255]` range
  38. #' and appending to the hex color.
  39. #' @inheritParams lighten_darken_color
  40. #' @param opacity Desired opacity of the output color
  41. #' @examples
  42. #' blue <- "#0e6ba8"
  43. #' blue_transparent <- apply_alpha(blue)
  44. #'
  45. #' if (requireNamespace("scales", quietly = TRUE)) {
  46. #' scales::show_col(c(blue, blue_transparent))
  47. #' }
  48. #' @return A character string with added opacity level as hexadecimal characters.
  49. #' @export
  50. apply_alpha <- function(color_hex, opacity = 0.5) {
  51. paste0(color_hex, as.hexmode(round(255 * opacity, 0)))
  52. }
  53. adjust_value_color <- function(color_hex, strength = 0.5) {
  54. color_hsv <- rgb2hsv(col2rgb(color_hex))[, 1]
  55. color_hsv["v"] <- strength
  56. hsv(color_hsv[1], color_hsv[2], color_hsv[3])
  57. }
  58. #' Choose dark or light color
  59. #'
  60. #' Takes a color input as `x` and returns either the black or white color (or
  61. #' expression) if dark or light text should be used over the input color for
  62. #' best contrast. Follows W3C Recommendations.
  63. #'
  64. #' @references <https://stackoverflow.com/a/3943023/2022615>
  65. #' @param x The background color (hex)
  66. #' @param black Text or foreground color, e.g. "#222" or
  67. #' `substitute(darken_color(x, 0.8))`, if black text provides the best contrast.
  68. #' @param white Text or foreground color or expression, e.g. "#EEE" or
  69. #' `substitute(lighten_color(x, 0.8))`, if white text provides the best contrast.
  70. #' @examples
  71. #' light_green <- "#c4d6b0"
  72. #' contrast_green <- choose_dark_or_light(light_green)
  73. #' dark_purple <- "#381d2a"
  74. #' contrast_purple <- choose_dark_or_light(dark_purple)
  75. #'
  76. #' if (requireNamespace("scales", quietly = TRUE)) {
  77. #' scales::show_col(c(light_green, contrast_green, dark_purple, contrast_purple))
  78. #' }
  79. #' @return The `black` color or `white` color according to which color provides
  80. #' the greates contrast with the input color.
  81. #'
  82. #' @export
  83. choose_dark_or_light <- function(x, black = "#000000", white = "#FFFFFF") {
  84. if (is_light_color(x)) eval(black) else eval(white)
  85. }
  86. is_light_color <- function(x) {
  87. # this function returns TRUE if the given color
  88. # is light-colored and requires dark text
  89. color_rgb <- col2rgb(x)[, 1]
  90. # from https://stackoverflow.com/a/3943023/2022615
  91. color_rgb <- color_rgb / 255
  92. color_rgb[color_rgb <= 0.03928] <- color_rgb[color_rgb <= 0.03928] / 12.92
  93. color_rgb[color_rgb > 0.03928] <- ((color_rgb[color_rgb > 0.03928] + 0.055) / 1.055)^2.4
  94. lum <- t(c(0.2126, 0.7152, 0.0722)) %*% color_rgb
  95. lum[1, 1] > 0.179
  96. }
  97. prepare_colors <- function(colors = NULL) {
  98. if (is.null(colors) || length(colors) < 1) return(NULL)
  99. if (is.null(names(colors))) {
  100. stop(
  101. "`colors` must have names corresponding to valid CSS classes",
  102. call. = FALSE
  103. )
  104. }
  105. if (any(grepl("\\s", names(colors)))) {
  106. stop(
  107. "Color names in `colors` must be valid CSS classes",
  108. " and cannot contain spaces",
  109. call. = FALSE)
  110. }
  111. maybe_bad_css <- unique(grep("^[_-]|[ .>~*:|+}/]", names(colors), value = TRUE))
  112. if (length(maybe_bad_css) > 0) {
  113. warning(
  114. "Color names in `colors` should be valid CSS classes: ",
  115. paste0("'", maybe_bad_css, "'", collapse = ", "),
  116. call. = FALSE
  117. )
  118. }
  119. whisker::iteratelist(colors, "color_name")
  120. }
  121. full_length_hex <- function(x) {
  122. varname <- substitute(x)
  123. bad_hex_msg <- str_wrap(
  124. "`", deparse(varname), "` is not a hexadecimal color: \"", x, "\". ",
  125. "theme_xaringan() requires colors to be specified in hexadecimal format.",
  126. " If you used valid CSS colors in your xaringan theme, please convert ",
  127. "these colors to hex format, e.g. \"#1a2b3c\"."
  128. )
  129. check_color_is_hex(x, stop, bad_hex_msg)
  130. x <- sub("^#", "", x)
  131. if (nchar(x) == 3) {
  132. x <- strsplit(x, character(0))[[1]]
  133. x <- rep(x, each = 2)
  134. x <- paste(x, collapse = "")
  135. }
  136. paste0("#", x)
  137. }
  138. check_color_is_hex <- function(
  139. color,
  140. throw = warning,
  141. msg = "{color} is not a hexadecimal color"
  142. ) {
  143. is_probably_hex <- grepl("^#", color) &&
  144. !grepl("[^#0-9a-fA-F]", color) &&
  145. nchar(sub("^#", "", color)) %in% c(3, 6)
  146. if (!is_probably_hex) {
  147. msg <- glue::glue(msg)
  148. if (!is.null(throw)) throw(str_wrap(msg), call. = FALSE)
  149. }
  150. is_probably_hex
  151. }