😎 Give your xaringan slides some style
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

163 lines
5.4KB

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