init
This commit is contained in:
commit
116abafc09
58 changed files with 5749 additions and 0 deletions
30
DESCRIPTION
Normal file
30
DESCRIPTION
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
Package: protomapr
|
||||||
|
Title: Add Protomaps Layers to Leaflet Maps
|
||||||
|
Version: 0.1.0
|
||||||
|
Authors@R: c(
|
||||||
|
person("Evan", "Morrison", , "evan@p34.au", role = c("aut", "cre")),
|
||||||
|
person("Brandon", "Liu", role = "cph",
|
||||||
|
comment = "Author of protomaps-leaflet JavaScript library"))
|
||||||
|
Description: Provides functions to add Protomaps vector tile layers to leaflet
|
||||||
|
maps in R. Wraps the 'protomaps-leaflet' JavaScript library by Brandon Liu
|
||||||
|
<https://protomaps.com/>. Supports PMTiles format, multiple built-in themes
|
||||||
|
(light, dark, white, grayscale, black), custom paint and label rules, and
|
||||||
|
various symbolizer types for styling map features.
|
||||||
|
License: MIT + file LICENSE
|
||||||
|
Encoding: UTF-8
|
||||||
|
Roxygen: list(markdown = TRUE)
|
||||||
|
RoxygenNote: 7.3.2
|
||||||
|
Imports:
|
||||||
|
leaflet (>= 2.0.0),
|
||||||
|
htmltools,
|
||||||
|
htmlwidgets,
|
||||||
|
jsonlite
|
||||||
|
Suggests:
|
||||||
|
testthat (>= 3.0.0),
|
||||||
|
knitr,
|
||||||
|
rmarkdown,
|
||||||
|
viridisLite,
|
||||||
|
RColorBrewer
|
||||||
|
VignetteBuilder: knitr
|
||||||
|
Config/testthat/edition: 3
|
||||||
|
URL: https://github.com/evmo/protomapr
|
||||||
2
LICENSE
Normal file
2
LICENSE
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
YEAR: 2024
|
||||||
|
COPYRIGHT HOLDER: protomapr authors
|
||||||
32
NAMESPACE
Normal file
32
NAMESPACE
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Generated by roxygen2: do not edit by hand
|
||||||
|
|
||||||
|
S3method(print,pm_style)
|
||||||
|
export(addProtomaps)
|
||||||
|
export(pmCenteredTextSymbolizer)
|
||||||
|
export(pmCircleSymbolizer)
|
||||||
|
export(pmCityLabels)
|
||||||
|
export(pmColors)
|
||||||
|
export(pmHideFeatures)
|
||||||
|
export(pmLabelRule)
|
||||||
|
export(pmLineLabelSymbolizer)
|
||||||
|
export(pmLineSymbolizer)
|
||||||
|
export(pmMinimal)
|
||||||
|
export(pmModifyStyle)
|
||||||
|
export(pmPaintRule)
|
||||||
|
export(pmPalette)
|
||||||
|
export(pmPaletteStyle)
|
||||||
|
export(pmPolygonSymbolizer)
|
||||||
|
export(pmShieldSymbolizer)
|
||||||
|
export(pmStyle)
|
||||||
|
export(pmTextSymbolizer)
|
||||||
|
export(protomapsDependency)
|
||||||
|
export(protomapsOptions)
|
||||||
|
export(protomaps_clear_cache)
|
||||||
|
export(protomaps_demo_url)
|
||||||
|
export(protomaps_sample_tiles)
|
||||||
|
export(protomaps_url)
|
||||||
|
export(set_protomaps_key)
|
||||||
|
import(leaflet)
|
||||||
|
importFrom(htmltools,htmlDependency)
|
||||||
|
importFrom(htmlwidgets,onRender)
|
||||||
|
importFrom(jsonlite,toJSON)
|
||||||
14
NEWS.md
Normal file
14
NEWS.md
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# protomapr 0.1.0
|
||||||
|
|
||||||
|
* Initial CRAN release
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* `addProtomaps()` - Add Protomaps vector tile layers to Leaflet maps
|
||||||
|
* Five built-in flavors: light, dark, white, grayscale, black
|
||||||
|
* `pmColors()` - Custom color overrides while preserving rendering rules
|
||||||
|
* Paint rules with `pmPaintRule()` for custom feature styling
|
||||||
|
* Label rules with `pmLabelRule()` for custom text labels
|
||||||
|
* Symbolizers for polygons, lines, circles, and text
|
||||||
|
* JavaScript filter expressions for feature-based styling
|
||||||
|
* Support for PMTiles format and tile API endpoints
|
||||||
435
R/addProtomaps.R
Normal file
435
R/addProtomaps.R
Normal file
|
|
@ -0,0 +1,435 @@
|
||||||
|
# Package-level constants for base flavor colors
|
||||||
|
.baseFlavors <- list(
|
||||||
|
|
||||||
|
light = list(
|
||||||
|
background = "#cccccc", earth = "#e0e0e0", park_a = "#cfddd5", park_b = "#9cd3b4",
|
||||||
|
hospital = "#e4dad9", industrial = "#d1dde1", school = "#e4ded7",
|
||||||
|
wood_a = "#d0ded0", wood_b = "#a0d9a0", pedestrian = "#e3e0d4",
|
||||||
|
scrub_a = "#cedcd7", scrub_b = "#99d2bb", glacier = "#e7e7e7",
|
||||||
|
sand = "#e2e0d7", beach = "#e8e4d0", aerodrome = "#dadbdf",
|
||||||
|
runway = "#e9e9ed", water = "#80deea", pier = "#e0e0e0",
|
||||||
|
zoo = "#c6dcdc", military = "#dcdcdc", ferry = "#5f9ea0",
|
||||||
|
boundary = "#aaaaaa", other = "#ebebeb", minor = "#ffffff",
|
||||||
|
link = "#ffffff", medium = "#f0eded", major = "#f5f5f5",
|
||||||
|
highway = "#ffffff", railway = "#a7b1b3",
|
||||||
|
ocean_label = "#5f9ea0", city_label = "#444444",
|
||||||
|
state_label = "#888888", country_label = "#666666"
|
||||||
|
),
|
||||||
|
dark = list(
|
||||||
|
background = "#2d2d2d", earth = "#3d3d3d", park_a = "#3a4a40", park_b = "#4a5a50",
|
||||||
|
hospital = "#4a4040", industrial = "#3a4044", school = "#4a4540",
|
||||||
|
wood_a = "#3a4a3a", wood_b = "#4a5a4a", pedestrian = "#3a3a35",
|
||||||
|
scrub_a = "#3a4540", scrub_b = "#4a5550", glacier = "#4a4a4a",
|
||||||
|
sand = "#4a4840", beach = "#4a4840", aerodrome = "#3a3a40",
|
||||||
|
runway = "#4a4a50", water = "#28404a", pier = "#3d3d3d",
|
||||||
|
zoo = "#3a4545", military = "#3a3a3a", ferry = "#3a5a6a",
|
||||||
|
boundary = "#555555", other = "#4a4a4a", minor = "#4a4a4a",
|
||||||
|
link = "#4a4a4a", medium = "#5a5a5a", major = "#5a5a5a",
|
||||||
|
highway = "#6a6a6a", railway = "#555555",
|
||||||
|
ocean_label = "#5a8a9a", city_label = "#cccccc",
|
||||||
|
state_label = "#888888", country_label = "#aaaaaa"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
#' Add a Protomaps layer to a Leaflet map
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Adds a vector tile layer from a PMTiles source to a Leaflet map using
|
||||||
|
#' the protomaps-leaflet library. Supports built-in flavors and custom
|
||||||
|
#' styling rules.
|
||||||
|
#'
|
||||||
|
#' @param map A leaflet map object created with \code{\link[leaflet]{leaflet}}.
|
||||||
|
#' @param url Character. URL to a PMTiles file or a tile endpoint with
|
||||||
|
#' \code{{z}/{x}/{y}.mvt} placeholders.
|
||||||
|
#' @param style Optional style object created with \code{\link{pmMinimal}} or
|
||||||
|
#' \code{\link{pmStyle}}. Provides a convenient way to apply preset styles.
|
||||||
|
#' If provided, overrides \code{colors} and \code{labelRules}.
|
||||||
|
#' @param flavor Character. Built-in flavor/theme to use. One of "light", "dark",
|
||||||
|
#' "white", "grayscale", or "black". Default is "light". Ignored if \code{style}
|
||||||
|
#' is provided.
|
||||||
|
#' @param colors Optional list of color overrides. Use \code{\link{pmColors}} to
|
||||||
|
#' create this. Overrides specific colors while keeping built-in rendering rules.
|
||||||
|
#' @param paintRules Optional list of paint rules created with \code{\link{pmPaintRule}}.
|
||||||
|
#' If provided, completely overrides the flavor's default paint rules.
|
||||||
|
#' For simple color changes, use \code{colors} instead.
|
||||||
|
#' @param labelRules Optional list of label rules created with \code{\link{pmLabelRule}}.
|
||||||
|
#' If provided, completely overrides the flavor's default label rules.
|
||||||
|
#' @param backgroundColor Character. Background color for the canvas.
|
||||||
|
#' Default is NULL (uses flavor default).
|
||||||
|
#' @param lang Character. Language code for labels (e.g., "en", "de", "zh").
|
||||||
|
#' Default is NULL (uses default language).
|
||||||
|
#' @param attribution Character. Attribution text for the layer.
|
||||||
|
#' Default is "Protomaps".
|
||||||
|
#' @param options A list of additional options created with \code{\link{protomapsOptions}}.
|
||||||
|
#' @param layerId Character. Layer ID for the protomaps layer.
|
||||||
|
#' @param group Character. Group name for layer control.
|
||||||
|
#'
|
||||||
|
#' @return A modified leaflet map object.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' library(leaflet)
|
||||||
|
#' library(protomapr)
|
||||||
|
#'
|
||||||
|
#' # Basic usage with demo tiles
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
#' addProtomaps(url = protomaps_demo_url())
|
||||||
|
#'
|
||||||
|
#' # Using dark flavor
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
#' addProtomaps(url = protomaps_demo_url(), flavor = "dark")
|
||||||
|
#'
|
||||||
|
#' # Custom colors with proper rendering
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
#' addProtomaps(
|
||||||
|
#' url = protomaps_demo_url(),
|
||||||
|
#' colors = pmColors(earth = "#d3d3d3", water = "#1a3a5c")
|
||||||
|
#' )
|
||||||
|
#'
|
||||||
|
#' # Using preset styles (recommended for common use cases)
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
#' addProtomaps(url = protomaps_demo_url(), style = pmStyle("minimal"))
|
||||||
|
#'
|
||||||
|
#' # Custom minimal style
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
#' addProtomaps(
|
||||||
|
#' url = protomaps_demo_url(),
|
||||||
|
#' style = pmMinimal(land = "#f5f5f0", water = "#1a3a5c", labels = TRUE)
|
||||||
|
#' )
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
#' @import leaflet
|
||||||
|
#' @importFrom htmlwidgets onRender
|
||||||
|
#' @importFrom jsonlite toJSON
|
||||||
|
addProtomaps <- function(map,
|
||||||
|
url,
|
||||||
|
style = NULL,
|
||||||
|
flavor = c("light", "dark", "white", "grayscale", "black"),
|
||||||
|
colors = NULL,
|
||||||
|
paintRules = NULL,
|
||||||
|
labelRules = NULL,
|
||||||
|
backgroundColor = NULL,
|
||||||
|
lang = NULL,
|
||||||
|
attribution = "Protomaps",
|
||||||
|
options = protomapsOptions(),
|
||||||
|
layerId = NULL,
|
||||||
|
group = NULL) {
|
||||||
|
|
||||||
|
flavor <- match.arg(flavor)
|
||||||
|
|
||||||
|
|
||||||
|
# Handle style parameter
|
||||||
|
if (!is.null(style)) {
|
||||||
|
if (inherits(style, "pm_style")) {
|
||||||
|
colors <- style$colors
|
||||||
|
labelRules <- style$labelRules
|
||||||
|
} else if (is.list(style)) {
|
||||||
|
if (!is.null(style$colors)) colors <- style$colors
|
||||||
|
if (!is.null(style$labelRules)) labelRules <- style$labelRules
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build the options object for JavaScript
|
||||||
|
jsOptions <- list(
|
||||||
|
url = url,
|
||||||
|
flavor = flavor,
|
||||||
|
attribution = attribution
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!is.null(colors)) {
|
||||||
|
jsOptions$customColors <- colors
|
||||||
|
jsOptions$baseFlavor <- .baseFlavors[[flavor]] %||% .baseFlavors$light
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is.null(backgroundColor)) {
|
||||||
|
jsOptions$backgroundColor <- backgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is.null(lang)) {
|
||||||
|
jsOptions$lang <- lang
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is.null(paintRules)) {
|
||||||
|
jsOptions$paintRules <- paintRules
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is.null(labelRules)) {
|
||||||
|
jsOptions$labelRules <- labelRules
|
||||||
|
}
|
||||||
|
|
||||||
|
# Merge additional options
|
||||||
|
jsOptions <- c(jsOptions, options)
|
||||||
|
|
||||||
|
if (!is.null(layerId)) {
|
||||||
|
jsOptions$layerId <- layerId
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is.null(group)) {
|
||||||
|
jsOptions$group <- group
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert to JSON
|
||||||
|
jsOptionsJson <- jsonlite::toJSON(jsOptions, auto_unbox = TRUE, null = "null")
|
||||||
|
|
||||||
|
# Add the protomaps dependency to the widget
|
||||||
|
map$dependencies <- c(map$dependencies, list(protomapsDependency()))
|
||||||
|
|
||||||
|
# JavaScript code to add the layer
|
||||||
|
jsCode <- sprintf("
|
||||||
|
function(el, x) {
|
||||||
|
var map = this;
|
||||||
|
var options = %s;
|
||||||
|
|
||||||
|
// Helper to create symbolizer from config
|
||||||
|
var symTypes = {
|
||||||
|
polygon: protomapsL.PolygonSymbolizer,
|
||||||
|
line: protomapsL.LineSymbolizer,
|
||||||
|
circle: protomapsL.CircleSymbolizer,
|
||||||
|
text: protomapsL.TextSymbolizer,
|
||||||
|
centeredText: protomapsL.CenteredTextSymbolizer,
|
||||||
|
lineLabel: protomapsL.LineLabelSymbolizer,
|
||||||
|
shield: protomapsL.ShieldSymbolizer
|
||||||
|
};
|
||||||
|
|
||||||
|
function createSymbolizer(sym, defaultType) {
|
||||||
|
var Ctor = symTypes[sym.type] || symTypes[defaultType];
|
||||||
|
return new Ctor(sym.options || {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function processRule(rule, defaultSymType) {
|
||||||
|
var result = {
|
||||||
|
dataLayer: rule.dataLayer,
|
||||||
|
symbolizer: createSymbolizer(rule.symbolizer, defaultSymType)
|
||||||
|
};
|
||||||
|
if (rule.minzoom !== null) result.minzoom = rule.minzoom;
|
||||||
|
if (rule.maxzoom !== null) result.maxzoom = rule.maxzoom;
|
||||||
|
if (rule.filter) {
|
||||||
|
try {
|
||||||
|
result.filter = new Function('zoom', 'feature', 'return ' + rule.filter);
|
||||||
|
} catch(e) {
|
||||||
|
console.error('Invalid filter:', rule.filter, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build layer options
|
||||||
|
var layerOptions = {
|
||||||
|
url: options.url,
|
||||||
|
attribution: options.attribution
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle custom colors - merge with base flavor
|
||||||
|
if (options.customColors && options.baseFlavor && !options.paintRules) {
|
||||||
|
var customFlavor = Object.assign({}, options.baseFlavor, options.customColors);
|
||||||
|
layerOptions.paintRules = protomapsL.paintRules(customFlavor);
|
||||||
|
layerOptions.labelRules = [];
|
||||||
|
if (customFlavor.background) {
|
||||||
|
layerOptions.backgroundColor = customFlavor.background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (options.flavor && !options.paintRules && !options.customColors) {
|
||||||
|
layerOptions.flavor = options.flavor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.lang) layerOptions.lang = options.lang;
|
||||||
|
|
||||||
|
if (options.paintRules) {
|
||||||
|
layerOptions.paintRules = options.paintRules.map(function(r) {
|
||||||
|
return processRule(r, 'polygon');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.labelRules) {
|
||||||
|
layerOptions.labelRules = options.labelRules.map(function(r) {
|
||||||
|
return processRule(r, 'centeredText');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.backgroundColor) {
|
||||||
|
layerOptions.backgroundColor = options.backgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.maxDataZoom) {
|
||||||
|
layerOptions.maxDataZoom = options.maxDataZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.tileSize) {
|
||||||
|
layerOptions.tileSize = options.tileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and add the layer
|
||||||
|
var protoLayer = protomapsL.leafletLayer(layerOptions);
|
||||||
|
protoLayer.addTo(map);
|
||||||
|
|
||||||
|
// Store reference for potential later use
|
||||||
|
if (options.layerId) {
|
||||||
|
if (!map._protomapsLayers) map._protomapsLayers = {};
|
||||||
|
map._protomapsLayers[options.layerId] = protoLayer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
", jsOptionsJson)
|
||||||
|
|
||||||
|
htmlwidgets::onRender(map, jsCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Protomaps layer options
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Create additional options for protomaps layer configuration.
|
||||||
|
#'
|
||||||
|
#' @param maxDataZoom Numeric. Maximum zoom level to fetch tile data.
|
||||||
|
#' Tiles beyond this zoom will be overzoomed.
|
||||||
|
#' @param tileSize Numeric. Size of tiles in pixels. Default is 256.
|
||||||
|
#' @param debug Logical. Enable debug mode to visualize tile boundaries.
|
||||||
|
#' @param ... Additional options passed to the layer.
|
||||||
|
#'
|
||||||
|
#' @return A list of options.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' protomapsOptions(maxDataZoom = 14, tileSize = 512)
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
protomapsOptions <- function(maxDataZoom = NULL,
|
||||||
|
tileSize = NULL,
|
||||||
|
debug = FALSE,
|
||||||
|
...) {
|
||||||
|
opts <- list(...)
|
||||||
|
|
||||||
|
if (!is.null(maxDataZoom)) opts$maxDataZoom <- maxDataZoom
|
||||||
|
if (!is.null(tileSize)) opts$tileSize <- tileSize
|
||||||
|
if (debug) opts$debug <- TRUE
|
||||||
|
|
||||||
|
opts
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create Protomaps HTML dependency
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates the HTML dependency for the protomaps-leaflet JavaScript library.
|
||||||
|
#' This is automatically included when using \code{\link{addProtomaps}}.
|
||||||
|
#'
|
||||||
|
#' @param version Character. Version of protomaps-leaflet to use.
|
||||||
|
#' Default is "5.1.0".
|
||||||
|
#'
|
||||||
|
#' @return An htmltools::htmlDependency object.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' protomapsDependency()
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
#' @importFrom htmltools htmlDependency
|
||||||
|
protomapsDependency <- function(version = "5.1.0") {
|
||||||
|
htmltools::htmlDependency(
|
||||||
|
name = "protomaps-leaflet",
|
||||||
|
version = version,
|
||||||
|
src = system.file(
|
||||||
|
sprintf("htmlwidgets/lib/protomaps-leaflet-%s", version),
|
||||||
|
package = "protomapr"
|
||||||
|
),
|
||||||
|
script = "protomaps-leaflet.js"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Get Protomaps API tile URL
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Returns a URL template for the Protomaps tile API. Requires an API key,
|
||||||
|
#' which can be passed directly or set via the \code{PROTOMAPS_API_KEY}
|
||||||
|
#' environment variable.
|
||||||
|
#'
|
||||||
|
#' Get a free API key (for non-commercial use) at \url{https://protomaps.com/}.
|
||||||
|
#' For commercial use or high traffic, consider self-hosting PMTiles files.
|
||||||
|
#'
|
||||||
|
#' @param api_key Character. Your Protomaps API key. If NULL (default),
|
||||||
|
#' uses the \code{PROTOMAPS_API_KEY} environment variable.
|
||||||
|
#'
|
||||||
|
#' @return Character. URL template for the tile API.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' # Set your API key as an environment variable (recommended)
|
||||||
|
#' Sys.setenv(PROTOMAPS_API_KEY = "your-api-key-here")
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' addProtomaps(url = protomaps_url())
|
||||||
|
#'
|
||||||
|
#' # Or pass the key directly
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' addProtomaps(url = protomaps_url(api_key = "your-api-key-here"))
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{set_protomaps_key}} for a convenient way to set the API key.
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
protomaps_url <- function(api_key = NULL) {
|
||||||
|
if (is.null(api_key)) {
|
||||||
|
api_key <- Sys.getenv("PROTOMAPS_API_KEY", unset = "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (api_key == "") {
|
||||||
|
stop(
|
||||||
|
"Protomaps API key required.\n",
|
||||||
|
"Get a free key at: https://protomaps.com/\n",
|
||||||
|
"Then either:\
|
||||||
|
",
|
||||||
|
"
|
||||||
|
- Set PROTOMAPS_API_KEY environment variable: Sys.setenv(PROTOMAPS_API_KEY = 'your-key')\n",
|
||||||
|
"
|
||||||
|
- Or pass directly: protomaps_url(api_key = 'your-key')\n",
|
||||||
|
"
|
||||||
|
- Or self-host PMTiles: see vignette('getting-started')",
|
||||||
|
call. = FALSE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf("https://api.protomaps.com/tiles/v4/{z}/{x}/{y}.mvt?key=%s", api_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Set Protomaps API key
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Convenience function to set your Protomaps API key for the current session.
|
||||||
|
#' The key is stored in the \code{PROTOMAPS_API_KEY} environment variable.
|
||||||
|
#'
|
||||||
|
#' For persistent storage, add to your \code{.Renviron} file:
|
||||||
|
#' \code{PROTOMAPS_API_KEY=your-key-here}
|
||||||
|
#'
|
||||||
|
#' Get a free API key at \url{https://protomaps.com/}.
|
||||||
|
#'
|
||||||
|
#' @param api_key Character. Your Protomaps API key.
|
||||||
|
#'
|
||||||
|
#' @return Invisibly returns the API key.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' set_protomaps_key("your-api-key-here")
|
||||||
|
#'
|
||||||
|
#' # Now protomaps_url() will work without arguments
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' addProtomaps(url = protomaps_url())
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
set_protomaps_key <- function(api_key) {
|
||||||
|
Sys.setenv(PROTOMAPS_API_KEY = api_key)
|
||||||
|
message("Protomaps API key set for this session.")
|
||||||
|
invisible(api_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' @rdname protomaps_url
|
||||||
|
#' @export
|
||||||
|
protomaps_demo_url <- function(api_key = NULL) {
|
||||||
|
.Deprecated("protomaps_url")
|
||||||
|
protomaps_url(api_key = api_key)
|
||||||
|
}
|
||||||
147
R/colors.R
Normal file
147
R/colors.R
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
#' Create custom color overrides
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a list of color overrides that can be applied to a built-in flavor.
|
||||||
|
#' This is the recommended way to customize map colors while keeping the
|
||||||
|
#' proper rendering rules (zoom handling, polygon simplification, etc.).
|
||||||
|
#'
|
||||||
|
#' @param background Background color
|
||||||
|
#' @param earth Land/earth color
|
||||||
|
#' @param water Water color
|
||||||
|
#' @param park Park/green space color (also called park_a or park_b)
|
||||||
|
#' @param wood Forest/woodland color (also called wood_a or wood_b)
|
||||||
|
#' @param hospital Hospital area color
|
||||||
|
#' @param industrial Industrial area color
|
||||||
|
#' @param school School/university area color
|
||||||
|
#' @param beach Beach color
|
||||||
|
#' @param glacier Glacier color
|
||||||
|
#' @param highway Highway road color
|
||||||
|
#' @param major Major road color
|
||||||
|
#' @param minor Minor road color
|
||||||
|
#' @param city_label City label color
|
||||||
|
#' @param state_label State/region label color
|
||||||
|
#' @param country_label Country label color
|
||||||
|
#' @param ocean_label Ocean label color
|
||||||
|
#' @param ... Additional color properties
|
||||||
|
#'
|
||||||
|
#' @return A list of color overrides to pass to \code{\link{addProtomaps}}.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' # Simple earth and water colors
|
||||||
|
#' pmColors(earth = "#d3d3d3", water = "#1a3a5c")
|
||||||
|
#'
|
||||||
|
#' # Dark theme with custom colors
|
||||||
|
#' pmColors(
|
||||||
|
#' background = "#1a1a2e",
|
||||||
|
#' earth = "#1a1a2e",
|
||||||
|
#' water = "#16213e",
|
||||||
|
#' park = "#1f4037",
|
||||||
|
#' highway = "#4a4a6a"
|
||||||
|
#' )
|
||||||
|
#'
|
||||||
|
#' # Minimal grayscale
|
||||||
|
#' pmColors(
|
||||||
|
#' background = "#ffffff",
|
||||||
|
#' earth = "#f5f5f5",
|
||||||
|
#' water = "#e0e0e0"
|
||||||
|
#' )
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{addProtomaps}}, \code{\link{protomaps_colors}}
|
||||||
|
#' @export
|
||||||
|
pmColors <- function(background = NULL,
|
||||||
|
earth = NULL,
|
||||||
|
water = NULL,
|
||||||
|
park = NULL,
|
||||||
|
wood = NULL,
|
||||||
|
hospital = NULL,
|
||||||
|
industrial = NULL,
|
||||||
|
school = NULL,
|
||||||
|
beach = NULL,
|
||||||
|
glacier = NULL,
|
||||||
|
highway = NULL,
|
||||||
|
major = NULL,
|
||||||
|
minor = NULL,
|
||||||
|
city_label = NULL,
|
||||||
|
state_label = NULL,
|
||||||
|
country_label = NULL,
|
||||||
|
ocean_label = NULL,
|
||||||
|
...) {
|
||||||
|
|
||||||
|
# Start with extra args, add named params, remove NULLs
|
||||||
|
colors <- c(
|
||||||
|
list(...),
|
||||||
|
list(
|
||||||
|
background = background, earth = earth, water = water,
|
||||||
|
hospital = hospital, industrial = industrial, school = school,
|
||||||
|
beach = beach, glacier = glacier, highway = highway, major = major,
|
||||||
|
city_label = city_label, state_label = state_label,
|
||||||
|
country_label = country_label, ocean_label = ocean_label,
|
||||||
|
# Expand paired colors
|
||||||
|
park_a = park, park_b = park,
|
||||||
|
wood_a = wood, wood_b = wood,
|
||||||
|
minor_a = minor, minor_b = minor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
colors[!vapply(colors, is.null, logical(1))]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Protomaps Color Properties Reference
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Reference documentation for all available color properties that can be
|
||||||
|
#' customized using \code{\link{pmColors}}.
|
||||||
|
#'
|
||||||
|
#' @section Base Colors:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{background}}{Map background color}
|
||||||
|
#' \item{\code{earth}}{Land/terrain color}
|
||||||
|
#' \item{\code{water}}{Water bodies color}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Land Use Colors:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{park_a}, \code{park_b}}{Park colors (use \code{park} in pmColors)}
|
||||||
|
#' \item{\code{wood_a}, \code{wood_b}}{Forest/woodland colors (use \code{wood} in pmColors)}
|
||||||
|
#' \item{\code{hospital}}{Hospital areas}
|
||||||
|
#' \item{\code{industrial}}{Industrial zones}
|
||||||
|
#' \item{\code{school}}{Schools and universities}
|
||||||
|
#' \item{\code{beach}}{Beach areas}
|
||||||
|
#' \item{\code{zoo}}{Zoo areas}
|
||||||
|
#' \item{\code{aerodrome}}{Airport areas}
|
||||||
|
#' \item{\code{glacier}}{Glacier areas}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Road Colors:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{highway}}{Highway/motorway color}
|
||||||
|
#' \item{\code{major}}{Major road color}
|
||||||
|
#' \item{\code{minor_a}, \code{minor_b}}{Minor road colors (use \code{minor} in pmColors)}
|
||||||
|
#' \item{\code{railway}}{Railway lines}
|
||||||
|
#' \item{\code{pier}}{Pier/dock structures}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Label Colors:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{city_label}}{City name labels}
|
||||||
|
#' \item{\code{state_label}}{State/region labels}
|
||||||
|
#' \item{\code{country_label}}{Country name labels}
|
||||||
|
#' \item{\code{ocean_label}}{Ocean/sea labels}
|
||||||
|
#' \item{\code{roads_label_major}}{Major road name labels}
|
||||||
|
#' \item{\code{roads_label_minor}}{Minor road name labels}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Landcover Colors (optional object):
|
||||||
|
#' These are specified as a nested object:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{grassland}}{Grassland areas}
|
||||||
|
#' \item{\code{barren}}{Barren land}
|
||||||
|
#' \item{\code{urban_area}}{Urban zones}
|
||||||
|
#' \item{\code{farmland}}{Agricultural areas}
|
||||||
|
#' \item{\code{forest}}{Forest areas}
|
||||||
|
#' \item{\code{scrub}}{Scrubland}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @name protomaps_colors
|
||||||
|
#' @seealso \code{\link{pmColors}}, \code{\link{addProtomaps}}
|
||||||
|
NULL
|
||||||
109
R/layers.R
Normal file
109
R/layers.R
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
#' Protomaps Basemap Layers Reference
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Reference documentation for the available layers and properties in the
|
||||||
|
#' Protomaps basemap. Use these layer names with \code{\link{pmPaintRule}}
|
||||||
|
#' and \code{\link{pmLabelRule}}, and filter on these properties.
|
||||||
|
#'
|
||||||
|
#' @section Layer Names:
|
||||||
|
#' The following layers are available for styling:
|
||||||
|
#'
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{earth}}{Land polygons}
|
||||||
|
#' \item{\code{water}}{Water polygons, lines, and label points}
|
||||||
|
#' \item{\code{landuse}}{Parks, forests, residential areas, etc.}
|
||||||
|
#' \item{\code{roads}}{Streets, highways, paths}
|
||||||
|
#' \item{\code{buildings}}{Building footprints and addresses}
|
||||||
|
#' \item{\code{places}}{City, town, and region labels}
|
||||||
|
#' \item{\code{pois}}{Points of interest}
|
||||||
|
#' \item{\code{boundaries}}{Administrative boundaries}
|
||||||
|
#' \item{\code{natural}}{Natural features like peaks, forests}
|
||||||
|
#' \item{\code{transit}}{Transit stations and lines}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Places Layer Properties:
|
||||||
|
#' Use these in filter expressions like \code{filter = "feature.props.kind === 'locality'"}
|
||||||
|
#'
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{kind}}{Place type: "country", "region", "locality", "macrohood", "neighbourhood"}
|
||||||
|
#' \item{\code{kind_detail}}{Detailed type: "city", "town", "village", "hamlet", "state", "province", "country"}
|
||||||
|
#' \item{\code{name}}{Place name}
|
||||||
|
#' \item{\code{population}}{Population count (integer)}
|
||||||
|
#' \item{\code{population_rank}}{Population rank (integer, higher = larger)}
|
||||||
|
#' \item{\code{min_zoom}}{Minimum zoom level where label appears (lower = more important)}
|
||||||
|
#' \item{\code{capital}}{Capital status (string)}
|
||||||
|
#' \item{\code{wikidata}}{Wikidata ID}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Water Layer Properties:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{kind}}{Water type: "water", "lake", "playa", "ocean", "other"}
|
||||||
|
#' \item{\code{kind_detail}}{Detailed type: "basin", "canal", "ditch", "dock", "drain", "lake", "reservoir", "river", "riverbank", "stream"}
|
||||||
|
#' \item{\code{name}}{Water body name}
|
||||||
|
#' \item{\code{intermittent}}{Boolean, seasonal water}
|
||||||
|
#' \item{\code{reservoir}}{Boolean}
|
||||||
|
#' \item{\code{alkaline}}{Boolean}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Roads Layer Properties:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{kind}}{Road class: "highway", "major_road", "medium_road", "minor_road", "path"}
|
||||||
|
#' \item{\code{kind_detail}}{Detailed type: "motorway", "trunk", "primary", "secondary", "tertiary", "residential", "service", "pedestrian", "footway", "cycleway"}
|
||||||
|
#' \item{\code{ref}}{Road reference number (e.g., "I-80", "US-101")}
|
||||||
|
#' \item{\code{name}}{Street name}
|
||||||
|
#' \item{\code{oneway}}{Boolean}
|
||||||
|
#' \item{\code{is_bridge}}{Boolean}
|
||||||
|
#' \item{\code{is_tunnel}}{Boolean}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Landuse Layer Properties:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{kind}}{Land use type: "park", "forest", "residential", "commercial", "industrial", "aerodrome", "cemetery", "hospital", "school", "stadium", "zoo"}
|
||||||
|
#' \item{\code{sport}}{Sport type for sports facilities}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Buildings Layer Properties:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{kind}}{Building type: "address", "building", "building_part"}
|
||||||
|
#' \item{\code{height}}{Building height in meters}
|
||||||
|
#' \item{\code{min_height}}{Base height for building parts}
|
||||||
|
#' \item{\code{addr_housenumber}}{Street address number}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section POIs Layer Properties:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{kind}}{POI type: "cafe", "restaurant", "hospital", "school", "bank", "pharmacy", "hotel", etc.}
|
||||||
|
#' \item{\code{name}}{POI name}
|
||||||
|
#' \item{\code{cuisine}}{Cuisine type for restaurants}
|
||||||
|
#' \item{\code{religion}}{Religion for places of worship}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Filter Examples:
|
||||||
|
#' \preformatted{
|
||||||
|
#' # Major cities only
|
||||||
|
#' filter = "feature.props.kind_detail === 'city'"
|
||||||
|
#'
|
||||||
|
#' # States/provinces
|
||||||
|
#' filter = "feature.props.kind === 'region'"
|
||||||
|
#'
|
||||||
|
#' # Important places (low min_zoom = important)
|
||||||
|
#' filter = "feature.props.min_zoom <= 6"
|
||||||
|
#'
|
||||||
|
#' # Large cities by population rank
|
||||||
|
#' filter = "feature.props.population_rank >= 10"
|
||||||
|
#'
|
||||||
|
#' # Highways only
|
||||||
|
#' filter = "feature.props.kind === 'highway'"
|
||||||
|
#'
|
||||||
|
#' # Parks
|
||||||
|
#' filter = "feature.props.kind === 'park'"
|
||||||
|
#'
|
||||||
|
#' # Combine conditions
|
||||||
|
#' filter = "feature.props.kind_detail === 'city' && feature.props.min_zoom <= 8"
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @name protomaps_layers
|
||||||
|
#' @aliases layers
|
||||||
|
#' @seealso \code{\link{pmPaintRule}}, \code{\link{pmLabelRule}}
|
||||||
|
#' @references \url{https://docs.protomaps.com/basemaps/layers}
|
||||||
|
NULL
|
||||||
180
R/palette.R
Normal file
180
R/palette.R
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
#' Apply Color Palette to Land Use Categories
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Maps colors from a palette to land use categories, enabling use of
|
||||||
|
#' viridis, RColorBrewer, and other R color palettes with Protomaps.
|
||||||
|
#'
|
||||||
|
#' @param palette Character vector of colors, or a function that generates colors.
|
||||||
|
#' Can be output from viridis::viridis(), RColorBrewer::brewer.pal(), etc.
|
||||||
|
#' @param categories Character vector of category names to map colors to.
|
||||||
|
#' Default maps to common land use types: water, park, wood, residential,
|
||||||
|
#' commercial, industrial.
|
||||||
|
#' @param n Integer. Number of colors to generate if palette is a function.
|
||||||
|
#' Default is NULL (uses length of categories).
|
||||||
|
#' @param background Character. Background/default color for unassigned categories.
|
||||||
|
#' Default is "#f8f8f8".
|
||||||
|
#'
|
||||||
|
#' @return A list of color mappings suitable for pmColors() or addProtomaps(colors=).
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' library(leaflet)
|
||||||
|
#' library(protomapr)
|
||||||
|
#'
|
||||||
|
#' # Using viridis palette for land use
|
||||||
|
#' if (requireNamespace("viridisLite", quietly = TRUE)) {
|
||||||
|
#' colors <- pmPalette(viridisLite::viridis(6))
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
#' addProtomaps(url = protomaps_url(), colors = colors)
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' # Using RColorBrewer
|
||||||
|
#' if (requireNamespace("RColorBrewer", quietly = TRUE)) {
|
||||||
|
#' colors <- pmPalette(RColorBrewer::brewer.pal(6, "Set2"))
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
#' addProtomaps(url = protomaps_url(), colors = colors)
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' # Custom category mapping
|
||||||
|
#' colors <- pmPalette(
|
||||||
|
#' c("#264653", "#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"),
|
||||||
|
#' categories = c("water", "park", "sand", "buildings", "highway")
|
||||||
|
#' )
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{pmPaletteStyle}}, \code{\link{pmColors}}
|
||||||
|
#' @export
|
||||||
|
pmPalette <- function(palette,
|
||||||
|
categories = NULL,
|
||||||
|
n = NULL,
|
||||||
|
background = "#f8f8f8") {
|
||||||
|
|
||||||
|
if (is.null(categories)) {
|
||||||
|
categories <- c("water", "park", "wood", "residential",
|
||||||
|
"commercial", "industrial")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is.function(palette)) {
|
||||||
|
n_colors <- n %||% length(categories)
|
||||||
|
colors <- palette(n_colors)
|
||||||
|
} else {
|
||||||
|
colors <- palette
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length(colors) < length(categories)) {
|
||||||
|
colors <- rep_len(colors, length(categories))
|
||||||
|
}
|
||||||
|
|
||||||
|
result <- list(background = background, earth = background)
|
||||||
|
|
||||||
|
category_mapping <- list(
|
||||||
|
water = "water",
|
||||||
|
park = c("park_a", "park_b"),
|
||||||
|
wood = c("wood_a", "wood_b"),
|
||||||
|
forest = c("wood_a", "wood_b"),
|
||||||
|
residential = "pedestrian",
|
||||||
|
commercial = "other",
|
||||||
|
industrial = "industrial",
|
||||||
|
hospital = "hospital",
|
||||||
|
school = "school",
|
||||||
|
beach = "beach",
|
||||||
|
sand = "sand",
|
||||||
|
buildings = "buildings",
|
||||||
|
highway = "highway",
|
||||||
|
roads = c("highway", "major", "medium", "minor"),
|
||||||
|
railway = "railway"
|
||||||
|
)
|
||||||
|
|
||||||
|
for (i in seq_along(categories)) {
|
||||||
|
cat_name <- categories[i]
|
||||||
|
color <- colors[i]
|
||||||
|
|
||||||
|
if (cat_name %in% names(category_mapping)) {
|
||||||
|
props <- category_mapping[[cat_name]]
|
||||||
|
for (prop in props) {
|
||||||
|
result[[prop]] <- color
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result[[cat_name]] <- color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create a Themed Palette Style
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a complete pm_style using a color palette. Combines pmPalette()
|
||||||
|
#' with styling for a consistent look.
|
||||||
|
#'
|
||||||
|
#' @param palette Character vector of colors or palette function.
|
||||||
|
#' @param water_color Character. Color for water features. If NULL, uses
|
||||||
|
#' first color from palette.
|
||||||
|
#' @param land_color Character. Color for land/background. Default is "#f8f8f8".
|
||||||
|
#' @param labels Logical. Whether to include city labels. Default is TRUE.
|
||||||
|
#' @param label_color Character. Color for labels. Default is "#333333".
|
||||||
|
#'
|
||||||
|
#' @return A pm_style object.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' library(leaflet)
|
||||||
|
#' library(protomapr)
|
||||||
|
#'
|
||||||
|
#' # Viridis-themed map
|
||||||
|
#' if (requireNamespace("viridisLite", quietly = TRUE)) {
|
||||||
|
#' style <- pmPaletteStyle(viridisLite::viridis(5, option = "D"))
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
#' addProtomaps(url = protomaps_url(), style = style)
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' # Custom palette
|
||||||
|
#' style <- pmPaletteStyle(
|
||||||
|
#' c("#264653", "#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"),
|
||||||
|
#' water_color = "#264653"
|
||||||
|
#' )
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{pmPalette}}, \code{\link{pmStyle}}
|
||||||
|
#' @export
|
||||||
|
pmPaletteStyle <- function(palette,
|
||||||
|
water_color = NULL,
|
||||||
|
land_color = "#f8f8f8",
|
||||||
|
labels = TRUE,
|
||||||
|
label_color = "#333333") {
|
||||||
|
|
||||||
|
if (is.function(palette)) {
|
||||||
|
colors <- palette(5)
|
||||||
|
} else {
|
||||||
|
colors <- palette
|
||||||
|
}
|
||||||
|
|
||||||
|
water <- water_color %||% colors[1]
|
||||||
|
|
||||||
|
base_colors <- pmPalette(colors, background = land_color)
|
||||||
|
base_colors$water <- water
|
||||||
|
base_colors$earth <- land_color
|
||||||
|
base_colors$background <- land_color
|
||||||
|
|
||||||
|
labelRules <- list()
|
||||||
|
if (labels) {
|
||||||
|
labelRules <- list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 12px sans-serif",
|
||||||
|
fill = label_color,
|
||||||
|
stroke = land_color,
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 6")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
structure(
|
||||||
|
list(colors = base_colors, labelRules = labelRules),
|
||||||
|
class = "pm_style"
|
||||||
|
)
|
||||||
|
}
|
||||||
44
R/protomapr-package.R
Normal file
44
R/protomapr-package.R
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#' protomapr: Add Protomaps Layers to Leaflet Maps
|
||||||
|
#'
|
||||||
|
#' The protomapr package provides functions to add Protomaps vector tile
|
||||||
|
#' layers to leaflet maps in R. Unlike raster tile providers, Protomaps
|
||||||
|
#' offers full customization of colors and features, self-hosting from a
|
||||||
|
#' single PMTiles file, and smooth vector rendering at any zoom level.
|
||||||
|
#' See \code{vignette("getting-started")} for why you might choose Protomaps
|
||||||
|
#' over standard provider tiles.
|
||||||
|
#'
|
||||||
|
#' @section Main Functions:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{\link{addProtomaps}}}{Add a Protomaps layer to a Leaflet map}
|
||||||
|
#' \item{\code{\link{protomapsOptions}}}{Configure additional layer options}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Symbolizers:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{\link{pmPolygonSymbolizer}}}{Style polygon features}
|
||||||
|
#' \item{\code{\link{pmLineSymbolizer}}}{Style line features}
|
||||||
|
#' \item{\code{\link{pmCircleSymbolizer}}}{Style point features as circles}
|
||||||
|
#' \item{\code{\link{pmTextSymbolizer}}}{Add text labels}
|
||||||
|
#' \item{\code{\link{pmCenteredTextSymbolizer}}}{Add centered text labels}
|
||||||
|
#' \item{\code{\link{pmLineLabelSymbolizer}}}{Add labels along lines}
|
||||||
|
#' \item{\code{\link{pmShieldSymbolizer}}}{Add shield/badge labels}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Rules:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{\code{\link{pmPaintRule}}}{Define how to paint features}
|
||||||
|
#' \item{\code{\link{pmLabelRule}}}{Define how to label features}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @section Available Themes:
|
||||||
|
#' The following built-in themes are available:
|
||||||
|
#' \itemize{
|
||||||
|
#' \item \code{"light"} - General-purpose light basemap
|
||||||
|
#' \item \code{"dark"} - General-purpose dark basemap
|
||||||
|
#' \item \code{"white"} - High-contrast white theme for data visualization
|
||||||
|
#' \item \code{"grayscale"} - Monochromatic theme
|
||||||
|
#' \item \code{"black"} - Dark theme for data visualization
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @keywords internal
|
||||||
|
"_PACKAGE"
|
||||||
106
R/rules.R
Normal file
106
R/rules.R
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
#' Create a Paint Rule
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a paint rule that specifies how to render features from a
|
||||||
|
#' particular data layer. Paint rules control the visual appearance of
|
||||||
|
#' polygon, line, and point features.
|
||||||
|
#'
|
||||||
|
#' @param dataLayer Character. The name of the data layer in the vector
|
||||||
|
#' tile source (e.g., "water", "earth", "roads").
|
||||||
|
#' @param symbolizer A symbolizer object created with one of the symbolizer
|
||||||
|
#' functions (e.g., \code{\link{pmPolygonSymbolizer}},
|
||||||
|
#' \code{\link{pmLineSymbolizer}}).
|
||||||
|
#' @param minzoom Numeric. Minimum zoom level at which this rule applies.
|
||||||
|
#' Default is NULL (applies at all zoom levels).
|
||||||
|
#' @param maxzoom Numeric. Maximum zoom level at which this rule applies.
|
||||||
|
#' Default is NULL (applies at all zoom levels).
|
||||||
|
#' @param filter Character. A JavaScript expression string that filters
|
||||||
|
#' features. The expression has access to \code{zoom} and \code{feature}
|
||||||
|
#' variables. Default is NULL (no filter).
|
||||||
|
#'
|
||||||
|
#' @return A list representing the paint rule configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' # Render water polygons in blue
|
||||||
|
#' pmPaintRule("water", pmPolygonSymbolizer(fill = "steelblue"))
|
||||||
|
#'
|
||||||
|
#' # Render roads with zoom-dependent visibility
|
||||||
|
#' pmPaintRule("roads", pmLineSymbolizer(color = "gray", width = 2),
|
||||||
|
#' minzoom = 10)
|
||||||
|
#'
|
||||||
|
#' # Filter to only show highways
|
||||||
|
#' pmPaintRule("roads",
|
||||||
|
#' pmLineSymbolizer(color = "orange", width = 4),
|
||||||
|
#' filter = "feature.props.kind === 'highway'")
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmPaintRule <- function(dataLayer,
|
||||||
|
symbolizer,
|
||||||
|
minzoom = NULL,
|
||||||
|
maxzoom = NULL,
|
||||||
|
filter = NULL) {
|
||||||
|
rule <- list(
|
||||||
|
dataLayer = dataLayer,
|
||||||
|
symbolizer = symbolizer
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!is.null(minzoom)) rule$minzoom <- minzoom
|
||||||
|
if (!is.null(maxzoom)) rule$maxzoom <- maxzoom
|
||||||
|
if (!is.null(filter)) rule$filter <- filter
|
||||||
|
|
||||||
|
rule
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create a Label Rule
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a label rule that specifies how to render text labels for
|
||||||
|
#' features from a particular data layer. Label rules control text
|
||||||
|
#' placement and styling, with automatic collision detection.
|
||||||
|
#'
|
||||||
|
#' @param dataLayer Character. The name of the data layer in the vector
|
||||||
|
#' tile source (e.g., "places", "roads").
|
||||||
|
#' @param symbolizer A text symbolizer object created with one of
|
||||||
|
#' \code{\link{pmTextSymbolizer}}, \code{\link{pmCenteredTextSymbolizer}},
|
||||||
|
#' \code{\link{pmLineLabelSymbolizer}}, or \code{\link{pmShieldSymbolizer}}.
|
||||||
|
#' @param minzoom Numeric. Minimum zoom level at which this rule applies.
|
||||||
|
#' Default is NULL (applies at all zoom levels).
|
||||||
|
#' @param maxzoom Numeric. Maximum zoom level at which this rule applies.
|
||||||
|
#' Default is NULL (applies at all zoom levels).
|
||||||
|
#' @param filter Character. A JavaScript expression string that filters
|
||||||
|
#' features. Default is NULL (no filter).
|
||||||
|
#'
|
||||||
|
#' @return A list representing the label rule configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' # Label cities
|
||||||
|
#' pmLabelRule("places",
|
||||||
|
#' pmCenteredTextSymbolizer(font = "14px Arial",
|
||||||
|
#' fill = "black",
|
||||||
|
#' stroke = "white",
|
||||||
|
#' width = 2))
|
||||||
|
#'
|
||||||
|
#' # Label streets along their paths
|
||||||
|
#' pmLabelRule("roads",
|
||||||
|
#' pmLineLabelSymbolizer(font = "11px Arial",
|
||||||
|
#' fill = "#333"),
|
||||||
|
#' minzoom = 14)
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmLabelRule <- function(dataLayer,
|
||||||
|
symbolizer,
|
||||||
|
minzoom = NULL,
|
||||||
|
maxzoom = NULL,
|
||||||
|
filter = NULL) {
|
||||||
|
rule <- list(
|
||||||
|
dataLayer = dataLayer,
|
||||||
|
symbolizer = symbolizer
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!is.null(minzoom)) rule$minzoom <- minzoom
|
||||||
|
if (!is.null(maxzoom)) rule$maxzoom <- maxzoom
|
||||||
|
if (!is.null(filter)) rule$filter <- filter
|
||||||
|
|
||||||
|
rule
|
||||||
|
}
|
||||||
128
R/sample-tiles.R
Normal file
128
R/sample-tiles.R
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
#' Get Path to Sample PMTiles File
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Returns the path to a sample PMTiles file for demos and testing.
|
||||||
|
#' On first use, downloads a small regional extract to the user's cache
|
||||||
|
#' directory.
|
||||||
|
#'
|
||||||
|
#' @param region Character. Region to download. Currently only "sf-bay"
|
||||||
|
#' (San Francisco Bay Area) is available. Default is "sf-bay".
|
||||||
|
#' @param cache_dir Character. Directory to cache the downloaded file.
|
||||||
|
#' Default uses \code{tools::R_user_dir()}.
|
||||||
|
#' @param force_download Logical. Force re-download even if cached.
|
||||||
|
#' Default is FALSE.
|
||||||
|
#'
|
||||||
|
#' @return Character. Path to the PMTiles file.
|
||||||
|
#'
|
||||||
|
#' @details
|
||||||
|
#' The sample tiles are hosted on GitHub releases and downloaded on first use.
|
||||||
|
#' Subsequent calls use the cached file. The SF Bay Area extract is
|
||||||
|
#' approximately 10-15MB and covers the greater San Francisco region at all
|
||||||
|
#' zoom levels.
|
||||||
|
#'
|
||||||
|
#' For production use, consider self-hosting your own PMTiles file. See
|
||||||
|
#' \code{vignette("getting-started")} for options.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' library(leaflet)
|
||||||
|
#' library(protomapr)
|
||||||
|
#'
|
||||||
|
#' # Use sample tiles for demos (downloads on first use)
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
#' addProtomaps(url = protomaps_sample_tiles())
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{protomaps_clear_cache}}, \code{\link{protomaps_url}}
|
||||||
|
#' @export
|
||||||
|
protomaps_sample_tiles <- function(region = "sf-bay",
|
||||||
|
cache_dir = NULL,
|
||||||
|
force_download = FALSE) {
|
||||||
|
|
||||||
|
region <- match.arg(region, choices = c("sf-bay"))
|
||||||
|
|
||||||
|
if (is.null(cache_dir)) {
|
||||||
|
cache_dir <- tools::R_user_dir("protomapr", which = "cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dir.exists(cache_dir)) {
|
||||||
|
dir.create(cache_dir, recursive = TRUE)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename <- sprintf("protomapr-sample-%s.pmtiles", region)
|
||||||
|
local_path <- file.path(cache_dir, filename)
|
||||||
|
|
||||||
|
if (file.exists(local_path) && !force_download) {
|
||||||
|
message("Using cached sample tiles: ", local_path)
|
||||||
|
return(local_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
base_url <- "https://github.com/evmo/protomapr/releases/download"
|
||||||
|
version <- "sample-tiles-v1"
|
||||||
|
download_url <- sprintf("%s/%s/%s", base_url, version, filename)
|
||||||
|
|
||||||
|
message("Downloading sample tiles (~10MB)...")
|
||||||
|
message("Source: ", download_url)
|
||||||
|
|
||||||
|
tryCatch({
|
||||||
|
utils::download.file(
|
||||||
|
url = download_url,
|
||||||
|
destfile = local_path,
|
||||||
|
mode = "wb",
|
||||||
|
quiet = FALSE
|
||||||
|
)
|
||||||
|
message("Downloaded to: ", local_path)
|
||||||
|
}, error = function(e) {
|
||||||
|
stop(
|
||||||
|
"Failed to download sample tiles.\n",
|
||||||
|
"Error: ", conditionMessage(e), "\n",
|
||||||
|
"Try again later or use protomaps_url() with an API key instead.",
|
||||||
|
call. = FALSE
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
local_path
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Clear Cached Sample Tiles
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Removes cached sample PMTiles files to free disk space.
|
||||||
|
#'
|
||||||
|
#' @param cache_dir Character. Cache directory. Default uses same as
|
||||||
|
#' \code{\link{protomaps_sample_tiles}}.
|
||||||
|
#'
|
||||||
|
#' @return Invisibly returns TRUE if files were removed, FALSE otherwise.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' # Clear all cached tiles
|
||||||
|
#' protomaps_clear_cache()
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{protomaps_sample_tiles}}
|
||||||
|
#' @export
|
||||||
|
protomaps_clear_cache <- function(cache_dir = NULL) {
|
||||||
|
if (is.null(cache_dir)) {
|
||||||
|
cache_dir <- tools::R_user_dir("protomapr", which = "cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dir.exists(cache_dir)) {
|
||||||
|
message("Cache directory does not exist: ", cache_dir)
|
||||||
|
return(invisible(FALSE))
|
||||||
|
}
|
||||||
|
|
||||||
|
files <- list.files(cache_dir, pattern = "\\.pmtiles$", full.names = TRUE)
|
||||||
|
|
||||||
|
if (length(files) == 0) {
|
||||||
|
message("No cached tiles found.")
|
||||||
|
return(invisible(FALSE))
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(files)
|
||||||
|
message(sprintf("Removed %d cached file(s).", length(files)))
|
||||||
|
|
||||||
|
invisible(TRUE)
|
||||||
|
}
|
||||||
673
R/styles.R
Normal file
673
R/styles.R
Normal file
|
|
@ -0,0 +1,673 @@
|
||||||
|
#' Create a minimal basemap style
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a minimal style with uniform land color, hiding roads, buildings,
|
||||||
|
#' and most labels. Ideal for data visualization overlays.
|
||||||
|
#'
|
||||||
|
#' @param land Character. Color for all land features. Default is "#f8f8f8".
|
||||||
|
#' @param water Character. Color for water features. Default is "#e0e8f0".
|
||||||
|
#' @param labels Logical. Whether to show city labels. Default is FALSE.
|
||||||
|
#' @param label_color Character. Color for labels if shown. Default is "#666666".
|
||||||
|
#'
|
||||||
|
#' @return A list with `colors` and `labelRules` components to pass to
|
||||||
|
#' \code{\link{addProtomaps}}.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' library(leaflet)
|
||||||
|
#' library(protomapr)
|
||||||
|
#'
|
||||||
|
#' # Ultra-minimal basemap
|
||||||
|
#' style <- pmMinimal()
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
#' addProtomaps(url = protomaps_url(), style = style)
|
||||||
|
#'
|
||||||
|
#' # Custom colors with major city labels
|
||||||
|
#' style <- pmMinimal(land = "#f5f5f0", water = "#1a3a5c", labels = TRUE)
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 8) %>%
|
||||||
|
#' addProtomaps(url = protomaps_url(), style = style)
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{pmStyle}}, \code{\link{addProtomaps}}
|
||||||
|
#' @export
|
||||||
|
pmMinimal <- function(land = "#f8f8f8",
|
||||||
|
water = "#e0e8f0",
|
||||||
|
labels = FALSE,
|
||||||
|
label_color = "#666666") {
|
||||||
|
|
||||||
|
colors <- pmColors(
|
||||||
|
background = land,
|
||||||
|
earth = land,
|
||||||
|
water = water,
|
||||||
|
# Land use - all same as land
|
||||||
|
park = land,
|
||||||
|
wood = land,
|
||||||
|
scrub_a = land,
|
||||||
|
scrub_b = land,
|
||||||
|
glacier = land,
|
||||||
|
sand = land,
|
||||||
|
beach = land,
|
||||||
|
hospital = land,
|
||||||
|
school = land,
|
||||||
|
industrial = land,
|
||||||
|
pedestrian = land,
|
||||||
|
zoo = land,
|
||||||
|
military = land,
|
||||||
|
aerodrome = land,
|
||||||
|
# Roads - hidden
|
||||||
|
highway = land,
|
||||||
|
major = land,
|
||||||
|
medium = land,
|
||||||
|
minor = land,
|
||||||
|
link = land,
|
||||||
|
other = land,
|
||||||
|
railway = land,
|
||||||
|
pier = land,
|
||||||
|
boundary = land,
|
||||||
|
# Buildings - hidden
|
||||||
|
buildings = land
|
||||||
|
)
|
||||||
|
|
||||||
|
labelRules <- list()
|
||||||
|
if (labels) {
|
||||||
|
labelRules <- list(
|
||||||
|
# Major cities only
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 12px sans-serif",
|
||||||
|
fill = label_color,
|
||||||
|
stroke = land,
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 6")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
structure(
|
||||||
|
list(colors = colors, labelRules = labelRules),
|
||||||
|
class = "pm_style"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Get a preset map style
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Returns a preset style configuration. Available presets provide common
|
||||||
|
#' styling patterns without manual configuration.
|
||||||
|
#'
|
||||||
|
#' @param name Character. Name of the preset style. One of:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{"minimal"}{Light gray land, light blue water, no labels}
|
||||||
|
#' \item{"minimal-dark"}{Dark land, dark blue water, no labels}
|
||||||
|
#' \item{"muted"}{Subtle colors, faint roads, major labels only}
|
||||||
|
#' \item{"watercolor"}{Soft, painterly aesthetic}
|
||||||
|
#' \item{"ink"}{Black lines on white, like a pen drawing}
|
||||||
|
#' \item{"terrain"}{Earthy tones with subtle elevation feel}
|
||||||
|
#' \item{"transit"}{Muted base with emphasized rail lines}
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @return A list with style components to pass to \code{\link{addProtomaps}}.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' library(leaflet)
|
||||||
|
#' library(protomapr)
|
||||||
|
#'
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
#' addProtomaps(url = protomaps_url(), style = pmStyle("minimal"))
|
||||||
|
#'
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
#' addProtomaps(url = protomaps_url(), style = pmStyle("watercolor"))
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{pmMinimal}}, \code{\link{addProtomaps}}
|
||||||
|
#' @export
|
||||||
|
pmStyle <- function(name = c("minimal", "minimal-dark", "muted", "watercolor",
|
||||||
|
"ink", "terrain", "transit")) {
|
||||||
|
name <- match.arg(name)
|
||||||
|
|
||||||
|
switch(name,
|
||||||
|
"minimal" = pmMinimal(),
|
||||||
|
|
||||||
|
"minimal-dark" = pmMinimal(land = "#1a1a1a", water = "#0d1520", label_color = "#888888"),
|
||||||
|
|
||||||
|
"muted" = {
|
||||||
|
colors <- pmColors(
|
||||||
|
background = "#fafafa",
|
||||||
|
earth = "#fafafa",
|
||||||
|
water = "#e8f0f4",
|
||||||
|
park = "#f0f4f0",
|
||||||
|
wood = "#eef2ee",
|
||||||
|
scrub_a = "#f5f5f5",
|
||||||
|
scrub_b = "#f5f5f5",
|
||||||
|
glacier = "#f8f8f8",
|
||||||
|
sand = "#f8f6f2",
|
||||||
|
beach = "#f8f6f2",
|
||||||
|
hospital = "#fafafa",
|
||||||
|
school = "#fafafa",
|
||||||
|
industrial = "#f5f5f5",
|
||||||
|
pedestrian = "#f8f8f8",
|
||||||
|
zoo = "#f0f4f0",
|
||||||
|
military = "#f5f5f5",
|
||||||
|
aerodrome = "#f5f5f5",
|
||||||
|
# Faint roads
|
||||||
|
highway = "#e0e0e0",
|
||||||
|
major = "#e8e8e8",
|
||||||
|
medium = "#f0f0f0",
|
||||||
|
minor = "#f5f5f5",
|
||||||
|
link = "#f5f5f5",
|
||||||
|
other = "#f8f8f8",
|
||||||
|
railway = "#e8e8e8",
|
||||||
|
pier = "#f0f0f0",
|
||||||
|
boundary = "#e8e8e8",
|
||||||
|
buildings = "#f0f0f0"
|
||||||
|
)
|
||||||
|
labelRules <- list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 11px sans-serif",
|
||||||
|
fill = "#666666",
|
||||||
|
stroke = "#fafafa",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 6"),
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 10px sans-serif",
|
||||||
|
fill = "#888888",
|
||||||
|
stroke = "#fafafa",
|
||||||
|
width = 1
|
||||||
|
), filter = "feature.props.kind === 'region'")
|
||||||
|
)
|
||||||
|
structure(list(colors = colors, labelRules = labelRules), class = "pm_style")
|
||||||
|
},
|
||||||
|
|
||||||
|
"watercolor" = {
|
||||||
|
bg <- "#f4f1ea"
|
||||||
|
colors <- pmColors(
|
||||||
|
background = bg,
|
||||||
|
earth = bg,
|
||||||
|
water = "#a8c8d4",
|
||||||
|
park = "#d4e6c3",
|
||||||
|
wood = "#c8ddb8",
|
||||||
|
scrub_a = "#dce8d0",
|
||||||
|
scrub_b = "#d0e0c4",
|
||||||
|
glacier = "#e8f0f4",
|
||||||
|
sand = "#f0e8d8",
|
||||||
|
beach = "#f5e6c8",
|
||||||
|
hospital = "#f0ebe4",
|
||||||
|
school = "#f0ebe4",
|
||||||
|
industrial = "#ebe6de",
|
||||||
|
pedestrian = "#f0ece4",
|
||||||
|
zoo = "#dce8d0",
|
||||||
|
military = "#e8e4dc",
|
||||||
|
aerodrome = "#ebe6de",
|
||||||
|
highway = "#e8e4dc",
|
||||||
|
major = "#ebe7df",
|
||||||
|
medium = "#f0ece4",
|
||||||
|
minor = bg,
|
||||||
|
link = bg,
|
||||||
|
other = bg,
|
||||||
|
railway = "#e0dcd4",
|
||||||
|
pier = "#e8e4dc",
|
||||||
|
boundary = "#e0dcd4",
|
||||||
|
buildings = "#e8e4dc"
|
||||||
|
)
|
||||||
|
labelRules <- list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 13px Georgia, serif",
|
||||||
|
fill = "#5c5c5c",
|
||||||
|
stroke = bg,
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.min_zoom <= 6"),
|
||||||
|
pmLabelRule("water", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 11px Georgia, serif",
|
||||||
|
fill = "#4a7c8c",
|
||||||
|
stroke = "#a8c8d4",
|
||||||
|
width = 1,
|
||||||
|
lineHeight = 1.5
|
||||||
|
))
|
||||||
|
)
|
||||||
|
structure(list(colors = colors, labelRules = labelRules), class = "pm_style")
|
||||||
|
},
|
||||||
|
|
||||||
|
"ink" = {
|
||||||
|
bg <- "#ffffff"
|
||||||
|
colors <- pmColors(
|
||||||
|
background = bg,
|
||||||
|
earth = bg,
|
||||||
|
water = bg,
|
||||||
|
park = bg, wood = bg, scrub_a = bg, scrub_b = bg,
|
||||||
|
glacier = bg, sand = bg, beach = bg,
|
||||||
|
hospital = bg, school = bg, industrial = bg,
|
||||||
|
pedestrian = bg, zoo = bg, military = bg, aerodrome = bg,
|
||||||
|
highway = "#000000",
|
||||||
|
major = "#000000",
|
||||||
|
medium = "#333333",
|
||||||
|
minor = "#666666",
|
||||||
|
link = "#666666",
|
||||||
|
other = "#999999",
|
||||||
|
railway = "#000000",
|
||||||
|
pier = "#666666",
|
||||||
|
boundary = "#cccccc",
|
||||||
|
buildings = bg
|
||||||
|
)
|
||||||
|
labelRules <- list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 12px 'Courier New', monospace",
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = bg,
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 6")
|
||||||
|
)
|
||||||
|
structure(list(colors = colors, labelRules = labelRules), class = "pm_style")
|
||||||
|
},
|
||||||
|
|
||||||
|
"terrain" = {
|
||||||
|
bg <- "#f4f0e8"
|
||||||
|
colors <- pmColors(
|
||||||
|
background = bg,
|
||||||
|
earth = bg,
|
||||||
|
water = "#a8c8d8",
|
||||||
|
park = "#d4e4c8",
|
||||||
|
wood = "#c8dcc0",
|
||||||
|
scrub_a = "#e0e8d8",
|
||||||
|
scrub_b = "#d8e0d0",
|
||||||
|
glacier = "#e8f0f4",
|
||||||
|
sand = "#f0e8d4",
|
||||||
|
beach = "#f4ecd8",
|
||||||
|
hospital = "#f0ece8",
|
||||||
|
school = "#f0ece8",
|
||||||
|
industrial = "#e8e4dc",
|
||||||
|
pedestrian = "#f0ece4",
|
||||||
|
zoo = "#d8e4d0",
|
||||||
|
military = "#e4e0d8",
|
||||||
|
aerodrome = "#e8e4dc",
|
||||||
|
highway = "#d8d4c8",
|
||||||
|
major = "#e0dcd0",
|
||||||
|
medium = "#e8e4d8",
|
||||||
|
minor = "#f0ece4",
|
||||||
|
link = "#f0ece4",
|
||||||
|
other = bg,
|
||||||
|
railway = "#c8c4b8",
|
||||||
|
pier = "#e0dcd0",
|
||||||
|
boundary = "#c8c4b8",
|
||||||
|
buildings = "#e8e4dc"
|
||||||
|
)
|
||||||
|
labelRules <- list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 12px sans-serif",
|
||||||
|
fill = "#5a5040",
|
||||||
|
stroke = bg,
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 6"),
|
||||||
|
pmLabelRule("natural", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 10px sans-serif",
|
||||||
|
fill = "#6a6050",
|
||||||
|
stroke = bg,
|
||||||
|
width = 1
|
||||||
|
))
|
||||||
|
)
|
||||||
|
structure(list(colors = colors, labelRules = labelRules), class = "pm_style")
|
||||||
|
},
|
||||||
|
|
||||||
|
"transit" = {
|
||||||
|
bg <- "#fafafa"
|
||||||
|
colors <- pmColors(
|
||||||
|
background = bg,
|
||||||
|
earth = bg,
|
||||||
|
water = "#e0e8f0",
|
||||||
|
park = "#f0f4f0",
|
||||||
|
wood = "#eef2ee",
|
||||||
|
scrub_a = "#f5f5f5",
|
||||||
|
scrub_b = "#f5f5f5",
|
||||||
|
glacier = "#f8f8f8",
|
||||||
|
sand = "#f8f6f2",
|
||||||
|
beach = "#f8f6f2",
|
||||||
|
hospital = bg,
|
||||||
|
school = bg,
|
||||||
|
industrial = "#f5f5f5",
|
||||||
|
pedestrian = "#f8f8f8",
|
||||||
|
zoo = "#f0f4f0",
|
||||||
|
military = "#f5f5f5",
|
||||||
|
aerodrome = "#f0f0f4",
|
||||||
|
highway = "#e8e8e8",
|
||||||
|
major = "#f0f0f0",
|
||||||
|
medium = "#f5f5f5",
|
||||||
|
minor = bg,
|
||||||
|
link = bg,
|
||||||
|
other = bg,
|
||||||
|
railway = "#e63946",
|
||||||
|
pier = "#f0f0f0",
|
||||||
|
boundary = "#e8e8e8",
|
||||||
|
buildings = "#f0f0f0"
|
||||||
|
)
|
||||||
|
labelRules <- list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 11px sans-serif",
|
||||||
|
fill = "#333333",
|
||||||
|
stroke = bg,
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 6"),
|
||||||
|
pmLabelRule("transit", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 10px sans-serif",
|
||||||
|
fill = "#e63946",
|
||||||
|
stroke = bg,
|
||||||
|
width = 2
|
||||||
|
))
|
||||||
|
)
|
||||||
|
structure(list(colors = colors, labelRules = labelRules), class = "pm_style")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create color overrides to hide specific features
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates color settings that hide specified feature categories by making
|
||||||
|
#' them match the background color.
|
||||||
|
#'
|
||||||
|
#' @param features Character vector. Features to hide. Options include:
|
||||||
|
#' "roads", "buildings", "landuse", "boundaries", "labels".
|
||||||
|
#' @param background Character. Background color that hidden features will
|
||||||
|
#' match. Default is "#f8f8f8".
|
||||||
|
#'
|
||||||
|
#' @return A list of color overrides to pass to \code{\link{pmColors}} or
|
||||||
|
#' merge with other colors.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' library(leaflet)
|
||||||
|
#' library(protomapr)
|
||||||
|
#'
|
||||||
|
#' # Hide roads and buildings but keep parks visible
|
||||||
|
#' hidden <- pmHideFeatures(c("roads", "buildings"))
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
#' addProtomaps(
|
||||||
|
#' url = protomaps_url(),
|
||||||
|
#' colors = modifyList(pmColors(water = "#1a3a5c"), hidden)
|
||||||
|
#' )
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmHideFeatures <- function(features, background = "#f8f8f8") {
|
||||||
|
colors <- list()
|
||||||
|
|
||||||
|
if ("roads" %in% features) {
|
||||||
|
colors <- c(colors, list(
|
||||||
|
highway = background, major = background, medium = background,
|
||||||
|
minor = background, link = background, other = background,
|
||||||
|
railway = background, pier = background
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("buildings" %in% features) {
|
||||||
|
colors <- c(colors, list(buildings = background))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("landuse" %in% features) {
|
||||||
|
colors <- c(colors, list(
|
||||||
|
park_a = background, park_b = background,
|
||||||
|
wood_a = background, wood_b = background,
|
||||||
|
scrub_a = background, scrub_b = background,
|
||||||
|
glacier = background, sand = background, beach = background,
|
||||||
|
hospital = background, school = background, industrial = background,
|
||||||
|
pedestrian = background, zoo = background, military = background,
|
||||||
|
aerodrome = background
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("boundaries" %in% features) {
|
||||||
|
colors <- c(colors, list(boundary = background))
|
||||||
|
}
|
||||||
|
|
||||||
|
colors
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create preset label rules for city names
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates label rules for displaying city/place names with common styling
|
||||||
|
#' patterns.
|
||||||
|
#'
|
||||||
|
#' @param style Character. Label style preset:
|
||||||
|
#' \describe{
|
||||||
|
#' \item{"hierarchical"}{Size varies by city importance (min_zoom)}
|
||||||
|
#' \item{"major-only"}{Only major cities (min_zoom <= 5)}
|
||||||
|
#' \item{"all"}{All cities with uniform styling}
|
||||||
|
#' }
|
||||||
|
#' @param color Character. Text color. Default is "#333333".
|
||||||
|
#' @param halo Character. Halo/stroke color. Default is "white".
|
||||||
|
#' @param include_regions Logical. Include state/region labels. Default is TRUE.
|
||||||
|
#'
|
||||||
|
#' @return A list of label rules to pass to \code{\link{addProtomaps}}.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' library(leaflet)
|
||||||
|
#' library(protomapr)
|
||||||
|
#'
|
||||||
|
#' leaflet() %>%
|
||||||
|
#' setView(lng = -122.4, lat = 37.8, zoom = 8) %>%
|
||||||
|
#' addProtomaps(
|
||||||
|
#' url = protomaps_url(),
|
||||||
|
#' colors = pmColors(earth = "#f0f0f0", water = "#1a3a5c"),
|
||||||
|
#' labelRules = pmCityLabels("hierarchical")
|
||||||
|
#' )
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmCityLabels <- function(style = c("hierarchical", "major-only", "all"),
|
||||||
|
color = "#333333",
|
||||||
|
halo = "white",
|
||||||
|
include_regions = TRUE) {
|
||||||
|
style <- match.arg(style)
|
||||||
|
|
||||||
|
rules <- switch(style,
|
||||||
|
"hierarchical" = list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 16px sans-serif", fill = color, stroke = halo, width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 4"),
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 13px sans-serif", fill = color, stroke = halo, width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom > 4 && feature.props.min_zoom <= 6"),
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 11px sans-serif", fill = color, stroke = halo, width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom > 6 && feature.props.min_zoom <= 8"),
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "400 9px sans-serif", fill = color, stroke = halo, width = 1
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom > 8")
|
||||||
|
),
|
||||||
|
|
||||||
|
"major-only" = list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 14px sans-serif", fill = color, stroke = halo, width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 5")
|
||||||
|
),
|
||||||
|
|
||||||
|
"all" = list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 11px sans-serif", fill = color, stroke = halo, width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality'")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (include_regions) {
|
||||||
|
rules <- c(rules, list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 12px sans-serif",
|
||||||
|
fill = "#888888",
|
||||||
|
stroke = halo,
|
||||||
|
width = 1
|
||||||
|
), filter = "feature.props.kind === 'region'")
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
rules
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Print method for pm_style objects
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Prints a formatted summary of a pm_style object showing colors and label rules.
|
||||||
|
#'
|
||||||
|
#' @param x A pm_style object.
|
||||||
|
#' @param ... Additional arguments (ignored).
|
||||||
|
#'
|
||||||
|
#' @return Invisibly returns x.
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
print.pm_style <- function(x, ...) {
|
||||||
|
cat("<pm_style>\n")
|
||||||
|
|
||||||
|
if (!is.null(x$colors) && length(x$colors) > 0) {
|
||||||
|
cat("\nColors:\n")
|
||||||
|
|
||||||
|
base_names <- c("background", "earth", "water")
|
||||||
|
road_names <- c("highway", "major", "medium", "minor", "link", "other", "railway", "pier")
|
||||||
|
landuse_names <- c("park", "park_a", "park_b", "wood", "wood_a", "wood_b",
|
||||||
|
"scrub_a", "scrub_b", "glacier", "sand", "beach",
|
||||||
|
"hospital", "school", "industrial", "pedestrian",
|
||||||
|
"zoo", "military", "aerodrome")
|
||||||
|
|
||||||
|
# Base colors
|
||||||
|
base <- x$colors[names(x$colors) %in% base_names]
|
||||||
|
if (length(base) > 0) {
|
||||||
|
cat(" Base:\n")
|
||||||
|
for (nm in intersect(base_names, names(base))) {
|
||||||
|
cat(sprintf(" %s: %s\n", nm, base[[nm]]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Roads - summarize if uniform
|
||||||
|
roads <- x$colors[names(x$colors) %in% road_names]
|
||||||
|
if (length(roads) > 0) {
|
||||||
|
unique_colors <- unique(unlist(roads))
|
||||||
|
if (length(unique_colors) == 1) {
|
||||||
|
cat(sprintf(" Roads: %s (uniform)\n", unique_colors))
|
||||||
|
} else {
|
||||||
|
cat(" Roads:\n")
|
||||||
|
for (nm in intersect(road_names, names(roads))) {
|
||||||
|
cat(sprintf(" %s: %s\n", nm, roads[[nm]]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Land use - summarize if uniform
|
||||||
|
landuse <- x$colors[names(x$colors) %in% landuse_names]
|
||||||
|
if (length(landuse) > 0) {
|
||||||
|
unique_colors <- unique(unlist(landuse))
|
||||||
|
if (length(unique_colors) == 1) {
|
||||||
|
cat(sprintf(" Land use: %s (uniform)\n", unique_colors))
|
||||||
|
} else {
|
||||||
|
n_landuse <- length(landuse)
|
||||||
|
cat(sprintf(" Land use: %d custom colors\n", n_landuse))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Other colors
|
||||||
|
other_names <- setdiff(names(x$colors), c(base_names, road_names, landuse_names))
|
||||||
|
if (length(other_names) > 0) {
|
||||||
|
cat(sprintf(" Other: %d additional colors\n", length(other_names)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is.null(x$labelRules) && length(x$labelRules) > 0) {
|
||||||
|
cat(sprintf("\nLabel Rules: %d\n", length(x$labelRules)))
|
||||||
|
for (i in seq_along(x$labelRules)) {
|
||||||
|
rule <- x$labelRules[[i]]
|
||||||
|
cat(sprintf(" [%d] %s", i, rule$dataLayer))
|
||||||
|
if (!is.null(rule$filter)) {
|
||||||
|
filter_display <- if (nchar(rule$filter) > 40) {
|
||||||
|
paste0(substr(rule$filter, 1, 37), "...")
|
||||||
|
} else {
|
||||||
|
rule$filter
|
||||||
|
}
|
||||||
|
cat(sprintf(" | %s", filter_display))
|
||||||
|
}
|
||||||
|
cat("\n")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cat("\nLabel Rules: none\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
invisible(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Modify an Existing Style
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a new pm_style by modifying an existing one. Useful for tweaking
|
||||||
|
#' preset styles without rebuilding from scratch.
|
||||||
|
#'
|
||||||
|
#' @param style A pm_style object to modify.
|
||||||
|
#' @param colors Named list of color overrides (from pmColors() or manual list).
|
||||||
|
#' @param labelRules Optional list of label rules to replace or add.
|
||||||
|
#' @param replace_labels Logical. If TRUE, replaces all label rules. If FALSE,
|
||||||
|
#' appends new rules. Default is FALSE.
|
||||||
|
#' @param ... Additional color overrides as named arguments.
|
||||||
|
#'
|
||||||
|
#' @return A new pm_style object with modifications applied.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' \dontrun{
|
||||||
|
#' # Start with watercolor, change water color
|
||||||
|
#' my_style <- pmModifyStyle(pmStyle("watercolor"), water = "#1a3a5c")
|
||||||
|
#'
|
||||||
|
#' # Add label rules to minimal style
|
||||||
|
#' my_style <- pmModifyStyle(
|
||||||
|
#' pmMinimal(),
|
||||||
|
#' labelRules = pmCityLabels("major-only")
|
||||||
|
#' )
|
||||||
|
#'
|
||||||
|
#' # Multiple modifications
|
||||||
|
#' my_style <- pmModifyStyle(
|
||||||
|
#' pmStyle("muted"),
|
||||||
|
#' colors = pmColors(water = "#2a4a6c", park = "#c0d8c0"),
|
||||||
|
#' replace_labels = TRUE,
|
||||||
|
#' labelRules = list(
|
||||||
|
#' pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
#' font = "bold 14px Arial",
|
||||||
|
#' fill = "#333"
|
||||||
|
#' ))
|
||||||
|
#' )
|
||||||
|
#' )
|
||||||
|
#' }
|
||||||
|
#'
|
||||||
|
#' @seealso \code{\link{pmStyle}}, \code{\link{pmMinimal}}
|
||||||
|
#' @export
|
||||||
|
pmModifyStyle <- function(style,
|
||||||
|
colors = NULL,
|
||||||
|
labelRules = NULL,
|
||||||
|
replace_labels = FALSE,
|
||||||
|
...) {
|
||||||
|
if (!inherits(style, "pm_style")) {
|
||||||
|
stop("'style' must be a pm_style object", call. = FALSE)
|
||||||
|
}
|
||||||
|
|
||||||
|
new_style <- style
|
||||||
|
|
||||||
|
extra_colors <- list(...)
|
||||||
|
if (!is.null(colors) || length(extra_colors) > 0) {
|
||||||
|
all_overrides <- c(colors, extra_colors)
|
||||||
|
new_style$colors <- utils::modifyList(
|
||||||
|
new_style$colors %||% list(),
|
||||||
|
all_overrides
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is.null(labelRules)) {
|
||||||
|
if (replace_labels) {
|
||||||
|
new_style$labelRules <- labelRules
|
||||||
|
} else {
|
||||||
|
new_style$labelRules <- c(new_style$labelRules, labelRules)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
structure(new_style, class = "pm_style")
|
||||||
|
}
|
||||||
315
R/symbolizers.R
Normal file
315
R/symbolizers.R
Normal file
|
|
@ -0,0 +1,315 @@
|
||||||
|
#' Create a Polygon Symbolizer
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a polygon symbolizer for rendering filled polygon features.
|
||||||
|
#'
|
||||||
|
#' @param fill Character. Fill color for the polygon. Can be a CSS color
|
||||||
|
#' string or a function specification.
|
||||||
|
#' @param stroke Character. Stroke (outline) color. Default is NULL (no stroke).
|
||||||
|
#' @param width Numeric. Stroke width in pixels. Default is 1.
|
||||||
|
#' @param opacity Numeric. Fill opacity from 0 to 1. Default is 1.
|
||||||
|
#' @param pattern Character. Fill pattern. One of NULL, "hatch", or "dot".
|
||||||
|
#' @param ... Additional symbolizer options.
|
||||||
|
#'
|
||||||
|
#' @return A list representing the symbolizer configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' # Simple blue fill
|
||||||
|
#' pmPolygonSymbolizer(fill = "steelblue")
|
||||||
|
#'
|
||||||
|
#' # With stroke
|
||||||
|
#' pmPolygonSymbolizer(fill = "#f0f0f0", stroke = "#333", width = 2)
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmPolygonSymbolizer <- function(fill = "#cccccc",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 1,
|
||||||
|
opacity = 1,
|
||||||
|
pattern = NULL,
|
||||||
|
...) {
|
||||||
|
opts <- list(fill = fill, ...)
|
||||||
|
|
||||||
|
if (!is.null(stroke)) opts$stroke <- stroke
|
||||||
|
if (width != 1) opts$width <- width
|
||||||
|
if (opacity != 1) opts$opacity <- opacity
|
||||||
|
if (!is.null(pattern)) opts$pattern <- pattern
|
||||||
|
|
||||||
|
list(
|
||||||
|
type = "polygon",
|
||||||
|
options = opts
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create a Line Symbolizer
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a line symbolizer for rendering line features.
|
||||||
|
#'
|
||||||
|
#' @param color Character. Line color. Default is "#000000".
|
||||||
|
#' @param width Numeric or function. Line width in pixels. Can be a fixed
|
||||||
|
#' value or a zoom-dependent specification.
|
||||||
|
#' @param dash List or NULL. Dash pattern as a vector of numbers, e.g.,
|
||||||
|
#' \code{c(4, 2)} for 4px dash, 2px gap.
|
||||||
|
#' @param dashColor Character. Color for dashes if using dash pattern.
|
||||||
|
#' @param dashWidth Numeric. Width of dashes.
|
||||||
|
#' @param lineCap Character. Line cap style: "butt", "round", or "square".
|
||||||
|
#' @param lineJoin Character
|
||||||
|
#' . Line join style: "miter", "round", or "bevel".
|
||||||
|
#' @param opacity Numeric. Line opacity from 0 to 1. Default is 1.
|
||||||
|
#' @param ... Additional symbolizer options.
|
||||||
|
#'
|
||||||
|
#' @return A list representing the symbolizer configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' # Simple black line
|
||||||
|
#' pmLineSymbolizer(color = "black", width = 2)
|
||||||
|
#'
|
||||||
|
#' # Dashed line
|
||||||
|
#' pmLineSymbolizer(color = "gray", width = 1, dash = c(4, 2))
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmLineSymbolizer <- function(color = "#000000",
|
||||||
|
width = 1,
|
||||||
|
dash = NULL,
|
||||||
|
dashColor = NULL,
|
||||||
|
dashWidth = NULL,
|
||||||
|
lineCap = NULL,
|
||||||
|
lineJoin = NULL,
|
||||||
|
opacity = 1,
|
||||||
|
...) {
|
||||||
|
opts <- list(color = color, width = width, ...)
|
||||||
|
|
||||||
|
if (!is.null(dash)) opts$dash <- dash
|
||||||
|
if (!is.null(dashColor)) opts$dashColor <- dashColor
|
||||||
|
if (!is.null(dashWidth)) opts$dashWidth <- dashWidth
|
||||||
|
if (!is.null(lineCap)) opts$lineCap <- lineCap
|
||||||
|
if (!is.null(lineJoin)) opts$lineJoin <- lineJoin
|
||||||
|
if (opacity != 1) opts$opacity <- opacity
|
||||||
|
|
||||||
|
list(
|
||||||
|
type = "line",
|
||||||
|
options = opts
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create a Circle Symbolizer
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a circle symbolizer for rendering point features as circles.
|
||||||
|
#'
|
||||||
|
#' @param radius Numeric. Circle radius in pixels. Default is 4.
|
||||||
|
#' @param fill Character. Fill color for the circle. Default is "#000000".
|
||||||
|
#' @param stroke Character. Stroke (outline) color. Default is NULL.
|
||||||
|
#' @param width Numeric. Stroke width in pixels. Default is 1.
|
||||||
|
#' @param opacity Numeric. Fill opacity from 0 to 1. Default is 1.
|
||||||
|
#' @param ... Additional symbolizer options.
|
||||||
|
#'
|
||||||
|
#' @return A list representing the symbolizer configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' # Simple red circle
|
||||||
|
#' pmCircleSymbolizer(radius = 6, fill = "red")
|
||||||
|
#'
|
||||||
|
#' # Circle with stroke
|
||||||
|
#' pmCircleSymbolizer(radius = 8, fill = "white", stroke = "black", width = 2)
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmCircleSymbolizer <- function(radius = 4,
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 1,
|
||||||
|
opacity = 1,
|
||||||
|
...) {
|
||||||
|
opts <- list(radius = radius, fill = fill, ...)
|
||||||
|
|
||||||
|
if (!is.null(stroke)) opts$stroke <- stroke
|
||||||
|
if (width != 1) opts$width <- width
|
||||||
|
if (opacity != 1) opts$opacity <- opacity
|
||||||
|
|
||||||
|
list(
|
||||||
|
type = "circle",
|
||||||
|
options = opts
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create a Text Symbolizer
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a text symbolizer for rendering text labels.
|
||||||
|
#'
|
||||||
|
#' @param font Character. Font specification (e.g., "12px sans-serif").
|
||||||
|
#' @param fill Character. Text fill color. Default is "#000000".
|
||||||
|
#' @param stroke Character. Text stroke (halo) color. Default is NULL.
|
||||||
|
#' @param width Numeric. Stroke width for text halo. Default is 0.
|
||||||
|
#' @param labelProps List. Properties to use for label text, in order of
|
||||||
|
#' preference. Default is \code{list("name")}.
|
||||||
|
#' @param textTransform Character. Text transformation: "uppercase",
|
||||||
|
#' "lowercase", or NULL.
|
||||||
|
#' @param ... Additional symbolizer options.
|
||||||
|
#'
|
||||||
|
#' @return A list representing the symbolizer configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' # Simple text label
|
||||||
|
#' pmTextSymbolizer(font = "12px Arial", fill = "black")
|
||||||
|
#'
|
||||||
|
#' # Text with halo
|
||||||
|
#' pmTextSymbolizer(font = "14px sans-serif", fill = "black",
|
||||||
|
#' stroke = "white", width = 2)
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmTextSymbolizer <- function(font = "12px sans-serif",
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 0,
|
||||||
|
labelProps = NULL,
|
||||||
|
textTransform = NULL,
|
||||||
|
...) {
|
||||||
|
opts <- list(font = font, fill = fill, ...)
|
||||||
|
|
||||||
|
if (!is.null(stroke)) opts$stroke <- stroke
|
||||||
|
if (width > 0) opts$width <- width
|
||||||
|
if (!is.null(labelProps)) opts$labelProps <- labelProps
|
||||||
|
if (!is.null(textTransform)) opts$textTransform <- textTransform
|
||||||
|
|
||||||
|
list(
|
||||||
|
type = "text",
|
||||||
|
options = opts
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create a Centered Text Symbolizer
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a centered text symbolizer for rendering text labels centered
|
||||||
|
#' on point features.
|
||||||
|
#'
|
||||||
|
#' @param font Character. Font specification (e.g., "12px sans-serif").
|
||||||
|
#' @param fill Character. Text fill color. Default is "#000000".
|
||||||
|
#' @param stroke Character. Text stroke (halo) color. Default is NULL.
|
||||||
|
#' @param width Numeric. Stroke width for text halo. Default is 0.
|
||||||
|
#' @param lineHeight Numeric. Line height multiplier for multi-line labels.
|
||||||
|
#' Default is NULL (uses library default). Use values like 1.0-1.2 for
|
||||||
|
#' tighter spacing.
|
||||||
|
#' @param labelProps List. Properties to use for label text, in order of
|
||||||
|
#' preference. Default is \code{list("name")}.
|
||||||
|
#' @param ... Additional symbolizer options.
|
||||||
|
#'
|
||||||
|
#' @return A list representing the symbolizer configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' pmCenteredTextSymbolizer(font = "14px Arial", fill = "black")
|
||||||
|
#'
|
||||||
|
#' # Tighter line spacing for multi-word labels
|
||||||
|
#' pmCenteredTextSymbolizer(font = "11px sans-serif", fill = "#444",
|
||||||
|
#' lineHeight = 1.1)
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmCenteredTextSymbolizer <- function(font = "12px sans-serif",
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 0,
|
||||||
|
lineHeight = NULL,
|
||||||
|
labelProps = NULL,
|
||||||
|
...) {
|
||||||
|
opts <- list(font = font, fill = fill, ...)
|
||||||
|
|
||||||
|
if (!is.null(stroke)) opts$stroke <- stroke
|
||||||
|
if (width > 0) opts$width <- width
|
||||||
|
if (!is.null(lineHeight)) opts$lineHeight <- lineHeight
|
||||||
|
if (!is.null(labelProps)) opts$labelProps <- labelProps
|
||||||
|
|
||||||
|
list(
|
||||||
|
type = "centeredText",
|
||||||
|
options = opts
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create a Line Label Symbolizer
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a line label symbolizer for rendering text labels along line
|
||||||
|
#' features (e.g., street names).
|
||||||
|
#'
|
||||||
|
#' @param font Character. Font specification (e.g., "12px sans-serif").
|
||||||
|
#' @param fill Character. Text fill color. Default is "#000000".
|
||||||
|
#' @param stroke Character. Text stroke (halo) color. Default is NULL.
|
||||||
|
#' @param width Numeric. Stroke width for text halo. Default is 0.
|
||||||
|
#' @param labelProps List. Properties to use for label text.
|
||||||
|
#' @param ... Additional symbolizer options.
|
||||||
|
#'
|
||||||
|
#' @return A list representing the symbolizer configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' pmLineLabelSymbolizer(font = "11px Arial", fill = "#333",
|
||||||
|
#' stroke = "white", width = 2)
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmLineLabelSymbolizer <- function(font = "12px sans-serif",
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 0,
|
||||||
|
labelProps = NULL,
|
||||||
|
...) {
|
||||||
|
opts <- list(font = font, fill = fill, ...)
|
||||||
|
|
||||||
|
if (!is.null(stroke)) opts$stroke <- stroke
|
||||||
|
if (width > 0) opts$width <- width
|
||||||
|
if (!is.null(labelProps)) opts$labelProps <- labelProps
|
||||||
|
|
||||||
|
list(
|
||||||
|
type = "lineLabel",
|
||||||
|
options = opts
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#' Create a Shield Symbolizer
|
||||||
|
#'
|
||||||
|
#' @description
|
||||||
|
#' Creates a shield symbolizer for rendering labeled badges or shields
|
||||||
|
#' (e.g., highway route markers).
|
||||||
|
#'
|
||||||
|
#' @param font Character. Font specification for shield text.
|
||||||
|
#' @param fill Character. Text fill color. Default is "#000000".
|
||||||
|
#' @param background Character. Shield background color. Default is "#ffffff".
|
||||||
|
#' @param stroke Character. Shield border color. Default is "#000000".
|
||||||
|
#' @param padding Numeric. Padding inside the shield in pixels. Default is 2.
|
||||||
|
#' @param labelProps List. Properties to use for shield text.
|
||||||
|
#' @param ... Additional symbolizer options.
|
||||||
|
#'
|
||||||
|
#' @return A list representing the symbolizer configuration.
|
||||||
|
#'
|
||||||
|
#' @examples
|
||||||
|
#' pmShieldSymbolizer(font = "10px Arial", fill = "black",
|
||||||
|
#' background = "white", stroke = "black")
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
pmShieldSymbolizer <- function(font = "10px sans-serif",
|
||||||
|
fill = "#000000",
|
||||||
|
background = "#ffffff",
|
||||||
|
stroke = "#000000",
|
||||||
|
padding = 2,
|
||||||
|
labelProps = NULL,
|
||||||
|
...) {
|
||||||
|
opts <- list(
|
||||||
|
font = font,
|
||||||
|
fill = fill,
|
||||||
|
background = background,
|
||||||
|
stroke = stroke,
|
||||||
|
padding = padding,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!is.null(labelProps)) opts$labelProps <- labelProps
|
||||||
|
|
||||||
|
list(
|
||||||
|
type = "shield",
|
||||||
|
options = opts
|
||||||
|
)
|
||||||
|
}
|
||||||
351
README.md
Normal file
351
README.md
Normal file
|
|
@ -0,0 +1,351 @@
|
||||||
|
# protomapr
|
||||||
|
|
||||||
|
An R package to add [Protomaps](https://protomaps.com/) vector tile layers to Leaflet maps.
|
||||||
|
|
||||||
|
## Why Protomaps?
|
||||||
|
|
||||||
|
Standard Leaflet maps use `addProviderTiles()` to load raster tiles from services like OpenStreetMap or CartoDB. Protomaps offers a vector tile alternative with key advantages:
|
||||||
|
|
||||||
|
| | Raster Tiles | Protomaps (Vector) |
|
||||||
|
|---|---|---|
|
||||||
|
| **Customization** | Limited to provider styles | Full control over colors, labels, features |
|
||||||
|
| **Self-hosting** | Requires tile server | Single PMTiles file, no server needed |
|
||||||
|
| **Feature control** | Show everything or nothing | Hide roads, buildings, labels selectively |
|
||||||
|
| **Privacy** | Requests to third-party servers | Self-host for complete privacy |
|
||||||
|
| **Rate limits** | Often have API quotas | No limits when self-hosted |
|
||||||
|
| **Zoom quality** | Can pixelate | Smooth at any zoom level |
|
||||||
|
| **File size** | Large (pre-rendered images) | Smaller (compressed vectors) |
|
||||||
|
|
||||||
|
**Use Protomaps when you need:**
|
||||||
|
- Custom branded maps matching your color scheme
|
||||||
|
- Minimal basemaps for data visualization (hide distracting features)
|
||||||
|
- Offline or embedded applications
|
||||||
|
- Privacy-sensitive contexts
|
||||||
|
- High-traffic apps without API rate limits
|
||||||
|
|
||||||
|
**Use providerTiles when:**
|
||||||
|
- Default styling is fine
|
||||||
|
- You need satellite/aerial imagery
|
||||||
|
- Quick prototypes
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```r
|
||||||
|
# Install from local source
|
||||||
|
devtools::install_local("path/to/protomapr")
|
||||||
|
|
||||||
|
# Or install dependencies and load
|
||||||
|
install.packages(c("leaflet", "htmltools", "htmlwidgets", "jsonlite"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```r
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Use the demo URL (free Protomaps daily build)
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(url = protomaps_demo_url())
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Sources
|
||||||
|
|
||||||
|
You have several options for PMTiles data:
|
||||||
|
|
||||||
|
### 1. Demo/Development (free)
|
||||||
|
|
||||||
|
Use `protomaps_demo_url()` which points to the Protomaps daily OpenStreetMap build:
|
||||||
|
|
||||||
|
```r
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = protomaps_demo_url())
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Self-hosted (recommended for production)
|
||||||
|
|
||||||
|
Download a PMTiles file and host it on cloud storage (S3, GCS, Cloudflare R2, etc.):
|
||||||
|
|
||||||
|
- Download daily builds: https://maps.protomaps.com/builds/
|
||||||
|
- Extract a region: https://slice.openstreetmap.us/
|
||||||
|
|
||||||
|
```r
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = "https://your-bucket.s3.amazonaws.com/tiles.pmtiles")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Local file
|
||||||
|
|
||||||
|
For local development, you can serve a PMTiles file locally:
|
||||||
|
|
||||||
|
```r
|
||||||
|
# Serve with a local HTTP server, then:
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = "http://localhost:8080/tiles.pmtiles")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
```r
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_demo_url(),
|
||||||
|
flavor = "light"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flavors
|
||||||
|
|
||||||
|
Five built-in flavors are available:
|
||||||
|
|
||||||
|
```r
|
||||||
|
# Light flavor (default)
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = protomaps_demo_url(), flavor = "light")
|
||||||
|
|
||||||
|
# Dark flavor
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = protomaps_demo_url(), flavor = "dark")
|
||||||
|
|
||||||
|
# White flavor (for data visualization)
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = protomaps_demo_url(), flavor = "white")
|
||||||
|
|
||||||
|
# Grayscale flavor
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = protomaps_demo_url(), flavor = "grayscale")
|
||||||
|
|
||||||
|
# Black flavor
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = protomaps_demo_url(), flavor = "black")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Styling
|
||||||
|
|
||||||
|
### Paint Rules
|
||||||
|
|
||||||
|
Control how features are rendered using paint rules:
|
||||||
|
```r
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_demo_url(),
|
||||||
|
paintRules = list(
|
||||||
|
pmPaintRule("water", pmPolygonSymbolizer(fill = "steelblue")),
|
||||||
|
pmPaintRule("earth", pmPolygonSymbolizer(fill = "#f0f0f0")),
|
||||||
|
pmPaintRule("roads", pmLineSymbolizer(color = "gray", width = 1)),
|
||||||
|
pmPaintRule("buildings", pmPolygonSymbolizer(
|
||||||
|
fill = "#d4d4d4",
|
||||||
|
stroke = "#999",
|
||||||
|
width = 0.5
|
||||||
|
))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Label Rules
|
||||||
|
|
||||||
|
Add text labels to features:
|
||||||
|
|
||||||
|
```r
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 14) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_demo_url(),
|
||||||
|
labelRules = list(
|
||||||
|
pmLabelRule("places",
|
||||||
|
pmCenteredTextSymbolizer(
|
||||||
|
font = "14px Arial",
|
||||||
|
fill = "black",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
)
|
||||||
|
),
|
||||||
|
pmLabelRule("roads",
|
||||||
|
pmLineLabelSymbolizer(
|
||||||
|
font = "11px Arial",
|
||||||
|
fill = "#333"
|
||||||
|
),
|
||||||
|
minzoom = 14
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Filtering Features
|
||||||
|
|
||||||
|
Use JavaScript filter expressions to style features based on their properties:
|
||||||
|
|
||||||
|
```r
|
||||||
|
# Cities only (not towns/villages)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(font = "14px Arial", fill = "black"),
|
||||||
|
filter = "feature.props.kind_detail === 'city'")
|
||||||
|
|
||||||
|
# States/regions
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(font = "18px Arial", fill = "#666"),
|
||||||
|
filter = "feature.props.kind === 'region'")
|
||||||
|
|
||||||
|
# Important places (low min_zoom = more important)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(font = "16px Arial", fill = "black"),
|
||||||
|
filter = "feature.props.min_zoom <= 6")
|
||||||
|
|
||||||
|
# Highways only
|
||||||
|
pmPaintRule("roads", pmLineSymbolizer(color = "orange", width = 3),
|
||||||
|
filter = "feature.props.kind === 'highway'")
|
||||||
|
|
||||||
|
# Show features at specific zoom levels
|
||||||
|
pmPaintRule("buildings", pmPolygonSymbolizer(fill = "#ccc"),
|
||||||
|
minzoom = 14, maxzoom = 18)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layers and Properties
|
||||||
|
|
||||||
|
For full documentation run `?protomaps_layers` in R. Quick reference:
|
||||||
|
|
||||||
|
### Layer Names
|
||||||
|
|
||||||
|
| Layer | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `earth` | Land polygons |
|
||||||
|
| `water` | Water bodies |
|
||||||
|
| `landuse` | Parks, forests, residential, etc. |
|
||||||
|
| `roads` | Streets and highways |
|
||||||
|
| `buildings` | Building footprints |
|
||||||
|
| `places` | City/town/region labels |
|
||||||
|
| `pois` | Points of interest |
|
||||||
|
| `boundaries` | Administrative boundaries |
|
||||||
|
|
||||||
|
### Key Properties for Filtering
|
||||||
|
|
||||||
|
**places:**
|
||||||
|
- `kind`: "country", "region", "locality"
|
||||||
|
- `kind_detail`: "city", "town", "village", "state", "province"
|
||||||
|
- `min_zoom`: importance (lower = more important)
|
||||||
|
- `population_rank`: size (higher = larger)
|
||||||
|
|
||||||
|
**water:**
|
||||||
|
- `kind`: "water", "lake", "ocean"
|
||||||
|
- `kind_detail`: "river", "lake", "reservoir", "stream"
|
||||||
|
|
||||||
|
**roads:**
|
||||||
|
- `kind`: "highway", "major_road", "minor_road", "path"
|
||||||
|
- `kind_detail`: "motorway", "primary", "residential", "footway"
|
||||||
|
|
||||||
|
**landuse:**
|
||||||
|
- `kind`: "park", "forest", "residential", "industrial"
|
||||||
|
|
||||||
|
## Symbolizer Reference
|
||||||
|
|
||||||
|
### pmPolygonSymbolizer
|
||||||
|
|
||||||
|
Style polygon features:
|
||||||
|
|
||||||
|
```r
|
||||||
|
pmPolygonSymbolizer(
|
||||||
|
fill = "#cccccc", # Fill color
|
||||||
|
stroke = "#333", # Outline color
|
||||||
|
width = 1, # Outline width
|
||||||
|
opacity = 0.8 # Fill opacity (0-1)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### pmLineSymbolizer
|
||||||
|
|
||||||
|
Style line features:
|
||||||
|
|
||||||
|
```r
|
||||||
|
pmLineSymbolizer(
|
||||||
|
color = "#000000", # Line color
|
||||||
|
width = 2, # Line width in pixels
|
||||||
|
dash = c(4, 2), # Dash pattern (4px dash, 2px gap)
|
||||||
|
lineCap = "round", # "butt", "round", or "square"
|
||||||
|
lineJoin = "round", # "miter", "round", or "bevel"
|
||||||
|
opacity = 1 # Line opacity (0-1)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### pmCircleSymbolizer
|
||||||
|
|
||||||
|
Style point features as circles:
|
||||||
|
|
||||||
|
```r
|
||||||
|
pmCircleSymbolizer(
|
||||||
|
radius = 6, # Circle radius in pixels
|
||||||
|
fill = "red", # Fill color
|
||||||
|
stroke = "black", # Outline color
|
||||||
|
width = 1 # Outline width
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### pmCenteredTextSymbolizer
|
||||||
|
|
||||||
|
Add centered text labels:
|
||||||
|
|
||||||
|
```r
|
||||||
|
pmCenteredTextSymbolizer(
|
||||||
|
font = "14px Arial", # CSS font specification
|
||||||
|
fill = "black", # Text color
|
||||||
|
stroke = "white", # Halo color
|
||||||
|
width = 2 # Halo width
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### pmLineLabelSymbolizer
|
||||||
|
|
||||||
|
Add labels along line features (e.g., street names):
|
||||||
|
|
||||||
|
```r
|
||||||
|
pmLineLabelSymbolizer(
|
||||||
|
font = "11px Arial",
|
||||||
|
fill = "#333",
|
||||||
|
stroke = "white",
|
||||||
|
width = 1
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### pmShieldSymbolizer
|
||||||
|
|
||||||
|
Add shield/badge labels (e.g., highway markers):
|
||||||
|
|
||||||
|
```r
|
||||||
|
pmShieldSymbolizer(
|
||||||
|
font = "10px Arial",
|
||||||
|
fill = "black",
|
||||||
|
background = "white",
|
||||||
|
stroke = "black",
|
||||||
|
padding = 2
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Additional Options
|
||||||
|
|
||||||
|
```r
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_demo_url(),
|
||||||
|
flavor = "light",
|
||||||
|
lang = "en", # Language for labels
|
||||||
|
attribution = "Protomaps", # Attribution text
|
||||||
|
options = protomapsOptions(
|
||||||
|
maxDataZoom = 14, # Max zoom for tile data
|
||||||
|
tileSize = 256, # Tile size in pixels
|
||||||
|
debug = FALSE # Debug mode
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
This package is a wrapper around [protomaps-leaflet](https://github.com/protomaps/protomaps-leaflet), created by [Brandon Liu](https://bdon.org/). The Protomaps project provides an incredible open-source stack for self-hosted vector maps, including the [PMTiles](https://docs.protomaps.com/pmtiles/) single-file tile archive format. Thanks to Brandon for making beautiful, customizable maps accessible to everyone.
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- [Protomaps](https://protomaps.com/)
|
||||||
|
- [protomaps-leaflet GitHub](https://github.com/protomaps/protomaps-leaflet)
|
||||||
|
- [PMTiles specification](https://docs.protomaps.com/pmtiles/)
|
||||||
|
- [Brandon Liu](https://bdon.org/)
|
||||||
95
_pkgdown.yml
Normal file
95
_pkgdown.yml
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
url: https://evmo.github.io/protomapr/
|
||||||
|
|
||||||
|
template:
|
||||||
|
bootstrap: 5
|
||||||
|
|
||||||
|
navbar:
|
||||||
|
structure:
|
||||||
|
left: [intro, reference, articles]
|
||||||
|
right: [search, github]
|
||||||
|
components:
|
||||||
|
articles:
|
||||||
|
text: Articles
|
||||||
|
menu:
|
||||||
|
- text: Getting Started
|
||||||
|
href: articles/getting-started.html
|
||||||
|
- text: Custom Styling
|
||||||
|
href: articles/custom-styling.html
|
||||||
|
- text: Data Visualization Basemaps
|
||||||
|
href: articles/data-viz-basemaps.html
|
||||||
|
- text: Labels and Filters
|
||||||
|
href: articles/labels-and-filters.html
|
||||||
|
|
||||||
|
reference:
|
||||||
|
- title: Add Protomaps to Maps
|
||||||
|
desc: Core function for adding vector tile layers
|
||||||
|
contents:
|
||||||
|
- addProtomaps
|
||||||
|
- protomapsOptions
|
||||||
|
- protomapsDependency
|
||||||
|
|
||||||
|
- title: Styles and Presets
|
||||||
|
desc: Pre-built style configurations
|
||||||
|
contents:
|
||||||
|
- pmStyle
|
||||||
|
- pmMinimal
|
||||||
|
- pmModifyStyle
|
||||||
|
- pmColors
|
||||||
|
- pmHideFeatures
|
||||||
|
- pmCityLabels
|
||||||
|
- print.pm_style
|
||||||
|
|
||||||
|
- title: Color Palettes
|
||||||
|
desc: Apply color palettes to map features
|
||||||
|
contents:
|
||||||
|
- pmPalette
|
||||||
|
- pmPaletteStyle
|
||||||
|
|
||||||
|
- title: Custom Rules
|
||||||
|
desc: Create custom paint and label rules
|
||||||
|
contents:
|
||||||
|
- pmPaintRule
|
||||||
|
- pmLabelRule
|
||||||
|
|
||||||
|
- title: Symbolizers
|
||||||
|
desc: Visual appearance specifications
|
||||||
|
contents:
|
||||||
|
- pmPolygonSymbolizer
|
||||||
|
- pmLineSymbolizer
|
||||||
|
- pmCircleSymbolizer
|
||||||
|
- pmTextSymbolizer
|
||||||
|
- pmCenteredTextSymbolizer
|
||||||
|
- pmLineLabelSymbolizer
|
||||||
|
- pmShieldSymbolizer
|
||||||
|
|
||||||
|
- title: Tile Sources
|
||||||
|
desc: Functions for tile URLs and API keys
|
||||||
|
contents:
|
||||||
|
- protomaps_url
|
||||||
|
- set_protomaps_key
|
||||||
|
- protomaps_sample_tiles
|
||||||
|
- protomaps_clear_cache
|
||||||
|
|
||||||
|
- title: Reference Data
|
||||||
|
desc: Documentation for layer properties
|
||||||
|
contents:
|
||||||
|
- protomaps_layers
|
||||||
|
- protomaps_colors
|
||||||
|
|
||||||
|
articles:
|
||||||
|
- title: Get Started
|
||||||
|
navbar: ~
|
||||||
|
contents:
|
||||||
|
- getting-started
|
||||||
|
- title: Customization
|
||||||
|
contents:
|
||||||
|
- custom-styling
|
||||||
|
- labels-and-filters
|
||||||
|
- title: Use Cases
|
||||||
|
contents:
|
||||||
|
- data-viz-basemaps
|
||||||
|
|
||||||
|
home:
|
||||||
|
links:
|
||||||
|
- text: Report a bug
|
||||||
|
href: https://github.com/evmo/protomapr/issues
|
||||||
25
cran-comments.md
Normal file
25
cran-comments.md
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
## R CMD check results
|
||||||
|
|
||||||
|
0 errors | 0 warnings | 0 notes
|
||||||
|
|
||||||
|
## Test environments
|
||||||
|
|
||||||
|
* local macOS (aarch64-apple-darwin), R 4.x
|
||||||
|
* GitHub Actions (ubuntu-latest), R release
|
||||||
|
* GitHub Actions (windows-latest), R release
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
This package imports:
|
||||||
|
- leaflet (>= 2.0.0)
|
||||||
|
- htmltools
|
||||||
|
- htmlwidgets
|
||||||
|
- jsonlite
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
This is a new submission to CRAN.
|
||||||
|
|
||||||
|
The package provides R bindings for the protomaps-leaflet JavaScript library,
|
||||||
|
enabling vector tile map layers in Leaflet maps. The JavaScript library is
|
||||||
|
loaded from a CDN (unpkg.com) at runtime.
|
||||||
File diff suppressed because one or more lines are too long
107
man/addProtomaps.Rd
Normal file
107
man/addProtomaps.Rd
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/addProtomaps.R
|
||||||
|
\name{addProtomaps}
|
||||||
|
\alias{addProtomaps}
|
||||||
|
\title{Add a Protomaps layer to a Leaflet map}
|
||||||
|
\usage{
|
||||||
|
addProtomaps(
|
||||||
|
map,
|
||||||
|
url,
|
||||||
|
style = NULL,
|
||||||
|
flavor = c("light", "dark", "white", "grayscale", "black"),
|
||||||
|
colors = NULL,
|
||||||
|
paintRules = NULL,
|
||||||
|
labelRules = NULL,
|
||||||
|
backgroundColor = NULL,
|
||||||
|
lang = NULL,
|
||||||
|
attribution = "Protomaps",
|
||||||
|
options = protomapsOptions(),
|
||||||
|
layerId = NULL,
|
||||||
|
group = NULL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{map}{A leaflet map object created with \code{\link[leaflet]{leaflet}}.}
|
||||||
|
|
||||||
|
\item{url}{Character. URL to a PMTiles file or a tile endpoint with
|
||||||
|
\code{{z}/{x}/{y}.mvt} placeholders.}
|
||||||
|
|
||||||
|
\item{style}{Optional style object created with \code{\link{pmMinimal}} or
|
||||||
|
\code{\link{pmStyle}}. Provides a convenient way to apply preset styles.
|
||||||
|
If provided, overrides \code{colors} and \code{labelRules}.}
|
||||||
|
|
||||||
|
\item{flavor}{Character. Built-in flavor/theme to use. One of "light", "dark",
|
||||||
|
"white", "grayscale", or "black". Default is "light". Ignored if \code{style}
|
||||||
|
is provided.}
|
||||||
|
|
||||||
|
\item{colors}{Optional list of color overrides. Use \code{\link{pmColors}} to
|
||||||
|
create this. Overrides specific colors while keeping built-in rendering rules.}
|
||||||
|
|
||||||
|
\item{paintRules}{Optional list of paint rules created with \code{\link{pmPaintRule}}.
|
||||||
|
If provided, completely overrides the flavor's default paint rules.
|
||||||
|
For simple color changes, use \code{colors} instead.}
|
||||||
|
|
||||||
|
\item{labelRules}{Optional list of label rules created with \code{\link{pmLabelRule}}.
|
||||||
|
If provided, completely overrides the flavor's default label rules.}
|
||||||
|
|
||||||
|
\item{backgroundColor}{Character. Background color for the canvas.
|
||||||
|
Default is NULL (uses flavor default).}
|
||||||
|
|
||||||
|
\item{lang}{Character. Language code for labels (e.g., "en", "de", "zh").
|
||||||
|
Default is NULL (uses default language).}
|
||||||
|
|
||||||
|
\item{attribution}{Character. Attribution text for the layer.
|
||||||
|
Default is "Protomaps".}
|
||||||
|
|
||||||
|
\item{options}{A list of additional options created with \code{\link{protomapsOptions}}.}
|
||||||
|
|
||||||
|
\item{layerId}{Character. Layer ID for the protomaps layer.}
|
||||||
|
|
||||||
|
\item{group}{Character. Group name for layer control.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A modified leaflet map object.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Adds a vector tile layer from a PMTiles source to a Leaflet map using
|
||||||
|
the protomaps-leaflet library. Supports built-in flavors and custom
|
||||||
|
styling rules.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Basic usage with demo tiles
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) \%>\%
|
||||||
|
addProtomaps(url = protomaps_demo_url())
|
||||||
|
|
||||||
|
# Using dark flavor
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) \%>\%
|
||||||
|
addProtomaps(url = protomaps_demo_url(), flavor = "dark")
|
||||||
|
|
||||||
|
# Custom colors with proper rendering
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) \%>\%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_demo_url(),
|
||||||
|
colors = pmColors(earth = "#d3d3d3", water = "#1a3a5c")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Using preset styles (recommended for common use cases)
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) \%>\%
|
||||||
|
addProtomaps(url = protomaps_demo_url(), style = pmStyle("minimal"))
|
||||||
|
|
||||||
|
# Custom minimal style
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) \%>\%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_demo_url(),
|
||||||
|
style = pmMinimal(land = "#f5f5f0", water = "#1a3a5c", labels = TRUE)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
49
man/pmCenteredTextSymbolizer.Rd
Normal file
49
man/pmCenteredTextSymbolizer.Rd
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/symbolizers.R
|
||||||
|
\name{pmCenteredTextSymbolizer}
|
||||||
|
\alias{pmCenteredTextSymbolizer}
|
||||||
|
\title{Create a Centered Text Symbolizer}
|
||||||
|
\usage{
|
||||||
|
pmCenteredTextSymbolizer(
|
||||||
|
font = "12px sans-serif",
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 0,
|
||||||
|
lineHeight = NULL,
|
||||||
|
labelProps = NULL,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{font}{Character. Font specification (e.g., "12px sans-serif").}
|
||||||
|
|
||||||
|
\item{fill}{Character. Text fill color. Default is "#000000".}
|
||||||
|
|
||||||
|
\item{stroke}{Character. Text stroke (halo) color. Default is NULL.}
|
||||||
|
|
||||||
|
\item{width}{Numeric. Stroke width for text halo. Default is 0.}
|
||||||
|
|
||||||
|
\item{lineHeight}{Numeric. Line height multiplier for multi-line labels.
|
||||||
|
Default is NULL (uses library default). Use values like 1.0-1.2 for
|
||||||
|
tighter spacing.}
|
||||||
|
|
||||||
|
\item{labelProps}{List. Properties to use for label text, in order of
|
||||||
|
preference. Default is \code{list("name")}.}
|
||||||
|
|
||||||
|
\item{...}{Additional symbolizer options.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the symbolizer configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a centered text symbolizer for rendering text labels centered
|
||||||
|
on point features.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
pmCenteredTextSymbolizer(font = "14px Arial", fill = "black")
|
||||||
|
|
||||||
|
# Tighter line spacing for multi-word labels
|
||||||
|
pmCenteredTextSymbolizer(font = "11px sans-serif", fill = "#444",
|
||||||
|
lineHeight = 1.1)
|
||||||
|
|
||||||
|
}
|
||||||
42
man/pmCircleSymbolizer.Rd
Normal file
42
man/pmCircleSymbolizer.Rd
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/symbolizers.R
|
||||||
|
\name{pmCircleSymbolizer}
|
||||||
|
\alias{pmCircleSymbolizer}
|
||||||
|
\title{Create a Circle Symbolizer}
|
||||||
|
\usage{
|
||||||
|
pmCircleSymbolizer(
|
||||||
|
radius = 4,
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 1,
|
||||||
|
opacity = 1,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{radius}{Numeric. Circle radius in pixels. Default is 4.}
|
||||||
|
|
||||||
|
\item{fill}{Character. Fill color for the circle. Default is "#000000".}
|
||||||
|
|
||||||
|
\item{stroke}{Character. Stroke (outline) color. Default is NULL.}
|
||||||
|
|
||||||
|
\item{width}{Numeric. Stroke width in pixels. Default is 1.}
|
||||||
|
|
||||||
|
\item{opacity}{Numeric. Fill opacity from 0 to 1. Default is 1.}
|
||||||
|
|
||||||
|
\item{...}{Additional symbolizer options.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the symbolizer configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a circle symbolizer for rendering point features as circles.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
# Simple red circle
|
||||||
|
pmCircleSymbolizer(radius = 6, fill = "red")
|
||||||
|
|
||||||
|
# Circle with stroke
|
||||||
|
pmCircleSymbolizer(radius = 8, fill = "white", stroke = "black", width = 2)
|
||||||
|
|
||||||
|
}
|
||||||
49
man/pmCityLabels.Rd
Normal file
49
man/pmCityLabels.Rd
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/styles.R
|
||||||
|
\name{pmCityLabels}
|
||||||
|
\alias{pmCityLabels}
|
||||||
|
\title{Create preset label rules for city names}
|
||||||
|
\usage{
|
||||||
|
pmCityLabels(
|
||||||
|
style = c("hierarchical", "major-only", "all"),
|
||||||
|
color = "#333333",
|
||||||
|
halo = "white",
|
||||||
|
include_regions = TRUE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{style}{Character. Label style preset:
|
||||||
|
\describe{
|
||||||
|
\item{"hierarchical"}{Size varies by city importance (min_zoom)}
|
||||||
|
\item{"major-only"}{Only major cities (min_zoom <= 5)}
|
||||||
|
\item{"all"}{All cities with uniform styling}
|
||||||
|
}}
|
||||||
|
|
||||||
|
\item{color}{Character. Text color. Default is "#333333".}
|
||||||
|
|
||||||
|
\item{halo}{Character. Halo/stroke color. Default is "white".}
|
||||||
|
|
||||||
|
\item{include_regions}{Logical. Include state/region labels. Default is TRUE.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list of label rules to pass to \code{\link{addProtomaps}}.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates label rules for displaying city/place names with common styling
|
||||||
|
patterns.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 8) \%>\%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
colors = pmColors(earth = "#f0f0f0", water = "#1a3a5c"),
|
||||||
|
labelRules = pmCityLabels("hierarchical")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
96
man/pmColors.Rd
Normal file
96
man/pmColors.Rd
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/colors.R
|
||||||
|
\name{pmColors}
|
||||||
|
\alias{pmColors}
|
||||||
|
\title{Create custom color overrides}
|
||||||
|
\usage{
|
||||||
|
pmColors(
|
||||||
|
background = NULL,
|
||||||
|
earth = NULL,
|
||||||
|
water = NULL,
|
||||||
|
park = NULL,
|
||||||
|
wood = NULL,
|
||||||
|
hospital = NULL,
|
||||||
|
industrial = NULL,
|
||||||
|
school = NULL,
|
||||||
|
beach = NULL,
|
||||||
|
glacier = NULL,
|
||||||
|
highway = NULL,
|
||||||
|
major = NULL,
|
||||||
|
minor = NULL,
|
||||||
|
city_label = NULL,
|
||||||
|
state_label = NULL,
|
||||||
|
country_label = NULL,
|
||||||
|
ocean_label = NULL,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{background}{Background color}
|
||||||
|
|
||||||
|
\item{earth}{Land/earth color}
|
||||||
|
|
||||||
|
\item{water}{Water color}
|
||||||
|
|
||||||
|
\item{park}{Park/green space color (also called park_a or park_b)}
|
||||||
|
|
||||||
|
\item{wood}{Forest/woodland color (also called wood_a or wood_b)}
|
||||||
|
|
||||||
|
\item{hospital}{Hospital area color}
|
||||||
|
|
||||||
|
\item{industrial}{Industrial area color}
|
||||||
|
|
||||||
|
\item{school}{School/university area color}
|
||||||
|
|
||||||
|
\item{beach}{Beach color}
|
||||||
|
|
||||||
|
\item{glacier}{Glacier color}
|
||||||
|
|
||||||
|
\item{highway}{Highway road color}
|
||||||
|
|
||||||
|
\item{major}{Major road color}
|
||||||
|
|
||||||
|
\item{minor}{Minor road color}
|
||||||
|
|
||||||
|
\item{city_label}{City label color}
|
||||||
|
|
||||||
|
\item{state_label}{State/region label color}
|
||||||
|
|
||||||
|
\item{country_label}{Country label color}
|
||||||
|
|
||||||
|
\item{ocean_label}{Ocean label color}
|
||||||
|
|
||||||
|
\item{...}{Additional color properties}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list of color overrides to pass to \code{\link{addProtomaps}}.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a list of color overrides that can be applied to a built-in flavor.
|
||||||
|
This is the recommended way to customize map colors while keeping the
|
||||||
|
proper rendering rules (zoom handling, polygon simplification, etc.).
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
# Simple earth and water colors
|
||||||
|
pmColors(earth = "#d3d3d3", water = "#1a3a5c")
|
||||||
|
|
||||||
|
# Dark theme with custom colors
|
||||||
|
pmColors(
|
||||||
|
background = "#1a1a2e",
|
||||||
|
earth = "#1a1a2e",
|
||||||
|
water = "#16213e",
|
||||||
|
park = "#1f4037",
|
||||||
|
highway = "#4a4a6a"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Minimal grayscale
|
||||||
|
pmColors(
|
||||||
|
background = "#ffffff",
|
||||||
|
earth = "#f5f5f5",
|
||||||
|
water = "#e0e0e0"
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{addProtomaps}}, \code{\link{protomaps_colors}}
|
||||||
|
}
|
||||||
39
man/pmHideFeatures.Rd
Normal file
39
man/pmHideFeatures.Rd
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/styles.R
|
||||||
|
\name{pmHideFeatures}
|
||||||
|
\alias{pmHideFeatures}
|
||||||
|
\title{Create color overrides to hide specific features}
|
||||||
|
\usage{
|
||||||
|
pmHideFeatures(features, background = "#f8f8f8")
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{features}{Character vector. Features to hide. Options include:
|
||||||
|
"roads", "buildings", "landuse", "boundaries", "labels".}
|
||||||
|
|
||||||
|
\item{background}{Character. Background color that hidden features will
|
||||||
|
match. Default is "#f8f8f8".}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list of color overrides to pass to \code{\link{pmColors}} or
|
||||||
|
merge with other colors.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates color settings that hide specified feature categories by making
|
||||||
|
them match the background color.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Hide roads and buildings but keep parks visible
|
||||||
|
hidden <- pmHideFeatures(c("roads", "buildings"))
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) \%>\%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
colors = modifyList(pmColors(water = "#1a3a5c"), hidden)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
54
man/pmLabelRule.Rd
Normal file
54
man/pmLabelRule.Rd
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/rules.R
|
||||||
|
\name{pmLabelRule}
|
||||||
|
\alias{pmLabelRule}
|
||||||
|
\title{Create a Label Rule}
|
||||||
|
\usage{
|
||||||
|
pmLabelRule(
|
||||||
|
dataLayer,
|
||||||
|
symbolizer,
|
||||||
|
minzoom = NULL,
|
||||||
|
maxzoom = NULL,
|
||||||
|
filter = NULL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{dataLayer}{Character. The name of the data layer in the vector
|
||||||
|
tile source (e.g., "places", "roads").}
|
||||||
|
|
||||||
|
\item{symbolizer}{A text symbolizer object created with one of
|
||||||
|
\code{\link{pmTextSymbolizer}}, \code{\link{pmCenteredTextSymbolizer}},
|
||||||
|
\code{\link{pmLineLabelSymbolizer}}, or \code{\link{pmShieldSymbolizer}}.}
|
||||||
|
|
||||||
|
\item{minzoom}{Numeric. Minimum zoom level at which this rule applies.
|
||||||
|
Default is NULL (applies at all zoom levels).}
|
||||||
|
|
||||||
|
\item{maxzoom}{Numeric. Maximum zoom level at which this rule applies.
|
||||||
|
Default is NULL (applies at all zoom levels).}
|
||||||
|
|
||||||
|
\item{filter}{Character. A JavaScript expression string that filters
|
||||||
|
features. Default is NULL (no filter).}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the label rule configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a label rule that specifies how to render text labels for
|
||||||
|
features from a particular data layer. Label rules control text
|
||||||
|
placement and styling, with automatic collision detection.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
# Label cities
|
||||||
|
pmLabelRule("places",
|
||||||
|
pmCenteredTextSymbolizer(font = "14px Arial",
|
||||||
|
fill = "black",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2))
|
||||||
|
|
||||||
|
# Label streets along their paths
|
||||||
|
pmLabelRule("roads",
|
||||||
|
pmLineLabelSymbolizer(font = "11px Arial",
|
||||||
|
fill = "#333"),
|
||||||
|
minzoom = 14)
|
||||||
|
|
||||||
|
}
|
||||||
40
man/pmLineLabelSymbolizer.Rd
Normal file
40
man/pmLineLabelSymbolizer.Rd
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/symbolizers.R
|
||||||
|
\name{pmLineLabelSymbolizer}
|
||||||
|
\alias{pmLineLabelSymbolizer}
|
||||||
|
\title{Create a Line Label Symbolizer}
|
||||||
|
\usage{
|
||||||
|
pmLineLabelSymbolizer(
|
||||||
|
font = "12px sans-serif",
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 0,
|
||||||
|
labelProps = NULL,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{font}{Character. Font specification (e.g., "12px sans-serif").}
|
||||||
|
|
||||||
|
\item{fill}{Character. Text fill color. Default is "#000000".}
|
||||||
|
|
||||||
|
\item{stroke}{Character. Text stroke (halo) color. Default is NULL.}
|
||||||
|
|
||||||
|
\item{width}{Numeric. Stroke width for text halo. Default is 0.}
|
||||||
|
|
||||||
|
\item{labelProps}{List. Properties to use for label text.}
|
||||||
|
|
||||||
|
\item{...}{Additional symbolizer options.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the symbolizer configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a line label symbolizer for rendering text labels along line
|
||||||
|
features (e.g., street names).
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
pmLineLabelSymbolizer(font = "11px Arial", fill = "#333",
|
||||||
|
stroke = "white", width = 2)
|
||||||
|
|
||||||
|
}
|
||||||
54
man/pmLineSymbolizer.Rd
Normal file
54
man/pmLineSymbolizer.Rd
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/symbolizers.R
|
||||||
|
\name{pmLineSymbolizer}
|
||||||
|
\alias{pmLineSymbolizer}
|
||||||
|
\title{Create a Line Symbolizer}
|
||||||
|
\usage{
|
||||||
|
pmLineSymbolizer(
|
||||||
|
color = "#000000",
|
||||||
|
width = 1,
|
||||||
|
dash = NULL,
|
||||||
|
dashColor = NULL,
|
||||||
|
dashWidth = NULL,
|
||||||
|
lineCap = NULL,
|
||||||
|
lineJoin = NULL,
|
||||||
|
opacity = 1,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{color}{Character. Line color. Default is "#000000".}
|
||||||
|
|
||||||
|
\item{width}{Numeric or function. Line width in pixels. Can be a fixed
|
||||||
|
value or a zoom-dependent specification.}
|
||||||
|
|
||||||
|
\item{dash}{List or NULL. Dash pattern as a vector of numbers, e.g.,
|
||||||
|
\code{c(4, 2)} for 4px dash, 2px gap.}
|
||||||
|
|
||||||
|
\item{dashColor}{Character. Color for dashes if using dash pattern.}
|
||||||
|
|
||||||
|
\item{dashWidth}{Numeric. Width of dashes.}
|
||||||
|
|
||||||
|
\item{lineCap}{Character. Line cap style: "butt", "round", or "square".}
|
||||||
|
|
||||||
|
\item{lineJoin}{Character
|
||||||
|
. Line join style: "miter", "round", or "bevel".}
|
||||||
|
|
||||||
|
\item{opacity}{Numeric. Line opacity from 0 to 1. Default is 1.}
|
||||||
|
|
||||||
|
\item{...}{Additional symbolizer options.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the symbolizer configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a line symbolizer for rendering line features.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
# Simple black line
|
||||||
|
pmLineSymbolizer(color = "black", width = 2)
|
||||||
|
|
||||||
|
# Dashed line
|
||||||
|
pmLineSymbolizer(color = "gray", width = 1, dash = c(4, 2))
|
||||||
|
|
||||||
|
}
|
||||||
52
man/pmMinimal.Rd
Normal file
52
man/pmMinimal.Rd
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/styles.R
|
||||||
|
\name{pmMinimal}
|
||||||
|
\alias{pmMinimal}
|
||||||
|
\title{Create a minimal basemap style}
|
||||||
|
\usage{
|
||||||
|
pmMinimal(
|
||||||
|
land = "#f8f8f8",
|
||||||
|
water = "#e0e8f0",
|
||||||
|
labels = FALSE,
|
||||||
|
label_color = "#666666"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{land}{Character. Color for all land features. Default is "#f8f8f8".}
|
||||||
|
|
||||||
|
\item{water}{Character. Color for water features. Default is "#e0e8f0".}
|
||||||
|
|
||||||
|
\item{labels}{Logical. Whether to show city labels. Default is FALSE.}
|
||||||
|
|
||||||
|
\item{label_color}{Character. Color for labels if shown. Default is "#666666".}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list with \code{colors} and \code{labelRules} components to pass to
|
||||||
|
\code{\link{addProtomaps}}.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a minimal style with uniform land color, hiding roads, buildings,
|
||||||
|
and most labels. Ideal for data visualization overlays.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Ultra-minimal basemap
|
||||||
|
style <- pmMinimal()
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) \%>\%
|
||||||
|
addProtomaps(url = protomaps_url(), style = style)
|
||||||
|
|
||||||
|
# Custom colors with major city labels
|
||||||
|
style <- pmMinimal(land = "#f5f5f0", water = "#1a3a5c", labels = TRUE)
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 8) \%>\%
|
||||||
|
addProtomaps(url = protomaps_url(), style = style)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{pmStyle}}, \code{\link{addProtomaps}}
|
||||||
|
}
|
||||||
62
man/pmModifyStyle.Rd
Normal file
62
man/pmModifyStyle.Rd
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/styles.R
|
||||||
|
\name{pmModifyStyle}
|
||||||
|
\alias{pmModifyStyle}
|
||||||
|
\title{Modify an Existing Style}
|
||||||
|
\usage{
|
||||||
|
pmModifyStyle(
|
||||||
|
style,
|
||||||
|
colors = NULL,
|
||||||
|
labelRules = NULL,
|
||||||
|
replace_labels = FALSE,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{style}{A pm_style object to modify.}
|
||||||
|
|
||||||
|
\item{colors}{Named list of color overrides (from pmColors() or manual list).}
|
||||||
|
|
||||||
|
\item{labelRules}{Optional list of label rules to replace or add.}
|
||||||
|
|
||||||
|
\item{replace_labels}{Logical. If TRUE, replaces all label rules. If FALSE,
|
||||||
|
appends new rules. Default is FALSE.}
|
||||||
|
|
||||||
|
\item{...}{Additional color overrides as named arguments.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A new pm_style object with modifications applied.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a new pm_style by modifying an existing one. Useful for tweaking
|
||||||
|
preset styles without rebuilding from scratch.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
# Start with watercolor, change water color
|
||||||
|
my_style <- pmModifyStyle(pmStyle("watercolor"), water = "#1a3a5c")
|
||||||
|
|
||||||
|
# Add label rules to minimal style
|
||||||
|
my_style <- pmModifyStyle(
|
||||||
|
pmMinimal(),
|
||||||
|
labelRules = pmCityLabels("major-only")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Multiple modifications
|
||||||
|
my_style <- pmModifyStyle(
|
||||||
|
pmStyle("muted"),
|
||||||
|
colors = pmColors(water = "#2a4a6c", park = "#c0d8c0"),
|
||||||
|
replace_labels = TRUE,
|
||||||
|
labelRules = list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "bold 14px Arial",
|
||||||
|
fill = "#333"
|
||||||
|
))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{pmStyle}}, \code{\link{pmMinimal}}
|
||||||
|
}
|
||||||
54
man/pmPaintRule.Rd
Normal file
54
man/pmPaintRule.Rd
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/rules.R
|
||||||
|
\name{pmPaintRule}
|
||||||
|
\alias{pmPaintRule}
|
||||||
|
\title{Create a Paint Rule}
|
||||||
|
\usage{
|
||||||
|
pmPaintRule(
|
||||||
|
dataLayer,
|
||||||
|
symbolizer,
|
||||||
|
minzoom = NULL,
|
||||||
|
maxzoom = NULL,
|
||||||
|
filter = NULL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{dataLayer}{Character. The name of the data layer in the vector
|
||||||
|
tile source (e.g., "water", "earth", "roads").}
|
||||||
|
|
||||||
|
\item{symbolizer}{A symbolizer object created with one of the symbolizer
|
||||||
|
functions (e.g., \code{\link{pmPolygonSymbolizer}},
|
||||||
|
\code{\link{pmLineSymbolizer}}).}
|
||||||
|
|
||||||
|
\item{minzoom}{Numeric. Minimum zoom level at which this rule applies.
|
||||||
|
Default is NULL (applies at all zoom levels).}
|
||||||
|
|
||||||
|
\item{maxzoom}{Numeric. Maximum zoom level at which this rule applies.
|
||||||
|
Default is NULL (applies at all zoom levels).}
|
||||||
|
|
||||||
|
\item{filter}{Character. A JavaScript expression string that filters
|
||||||
|
features. The expression has access to \code{zoom} and \code{feature}
|
||||||
|
variables. Default is NULL (no filter).}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the paint rule configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a paint rule that specifies how to render features from a
|
||||||
|
particular data layer. Paint rules control the visual appearance of
|
||||||
|
polygon, line, and point features.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
# Render water polygons in blue
|
||||||
|
pmPaintRule("water", pmPolygonSymbolizer(fill = "steelblue"))
|
||||||
|
|
||||||
|
# Render roads with zoom-dependent visibility
|
||||||
|
pmPaintRule("roads", pmLineSymbolizer(color = "gray", width = 2),
|
||||||
|
minzoom = 10)
|
||||||
|
|
||||||
|
# Filter to only show highways
|
||||||
|
pmPaintRule("roads",
|
||||||
|
pmLineSymbolizer(color = "orange", width = 4),
|
||||||
|
filter = "feature.props.kind === 'highway'")
|
||||||
|
|
||||||
|
}
|
||||||
61
man/pmPalette.Rd
Normal file
61
man/pmPalette.Rd
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/palette.R
|
||||||
|
\name{pmPalette}
|
||||||
|
\alias{pmPalette}
|
||||||
|
\title{Apply Color Palette to Land Use Categories}
|
||||||
|
\usage{
|
||||||
|
pmPalette(palette, categories = NULL, n = NULL, background = "#f8f8f8")
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{palette}{Character vector of colors, or a function that generates colors.
|
||||||
|
Can be output from viridis::viridis(), RColorBrewer::brewer.pal(), etc.}
|
||||||
|
|
||||||
|
\item{categories}{Character vector of category names to map colors to.
|
||||||
|
Default maps to common land use types: water, park, wood, residential,
|
||||||
|
commercial, industrial.}
|
||||||
|
|
||||||
|
\item{n}{Integer. Number of colors to generate if palette is a function.
|
||||||
|
Default is NULL (uses length of categories).}
|
||||||
|
|
||||||
|
\item{background}{Character. Background/default color for unassigned categories.
|
||||||
|
Default is "#f8f8f8".}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list of color mappings suitable for pmColors() or addProtomaps(colors=).
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Maps colors from a palette to land use categories, enabling use of
|
||||||
|
viridis, RColorBrewer, and other R color palettes with Protomaps.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Using viridis palette for land use
|
||||||
|
if (requireNamespace("viridisLite", quietly = TRUE)) {
|
||||||
|
colors <- pmPalette(viridisLite::viridis(6))
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) \%>\%
|
||||||
|
addProtomaps(url = protomaps_url(), colors = colors)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Using RColorBrewer
|
||||||
|
if (requireNamespace("RColorBrewer", quietly = TRUE)) {
|
||||||
|
colors <- pmPalette(RColorBrewer::brewer.pal(6, "Set2"))
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) \%>\%
|
||||||
|
addProtomaps(url = protomaps_url(), colors = colors)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Custom category mapping
|
||||||
|
colors <- pmPalette(
|
||||||
|
c("#264653", "#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"),
|
||||||
|
categories = c("water", "park", "sand", "buildings", "highway")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{pmPaletteStyle}}, \code{\link{pmColors}}
|
||||||
|
}
|
||||||
57
man/pmPaletteStyle.Rd
Normal file
57
man/pmPaletteStyle.Rd
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/palette.R
|
||||||
|
\name{pmPaletteStyle}
|
||||||
|
\alias{pmPaletteStyle}
|
||||||
|
\title{Create a Themed Palette Style}
|
||||||
|
\usage{
|
||||||
|
pmPaletteStyle(
|
||||||
|
palette,
|
||||||
|
water_color = NULL,
|
||||||
|
land_color = "#f8f8f8",
|
||||||
|
labels = TRUE,
|
||||||
|
label_color = "#333333"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{palette}{Character vector of colors or palette function.}
|
||||||
|
|
||||||
|
\item{water_color}{Character. Color for water features. If NULL, uses
|
||||||
|
first color from palette.}
|
||||||
|
|
||||||
|
\item{land_color}{Character. Color for land/background. Default is "#f8f8f8".}
|
||||||
|
|
||||||
|
\item{labels}{Logical. Whether to include city labels. Default is TRUE.}
|
||||||
|
|
||||||
|
\item{label_color}{Character. Color for labels. Default is "#333333".}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A pm_style object.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a complete pm_style using a color palette. Combines pmPalette()
|
||||||
|
with styling for a consistent look.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Viridis-themed map
|
||||||
|
if (requireNamespace("viridisLite", quietly = TRUE)) {
|
||||||
|
style <- pmPaletteStyle(viridisLite::viridis(5, option = "D"))
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) \%>\%
|
||||||
|
addProtomaps(url = protomaps_url(), style = style)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Custom palette
|
||||||
|
style <- pmPaletteStyle(
|
||||||
|
c("#264653", "#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"),
|
||||||
|
water_color = "#264653"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{pmPalette}}, \code{\link{pmStyle}}
|
||||||
|
}
|
||||||
43
man/pmPolygonSymbolizer.Rd
Normal file
43
man/pmPolygonSymbolizer.Rd
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/symbolizers.R
|
||||||
|
\name{pmPolygonSymbolizer}
|
||||||
|
\alias{pmPolygonSymbolizer}
|
||||||
|
\title{Create a Polygon Symbolizer}
|
||||||
|
\usage{
|
||||||
|
pmPolygonSymbolizer(
|
||||||
|
fill = "#cccccc",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 1,
|
||||||
|
opacity = 1,
|
||||||
|
pattern = NULL,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{fill}{Character. Fill color for the polygon. Can be a CSS color
|
||||||
|
string or a function specification.}
|
||||||
|
|
||||||
|
\item{stroke}{Character. Stroke (outline) color. Default is NULL (no stroke).}
|
||||||
|
|
||||||
|
\item{width}{Numeric. Stroke width in pixels. Default is 1.}
|
||||||
|
|
||||||
|
\item{opacity}{Numeric. Fill opacity from 0 to 1. Default is 1.}
|
||||||
|
|
||||||
|
\item{pattern}{Character. Fill pattern. One of NULL, "hatch", or "dot".}
|
||||||
|
|
||||||
|
\item{...}{Additional symbolizer options.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the symbolizer configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a polygon symbolizer for rendering filled polygon features.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
# Simple blue fill
|
||||||
|
pmPolygonSymbolizer(fill = "steelblue")
|
||||||
|
|
||||||
|
# With stroke
|
||||||
|
pmPolygonSymbolizer(fill = "#f0f0f0", stroke = "#333", width = 2)
|
||||||
|
|
||||||
|
}
|
||||||
43
man/pmShieldSymbolizer.Rd
Normal file
43
man/pmShieldSymbolizer.Rd
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/symbolizers.R
|
||||||
|
\name{pmShieldSymbolizer}
|
||||||
|
\alias{pmShieldSymbolizer}
|
||||||
|
\title{Create a Shield Symbolizer}
|
||||||
|
\usage{
|
||||||
|
pmShieldSymbolizer(
|
||||||
|
font = "10px sans-serif",
|
||||||
|
fill = "#000000",
|
||||||
|
background = "#ffffff",
|
||||||
|
stroke = "#000000",
|
||||||
|
padding = 2,
|
||||||
|
labelProps = NULL,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{font}{Character. Font specification for shield text.}
|
||||||
|
|
||||||
|
\item{fill}{Character. Text fill color. Default is "#000000".}
|
||||||
|
|
||||||
|
\item{background}{Character. Shield background color. Default is "#ffffff".}
|
||||||
|
|
||||||
|
\item{stroke}{Character. Shield border color. Default is "#000000".}
|
||||||
|
|
||||||
|
\item{padding}{Numeric. Padding inside the shield in pixels. Default is 2.}
|
||||||
|
|
||||||
|
\item{labelProps}{List. Properties to use for shield text.}
|
||||||
|
|
||||||
|
\item{...}{Additional symbolizer options.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the symbolizer configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a shield symbolizer for rendering labeled badges or shields
|
||||||
|
(e.g., highway route markers).
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
pmShieldSymbolizer(font = "10px Arial", fill = "black",
|
||||||
|
background = "white", stroke = "black")
|
||||||
|
|
||||||
|
}
|
||||||
47
man/pmStyle.Rd
Normal file
47
man/pmStyle.Rd
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/styles.R
|
||||||
|
\name{pmStyle}
|
||||||
|
\alias{pmStyle}
|
||||||
|
\title{Get a preset map style}
|
||||||
|
\usage{
|
||||||
|
pmStyle(
|
||||||
|
name = c("minimal", "minimal-dark", "muted", "watercolor", "ink", "terrain", "transit")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{name}{Character. Name of the preset style. One of:
|
||||||
|
\describe{
|
||||||
|
\item{"minimal"}{Light gray land, light blue water, no labels}
|
||||||
|
\item{"minimal-dark"}{Dark land, dark blue water, no labels}
|
||||||
|
\item{"muted"}{Subtle colors, faint roads, major labels only}
|
||||||
|
\item{"watercolor"}{Soft, painterly aesthetic}
|
||||||
|
\item{"ink"}{Black lines on white, like a pen drawing}
|
||||||
|
\item{"terrain"}{Earthy tones with subtle elevation feel}
|
||||||
|
\item{"transit"}{Muted base with emphasized rail lines}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list with style components to pass to \code{\link{addProtomaps}}.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Returns a preset style configuration. Available presets provide common
|
||||||
|
styling patterns without manual configuration.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) \%>\%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmStyle("minimal"))
|
||||||
|
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) \%>\%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmStyle("watercolor"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{pmMinimal}}, \code{\link{addProtomaps}}
|
||||||
|
}
|
||||||
48
man/pmTextSymbolizer.Rd
Normal file
48
man/pmTextSymbolizer.Rd
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/symbolizers.R
|
||||||
|
\name{pmTextSymbolizer}
|
||||||
|
\alias{pmTextSymbolizer}
|
||||||
|
\title{Create a Text Symbolizer}
|
||||||
|
\usage{
|
||||||
|
pmTextSymbolizer(
|
||||||
|
font = "12px sans-serif",
|
||||||
|
fill = "#000000",
|
||||||
|
stroke = NULL,
|
||||||
|
width = 0,
|
||||||
|
labelProps = NULL,
|
||||||
|
textTransform = NULL,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{font}{Character. Font specification (e.g., "12px sans-serif").}
|
||||||
|
|
||||||
|
\item{fill}{Character. Text fill color. Default is "#000000".}
|
||||||
|
|
||||||
|
\item{stroke}{Character. Text stroke (halo) color. Default is NULL.}
|
||||||
|
|
||||||
|
\item{width}{Numeric. Stroke width for text halo. Default is 0.}
|
||||||
|
|
||||||
|
\item{labelProps}{List. Properties to use for label text, in order of
|
||||||
|
preference. Default is \code{list("name")}.}
|
||||||
|
|
||||||
|
\item{textTransform}{Character. Text transformation: "uppercase",
|
||||||
|
"lowercase", or NULL.}
|
||||||
|
|
||||||
|
\item{...}{Additional symbolizer options.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list representing the symbolizer configuration.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates a text symbolizer for rendering text labels.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
# Simple text label
|
||||||
|
pmTextSymbolizer(font = "12px Arial", fill = "black")
|
||||||
|
|
||||||
|
# Text with halo
|
||||||
|
pmTextSymbolizer(font = "14px sans-serif", fill = "black",
|
||||||
|
stroke = "white", width = 2)
|
||||||
|
|
||||||
|
}
|
||||||
19
man/print.pm_style.Rd
Normal file
19
man/print.pm_style.Rd
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/styles.R
|
||||||
|
\name{print.pm_style}
|
||||||
|
\alias{print.pm_style}
|
||||||
|
\title{Print method for pm_style objects}
|
||||||
|
\usage{
|
||||||
|
\method{print}{pm_style}(x, ...)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{x}{A pm_style object.}
|
||||||
|
|
||||||
|
\item{...}{Additional arguments (ignored).}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
Invisibly returns x.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Prints a formatted summary of a pm_style object showing colors and label rules.
|
||||||
|
}
|
||||||
73
man/protomapr-package.Rd
Normal file
73
man/protomapr-package.Rd
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/protomapr-package.R
|
||||||
|
\docType{package}
|
||||||
|
\name{protomapr-package}
|
||||||
|
\alias{protomapr}
|
||||||
|
\alias{protomapr-package}
|
||||||
|
\title{protomapr: Add Protomaps Layers to Leaflet Maps}
|
||||||
|
\description{
|
||||||
|
The protomapr package provides functions to add Protomaps vector tile
|
||||||
|
layers to leaflet maps in R. Unlike raster tile providers, Protomaps
|
||||||
|
offers full customization of colors and features, self-hosting from a
|
||||||
|
single PMTiles file, and smooth vector rendering at any zoom level.
|
||||||
|
See \code{vignette("getting-started")} for why you might choose Protomaps
|
||||||
|
over standard provider tiles.
|
||||||
|
}
|
||||||
|
\section{Main Functions}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{\link{addProtomaps}}}{Add a Protomaps layer to a Leaflet map}
|
||||||
|
\item{\code{\link{protomapsOptions}}}{Configure additional layer options}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Symbolizers}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{\link{pmPolygonSymbolizer}}}{Style polygon features}
|
||||||
|
\item{\code{\link{pmLineSymbolizer}}}{Style line features}
|
||||||
|
\item{\code{\link{pmCircleSymbolizer}}}{Style point features as circles}
|
||||||
|
\item{\code{\link{pmTextSymbolizer}}}{Add text labels}
|
||||||
|
\item{\code{\link{pmCenteredTextSymbolizer}}}{Add centered text labels}
|
||||||
|
\item{\code{\link{pmLineLabelSymbolizer}}}{Add labels along lines}
|
||||||
|
\item{\code{\link{pmShieldSymbolizer}}}{Add shield/badge labels}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Rules}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{\link{pmPaintRule}}}{Define how to paint features}
|
||||||
|
\item{\code{\link{pmLabelRule}}}{Define how to label features}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Available Themes}{
|
||||||
|
|
||||||
|
The following built-in themes are available:
|
||||||
|
\itemize{
|
||||||
|
\item \code{"light"} - General-purpose light basemap
|
||||||
|
\item \code{"dark"} - General-purpose dark basemap
|
||||||
|
\item \code{"white"} - High-contrast white theme for data visualization
|
||||||
|
\item \code{"grayscale"} - Monochromatic theme
|
||||||
|
\item \code{"black"} - Dark theme for data visualization
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\seealso{
|
||||||
|
Useful links:
|
||||||
|
\itemize{
|
||||||
|
\item \url{https://github.com/evmo/protomapr}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\author{
|
||||||
|
\strong{Maintainer}: Evan Morrison \email{evan@p34.au}
|
||||||
|
|
||||||
|
Other contributors:
|
||||||
|
\itemize{
|
||||||
|
\item Brandon Liu (Author of protomaps-leaflet JavaScript library) [copyright holder]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\keyword{internal}
|
||||||
23
man/protomapsDependency.Rd
Normal file
23
man/protomapsDependency.Rd
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/addProtomaps.R
|
||||||
|
\name{protomapsDependency}
|
||||||
|
\alias{protomapsDependency}
|
||||||
|
\title{Create Protomaps HTML dependency}
|
||||||
|
\usage{
|
||||||
|
protomapsDependency(version = "5.1.0")
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{version}{Character. Version of protomaps-leaflet to use.
|
||||||
|
Default is "5.1.0".}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
An htmltools::htmlDependency object.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Creates the HTML dependency for the protomaps-leaflet JavaScript library.
|
||||||
|
This is automatically included when using \code{\link{addProtomaps}}.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
protomapsDependency()
|
||||||
|
|
||||||
|
}
|
||||||
28
man/protomapsOptions.Rd
Normal file
28
man/protomapsOptions.Rd
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/addProtomaps.R
|
||||||
|
\name{protomapsOptions}
|
||||||
|
\alias{protomapsOptions}
|
||||||
|
\title{Protomaps layer options}
|
||||||
|
\usage{
|
||||||
|
protomapsOptions(maxDataZoom = NULL, tileSize = NULL, debug = FALSE, ...)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{maxDataZoom}{Numeric. Maximum zoom level to fetch tile data.
|
||||||
|
Tiles beyond this zoom will be overzoomed.}
|
||||||
|
|
||||||
|
\item{tileSize}{Numeric. Size of tiles in pixels. Default is 256.}
|
||||||
|
|
||||||
|
\item{debug}{Logical. Enable debug mode to visualize tile boundaries.}
|
||||||
|
|
||||||
|
\item{...}{Additional options passed to the layer.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
A list of options.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Create additional options for protomaps layer configuration.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
protomapsOptions(maxDataZoom = 14, tileSize = 512)
|
||||||
|
|
||||||
|
}
|
||||||
28
man/protomaps_clear_cache.Rd
Normal file
28
man/protomaps_clear_cache.Rd
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/sample-tiles.R
|
||||||
|
\name{protomaps_clear_cache}
|
||||||
|
\alias{protomaps_clear_cache}
|
||||||
|
\title{Clear Cached Sample Tiles}
|
||||||
|
\usage{
|
||||||
|
protomaps_clear_cache(cache_dir = NULL)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{cache_dir}{Character. Cache directory. Default uses same as
|
||||||
|
\code{\link{protomaps_sample_tiles}}.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
Invisibly returns TRUE if files were removed, FALSE otherwise.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Removes cached sample PMTiles files to free disk space.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
# Clear all cached tiles
|
||||||
|
protomaps_clear_cache()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{protomaps_sample_tiles}}
|
||||||
|
}
|
||||||
72
man/protomaps_colors.Rd
Normal file
72
man/protomaps_colors.Rd
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/colors.R
|
||||||
|
\name{protomaps_colors}
|
||||||
|
\alias{protomaps_colors}
|
||||||
|
\title{Protomaps Color Properties Reference}
|
||||||
|
\description{
|
||||||
|
Reference documentation for all available color properties that can be
|
||||||
|
customized using \code{\link{pmColors}}.
|
||||||
|
}
|
||||||
|
\section{Base Colors}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{background}}{Map background color}
|
||||||
|
\item{\code{earth}}{Land/terrain color}
|
||||||
|
\item{\code{water}}{Water bodies color}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Land Use Colors}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{park_a}, \code{park_b}}{Park colors (use \code{park} in pmColors)}
|
||||||
|
\item{\code{wood_a}, \code{wood_b}}{Forest/woodland colors (use \code{wood} in pmColors)}
|
||||||
|
\item{\code{hospital}}{Hospital areas}
|
||||||
|
\item{\code{industrial}}{Industrial zones}
|
||||||
|
\item{\code{school}}{Schools and universities}
|
||||||
|
\item{\code{beach}}{Beach areas}
|
||||||
|
\item{\code{zoo}}{Zoo areas}
|
||||||
|
\item{\code{aerodrome}}{Airport areas}
|
||||||
|
\item{\code{glacier}}{Glacier areas}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Road Colors}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{highway}}{Highway/motorway color}
|
||||||
|
\item{\code{major}}{Major road color}
|
||||||
|
\item{\code{minor_a}, \code{minor_b}}{Minor road colors (use \code{minor} in pmColors)}
|
||||||
|
\item{\code{railway}}{Railway lines}
|
||||||
|
\item{\code{pier}}{Pier/dock structures}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Label Colors}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{city_label}}{City name labels}
|
||||||
|
\item{\code{state_label}}{State/region labels}
|
||||||
|
\item{\code{country_label}}{Country name labels}
|
||||||
|
\item{\code{ocean_label}}{Ocean/sea labels}
|
||||||
|
\item{\code{roads_label_major}}{Major road name labels}
|
||||||
|
\item{\code{roads_label_minor}}{Minor road name labels}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Landcover Colors (optional object)}{
|
||||||
|
|
||||||
|
These are specified as a nested object:
|
||||||
|
\describe{
|
||||||
|
\item{\code{grassland}}{Grassland areas}
|
||||||
|
\item{\code{barren}}{Barren land}
|
||||||
|
\item{\code{urban_area}}{Urban zones}
|
||||||
|
\item{\code{farmland}}{Agricultural areas}
|
||||||
|
\item{\code{forest}}{Forest areas}
|
||||||
|
\item{\code{scrub}}{Scrubland}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\seealso{
|
||||||
|
\code{\link{pmColors}}, \code{\link{addProtomaps}}
|
||||||
|
}
|
||||||
130
man/protomaps_layers.Rd
Normal file
130
man/protomaps_layers.Rd
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/layers.R
|
||||||
|
\name{protomaps_layers}
|
||||||
|
\alias{protomaps_layers}
|
||||||
|
\alias{layers}
|
||||||
|
\title{Protomaps Basemap Layers Reference}
|
||||||
|
\description{
|
||||||
|
Reference documentation for the available layers and properties in the
|
||||||
|
Protomaps basemap. Use these layer names with \code{\link{pmPaintRule}}
|
||||||
|
and \code{\link{pmLabelRule}}, and filter on these properties.
|
||||||
|
}
|
||||||
|
\section{Layer Names}{
|
||||||
|
|
||||||
|
The following layers are available for styling:
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{earth}}{Land polygons}
|
||||||
|
\item{\code{water}}{Water polygons, lines, and label points}
|
||||||
|
\item{\code{landuse}}{Parks, forests, residential areas, etc.}
|
||||||
|
\item{\code{roads}}{Streets, highways, paths}
|
||||||
|
\item{\code{buildings}}{Building footprints and addresses}
|
||||||
|
\item{\code{places}}{City, town, and region labels}
|
||||||
|
\item{\code{pois}}{Points of interest}
|
||||||
|
\item{\code{boundaries}}{Administrative boundaries}
|
||||||
|
\item{\code{natural}}{Natural features like peaks, forests}
|
||||||
|
\item{\code{transit}}{Transit stations and lines}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Places Layer Properties}{
|
||||||
|
|
||||||
|
Use these in filter expressions like \code{filter = "feature.props.kind === 'locality'"}
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{kind}}{Place type: "country", "region", "locality", "macrohood", "neighbourhood"}
|
||||||
|
\item{\code{kind_detail}}{Detailed type: "city", "town", "village", "hamlet", "state", "province", "country"}
|
||||||
|
\item{\code{name}}{Place name}
|
||||||
|
\item{\code{population}}{Population count (integer)}
|
||||||
|
\item{\code{population_rank}}{Population rank (integer, higher = larger)}
|
||||||
|
\item{\code{min_zoom}}{Minimum zoom level where label appears (lower = more important)}
|
||||||
|
\item{\code{capital}}{Capital status (string)}
|
||||||
|
\item{\code{wikidata}}{Wikidata ID}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Water Layer Properties}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{kind}}{Water type: "water", "lake", "playa", "ocean", "other"}
|
||||||
|
\item{\code{kind_detail}}{Detailed type: "basin", "canal", "ditch", "dock", "drain", "lake", "reservoir", "river", "riverbank", "stream"}
|
||||||
|
\item{\code{name}}{Water body name}
|
||||||
|
\item{\code{intermittent}}{Boolean, seasonal water}
|
||||||
|
\item{\code{reservoir}}{Boolean}
|
||||||
|
\item{\code{alkaline}}{Boolean}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Roads Layer Properties}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{kind}}{Road class: "highway", "major_road", "medium_road", "minor_road", "path"}
|
||||||
|
\item{\code{kind_detail}}{Detailed type: "motorway", "trunk", "primary", "secondary", "tertiary", "residential", "service", "pedestrian", "footway", "cycleway"}
|
||||||
|
\item{\code{ref}}{Road reference number (e.g., "I-80", "US-101")}
|
||||||
|
\item{\code{name}}{Street name}
|
||||||
|
\item{\code{oneway}}{Boolean}
|
||||||
|
\item{\code{is_bridge}}{Boolean}
|
||||||
|
\item{\code{is_tunnel}}{Boolean}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Landuse Layer Properties}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{kind}}{Land use type: "park", "forest", "residential", "commercial", "industrial", "aerodrome", "cemetery", "hospital", "school", "stadium", "zoo"}
|
||||||
|
\item{\code{sport}}{Sport type for sports facilities}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Buildings Layer Properties}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{kind}}{Building type: "address", "building", "building_part"}
|
||||||
|
\item{\code{height}}{Building height in meters}
|
||||||
|
\item{\code{min_height}}{Base height for building parts}
|
||||||
|
\item{\code{addr_housenumber}}{Street address number}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{POIs Layer Properties}{
|
||||||
|
|
||||||
|
\describe{
|
||||||
|
\item{\code{kind}}{POI type: "cafe", "restaurant", "hospital", "school", "bank", "pharmacy", "hotel", etc.}
|
||||||
|
\item{\code{name}}{POI name}
|
||||||
|
\item{\code{cuisine}}{Cuisine type for restaurants}
|
||||||
|
\item{\code{religion}}{Religion for places of worship}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\section{Filter Examples}{
|
||||||
|
|
||||||
|
\preformatted{
|
||||||
|
# Major cities only
|
||||||
|
filter = "feature.props.kind_detail === 'city'"
|
||||||
|
|
||||||
|
# States/provinces
|
||||||
|
filter = "feature.props.kind === 'region'"
|
||||||
|
|
||||||
|
# Important places (low min_zoom = important)
|
||||||
|
filter = "feature.props.min_zoom <= 6"
|
||||||
|
|
||||||
|
# Large cities by population rank
|
||||||
|
filter = "feature.props.population_rank >= 10"
|
||||||
|
|
||||||
|
# Highways only
|
||||||
|
filter = "feature.props.kind === 'highway'"
|
||||||
|
|
||||||
|
# Parks
|
||||||
|
filter = "feature.props.kind === 'park'"
|
||||||
|
|
||||||
|
# Combine conditions
|
||||||
|
filter = "feature.props.kind_detail === 'city' && feature.props.min_zoom <= 8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\references{
|
||||||
|
\url{https://docs.protomaps.com/basemaps/layers}
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{pmPaintRule}}, \code{\link{pmLabelRule}}
|
||||||
|
}
|
||||||
54
man/protomaps_sample_tiles.Rd
Normal file
54
man/protomaps_sample_tiles.Rd
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/sample-tiles.R
|
||||||
|
\name{protomaps_sample_tiles}
|
||||||
|
\alias{protomaps_sample_tiles}
|
||||||
|
\title{Get Path to Sample PMTiles File}
|
||||||
|
\usage{
|
||||||
|
protomaps_sample_tiles(
|
||||||
|
region = "sf-bay",
|
||||||
|
cache_dir = NULL,
|
||||||
|
force_download = FALSE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{region}{Character. Region to download. Currently only "sf-bay"
|
||||||
|
(San Francisco Bay Area) is available. Default is "sf-bay".}
|
||||||
|
|
||||||
|
\item{cache_dir}{Character. Directory to cache the downloaded file.
|
||||||
|
Default uses \code{tools::R_user_dir()}.}
|
||||||
|
|
||||||
|
\item{force_download}{Logical. Force re-download even if cached.
|
||||||
|
Default is FALSE.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
Character. Path to the PMTiles file.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Returns the path to a sample PMTiles file for demos and testing.
|
||||||
|
On first use, downloads a small regional extract to the user's cache
|
||||||
|
directory.
|
||||||
|
}
|
||||||
|
\details{
|
||||||
|
The sample tiles are hosted on GitHub releases and downloaded on first use.
|
||||||
|
Subsequent calls use the cached file. The SF Bay Area extract is
|
||||||
|
approximately 10-15MB and covers the greater San Francisco region at all
|
||||||
|
zoom levels.
|
||||||
|
|
||||||
|
For production use, consider self-hosting your own PMTiles file. See
|
||||||
|
\code{vignette("getting-started")} for options.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Use sample tiles for demos (downloads on first use)
|
||||||
|
leaflet() \%>\%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) \%>\%
|
||||||
|
addProtomaps(url = protomaps_sample_tiles())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{protomaps_clear_cache}}, \code{\link{protomaps_url}}
|
||||||
|
}
|
||||||
42
man/protomaps_url.Rd
Normal file
42
man/protomaps_url.Rd
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/addProtomaps.R
|
||||||
|
\name{protomaps_url}
|
||||||
|
\alias{protomaps_url}
|
||||||
|
\alias{protomaps_demo_url}
|
||||||
|
\title{Get Protomaps API tile URL}
|
||||||
|
\usage{
|
||||||
|
protomaps_url(api_key = NULL)
|
||||||
|
|
||||||
|
protomaps_demo_url(api_key = NULL)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{api_key}{Character. Your Protomaps API key. If NULL (default),
|
||||||
|
uses the \code{PROTOMAPS_API_KEY} environment variable.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
Character. URL template for the tile API.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Returns a URL template for the Protomaps tile API. Requires an API key,
|
||||||
|
which can be passed directly or set via the \code{PROTOMAPS_API_KEY}
|
||||||
|
environment variable.
|
||||||
|
|
||||||
|
Get a free API key (for non-commercial use) at \url{https://protomaps.com/}.
|
||||||
|
For commercial use or high traffic, consider self-hosting PMTiles files.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
# Set your API key as an environment variable (recommended)
|
||||||
|
Sys.setenv(PROTOMAPS_API_KEY = "your-api-key-here")
|
||||||
|
leaflet() \%>\%
|
||||||
|
addProtomaps(url = protomaps_url())
|
||||||
|
|
||||||
|
# Or pass the key directly
|
||||||
|
leaflet() \%>\%
|
||||||
|
addProtomaps(url = protomaps_url(api_key = "your-api-key-here"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
\code{\link{set_protomaps_key}} for a convenient way to set the API key.
|
||||||
|
}
|
||||||
33
man/set_protomaps_key.Rd
Normal file
33
man/set_protomaps_key.Rd
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
% Generated by roxygen2: do not edit by hand
|
||||||
|
% Please edit documentation in R/addProtomaps.R
|
||||||
|
\name{set_protomaps_key}
|
||||||
|
\alias{set_protomaps_key}
|
||||||
|
\title{Set Protomaps API key}
|
||||||
|
\usage{
|
||||||
|
set_protomaps_key(api_key)
|
||||||
|
}
|
||||||
|
\arguments{
|
||||||
|
\item{api_key}{Character. Your Protomaps API key.}
|
||||||
|
}
|
||||||
|
\value{
|
||||||
|
Invisibly returns the API key.
|
||||||
|
}
|
||||||
|
\description{
|
||||||
|
Convenience function to set your Protomaps API key for the current session.
|
||||||
|
The key is stored in the \code{PROTOMAPS_API_KEY} environment variable.
|
||||||
|
|
||||||
|
For persistent storage, add to your \code{.Renviron} file:
|
||||||
|
\code{PROTOMAPS_API_KEY=your-key-here}
|
||||||
|
|
||||||
|
Get a free API key at \url{https://protomaps.com/}.
|
||||||
|
}
|
||||||
|
\examples{
|
||||||
|
\dontrun{
|
||||||
|
set_protomaps_key("your-api-key-here")
|
||||||
|
|
||||||
|
# Now protomaps_url() will work without arguments
|
||||||
|
leaflet() \%>\%
|
||||||
|
addProtomaps(url = protomaps_url())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
21
protomapr.Rproj
Normal file
21
protomapr.Rproj
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
Version: 1.0
|
||||||
|
|
||||||
|
RestoreWorkspace: Default
|
||||||
|
SaveWorkspace: Default
|
||||||
|
AlwaysSaveHistory: Default
|
||||||
|
|
||||||
|
EnableCodeIndexing: Yes
|
||||||
|
UseSpacesForTab: Yes
|
||||||
|
NumSpacesForTab: 2
|
||||||
|
Encoding: UTF-8
|
||||||
|
|
||||||
|
RnwWeave: Sweave
|
||||||
|
LaTeX: pdfLaTeX
|
||||||
|
|
||||||
|
AutoAppendNewline: Yes
|
||||||
|
StripTrailingWhitespace: Yes
|
||||||
|
|
||||||
|
BuildType: Package
|
||||||
|
PackageUseDevtools: Yes
|
||||||
|
PackageInstallArgs: --no-multiarch --with-keep.source
|
||||||
|
PackageRoxygenize: rd,collate,namespace
|
||||||
4
tests/testthat.R
Normal file
4
tests/testthat.R
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
library(testthat)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
test_check("protomapr")
|
||||||
74
tests/testthat/test-addProtomaps.R
Normal file
74
tests/testthat/test-addProtomaps.R
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
test_that("protomaps_url requires API key", {
|
||||||
|
# Clear any existing env var
|
||||||
|
|
||||||
|
old_key <- Sys.getenv("PROTOMAPS_API_KEY")
|
||||||
|
Sys.unsetenv("PROTOMAPS_API_KEY")
|
||||||
|
on.exit(Sys.setenv(PROTOMAPS_API_KEY = old_key))
|
||||||
|
|
||||||
|
expect_error(protomaps_url(), "API key required")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomaps_url accepts direct API key", {
|
||||||
|
url <- protomaps_url(api_key = "test-key")
|
||||||
|
expect_true(grepl("api.protomaps.com", url))
|
||||||
|
expect_true(grepl("\\{z\\}/\\{x\\}/\\{y\\}", url))
|
||||||
|
expect_true(grepl("key=test-key", url))
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomaps_url uses environment variable", {
|
||||||
|
old_key <- Sys.getenv("PROTOMAPS_API_KEY")
|
||||||
|
Sys.setenv(PROTOMAPS_API_KEY = "env-test-key")
|
||||||
|
on.exit(Sys.setenv(PROTOMAPS_API_KEY = old_key))
|
||||||
|
|
||||||
|
url <- protomaps_url()
|
||||||
|
expect_true(grepl("key=env-test-key", url))
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("set_protomaps_key sets environment variable", {
|
||||||
|
old_key <- Sys.getenv("PROTOMAPS_API_KEY")
|
||||||
|
on.exit(Sys.setenv(PROTOMAPS_API_KEY = old_key))
|
||||||
|
|
||||||
|
expect_message(set_protomaps_key("my-key"), "API key set")
|
||||||
|
expect_equal(Sys.getenv("PROTOMAPS_API_KEY"), "my-key")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomaps_demo_url is deprecated", {
|
||||||
|
expect_warning(protomaps_demo_url(api_key = "test"), "deprecated")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomapsOptions creates correct structure", {
|
||||||
|
opts <- protomapsOptions(maxDataZoom = 14, tileSize = 512)
|
||||||
|
expect_equal(opts$maxDataZoom, 14)
|
||||||
|
expect_equal(opts$tileSize, 512)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomapsOptions handles debug mode", {
|
||||||
|
opts <- protomapsOptions(debug = TRUE)
|
||||||
|
expect_true(opts$debug)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomapsDependency returns htmlDependency", {
|
||||||
|
dep <- protomapsDependency()
|
||||||
|
expect_s3_class(dep, "html_dependency")
|
||||||
|
expect_equal(dep$name, "protomaps-leaflet")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("addProtomaps returns modified leaflet map", {
|
||||||
|
skip_if_not_installed("leaflet")
|
||||||
|
|
||||||
|
map <- leaflet::leaflet()
|
||||||
|
# Use mock URL to avoid API key requirement
|
||||||
|
result <- addProtomaps(map, url = "https://example.com/tiles.pmtiles")
|
||||||
|
|
||||||
|
expect_s3_class(result, "leaflet")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("addProtomaps validates flavor argument", {
|
||||||
|
skip_if_not_installed("leaflet")
|
||||||
|
|
||||||
|
map <- leaflet::leaflet()
|
||||||
|
expect_error(
|
||||||
|
addProtomaps(map, url = "https://example.com/tiles.pmtiles", flavor = "invalid"),
|
||||||
|
"should be one of"
|
||||||
|
)
|
||||||
|
})
|
||||||
34
tests/testthat/test-colors.R
Normal file
34
tests/testthat/test-colors.R
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
test_that("pmColors creates correct structure", {
|
||||||
|
colors <- pmColors(earth = "#d3d3d3", water = "#1a3a5c")
|
||||||
|
|
||||||
|
expect_equal(colors$earth, "#d3d3d3")
|
||||||
|
expect_equal(colors$water, "#1a3a5c")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmColors expands park to park_a and park_b", {
|
||||||
|
colors <- pmColors(park = "#00ff00")
|
||||||
|
|
||||||
|
expect_equal(colors$park_a, "#00ff00")
|
||||||
|
expect_equal(colors$park_b, "#00ff00")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmColors expands wood to wood_a and wood_b", {
|
||||||
|
colors <- pmColors(wood = "#228b22")
|
||||||
|
|
||||||
|
expect_equal(colors$wood_a, "#228b22")
|
||||||
|
expect_equal(colors$wood_b, "#228b22")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmColors expands minor to minor_a and minor_b", {
|
||||||
|
colors <- pmColors(minor = "#ffffff")
|
||||||
|
|
||||||
|
expect_equal(colors$minor_a, "#ffffff")
|
||||||
|
expect_equal(colors$minor_b, "#ffffff")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmColors passes through additional properties", {
|
||||||
|
colors <- pmColors(earth = "#ccc", custom_prop = "#abc")
|
||||||
|
|
||||||
|
expect_equal(colors$earth, "#ccc")
|
||||||
|
expect_equal(colors$custom_prop, "#abc")
|
||||||
|
})
|
||||||
71
tests/testthat/test-palette.R
Normal file
71
tests/testthat/test-palette.R
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
test_that("pmPalette creates color mapping", {
|
||||||
|
colors <- pmPalette(c("#ff0000", "#00ff00", "#0000ff"))
|
||||||
|
|
||||||
|
expect_true("water" %in% names(colors))
|
||||||
|
expect_true("background" %in% names(colors))
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPalette expands paired colors", {
|
||||||
|
colors <- pmPalette(c("#ff0000", "#00ff00"), categories = c("water", "park"))
|
||||||
|
|
||||||
|
expect_equal(colors$park_a, "#00ff00")
|
||||||
|
expect_equal(colors$park_b, "#00ff00")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPalette handles custom categories", {
|
||||||
|
colors <- pmPalette(
|
||||||
|
c("#111", "#222", "#333"),
|
||||||
|
categories = c("water", "buildings", "highway")
|
||||||
|
)
|
||||||
|
|
||||||
|
expect_equal(colors$water, "#111")
|
||||||
|
expect_equal(colors$buildings, "#222")
|
||||||
|
expect_equal(colors$highway, "#333")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPalette recycles colors if needed", {
|
||||||
|
colors <- pmPalette(c("#aaa", "#bbb"), categories = c("a", "b", "c", "d"))
|
||||||
|
|
||||||
|
expect_equal(length(colors), 6) # 4 categories + background + earth
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPalette handles palette functions", {
|
||||||
|
skip_if_not_installed("viridisLite")
|
||||||
|
|
||||||
|
colors <- pmPalette(viridisLite::viridis, n = 5)
|
||||||
|
expect_true("water" %in% names(colors))
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPaletteStyle creates pm_style", {
|
||||||
|
style <- pmPaletteStyle(c("#1a1a2e", "#16213e", "#0f3460", "#e94560", "#533483"))
|
||||||
|
|
||||||
|
expect_s3_class(style, "pm_style")
|
||||||
|
expect_true(length(style$labelRules) > 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPaletteStyle respects labels parameter", {
|
||||||
|
style_with <- pmPaletteStyle(c("#000", "#fff"), labels = TRUE)
|
||||||
|
style_without <- pmPaletteStyle(c("#000", "#fff"), labels = FALSE)
|
||||||
|
|
||||||
|
expect_true(length(style_with$labelRules) > 0)
|
||||||
|
expect_equal(length(style_without$labelRules), 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPaletteStyle uses water_color parameter", {
|
||||||
|
style <- pmPaletteStyle(
|
||||||
|
c("#aaa", "#bbb", "#ccc"),
|
||||||
|
water_color = "#123456"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect_equal(style$colors$water, "#123456")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPaletteStyle uses land_color parameter", {
|
||||||
|
style <- pmPaletteStyle(
|
||||||
|
c("#aaa", "#bbb", "#ccc"),
|
||||||
|
land_color = "#fedcba"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect_equal(style$colors$background, "#fedcba")
|
||||||
|
expect_equal(style$colors$earth, "#fedcba")
|
||||||
|
})
|
||||||
37
tests/testthat/test-rules.R
Normal file
37
tests/testthat/test-rules.R
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
test_that("pmPaintRule creates correct structure", {
|
||||||
|
sym <- pmPolygonSymbolizer(fill = "blue")
|
||||||
|
rule <- pmPaintRule("water", sym)
|
||||||
|
|
||||||
|
expect_equal(rule$dataLayer, "water")
|
||||||
|
expect_equal(rule$symbolizer$type, "polygon")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPaintRule handles zoom constraints", {
|
||||||
|
sym <- pmPolygonSymbolizer(fill = "gray")
|
||||||
|
rule <- pmPaintRule("buildings", sym, minzoom = 14, maxzoom = 18)
|
||||||
|
|
||||||
|
expect_equal(rule$minzoom, 14)
|
||||||
|
expect_equal(rule$maxzoom, 18)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPaintRule handles filters", {
|
||||||
|
sym <- pmLineSymbolizer(color = "orange")
|
||||||
|
rule <- pmPaintRule("roads", sym, filter = "feature.props.kind === 'highway'")
|
||||||
|
|
||||||
|
expect_equal(rule$filter, "feature.props.kind === 'highway'")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmLabelRule creates correct structure", {
|
||||||
|
sym <- pmCenteredTextSymbolizer(font = "14px Arial", fill = "black")
|
||||||
|
rule <- pmLabelRule("places", sym)
|
||||||
|
|
||||||
|
expect_equal(rule$dataLayer, "places")
|
||||||
|
expect_equal(rule$symbolizer$type, "centeredText")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmLabelRule handles filters", {
|
||||||
|
sym <- pmCenteredTextSymbolizer(font = "14px Arial", fill = "black")
|
||||||
|
rule <- pmLabelRule("places", sym, filter = "feature.props.kind === 'locality'")
|
||||||
|
|
||||||
|
expect_equal(rule$filter, "feature.props.kind === 'locality'")
|
||||||
|
})
|
||||||
65
tests/testthat/test-sample-tiles.R
Normal file
65
tests/testthat/test-sample-tiles.R
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
test_that("protomaps_sample_tiles validates region", {
|
||||||
|
expect_error(
|
||||||
|
protomaps_sample_tiles(region = "invalid"),
|
||||||
|
"sf-bay"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomaps_sample_tiles uses cached file", {
|
||||||
|
temp_dir <- tempdir()
|
||||||
|
temp_file <- file.path(temp_dir, "protomapr-sample-sf-bay.pmtiles")
|
||||||
|
|
||||||
|
# Create fake cached file
|
||||||
|
writeLines("test", temp_file)
|
||||||
|
|
||||||
|
expect_message(
|
||||||
|
result <- protomaps_sample_tiles(cache_dir = temp_dir),
|
||||||
|
"Using cached"
|
||||||
|
)
|
||||||
|
expect_equal(result, temp_file)
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
unlink(temp_file)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomaps_clear_cache handles missing directory", {
|
||||||
|
expect_message(
|
||||||
|
protomaps_clear_cache(cache_dir = "/nonexistent/path/12345"),
|
||||||
|
"does not exist"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomaps_clear_cache handles empty cache", {
|
||||||
|
temp_dir <- tempdir()
|
||||||
|
cache_subdir <- file.path(temp_dir, "protomapr_test_cache")
|
||||||
|
dir.create(cache_subdir, showWarnings = FALSE)
|
||||||
|
|
||||||
|
expect_message(
|
||||||
|
protomaps_clear_cache(cache_dir = cache_subdir),
|
||||||
|
"No cached tiles"
|
||||||
|
)
|
||||||
|
|
||||||
|
unlink(cache_subdir, recursive = TRUE)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("protomaps_clear_cache removes pmtiles files", {
|
||||||
|
temp_dir <- tempdir()
|
||||||
|
cache_subdir <- file.path(temp_dir, "protomapr_test_cache2")
|
||||||
|
dir.create(cache_subdir, showWarnings = FALSE)
|
||||||
|
|
||||||
|
# Create fake cached files
|
||||||
|
writeLines("test1", file.path(cache_subdir, "test1.pmtiles"))
|
||||||
|
writeLines("test2", file.path(cache_subdir, "test2.pmtiles"))
|
||||||
|
writeLines("keep", file.path(cache_subdir, "other.txt"))
|
||||||
|
|
||||||
|
result <- expect_message(
|
||||||
|
protomaps_clear_cache(cache_dir = cache_subdir),
|
||||||
|
"Removed 2"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check pmtiles removed but other file kept
|
||||||
|
expect_false(file.exists(file.path(cache_subdir, "test1.pmtiles")))
|
||||||
|
expect_true(file.exists(file.path(cache_subdir, "other.txt")))
|
||||||
|
|
||||||
|
unlink(cache_subdir, recursive = TRUE)
|
||||||
|
})
|
||||||
173
tests/testthat/test-styles.R
Normal file
173
tests/testthat/test-styles.R
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
test_that("pmMinimal creates correct structure", {
|
||||||
|
style <- pmMinimal()
|
||||||
|
|
||||||
|
expect_s3_class(style, "pm_style")
|
||||||
|
expect_true("colors" %in% names(style))
|
||||||
|
expect_true("labelRules" %in% names(style))
|
||||||
|
expect_equal(length(style$labelRules), 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmMinimal with labels creates label rules", {
|
||||||
|
style <- pmMinimal(labels = TRUE)
|
||||||
|
|
||||||
|
expect_equal(length(style$labelRules), 1)
|
||||||
|
expect_equal(style$labelRules[[1]]$dataLayer, "places")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmMinimal uses custom colors", {
|
||||||
|
style <- pmMinimal(land = "#ffffff", water = "#000000")
|
||||||
|
|
||||||
|
expect_equal(style$colors$earth, "#ffffff")
|
||||||
|
expect_equal(style$colors$water, "#000000")
|
||||||
|
expect_equal(style$colors$background, "#ffffff")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmStyle returns valid presets", {
|
||||||
|
minimal <- pmStyle("minimal")
|
||||||
|
expect_s3_class(minimal, "pm_style")
|
||||||
|
|
||||||
|
dark <- pmStyle("minimal-dark")
|
||||||
|
expect_s3_class(dark, "pm_style")
|
||||||
|
expect_equal(dark$colors$earth, "#1a1a1a")
|
||||||
|
|
||||||
|
muted <- pmStyle("muted")
|
||||||
|
expect_s3_class(muted, "pm_style")
|
||||||
|
expect_true(length(muted$labelRules) > 0)
|
||||||
|
|
||||||
|
watercolor <- pmStyle("watercolor")
|
||||||
|
expect_s3_class(watercolor, "pm_style")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmStyle validates name argument", {
|
||||||
|
expect_error(pmStyle("invalid"), "should be one of")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmHideFeatures hides roads", {
|
||||||
|
hidden <- pmHideFeatures("roads", background = "#fff")
|
||||||
|
|
||||||
|
expect_equal(hidden$highway, "#fff")
|
||||||
|
expect_equal(hidden$major, "#fff")
|
||||||
|
expect_equal(hidden$minor, "#fff")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmHideFeatures hides buildings", {
|
||||||
|
hidden <- pmHideFeatures("buildings", background = "#eee")
|
||||||
|
|
||||||
|
expect_equal(hidden$buildings, "#eee")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmHideFeatures hides multiple categories", {
|
||||||
|
hidden <- pmHideFeatures(c("roads", "buildings", "landuse"), background = "#ccc")
|
||||||
|
|
||||||
|
expect_equal(hidden$highway, "#ccc")
|
||||||
|
expect_equal(hidden$buildings, "#ccc")
|
||||||
|
expect_equal(hidden$park_a, "#ccc")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmCityLabels creates hierarchical labels", {
|
||||||
|
labels <- pmCityLabels("hierarchical")
|
||||||
|
|
||||||
|
expect_true(length(labels) >= 4) # 4 size levels + optional region
|
||||||
|
expect_equal(labels[[1]]$dataLayer, "places")
|
||||||
|
})
|
||||||
|
test_that("pmCityLabels creates major-only labels", {
|
||||||
|
labels <- pmCityLabels("major-only", include_regions = FALSE)
|
||||||
|
|
||||||
|
expect_equal(length(labels), 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmCityLabels respects include_regions", {
|
||||||
|
with_regions <- pmCityLabels("major-only", include_regions = TRUE)
|
||||||
|
without_regions <- pmCityLabels("major-only", include_regions = FALSE)
|
||||||
|
|
||||||
|
expect_equal(length(with_regions), length(without_regions) + 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("addProtomaps accepts style parameter", {
|
||||||
|
skip_if_not_installed("leaflet")
|
||||||
|
|
||||||
|
map <- leaflet::leaflet()
|
||||||
|
# Use a mock URL since we're just testing the R code, not actual tile loading
|
||||||
|
result <- addProtomaps(map, url = "https://example.com/tiles.pmtiles", style = pmStyle("minimal"))
|
||||||
|
|
||||||
|
expect_s3_class(result, "leaflet")
|
||||||
|
})
|
||||||
|
|
||||||
|
# New style presets
|
||||||
|
test_that("pmStyle returns ink preset", {
|
||||||
|
ink <- pmStyle("ink")
|
||||||
|
expect_s3_class(ink, "pm_style")
|
||||||
|
expect_equal(ink$colors$background, "#ffffff")
|
||||||
|
expect_equal(ink$colors$highway, "#000000")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmStyle returns terrain preset", {
|
||||||
|
terrain <- pmStyle("terrain")
|
||||||
|
expect_s3_class(terrain, "pm_style")
|
||||||
|
expect_true(length(terrain$labelRules) >= 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmStyle returns transit preset", {
|
||||||
|
transit <- pmStyle("transit")
|
||||||
|
expect_s3_class(transit, "pm_style")
|
||||||
|
expect_equal(transit$colors$railway, "#e63946")
|
||||||
|
})
|
||||||
|
|
||||||
|
# print.pm_style
|
||||||
|
test_that("print.pm_style outputs formatted text", {
|
||||||
|
style <- pmMinimal(land = "#ffffff", water = "#000000", labels = TRUE)
|
||||||
|
|
||||||
|
output <- capture.output(print(style))
|
||||||
|
expect_true(any(grepl("<pm_style>", output)))
|
||||||
|
expect_true(any(grepl("Colors:", output)))
|
||||||
|
expect_true(any(grepl("Label Rules:", output)))
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("print.pm_style handles style with no labels", {
|
||||||
|
style <- pmMinimal()
|
||||||
|
|
||||||
|
output <- capture.output(print(style))
|
||||||
|
expect_true(any(grepl("Label Rules: none", output)))
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("print.pm_style summarizes uniform colors", {
|
||||||
|
style <- pmMinimal()
|
||||||
|
|
||||||
|
output <- capture.output(print(style))
|
||||||
|
expect_true(any(grepl("uniform", output)))
|
||||||
|
})
|
||||||
|
|
||||||
|
# pmModifyStyle
|
||||||
|
test_that("pmModifyStyle preserves class", {
|
||||||
|
modified <- pmModifyStyle(pmMinimal(), water = "#000000")
|
||||||
|
expect_s3_class(modified, "pm_style")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmModifyStyle merges colors", {
|
||||||
|
original <- pmMinimal(land = "#ffffff", water = "#aaaaaa")
|
||||||
|
modified <- pmModifyStyle(original, water = "#000000")
|
||||||
|
|
||||||
|
expect_equal(modified$colors$water, "#000000")
|
||||||
|
expect_equal(modified$colors$earth, "#ffffff")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmModifyStyle appends label rules by default", {
|
||||||
|
original <- pmMinimal(labels = TRUE)
|
||||||
|
new_rules <- list(pmLabelRule("water", pmCenteredTextSymbolizer()))
|
||||||
|
|
||||||
|
modified <- pmModifyStyle(original, labelRules = new_rules)
|
||||||
|
expect_equal(length(modified$labelRules), 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmModifyStyle replaces labels when requested", {
|
||||||
|
original <- pmMinimal(labels = TRUE)
|
||||||
|
new_rules <- list(pmLabelRule("water", pmCenteredTextSymbolizer()))
|
||||||
|
|
||||||
|
modified <- pmModifyStyle(original, labelRules = new_rules, replace_labels = TRUE)
|
||||||
|
expect_equal(length(modified$labelRules), 1)
|
||||||
|
expect_equal(modified$labelRules[[1]]$dataLayer, "water")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmModifyStyle requires pm_style input", {
|
||||||
|
expect_error(pmModifyStyle(list()), "must be a pm_style")
|
||||||
|
})
|
||||||
56
tests/testthat/test-symbolizers.R
Normal file
56
tests/testthat/test-symbolizers.R
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
test_that("pmPolygonSymbolizer creates correct structure", {
|
||||||
|
sym <- pmPolygonSymbolizer(fill = "blue")
|
||||||
|
expect_equal(sym$type, "polygon")
|
||||||
|
expect_equal(sym$options$fill, "blue")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmPolygonSymbolizer handles optional parameters", {
|
||||||
|
sym <- pmPolygonSymbolizer(fill = "red", stroke = "black", width = 2, opacity = 0.5)
|
||||||
|
expect_equal(sym$options$fill, "red")
|
||||||
|
expect_equal(sym$options$stroke, "black")
|
||||||
|
expect_equal(sym$options$width, 2)
|
||||||
|
expect_equal(sym$options$opacity, 0.5)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmLineSymbolizer creates correct structure", {
|
||||||
|
sym <- pmLineSymbolizer(color = "gray", width = 3)
|
||||||
|
expect_equal(sym$type, "line")
|
||||||
|
expect_equal(sym$options$color, "gray")
|
||||||
|
expect_equal(sym$options$width, 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmLineSymbolizer handles dash patterns", {
|
||||||
|
sym <- pmLineSymbolizer(color = "black", dash = c(4, 2))
|
||||||
|
expect_equal(sym$options$dash, c(4, 2))
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmCircleSymbolizer creates correct structure", {
|
||||||
|
sym <- pmCircleSymbolizer(radius = 8, fill = "red")
|
||||||
|
expect_equal(sym$type, "circle")
|
||||||
|
expect_equal(sym$options$radius, 8)
|
||||||
|
expect_equal(sym$options$fill, "red")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmCenteredTextSymbolizer creates correct structure", {
|
||||||
|
sym <- pmCenteredTextSymbolizer(font = "14px Arial", fill = "black")
|
||||||
|
expect_equal(sym$type, "centeredText")
|
||||||
|
expect_equal(sym$options$font, "14px Arial")
|
||||||
|
expect_equal(sym$options$fill, "black")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmCenteredTextSymbolizer handles lineHeight", {
|
||||||
|
sym <- pmCenteredTextSymbolizer(font = "12px sans-serif", lineHeight = 1.5)
|
||||||
|
expect_equal(sym$options$lineHeight, 1.5)
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmLineLabelSymbolizer creates correct structure", {
|
||||||
|
sym <- pmLineLabelSymbolizer(font = "11px Arial", fill = "#333")
|
||||||
|
expect_equal(sym$type, "lineLabel")
|
||||||
|
expect_equal(sym$options$font, "11px Arial")
|
||||||
|
})
|
||||||
|
|
||||||
|
test_that("pmShieldSymbolizer creates correct structure", {
|
||||||
|
sym <- pmShieldSymbolizer(font = "10px Arial", background = "yellow")
|
||||||
|
expect_equal(sym$type, "shield")
|
||||||
|
expect_equal(sym$options$background, "yellow")
|
||||||
|
})
|
||||||
231
vignettes/custom-styling.Rmd
Normal file
231
vignettes/custom-styling.Rmd
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
---
|
||||||
|
title: "Custom Map Styling"
|
||||||
|
output: rmarkdown::html_vignette
|
||||||
|
vignette: >
|
||||||
|
%\VignetteIndexEntry{Custom Map Styling}
|
||||||
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
|
%\VignetteEncoding{UTF-8}
|
||||||
|
---
|
||||||
|
|
||||||
|
```{r, include = FALSE}
|
||||||
|
knitr::opts_chunk$set(
|
||||||
|
collapse = TRUE,
|
||||||
|
comment = "#>",
|
||||||
|
eval = FALSE
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
*Note: Code examples are not evaluated in this vignette. Copy and run them in your R console to see the interactive maps.*
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
protomapr provides extensive customization options for map styling. This vignette shows how to create a minimal basemap with custom colors and filtered labels.
|
||||||
|
|
||||||
|
## Simple Color Customization
|
||||||
|
|
||||||
|
Use `pmColors()` to override specific colors while keeping proper rendering:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
colors = pmColors(earth = "#f5f5f5", water = "#1a3a5c")
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating a Minimal Basemap
|
||||||
|
|
||||||
|
This example creates a clean, minimal map with:
|
||||||
|
|
||||||
|
- Uniform gray land (no parks, forests, or other land use distinctions)
|
||||||
|
- Dark blue water
|
||||||
|
- No roads or buildings
|
||||||
|
- Hierarchical city labels based on importance
|
||||||
|
- Styled water and island labels
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 8) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
colors = pmColors(
|
||||||
|
# Base colors - all land features same gray
|
||||||
|
background = "#d3d3d3",
|
||||||
|
earth = "#d3d3d3",
|
||||||
|
water = "#1a3a5c",
|
||||||
|
|
||||||
|
# Land use - all matching background
|
||||||
|
park = "#d3d3d3",
|
||||||
|
wood = "#d3d3d3",
|
||||||
|
scrub_a = "#d3d3d3",
|
||||||
|
scrub_b = "#d3d3d3",
|
||||||
|
glacier = "#d3d3d3",
|
||||||
|
sand = "#d3d3d3",
|
||||||
|
beach = "#d3d3d3",
|
||||||
|
hospital = "#d3d3d3",
|
||||||
|
school = "#d3d3d3",
|
||||||
|
industrial = "#d3d3d3",
|
||||||
|
pedestrian = "#d3d3d3",
|
||||||
|
zoo = "#d3d3d3",
|
||||||
|
military = "#d3d3d3",
|
||||||
|
aerodrome = "#d3d3d3",
|
||||||
|
|
||||||
|
# Hide roads
|
||||||
|
highway = "#d3d3d3",
|
||||||
|
major = "#d3d3d3",
|
||||||
|
medium = "#d3d3d3",
|
||||||
|
minor = "#d3d3d3",
|
||||||
|
link = "#d3d3d3",
|
||||||
|
other = "#d3d3d3",
|
||||||
|
railway = "#d3d3d3",
|
||||||
|
boundary = "#d3d3d3",
|
||||||
|
pier = "#d3d3d3",
|
||||||
|
buildings = "#d3d3d3"
|
||||||
|
),
|
||||||
|
labelRules = list(
|
||||||
|
# States/regions - large italic
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 20px sans-serif",
|
||||||
|
fill = "#666",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'region'"),
|
||||||
|
|
||||||
|
# Major metros (min_zoom <= 4: LA, SF, San Diego, Phoenix, Vegas)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 18px sans-serif",
|
||||||
|
fill = "#111",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 4"),
|
||||||
|
|
||||||
|
# Large cities (min_zoom 5-6: Fresno, Sacramento, Long Beach, etc.)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 14px sans-serif",
|
||||||
|
fill = "#222",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom > 4 && feature.props.min_zoom <= 6"),
|
||||||
|
|
||||||
|
# Medium cities (min_zoom 7)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 12px sans-serif",
|
||||||
|
fill = "#333",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom === 7"),
|
||||||
|
|
||||||
|
# Small towns (min_zoom >= 8)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 10px sans-serif",
|
||||||
|
fill = "#444",
|
||||||
|
stroke = "white",
|
||||||
|
width = 1
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom >= 8"),
|
||||||
|
|
||||||
|
# Water labels
|
||||||
|
pmLabelRule("water", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 11px sans-serif",
|
||||||
|
fill = "#0d2840",
|
||||||
|
stroke = "#d3d3d3",
|
||||||
|
width = 1,
|
||||||
|
lineHeight = 1.5
|
||||||
|
)),
|
||||||
|
|
||||||
|
# Natural features
|
||||||
|
pmLabelRule("natural", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 11px sans-serif",
|
||||||
|
fill = "#444",
|
||||||
|
stroke = "white",
|
||||||
|
width = 1,
|
||||||
|
lineHeight = 1.5
|
||||||
|
)),
|
||||||
|
|
||||||
|
# Earth features (islands)
|
||||||
|
pmLabelRule("earth", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 11px sans-serif",
|
||||||
|
fill = "#444",
|
||||||
|
stroke = "white",
|
||||||
|
width = 1,
|
||||||
|
lineHeight = 1.5
|
||||||
|
))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Understanding Label Filters
|
||||||
|
|
||||||
|
Labels are filtered using JavaScript expressions on feature properties:
|
||||||
|
|
||||||
|
### Place Properties
|
||||||
|
|
||||||
|
| Property | Description | Example Values |
|
||||||
|
|----------|-------------|----------------|
|
||||||
|
| `kind` | Feature type | "country", "region", "locality" |
|
||||||
|
| `kind_detail` | Specific type | "city", "town", "village", "state" |
|
||||||
|
| `min_zoom` | Importance (lower = more important) | LA=2, SF=3, Fresno=5 |
|
||||||
|
| `population_rank` | Population size | Higher = larger |
|
||||||
|
|
||||||
|
### Filter Examples
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
# Only states/regions
|
||||||
|
filter = "feature.props.kind === 'region'"
|
||||||
|
|
||||||
|
# Only cities (not towns/villages)
|
||||||
|
filter = "feature.props.kind_detail === 'city'"
|
||||||
|
|
||||||
|
# Major cities only
|
||||||
|
filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 4"
|
||||||
|
|
||||||
|
# Medium-sized cities
|
||||||
|
filter = "feature.props.kind === 'locality' && feature.props.min_zoom > 4 && feature.props.min_zoom <= 6"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Symbolizer Options
|
||||||
|
|
||||||
|
### Text Symbolizers
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
pmCenteredTextSymbolizer(
|
||||||
|
font = "600 14px sans-serif", # CSS font (weight size family)
|
||||||
|
fill = "#222", # Text color
|
||||||
|
stroke = "white", # Halo color
|
||||||
|
width = 2, # Halo width
|
||||||
|
lineHeight = 1.5 # Line spacing for multi-word labels
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Font Specifications
|
||||||
|
|
||||||
|
Fonts follow CSS syntax: `"[weight] [style] size family"`
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
# Bold
|
||||||
|
font = "600 14px sans-serif"
|
||||||
|
font = "bold 14px Arial"
|
||||||
|
|
||||||
|
# Italic
|
||||||
|
font = "italic 12px sans-serif"
|
||||||
|
|
||||||
|
# Bold italic
|
||||||
|
font = "italic 600 14px sans-serif"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layer Reference
|
||||||
|
|
||||||
|
| Layer | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `earth` | Land polygons, islands |
|
||||||
|
| `water` | Water bodies |
|
||||||
|
| `places` | City/region labels |
|
||||||
|
| `natural` | Natural features |
|
||||||
|
| `landuse` | Parks, forests, etc. |
|
||||||
|
| `roads` | Streets and highways |
|
||||||
|
| `buildings` | Building footprints |
|
||||||
|
|
||||||
|
See `?protomaps_layers` for complete documentation.
|
||||||
190
vignettes/data-viz-basemaps.Rmd
Normal file
190
vignettes/data-viz-basemaps.Rmd
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
---
|
||||||
|
title: "Basemaps for Data Visualization"
|
||||||
|
output: rmarkdown::html_vignette
|
||||||
|
vignette: >
|
||||||
|
%\VignetteIndexEntry{Basemaps for Data Visualization}
|
||||||
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
|
%\VignetteEncoding{UTF-8}
|
||||||
|
---
|
||||||
|
|
||||||
|
```{r, include = FALSE}
|
||||||
|
knitr::opts_chunk$set(
|
||||||
|
collapse = TRUE,
|
||||||
|
comment = "#>",
|
||||||
|
eval = FALSE
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
*Note: Code examples are not evaluated in this vignette. Copy and run them in your R console to see the interactive maps.*
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
When overlaying data on maps, busy basemaps can distract from your visualization. This vignette shows how to create minimal, muted basemaps that let your data stand out.
|
||||||
|
|
||||||
|
## Ultra-Minimal: Land and Water Only
|
||||||
|
|
||||||
|
Strip everything except land and water boundaries using `pmMinimal()`:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Using the convenience function - just two lines!
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmMinimal())
|
||||||
|
|
||||||
|
# Custom colors
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
style = pmMinimal(land = "#f5f5f0", water = "#c8dce8")
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Subtle Context: Faint Roads
|
||||||
|
|
||||||
|
Keep roads barely visible for orientation without distraction:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -73.98, lat = 40.75, zoom = 12) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
colors = pmColors(
|
||||||
|
background = "#ffffff",
|
||||||
|
earth = "#fafafa",
|
||||||
|
water = "#f0f4f8",
|
||||||
|
# Muted land use
|
||||||
|
park = "#f5f7f5",
|
||||||
|
wood = "#f5f7f5",
|
||||||
|
scrub_a = "#fafafa",
|
||||||
|
scrub_b = "#fafafa",
|
||||||
|
glacier = "#fafafa",
|
||||||
|
sand = "#fafafa",
|
||||||
|
beach = "#fafafa",
|
||||||
|
hospital = "#fafafa",
|
||||||
|
school = "#fafafa",
|
||||||
|
industrial = "#fafafa",
|
||||||
|
pedestrian = "#fafafa",
|
||||||
|
zoo = "#fafafa",
|
||||||
|
military = "#fafafa",
|
||||||
|
aerodrome = "#fafafa",
|
||||||
|
# Faint roads - just slightly darker than background
|
||||||
|
highway = "#e8e8e8",
|
||||||
|
major = "#efefef",
|
||||||
|
medium = "#f5f5f5",
|
||||||
|
minor = "#fafafa",
|
||||||
|
link = "#fafafa",
|
||||||
|
other = "#fafafa",
|
||||||
|
railway = "#f0f0f0",
|
||||||
|
pier = "#fafafa",
|
||||||
|
boundary = "#fafafa",
|
||||||
|
buildings = "#fafafa"
|
||||||
|
),
|
||||||
|
labelRules = list()
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dark Mode for Bright Data
|
||||||
|
|
||||||
|
Dark basemaps make colorful data points pop. Use the `minimal-dark` preset:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 11) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmStyle("minimal-dark"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Muted with Major Labels Only
|
||||||
|
|
||||||
|
Sometimes you need city names for context but nothing else. Use `pmMinimal()` with `labels = TRUE`:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -100, lat = 40, zoom = 4) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
style = pmMinimal(land = "#f5f5f0", water = "#d4e4ed", labels = TRUE)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Or use the "muted" preset which includes subtle roads and labels
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -100, lat = 40, zoom = 4) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmStyle("muted"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Choropleth-Friendly: No Fill Competition
|
||||||
|
|
||||||
|
For choropleth maps, you want boundaries visible but no competing fill colors:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -98, lat = 38, zoom = 4) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
colors = pmColors(
|
||||||
|
background = "#ffffff",
|
||||||
|
earth = "#ffffff",
|
||||||
|
water = "#ffffff",
|
||||||
|
# Hide all land use
|
||||||
|
park = "#ffffff",
|
||||||
|
wood = "#ffffff",
|
||||||
|
scrub_a = "#ffffff",
|
||||||
|
scrub_b = "#ffffff",
|
||||||
|
glacier = "#ffffff",
|
||||||
|
sand = "#ffffff",
|
||||||
|
beach = "#ffffff",
|
||||||
|
hospital = "#ffffff",
|
||||||
|
school = "#ffffff",
|
||||||
|
industrial = "#ffffff",
|
||||||
|
pedestrian = "#ffffff",
|
||||||
|
zoo = "#ffffff",
|
||||||
|
military = "#ffffff",
|
||||||
|
aerodrome = "#ffffff",
|
||||||
|
# Hide roads
|
||||||
|
highway = "#ffffff",
|
||||||
|
major = "#ffffff",
|
||||||
|
medium = "#ffffff",
|
||||||
|
minor = "#ffffff",
|
||||||
|
link = "#ffffff",
|
||||||
|
other = "#ffffff",
|
||||||
|
railway = "#ffffff",
|
||||||
|
pier = "#ffffff",
|
||||||
|
buildings = "#ffffff",
|
||||||
|
# Keep boundaries visible
|
||||||
|
boundary = "#cccccc"
|
||||||
|
),
|
||||||
|
labelRules = list(
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 11px sans-serif",
|
||||||
|
fill = "#333333",
|
||||||
|
stroke = "#ffffff",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'region'")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Watercolor Style
|
||||||
|
|
||||||
|
Soft, hand-drawn aesthetic using the `watercolor` preset:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmStyle("watercolor"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tips for Data Visualization Basemaps
|
||||||
|
|
||||||
|
1. **Match your data colors**: If your data uses warm colors, use cool-toned basemaps (and vice versa)
|
||||||
|
|
||||||
|
2. **Consider accessibility**: Ensure sufficient contrast between your data and basemap
|
||||||
|
|
||||||
|
3. **Remove labels when zoomed in**: Dense point data doesn't need city labels competing for attention
|
||||||
|
|
||||||
|
4. **Use transparency**: Leaflet markers and shapes can use alpha values to blend with basemaps
|
||||||
|
|
||||||
|
5. **Test at all zoom levels**: A basemap that works at zoom 10 may be too busy at zoom 15
|
||||||
258
vignettes/getting-started.Rmd
Normal file
258
vignettes/getting-started.Rmd
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
---
|
||||||
|
title: "Getting Started with protomapr"
|
||||||
|
output: rmarkdown::html_vignette
|
||||||
|
vignette: >
|
||||||
|
%\VignetteIndexEntry{Getting Started with protomapr}
|
||||||
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
|
%\VignetteEncoding{UTF-8}
|
||||||
|
---
|
||||||
|
|
||||||
|
```{r, include = FALSE}
|
||||||
|
knitr::opts_chunk$set(
|
||||||
|
collapse = TRUE,
|
||||||
|
comment = "#>",
|
||||||
|
eval = FALSE
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
*Note: Code examples are not evaluated in this vignette. Copy and run them in your R console to see the interactive maps.*
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
protomapr adds [Protomaps](https://protomaps.com/) vector tile layers to Leaflet maps in R. Protomaps provides fast, customizable map tiles using the PMTiles format.
|
||||||
|
|
||||||
|
## Why Protomaps?
|
||||||
|
|
||||||
|
Standard Leaflet maps use `addProviderTiles()` to load raster tiles from services like OpenStreetMap, Stadia, or CartoDB. These work well but have limitations:
|
||||||
|
|
||||||
|
| Feature | Raster Tiles (providerTiles) | Vector Tiles (Protomaps) |
|
||||||
|
|---------|------------------------------|--------------------------|
|
||||||
|
| Customization | Limited to provider's styles | Full control over colors, labels, features |
|
||||||
|
| Self-hosting | Requires tile server infrastructure | Single PMTiles file, no server needed |
|
||||||
|
| File size | Large (pre-rendered images) | Small (compressed vectors) |
|
||||||
|
| Zoom transitions | Can appear pixelated | Smooth at any zoom level |
|
||||||
|
| Offline use | Difficult | Easy with local PMTiles file |
|
||||||
|
| Privacy | Requests go to third-party servers | Self-host for complete privacy |
|
||||||
|
| Rate limits | Often have API limits | No limits when self-hosted |
|
||||||
|
| Feature filtering | Not possible | Hide roads, buildings, labels, etc. |
|
||||||
|
|
||||||
|
### When to use Protomaps
|
||||||
|
|
||||||
|
- **Custom branded maps**: Match your organization's color scheme
|
||||||
|
- **Minimal basemaps**: Hide distracting features for data visualization overlays
|
||||||
|
- **Offline/embedded applications**: Bundle a PMTiles file with your app
|
||||||
|
- **Privacy-sensitive contexts**: No third-party tile requests
|
||||||
|
- **High-traffic applications**: Avoid API rate limits
|
||||||
|
|
||||||
|
### When providerTiles may be simpler
|
||||||
|
|
||||||
|
- Quick prototypes where default styling is fine
|
||||||
|
- Satellite/aerial imagery (Protomaps is vector-only)
|
||||||
|
- When you don't need customization
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```{r, eval = FALSE}
|
||||||
|
# Install from CRAN
|
||||||
|
install.packages("protomapr")
|
||||||
|
|
||||||
|
# Or install development version
|
||||||
|
# devtools::install_github("yourusername/protomapr")
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Key Setup
|
||||||
|
|
||||||
|
Before using the Protomaps tile API, you need a free API key:
|
||||||
|
|
||||||
|
1. Sign up at https://protomaps.com/
|
||||||
|
2. Set your key for the session:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
# Set your API key (do this once per session)
|
||||||
|
set_protomaps_key("your-api-key-here")
|
||||||
|
|
||||||
|
# Or set via environment variable
|
||||||
|
Sys.setenv(PROTOMAPS_API_KEY = "your-api-key-here")
|
||||||
|
```
|
||||||
|
For persistent storage, add to your `.Renviron` file: `PROTOMAPS_API_KEY=your-key-here`
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
# Create a map with default light theme
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(url = protomaps_url())
|
||||||
|
```
|
||||||
|
|
||||||
|
## Built-in Flavors
|
||||||
|
|
||||||
|
protomapr includes five built-in flavors:
|
||||||
|
```{r}
|
||||||
|
# Light (default)
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), flavor = "light")
|
||||||
|
|
||||||
|
# Dark
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), flavor = "dark")
|
||||||
|
|
||||||
|
# White (minimal, good for data visualization overlays)
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), flavor = "white")
|
||||||
|
|
||||||
|
# Grayscale
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), flavor = "grayscale")
|
||||||
|
|
||||||
|
# Black
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 12) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), flavor = "black")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Sources
|
||||||
|
|
||||||
|
### Demo/Development
|
||||||
|
Use `protomaps_url()` for testing (uses Protomaps daily OpenStreetMap build):
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = protomaps_url())
|
||||||
|
```
|
||||||
|
|
||||||
|
### Self-hosted (recommended for production)
|
||||||
|
|
||||||
|
For production use, self-host a PMTiles file. This eliminates API rate limits, ensures privacy, and enables offline use.
|
||||||
|
|
||||||
|
#### Getting PMTiles files
|
||||||
|
|
||||||
|
**Option 1: Regional extract (recommended)**
|
||||||
|
|
||||||
|
Use [Protomaps Slice](https://slice.openstreetmap.us/) to extract just the region you need:
|
||||||
|
|
||||||
|
1. Go to https://slice.openstreetmap.us/
|
||||||
|
2. Draw a bounding box around your area of interest
|
||||||
|
3. Download the resulting PMTiles file (typically 10-500MB depending on region size)
|
||||||
|
|
||||||
|
**Option 2: Daily world builds**
|
||||||
|
|
||||||
|
Full planet builds are available at https://build.protomaps.com/ (~100GB). Only recommended if you need global coverage.
|
||||||
|
|
||||||
|
**Option 3: pmtiles CLI**
|
||||||
|
|
||||||
|
For scripted workflows, use the [pmtiles CLI tool](https://github.com/protomaps/go-pmtiles):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install (requires Go)
|
||||||
|
go install github.com/protomaps/go-pmtiles/cmd/pmtiles@latest
|
||||||
|
|
||||||
|
# Extract a region from a larger file
|
||||||
|
pmtiles extract world.pmtiles california.pmtiles --bbox=-124.5,32.5,-114.1,42.0
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Hosting options
|
||||||
|
|
||||||
|
**Cloud storage (simplest)**
|
||||||
|
|
||||||
|
Upload to S3, Google Cloud Storage, or Cloudflare R2. PMTiles supports HTTP range requests, so no special server is needed.
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
# S3
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = "https://your-bucket.s3.amazonaws.com/tiles.pmtiles")
|
||||||
|
|
||||||
|
# Cloudflare R2
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = "https://your-bucket.r2.cloudflarestorage.com/tiles.pmtiles")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important:** Enable CORS on your bucket to allow browser requests. Example S3 CORS policy:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[{
|
||||||
|
"AllowedOrigins": ["*"],
|
||||||
|
"AllowedMethods": ["GET", "HEAD"],
|
||||||
|
"AllowedHeaders": ["Range"],
|
||||||
|
"ExposeHeaders": ["Content-Length", "Content-Range"]
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Local file (Shiny apps)**
|
||||||
|
|
||||||
|
For Shiny applications, serve PMTiles from `www/`:
|
||||||
|
|
||||||
|
```r
|
||||||
|
# In your Shiny app, place tiles.pmtiles in www/ folder
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = "tiles.pmtiles")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Local development**
|
||||||
|
|
||||||
|
For local testing, use a simple HTTP server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Python
|
||||||
|
cd /path/to/pmtiles/folder
|
||||||
|
python -m http.server 8000
|
||||||
|
|
||||||
|
# Then in R
|
||||||
|
leaflet() %>%
|
||||||
|
addProtomaps(url = "http://localhost:8000/tiles.pmtiles")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Preset Styles
|
||||||
|
|
||||||
|
For common use cases, protomapr provides preset styles that are simpler than the built-in flavors:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
# Ultra-minimal basemap for data visualization
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmMinimal())
|
||||||
|
|
||||||
|
# Minimal with city labels
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmMinimal(labels = TRUE))
|
||||||
|
|
||||||
|
# Dark minimal
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmStyle("minimal-dark"))
|
||||||
|
|
||||||
|
# Soft watercolor aesthetic
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmStyle("watercolor"))
|
||||||
|
|
||||||
|
# Muted with subtle roads
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
addProtomaps(url = protomaps_url(), style = pmStyle("muted"))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Available presets
|
||||||
|
|
||||||
|
| Preset | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `pmMinimal()` | Hides roads, buildings, land use - shows only land and water |
|
||||||
|
| `pmStyle("minimal")` | Same as `pmMinimal()` |
|
||||||
|
| `pmStyle("minimal-dark")` | Dark version of minimal |
|
||||||
|
| `pmStyle("muted")` | Subtle colors, faint roads, major city labels |
|
||||||
|
| `pmStyle("watercolor")` | Soft, hand-painted aesthetic |
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
See `vignette("custom-styling")` to learn how to customize colors, labels, and map features.
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
This package wraps [protomaps-leaflet](https://github.com/protomaps/protomaps-leaflet), created by [Brandon Liu](https://bdon.org/). The Protomaps project provides an open-source stack for self-hosted vector maps, including the PMTiles format. Thanks to Brandon for making beautiful, customizable maps accessible to everyone.
|
||||||
327
vignettes/labels-and-filters.Rmd
Normal file
327
vignettes/labels-and-filters.Rmd
Normal file
|
|
@ -0,0 +1,327 @@
|
||||||
|
---
|
||||||
|
title: "Labels, Filters, and Feature Selection"
|
||||||
|
output: rmarkdown::html_vignette
|
||||||
|
vignette: >
|
||||||
|
%\VignetteIndexEntry{Labels, Filters, and Feature Selection}
|
||||||
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
|
%\VignetteEncoding{UTF-8}
|
||||||
|
---
|
||||||
|
|
||||||
|
```{r, include = FALSE}
|
||||||
|
knitr::opts_chunk$set(
|
||||||
|
collapse = TRUE,
|
||||||
|
comment = "#>",
|
||||||
|
eval = FALSE
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
*Note: Code examples are not evaluated in this vignette. Copy and run them in your R console to see the interactive maps.*
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Protomaps vector tiles contain rich metadata about each feature. This vignette shows how to use filters to selectively style and label features based on their properties.
|
||||||
|
|
||||||
|
## Understanding Feature Properties
|
||||||
|
|
||||||
|
Each feature in the vector tiles has a `props` object with metadata. Common properties include:
|
||||||
|
|
||||||
|
| Layer | Property | Values |
|
||||||
|
|-------|----------|--------|
|
||||||
|
| places | `kind` | "country", "region", "locality" |
|
||||||
|
| places | `min_zoom` | 1-15 (lower = more important) |
|
||||||
|
| roads | `kind` | "highway", "major_road", "minor_road", "path" |
|
||||||
|
| water | `kind` | "ocean", "lake", "river" |
|
||||||
|
| landuse | `kind` | "park", "forest", "residential", "industrial" |
|
||||||
|
|
||||||
|
## Hierarchical City Labels
|
||||||
|
|
||||||
|
Style cities by importance using `min_zoom`:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
library(leaflet)
|
||||||
|
library(protomapr)
|
||||||
|
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -100, lat = 40, zoom = 5) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
flavor = "light",
|
||||||
|
labelRules = list(
|
||||||
|
# Capital cities and major metros (min_zoom 1-3)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "700 16px sans-serif",
|
||||||
|
fill = "#1a1a1a",
|
||||||
|
stroke = "white",
|
||||||
|
width = 3
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 3"),
|
||||||
|
|
||||||
|
# Large cities (min_zoom 4-5)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 13px sans-serif",
|
||||||
|
fill = "#333333",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom > 3 && feature.props.min_zoom <= 5"),
|
||||||
|
|
||||||
|
# Medium cities (min_zoom 6-7)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "500 11px sans-serif",
|
||||||
|
fill = "#555555",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom > 5 && feature.props.min_zoom <= 7"),
|
||||||
|
|
||||||
|
# States/provinces
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 300 14px sans-serif",
|
||||||
|
fill = "#888888",
|
||||||
|
stroke = "white",
|
||||||
|
width = 1
|
||||||
|
), filter = "feature.props.kind === 'region'")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Road Hierarchy Styling
|
||||||
|
|
||||||
|
Style different road types with distinct colors and widths:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.78, zoom = 13) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
paintRules = list(
|
||||||
|
# Base layers
|
||||||
|
pmPaintRule("earth", pmPolygonSymbolizer(fill = "#f5f5f5")),
|
||||||
|
pmPaintRule("water", pmPolygonSymbolizer(fill = "#cce0eb")),
|
||||||
|
pmPaintRule("landuse", pmPolygonSymbolizer(fill = "#e8f0e8"),
|
||||||
|
filter = "feature.props.kind === 'park'"),
|
||||||
|
|
||||||
|
# Highways - orange, thick
|
||||||
|
pmPaintRule("roads", pmLineSymbolizer(color = "#f59e0b", width = 4),
|
||||||
|
filter = "feature.props.kind === 'highway'"),
|
||||||
|
|
||||||
|
# Major roads - dark gray, medium
|
||||||
|
pmPaintRule("roads", pmLineSymbolizer(color = "#6b7280", width = 2.5),
|
||||||
|
filter = "feature.props.kind === 'major_road'"),
|
||||||
|
|
||||||
|
# Minor roads - light gray, thin
|
||||||
|
pmPaintRule("roads", pmLineSymbolizer(color = "#9ca3af", width = 1.5),
|
||||||
|
filter = "feature.props.kind === 'minor_road'"),
|
||||||
|
|
||||||
|
# Paths - dashed
|
||||||
|
pmPaintRule("roads", pmLineSymbolizer(color = "#d1d5db", width = 1, dash = c(3, 2)),
|
||||||
|
filter = "feature.props.kind === 'path'")
|
||||||
|
),
|
||||||
|
labelRules = list(
|
||||||
|
pmLabelRule("roads", pmLineLabelSymbolizer(
|
||||||
|
font = "600 10px sans-serif",
|
||||||
|
fill = "#f59e0b",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'highway'", minzoom = 12),
|
||||||
|
|
||||||
|
pmLabelRule("roads", pmLineLabelSymbolizer(
|
||||||
|
font = "500 9px sans-serif",
|
||||||
|
fill = "#4b5563",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'major_road'", minzoom = 14)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Water Feature Labels
|
||||||
|
|
||||||
|
Style different water bodies appropriately:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.8, zoom = 10) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
colors = pmColors(
|
||||||
|
earth = "#f0f0f0",
|
||||||
|
water = "#1e40af"
|
||||||
|
),
|
||||||
|
labelRules = list(
|
||||||
|
# Ocean labels - large, bold
|
||||||
|
pmLabelRule("water", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 700 18px sans-serif",
|
||||||
|
fill = "#1e3a5f",
|
||||||
|
stroke = "#e0f0ff",
|
||||||
|
width = 2,
|
||||||
|
lineHeight = 1.5
|
||||||
|
), filter = "feature.props.kind === 'ocean'"),
|
||||||
|
|
||||||
|
# Bay/gulf labels
|
||||||
|
pmLabelRule("water", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 500 14px sans-serif",
|
||||||
|
fill = "#1e4070",
|
||||||
|
stroke = "#e0f0ff",
|
||||||
|
width = 2,
|
||||||
|
lineHeight = 1.5
|
||||||
|
), filter = "feature.props.kind === 'bay' || feature.props.kind === 'gulf'"),
|
||||||
|
|
||||||
|
# Lakes
|
||||||
|
pmLabelRule("water", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 11px sans-serif",
|
||||||
|
fill = "#2050a0",
|
||||||
|
stroke = "#e0f0ff",
|
||||||
|
width = 1,
|
||||||
|
lineHeight = 1.5
|
||||||
|
), filter = "feature.props.kind === 'lake' || feature.props.kind === 'water'")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zoom-Dependent Visibility
|
||||||
|
|
||||||
|
Show different features at different zoom levels:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.78, zoom = 14) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
paintRules = list(
|
||||||
|
pmPaintRule("earth", pmPolygonSymbolizer(fill = "#f8f8f8")),
|
||||||
|
pmPaintRule("water", pmPolygonSymbolizer(fill = "#d0e8f0")),
|
||||||
|
pmPaintRule("landuse", pmPolygonSymbolizer(fill = "#e0f0e0")),
|
||||||
|
|
||||||
|
# Buildings only visible at zoom 14+
|
||||||
|
pmPaintRule("buildings", pmPolygonSymbolizer(
|
||||||
|
fill = "#e0e0e0",
|
||||||
|
stroke = "#cccccc",
|
||||||
|
width = 0.5
|
||||||
|
), minzoom = 14),
|
||||||
|
|
||||||
|
# Roads
|
||||||
|
pmPaintRule("roads", pmLineSymbolizer(color = "#888888", width = 2))
|
||||||
|
),
|
||||||
|
labelRules = list(
|
||||||
|
# Neighborhoods at medium zoom
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 12px sans-serif",
|
||||||
|
fill = "#444444",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'neighbourhood'", minzoom = 13, maxzoom = 16),
|
||||||
|
|
||||||
|
# Street names at high zoom only
|
||||||
|
pmLabelRule("roads", pmLineLabelSymbolizer(
|
||||||
|
font = "500 9px sans-serif",
|
||||||
|
fill = "#666666",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), minzoom = 15)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## POI (Points of Interest) Styling
|
||||||
|
|
||||||
|
Show specific categories of points of interest:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.78, zoom = 15) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
flavor = "light",
|
||||||
|
paintRules = list(
|
||||||
|
# Restaurants
|
||||||
|
pmPaintRule("pois", pmCircleSymbolizer(
|
||||||
|
radius = 5,
|
||||||
|
fill = "#ef4444",
|
||||||
|
stroke = "white",
|
||||||
|
width = 1
|
||||||
|
), filter = "feature.props.kind === 'restaurant'"),
|
||||||
|
|
||||||
|
# Cafes
|
||||||
|
pmPaintRule("pois", pmCircleSymbolizer(
|
||||||
|
radius = 5,
|
||||||
|
fill = "#8b5cf6",
|
||||||
|
stroke = "white",
|
||||||
|
width = 1
|
||||||
|
), filter = "feature.props.kind === 'cafe'"),
|
||||||
|
|
||||||
|
# Parks
|
||||||
|
pmPaintRule("pois", pmCircleSymbolizer(
|
||||||
|
radius = 6,
|
||||||
|
fill = "#22c55e",
|
||||||
|
stroke = "white",
|
||||||
|
width = 1
|
||||||
|
), filter = "feature.props.kind === 'park'")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Combining Multiple Filters
|
||||||
|
|
||||||
|
Use logical operators for complex filtering:
|
||||||
|
|
||||||
|
```{r}
|
||||||
|
leaflet() %>%
|
||||||
|
setView(lng = -122.4, lat = 37.78, zoom = 12) %>%
|
||||||
|
addProtomaps(
|
||||||
|
url = protomaps_url(),
|
||||||
|
colors = pmColors(earth = "#f5f5f5", water = "#ddeeff"),
|
||||||
|
labelRules = list(
|
||||||
|
# Large cities in California (using bounding box approximation)
|
||||||
|
pmLabelRule("places", pmCenteredTextSymbolizer(
|
||||||
|
font = "600 14px sans-serif",
|
||||||
|
fill = "#1a1a1a",
|
||||||
|
stroke = "white",
|
||||||
|
width = 2
|
||||||
|
), filter = "feature.props.kind === 'locality' && feature.props.min_zoom <= 6"),
|
||||||
|
|
||||||
|
# Exclude small water features
|
||||||
|
pmLabelRule("water", pmCenteredTextSymbolizer(
|
||||||
|
font = "italic 11px sans-serif",
|
||||||
|
fill = "#3366aa",
|
||||||
|
stroke = "#ddeeff",
|
||||||
|
width = 1,
|
||||||
|
lineHeight = 1.5
|
||||||
|
), filter = "feature.props.kind !== 'stream' && feature.props.kind !== 'river'")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Filter Expression Reference
|
||||||
|
|
||||||
|
Filters are JavaScript expressions with access to `zoom` and `feature`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Equality
|
||||||
|
feature.props.kind === 'highway'
|
||||||
|
|
||||||
|
// Inequality
|
||||||
|
feature.props.min_zoom <= 5
|
||||||
|
|
||||||
|
// Logical AND
|
||||||
|
feature.props.kind === 'locality' && feature.props.min_zoom <= 4
|
||||||
|
|
||||||
|
// Logical OR
|
||||||
|
feature.props.kind === 'lake' || feature.props.kind === 'reservoir'
|
||||||
|
|
||||||
|
// NOT
|
||||||
|
feature.props.kind !== 'path'
|
||||||
|
|
||||||
|
// Zoom-based (though minzoom/maxzoom params are preferred)
|
||||||
|
zoom >= 12 && feature.props.kind === 'minor_road'
|
||||||
|
|
||||||
|
// Check if property exists
|
||||||
|
feature.props.name !== undefined
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
1. **Use minzoom/maxzoom params** instead of zoom filters when possible - they're more efficient
|
||||||
|
|
||||||
|
2. **Order matters**: Rules are applied in order; later rules can override earlier ones
|
||||||
|
|
||||||
|
3. **Test with the built-in flavors first** to understand which features appear at which zooms
|
||||||
|
|
||||||
|
4. **Check the console**: Invalid filter expressions log errors to the browser console
|
||||||
Loading…
Add table
Add a link
Reference in a new issue