Nothing
#' Popup specification for interactive maps
#'
#' `tm_popup()` specifies the popups that are shown in interactive (`"view"`)
#' mode when a feature is clicked. It is passed to the `popup` argument of the
#' layer functions ([tm_polygons()], [tm_symbols()], [tm_lines()], etc.). It
#' replaces the (now deprecated) layer arguments `popup.vars` and `popup.format`.
#'
#' @param vars Names of the data variables that are shown in the popup table.
#' A (possibly named) character vector; when named, the names are used as
#' labels in the popup table. Besides a character vector, the following
#' special values are supported (identical to the former `popup.vars`
#' argument):
#' \describe{
#' \item{`TRUE`}{show all variables of the shape object;}
#' \item{`FALSE`}{disable popups;}
#' \item{`NA` (default)}{automatic: if map variables (e.g. `fill`) are
#' used, only those are shown, otherwise all variables of the shape
#' object are shown.}
#' }
#' @param title Name of the data variable used as the popup title (the bold
#' header shown above the popup table). This overrules the layer argument
#' `id`, analogous to how `hover` overrules `id` for hover labels. The
#' default (`NA`) means that the popup title is derived from `id` (the former,
#' and still default, behavior). A length-one character vector is expected;
#' a named value is allowed and reserved for future use.
#' @param format A list of formatting options for the popup values, the output
#' of [tm_label_format()]. Only applicable to numeric data variables. If one
#' list of formatting options is provided, it is applied to all numeric
#' variables of `vars`. A (named) list of lists can also be provided; in that
#' case, each list of formatting options is applied to the named variable.
#' @param width Width of the popup content (view mode). A bare number is
#' interpreted as pixels (e.g. `300` means `"300px"`); a character string is
#' used as-is, so any CSS length is accepted (`"300px"`, `"20em"`, `"50%"`).
#' The default `"auto"` lets the popup size to its content.
#' @param max.height Maximum height of the popup table before it becomes
#' vertically scrollable (view mode). A bare number is interpreted as `em`
#' (e.g. `5` means `"5em"`, roughly "show 5 lines"); a character string is
#' used as-is. Default `"25em"`. Use `max.height = "none"` (or `NA`/`Inf`) to
#' remove the cap, so the popup grows to fit its content and never scrolls.
#' @param title.align,label.align,value.align Horizontal alignment of the
#' popup title (bold header), the variable-name (label) column, and the value
#' column respectively. Each one of `"left"`, `"center"`, or `"right"`.
#' Defaults: title `"left"`, label `"left"`, value `"right"`.
#' @param title.color,label.color,value.color Text color of the popup title,
#' the label column, and the value column respectively. `NULL` (the default
#' for title and value) inherits the browser/popup default; `label.color`
#' defaults to `"#888888"` (grey).
#' @param css Optional free-form CSS, injected verbatim as a `<style>` block in
#' each popup, for full restyling beyond the arguments above. Target the
#' semantic classes `.tmap-popup` (container), `.tmap-popup-table`,
#' `.tmap-popup-title`, `.tmap-popup-label`, and `.tmap-popup-value`. To size
#' the popup box itself, target the backend's own popup element
#' (`.leaflet-popup-content` in view mode, `.maplibregl-popup-content` in
#' maplibre mode). Default `NULL`.
#' @return A `tm_popup` object.
#' @seealso [tm_polygons()], [tm_symbols()], [tm_lines()]
#' @export
tm_popup = function(vars = NA,
title = NA,
format = tm_label_format(),
width = "auto",
max.height = "25em",
title.align = "left",
title.color = NULL,
label.align = "left",
label.color = "#888888",
value.align = "right",
value.color = NULL,
css = NULL) {
structure(
list(vars = vars,
title = title,
format = format,
layout = list(width = width,
max.height = max.height,
title.align = title.align,
title.color = title.color,
label.align = label.align,
label.color = label.color,
value.align = value.align,
value.color = value.color,
css = css)),
class = c("tm_popup", "list")
)
}
# Internal: default popup layout, and completion of a (possibly partial or
# NULL) layout list with these defaults. Used by view_format_popups() so that
# callers passing layout = NULL (e.g. extension layers, or the inset-frame and
# raster code paths) fall back to the documented defaults.
popup_layout_default = function() {
list(width = "auto",
max.height = "25em",
title.align = "left",
title.color = NULL,
label.align = "left",
label.color = "#888888",
value.align = "right",
value.color = NULL,
css = NULL)
}
complete_popup_layout = function(x) {
d = popup_layout_default()
if (is.null(x) || !length(x)) {
out = d
} else {
x = x[!vapply(x, is.null, logical(1))]
out = utils::modifyList(d, x)
}
# Allow bare numbers as CSS lengths. A unit-less number is interpreted with
# a sensible default unit per property: pixels for width (e.g. width = 300
# -> "300px") and em for max.height (e.g. max.height = 5 -> "5em", i.e.
# roughly "show 5 lines"). Character values are passed through unchanged, so
# any CSS length ("300px", "20em", "50%", "auto") still works.
out$width = .as_css_length(out$width, "px")
out$max.height = .as_css_length(out$max.height, "em")
out
}
.as_css_length = function(x, unit = "px") {
# NA / non-finite means "no cap" (used by max.height to disable scrolling).
if (length(x) == 1L && is.na(x)) return("none")
if (is.numeric(x)) {
if (!is.finite(x)) return("none")
return(paste0(x, unit))
}
x
}
# Internal: build an inline style="" attribute from an optional alignment and
# color, omitting any component that is NULL/NA. Returns "" when neither is set.
# Shared by the popup formatters so the title/label/value cells are styled
# consistently.
.popup_style_attr = function(align = NULL, color = NULL) {
parts = c(if (!is.null(align) && !is.na(align)) paste0("text-align:", align),
if (!is.null(color) && !is.na(color)) paste0("color:", color))
if (!length(parts)) "" else paste0(" style=\"", paste(parts, collapse = "; "), ";\"")
}
#' @export
print.tm_popup = function(x, ...) {
cli::cli_text("{.cls tm_popup} specification")
invisible(x)
}
# Internal: resolve the popup specification of a layer function.
#
# It combines the new `popup` argument (a `tm_popup` object, or a bare value
# that is interpreted as `vars`) with the deprecated `popup.vars` /
# `popup.format` arguments, and returns a list with the three element fields
# that are stored on the tm_element: `vars`, `format`, and `title`.
#
# The `*.called` flags indicate whether the user explicitly supplied the
# corresponding argument (typically `"<arg>" %in% args_called`). They are used
# to decide (a) which source wins and (b) whether to emit a deprecation
# message. Because the convenience wrappers (e.g. `tm_dots()`, `tm_fill()`)
# forward these arguments via `...` rather than as their own formals, the
# `args_called` of the primitive layer function reliably reflects user intent.
process_popup = function(popup = tm_popup(),
popup.vars = NA,
popup.format = tm_label_format(),
popup.called = FALSE,
popup.vars.called = FALSE,
popup.format.called = FALSE,
layer_fun = NULL) {
depr_called = popup.vars.called || popup.format.called
if (popup.called) {
# New API used.
if (depr_called) message_popup_both(layer_fun)
if (!inherits(popup, "tm_popup")) {
# Permissive shorthand, e.g. popup = c("a", "b") or popup = FALSE.
popup = tm_popup(vars = popup)
}
} else if (depr_called) {
# Only the deprecated arguments were used.
message_popup_deprecated(layer_fun)
popup = tm_popup(vars = popup.vars, format = popup.format)
}
# else: keep the (default) `popup`, i.e. tm_popup().
# Guard against a NULL format (e.g. tm_popup(format = NULL)).
format = popup$format
if (is.null(format)) format = tm_label_format()
# Layout (scalar styling). It is present on tm_popup objects; for a bare
# shorthand value it falls back to the defaults.
layout = popup$layout
if (is.null(layout)) layout = popup_layout_default()
list(vars = popup$vars,
format = format,
title = popup$title,
layout = layout)
}
message_popup_deprecated = function(layer_fun = NULL) {
fn = if (is.null(layer_fun)) "the layer function" else paste0(layer_fun, "()")
cli::cli_inform(
c("{.field [deprecated]} The arguments {.arg popup.vars} and {.arg popup.format} of {.code {fn}} are deprecated.",
"i" = "Use {.arg popup} with {.fn tm_popup} instead, e.g. {.code popup = tm_popup(vars = ..., format = ...)}."),
.frequency = "regularly",
.frequency_id = "popup-vars-deprecated"
)
}
message_popup_both = function(layer_fun = NULL) {
fn = if (is.null(layer_fun)) "the layer function" else paste0(layer_fun, "()")
cli::cli_inform(
c("{.field [popup]} Both {.arg popup} and the deprecated {.arg popup.vars}/{.arg popup.format} were supplied to {.code {fn}}.",
"i" = "The deprecated arguments are ignored in favour of {.arg popup}."),
.frequency = "regularly",
.frequency_id = "popup-both"
)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.