diff --git a/DESCRIPTION b/DESCRIPTION index 31a58752..4aa34c4a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -33,4 +33,4 @@ Suggests: curl URL: https://trafficonese.github.io/leaflet.extras2/, https://github.com/trafficonese/leaflet.extras2 BugReports: https://github.com/trafficonese/leaflet.extras2/issues -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 diff --git a/NAMESPACE b/NAMESPACE index 88194ff4..697d4400 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -15,6 +15,7 @@ export(addHistory) export(addItemContextmenu) export(addLabelgun) export(addLatLngMoving) +export(addLayerGroupCollision) export(addLeafletsync) export(addLeafletsyncDependency) export(addMapkeyMarkers) diff --git a/NEWS.md b/NEWS.md index 3320c1f8..463fe55e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # leaflet.extras2 (development version) +* Included [LayerGroup.Collision](https://github.com/MazeMap/Leaflet.LayerGroup.Collision) plugin * Included [OSM Buildings](https://osmbuildings.org/documentation/leaflet/) plugin * New Function `addDivicon` adds `DivIcon` markers to Leaflet maps with support for custom HTML and CSS classes. See the example in `./inst/examples/divicons_html_app.R` * Added `addClusterCharts` to enable **pie** and **bar** charts in Marker clusters using `Leaflet.markercluster`, `d3` and `L.DivIcon`, with support for customizable category styling and various aggregation methods like **sum, min, max, mean**, and **median**. diff --git a/R/divicon.R b/R/divicon.R index 0f1daa3e..d785ef68 100644 --- a/R/divicon.R +++ b/R/divicon.R @@ -17,13 +17,11 @@ diviconDependency <- function() { #' for latitude and longitude coordinates. It allows for the application of custom HTML #' content and CSS classes to each marker, providing high flexibility in marker design. #' -#' @param map The Leaflet map object to which the DivIcon markers will be added. #' @inheritParams leaflet::addAwesomeMarkers -#' @param className A single CSS class or a vector of CSS classes to apply to the DivIcon markers. -#' @param html A single HTML string or a vector of HTML strings to display within the DivIcon markers. +#' @param className A single CSS class or a vector of CSS classes. +#' @param html A single HTML string or a vector of HTML strings. #' @param divOptions A list of extra options for Leaflet DivIcon. -#' @param options A list of extra options for the markers. -#' See \code{\link[leaflet]{markerOptions}} for more details. +#' #' @family DivIcon Functions #' @return The modified Leaflet map object. #' @export diff --git a/R/layergroupcollision.R b/R/layergroupcollision.R new file mode 100644 index 00000000..7ae1e919 --- /dev/null +++ b/R/layergroupcollision.R @@ -0,0 +1,87 @@ +layergroupCollisionDependency <- function() { + list( + htmltools::htmlDependency( + "lfx-layergroupcollision", + version = "1.0.0", + src = system.file("htmlwidgets/lfx-layergroupcollision", + package = "leaflet.extras2" + ), + script = c( + "rbush.min.js", + "Leaflet.LayerGroup.Collision.js", + "layergroup-binding.js" + ), + all_files = TRUE + ) + ) +} + +#' Add LayerGroup Collision Plugin to Leaflet Map +#' +#' @description Integrates the LayerGroup Collision plugin into a Leaflet map, +#' which hides overlapping markers and only displays the first added marker in a +#' collision group. Markers must be static; dynamic changes, dragging, and +#' deletions are not supported. + +#' The function transforms spatial data into GeoJSON format and uses `L.DivIcon`, +#' allowing you to pass HTML content and CSS classes to style the markers. +#' +#' @param group the name of the group. It needs to be single string. +#' @param margin defines the margin between markers, in pixels +#' @return A leaflet map object with the LayerGroup Collision plugin added. +#' @export +#' +#' @inheritParams addDivicon +#' @references \url{https://github.com/MazeMap/Leaflet.LayerGroup.Collision} +#' +#' @name LayerroupCollision +#' @examples +#' library(leaflet) +#' library(sf) +#' library(leaflet.extras2) +#' +#' df <- sf::st_as_sf(atlStorms2005) +#' df <- suppressWarnings(st_cast(df, "POINT")) +#' df <- df[sample(1:nrow(df), 150, replace = FALSE), ] +#' df$classes <- sample(x = 1:5, nrow(df), replace = TRUE) +#' +#' leaflet() %>% +#' addProviderTiles("CartoDB.Positron") %>% +#' leaflet::addLayersControl(overlayGroups = c("Labels")) %>% +#' addLayerGroupCollision( +#' data = df, +#' html = ~ paste0( +#' '
', +#' '
', Name, "
", +#' '
MaxWind: ', MaxWind, "
", +#' "
" +#' ), +#' className = ~ paste0("my-label my-label-", classes), +#' group = "Labels" +#' ) +addLayerGroupCollision <- function( + map, group = NULL, + className = NULL, html = NULL, + margin = 5, data = getMapData(map)) { + map$dependencies <- c(map$dependencies, layergroupCollisionDependency()) + + ## Make Geojson and Assign Class & HTML columns ########### + if (!inherits(data, "sf")) { + data <- sf::st_as_sf(data) + } + data$className__ <- evalFormula(className, data) + data$html__ <- evalFormula(html, data) + geojson <- yyjsonr::write_geojson_str(data) + class(geojson) <- c("geojson", "json") + + ## Derive Points and Invoke Method ################## + pts <- derivePoints( + data, NULL, NULL, TRUE, TRUE, + "addLayerGroupCollision" + ) + invokeMethod( + map, NULL, "addLayerGroupCollision", + geojson, group, margin + ) %>% + expandLimits(pts$lat, pts$lng) +} diff --git a/R/tangram.R b/R/tangram.R index 5dfcb57c..48c75260 100644 --- a/R/tangram.R +++ b/R/tangram.R @@ -58,7 +58,7 @@ tangram_deps <- function() { addTangram <- function(map, scene = NULL, layerId = NULL, group = NULL, options = NULL) { if ((is.null(scene) || !is.character(scene) || - (!gsub(".*\\.", "", scene) %in% c("yaml", "zip")))) { + (!gsub(".*\\.", "", scene) %in% c("yaml", "zip")))) { stop( "The scene must point to a valid .yaml or .zip file.\n", "See the documentation for further information." diff --git a/R/timeslider.R b/R/timeslider.R index f68b86ea..9d6162b7 100644 --- a/R/timeslider.R +++ b/R/timeslider.R @@ -3,7 +3,8 @@ timesliderDependencies <- function() { htmlDependency( "lfx-timeslider", "1.0.0", src = system.file("htmlwidgets/lfx-timeslider", - package = "leaflet.extras2"), + package = "leaflet.extras2" + ), stylesheet = "jquery-ui.css", script = c( "jquery-ui.min.js", @@ -109,8 +110,10 @@ addTimeslider <- function(map, data, radius = 10, ## Add Deps and invoke Leaflet map$dependencies <- c(map$dependencies, timesliderDependencies()) - invokeMethod(map, NULL, "addTimeslider", data, options, - popupOptions, labelOptions) %>% + invokeMethod( + map, NULL, "addTimeslider", data, options, + popupOptions, labelOptions + ) %>% expandLimits(bbox[c(2, 4)], bbox[c(1, 3)]) } diff --git a/R/velocity.R b/R/velocity.R index e2cce386..f8f1cb17 100644 --- a/R/velocity.R +++ b/R/velocity.R @@ -3,7 +3,8 @@ velocityDependencies <- function() { htmlDependency( "lfx-velocity", "1.0.0", src = system.file("htmlwidgets/lfx-velocity", - package = "leaflet.extras2"), + package = "leaflet.extras2" + ), script = c( "leaflet-velocity.js", "leaflet-velocity-bindings.js" diff --git a/README.md b/README.md index 80044056..561bad76 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ If you need a plugin that is not already implemented create an [issue](https://g - [Hexbin-D3](https://github.com/bluehalo/leaflet-d3#hexbins-api) - [History](https://github.com/cscott530/leaflet-history) - [Labelgun](https://github.com/Geovation/labelgun) +- [LayerGroup.Collision](https://github.com/MazeMap/Leaflet.LayerGroup.Collision) - [Leaflet.Sync](https://github.com/jieter/Leaflet.Sync) - [Mapkey Icons](https://github.com/mapshakers/leaflet-mapkey-icon) - [Moving Markers](https://github.com/ewoken/Leaflet.MovingMarker) diff --git a/_pkgdown.yml b/_pkgdown.yml index 2c74d53d..10fe31f5 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -59,6 +59,9 @@ reference: - title: Labelgun contents: - matches("Labelgun") + - title: LayerGroup.Collision + contents: + - matches("LayerGroupCollision") - title: Mapkey Icons contents: - matches("Mapkey") diff --git a/data-raw/data-raw.R b/data-raw/data-raw.R index 490eab67..9469b67c 100644 --- a/data-raw/data-raw.R +++ b/data-raw/data-raw.R @@ -1,6 +1,8 @@ gibs_layerslink <- paste0( system.file("htmlwidgets/lfx-gibs", - package = "leaflet.extras2"), "/gibs_layers_meta.json") + package = "leaflet.extras2" + ), "/gibs_layers_meta.json" +) gibs_layers <- jsonify::from_json(json = gibs_layerslink, simplify = TRUE) gibs_layers <- data.frame(do.call(rbind, gibs_layers), stringsAsFactors = FALSE) gibs_layers$title <- as.character(gibs_layers$title) diff --git a/inst/examples/layergroupcollision_app.R b/inst/examples/layergroupcollision_app.R new file mode 100644 index 00000000..2f6d6eeb --- /dev/null +++ b/inst/examples/layergroupcollision_app.R @@ -0,0 +1,53 @@ +library(shiny) +library(leaflet) +library(sf) +library(leaflet.extras2) +options("shiny.autoreload" = TRUE) + +df <- sf::st_as_sf(atlStorms2005) +df <- suppressWarnings(st_cast(df, "POINT")) +df <- df[sample(1:nrow(df), 150, replace = FALSE),] +df$classes = sample(x = 1:5, nrow(df), replace = TRUE) + +## Ordering is important +df <- df[order(df$classes, decreasing = FALSE),] + +ui <- fluidPage( + ## CSS-style ############ + tags$head(tags$style(" + .my-label { + background: white; + border: 1px solid #888; + position: relative; + display: inline-block; + white-space: nowrap; + } + .my-label-1 { font-size: 28px; background-color: red; top: -26px; } + .my-label-2 { font-size: 24px; background-color: orange; top: -25px; } + .my-label-3 { font-size: 22px; background-color: yellow; top: -24px; } + .my-label-4 { font-size: 16px; background-color: green; top: -23px; } + .my-label-5 { font-size: 15px; background-color: lightgreen; top: -22px; } + ")), + leafletOutput("map", height = 800) +) + +## Server ########### +server <- function(input, output, session) { + output$map <- renderLeaflet({ + leaflet() %>% + addProviderTiles("CartoDB.Positron") %>% + leaflet::addLayersControl(overlayGroups = c("Labels")) %>% + addLayerGroupCollision(data = df + , html = ~paste0( + '
', + '
', Name, '
', + '
MaxWind: ', MaxWind, '
', + '
' + ) + , className = ~paste0("my-label my-label-", classes) + , group = "Labels" + ) + + }) +} +shinyApp(ui, server) diff --git a/inst/htmlwidgets/lfx-layergroupcollision/Leaflet.LayerGroup.Collision.js b/inst/htmlwidgets/lfx-layergroupcollision/Leaflet.LayerGroup.Collision.js new file mode 100644 index 00000000..5dbb7d84 --- /dev/null +++ b/inst/htmlwidgets/lfx-layergroupcollision/Leaflet.LayerGroup.Collision.js @@ -0,0 +1,244 @@ + + +var isMSIE8 = !('getComputedStyle' in window && typeof window.getComputedStyle === 'function') + +function extensions(parentClass) { return { + + initialize: function (arg1, arg2) { + var options; + if (parentClass === L.GeoJSON) { + parentClass.prototype.initialize.call(this, arg1, arg2); + options = arg2; + } else { + parentClass.prototype.initialize.call(this, arg1); + options = arg1; + } + this._originalLayers = []; + this._visibleLayers = []; + this._staticLayers = []; + this._rbush = []; + this._cachedRelativeBoxes = []; + this._margin = options.margin || 0; + this._rbush = null; + }, + + addLayer: function(layer) { + if ( !('options' in layer) || !('icon' in layer.options)) { + this._staticLayers.push(layer); + parentClass.prototype.addLayer.call(this, layer); + return; + } + + this._originalLayers.push(layer); + if (this._map) { + this._maybeAddLayerToRBush( layer ); + } + }, + + removeLayer: function(layer) { + this._rbush.remove(this._cachedRelativeBoxes[layer._leaflet_id]); + delete this._cachedRelativeBoxes[layer._leaflet_id]; + parentClass.prototype.removeLayer.call(this,layer); + var i; + + i = this._originalLayers.indexOf(layer); + if (i !== -1) { this._originalLayers.splice(i,1); } + + i = this._visibleLayers.indexOf(layer); + if (i !== -1) { this._visibleLayers.splice(i,1); } + + i = this._staticLayers.indexOf(layer); + if (i !== -1) { this._staticLayers.splice(i,1); } + }, + + clearLayers: function() { + this._rbush = rbush(); + this._originalLayers = []; + this._visibleLayers = []; + this._staticLayers = []; + this._cachedRelativeBoxes = []; + parentClass.prototype.clearLayers.call(this); + }, + + onAdd: function (map) { + this._map = map; + + for (var i in this._staticLayers) { + map.addLayer(this._staticLayers[i]); + } + + this._onZoomEnd(); + map.on('zoomend', this._onZoomEnd, this); + }, + + onRemove: function(map) { + for (var i in this._staticLayers) { + map.removeLayer(this._staticLayers[i]); + } + map.off('zoomend', this._onZoomEnd, this); + parentClass.prototype.onRemove.call(this, map); + }, + + _maybeAddLayerToRBush: function(layer) { + + var z = this._map.getZoom(); + var bush = this._rbush; + + var boxes = this._cachedRelativeBoxes[layer._leaflet_id]; + var visible = false; + if (!boxes) { + // Add the layer to the map so it's instantiated on the DOM, + // in order to fetch its position and size. + parentClass.prototype.addLayer.call(this, layer); + var visible = true; +// var htmlElement = layer._icon; + var box = this._getIconBox(layer._icon); + boxes = this._getRelativeBoxes(layer._icon.children, box); + boxes.push(box); + this._cachedRelativeBoxes[layer._leaflet_id] = boxes; + } + + boxes = this._positionBoxes(this._map.latLngToLayerPoint(layer.getLatLng()),boxes); + + var collision = false; + for (var i=0; i 0; + } + + if (!collision) { + if (!visible) { + parentClass.prototype.addLayer.call(this, layer); + } + this._visibleLayers.push(layer); + bush.load(boxes); + } else { + parentClass.prototype.removeLayer.call(this, layer); + } + }, + + + // Returns a plain array with the relative dimensions of a L.Icon, based + // on the computed values from iconSize and iconAnchor. + _getIconBox: function (el) { + + if (isMSIE8) { + // Fallback for MSIE8, will most probably fail on edge cases + return [ 0, 0, el.offsetWidth, el.offsetHeight]; + } + + var styles = window.getComputedStyle(el); + + // getComputedStyle() should return values already in pixels, so using parseInt() + // is not as much as a hack as it seems to be. + + return [ + parseInt(styles.marginLeft), + parseInt(styles.marginTop), + parseInt(styles.marginLeft) + parseInt(styles.width), + parseInt(styles.marginTop) + parseInt(styles.height) + ]; + }, + + + // Much like _getIconBox, but works for positioned HTML elements, based on offsetWidth/offsetHeight. + _getRelativeBoxes: function(els,baseBox) { + var boxes = []; + for (var i=0; i" + + feat.properties["html__"] + + "" + }) + , interactive: false // Post-0.7.3 + , clickable: false // 0.7.3 + }); + + collisionLayer.addLayer(marker); + } + this.layerManager.addLayer(collisionLayer, "collison", null, group); + +}; diff --git a/inst/htmlwidgets/lfx-layergroupcollision/rbush.min.js b/inst/htmlwidgets/lfx-layergroupcollision/rbush.min.js new file mode 100644 index 00000000..5df616d0 --- /dev/null +++ b/inst/htmlwidgets/lfx-layergroupcollision/rbush.min.js @@ -0,0 +1,617 @@ +/* + (c) 2015, Vladimir Agafonkin + RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles. + https://github.com/mourner/rbush +*/ + +(function () { +'use strict'; + +function rbush(maxEntries, format) { + if (!(this instanceof rbush)) return new rbush(maxEntries, format); + + // max entries in a node is 9 by default; min node fill is 40% for best performance + this._maxEntries = Math.max(4, maxEntries || 9); + this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4)); + + if (format) { + this._initFormat(format); + } + + this.clear(); +} + +rbush.prototype = { + + all: function () { + return this._all(this.data, []); + }, + + search: function (bbox) { + + var node = this.data, + result = [], + toBBox = this.toBBox; + + if (!intersects(bbox, node.bbox)) return result; + + var nodesToSearch = [], + i, len, child, childBBox; + + while (node) { + for (i = 0, len = node.children.length; i < len; i++) { + + child = node.children[i]; + childBBox = node.leaf ? toBBox(child) : child.bbox; + + if (intersects(bbox, childBBox)) { + if (node.leaf) result.push(child); + else if (contains(bbox, childBBox)) this._all(child, result); + else nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } + + return result; + }, + + collides: function (bbox) { + + var node = this.data, + toBBox = this.toBBox; + + if (!intersects(bbox, node.bbox)) return false; + + var nodesToSearch = [], + i, len, child, childBBox; + + while (node) { + for (i = 0, len = node.children.length; i < len; i++) { + + child = node.children[i]; + childBBox = node.leaf ? toBBox(child) : child.bbox; + + if (intersects(bbox, childBBox)) { + if (node.leaf || contains(bbox, childBBox)) return true; + nodesToSearch.push(child); + } + } + node = nodesToSearch.pop(); + } + + return false; + }, + + load: function (data) { + if (!(data && data.length)) return this; + + if (data.length < this._minEntries) { + for (var i = 0, len = data.length; i < len; i++) { + this.insert(data[i]); + } + return this; + } + + // recursively build the tree with the given data from stratch using OMT algorithm + var node = this._build(data.slice(), 0, data.length - 1, 0); + + if (!this.data.children.length) { + // save as is if tree is empty + this.data = node; + + } else if (this.data.height === node.height) { + // split root if trees have the same height + this._splitRoot(this.data, node); + + } else { + if (this.data.height < node.height) { + // swap trees if inserted one is bigger + var tmpNode = this.data; + this.data = node; + node = tmpNode; + } + + // insert the small tree into the large tree at appropriate level + this._insert(node, this.data.height - node.height - 1, true); + } + + return this; + }, + + insert: function (item) { + if (item) this._insert(item, this.data.height - 1); + return this; + }, + + clear: function () { + this.data = { + children: [], + height: 1, + bbox: empty(), + leaf: true + }; + return this; + }, + + remove: function (item) { + if (!item) return this; + + var node = this.data, + bbox = this.toBBox(item), + path = [], + indexes = [], + i, parent, index, goingUp; + + // depth-first iterative tree traversal + while (node || path.length) { + + if (!node) { // go up + node = path.pop(); + parent = path[path.length - 1]; + i = indexes.pop(); + goingUp = true; + } + + if (node.leaf) { // check current node + index = node.children.indexOf(item); + + if (index !== -1) { + // item found, remove the item and condense tree upwards + node.children.splice(index, 1); + path.push(node); + this._condense(path); + return this; + } + } + + if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down + path.push(node); + indexes.push(i); + i = 0; + parent = node; + node = node.children[0]; + + } else if (parent) { // go right + i++; + node = parent.children[i]; + goingUp = false; + + } else node = null; // nothing found + } + + return this; + }, + + toBBox: function (item) { return item; }, + + compareMinX: function (a, b) { return a[0] - b[0]; }, + compareMinY: function (a, b) { return a[1] - b[1]; }, + + toJSON: function () { return this.data; }, + + fromJSON: function (data) { + this.data = data; + return this; + }, + + _all: function (node, result) { + var nodesToSearch = []; + while (node) { + if (node.leaf) result.push.apply(result, node.children); + else nodesToSearch.push.apply(nodesToSearch, node.children); + + node = nodesToSearch.pop(); + } + return result; + }, + + _build: function (items, left, right, height) { + + var N = right - left + 1, + M = this._maxEntries, + node; + + if (N <= M) { + // reached leaf level; return leaf + node = { + children: items.slice(left, right + 1), + height: 1, + bbox: null, + leaf: true + }; + calcBBox(node, this.toBBox); + return node; + } + + if (!height) { + // target height of the bulk-loaded tree + height = Math.ceil(Math.log(N) / Math.log(M)); + + // target number of root entries to maximize storage utilization + M = Math.ceil(N / Math.pow(M, height - 1)); + } + + node = { + children: [], + height: height, + bbox: null, + leaf: false + }; + + // split the items into M mostly square tiles + + var N2 = Math.ceil(N / M), + N1 = N2 * Math.ceil(Math.sqrt(M)), + i, j, right2, right3; + + multiSelect(items, left, right, N1, this.compareMinX); + + for (i = left; i <= right; i += N1) { + + right2 = Math.min(i + N1 - 1, right); + + multiSelect(items, i, right2, N2, this.compareMinY); + + for (j = i; j <= right2; j += N2) { + + right3 = Math.min(j + N2 - 1, right2); + + // pack each entry recursively + node.children.push(this._build(items, j, right3, height - 1)); + } + } + + calcBBox(node, this.toBBox); + + return node; + }, + + _chooseSubtree: function (bbox, node, level, path) { + + var i, len, child, targetNode, area, enlargement, minArea, minEnlargement; + + while (true) { + path.push(node); + + if (node.leaf || path.length - 1 === level) break; + + minArea = minEnlargement = Infinity; + + for (i = 0, len = node.children.length; i < len; i++) { + child = node.children[i]; + area = bboxArea(child.bbox); + enlargement = enlargedArea(bbox, child.bbox) - area; + + // choose entry with the least area enlargement + if (enlargement < minEnlargement) { + minEnlargement = enlargement; + minArea = area < minArea ? area : minArea; + targetNode = child; + + } else if (enlargement === minEnlargement) { + // otherwise choose one with the smallest area + if (area < minArea) { + minArea = area; + targetNode = child; + } + } + } + + node = targetNode || node.children[0]; + } + + return node; + }, + + _insert: function (item, level, isNode) { + + var toBBox = this.toBBox, + bbox = isNode ? item.bbox : toBBox(item), + insertPath = []; + + // find the best node for accommodating the item, saving all nodes along the path too + var node = this._chooseSubtree(bbox, this.data, level, insertPath); + + // put the item into the node + node.children.push(item); + extend(node.bbox, bbox); + + // split on node overflow; propagate upwards if necessary + while (level >= 0) { + if (insertPath[level].children.length > this._maxEntries) { + this._split(insertPath, level); + level--; + } else break; + } + + // adjust bboxes along the insertion path + this._adjustParentBBoxes(bbox, insertPath, level); + }, + + // split overflowed node into two + _split: function (insertPath, level) { + + var node = insertPath[level], + M = node.children.length, + m = this._minEntries; + + this._chooseSplitAxis(node, m, M); + + var splitIndex = this._chooseSplitIndex(node, m, M); + + var newNode = { + children: node.children.splice(splitIndex, node.children.length - splitIndex), + height: node.height, + bbox: null, + leaf: false + }; + + if (node.leaf) newNode.leaf = true; + + calcBBox(node, this.toBBox); + calcBBox(newNode, this.toBBox); + + if (level) insertPath[level - 1].children.push(newNode); + else this._splitRoot(node, newNode); + }, + + _splitRoot: function (node, newNode) { + // split root node + this.data = { + children: [node, newNode], + height: node.height + 1, + bbox: null, + leaf: false + }; + calcBBox(this.data, this.toBBox); + }, + + _chooseSplitIndex: function (node, m, M) { + + var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index; + + minOverlap = minArea = Infinity; + + for (i = m; i <= M - m; i++) { + bbox1 = distBBox(node, 0, i, this.toBBox); + bbox2 = distBBox(node, i, M, this.toBBox); + + overlap = intersectionArea(bbox1, bbox2); + area = bboxArea(bbox1) + bboxArea(bbox2); + + // choose distribution with minimum overlap + if (overlap < minOverlap) { + minOverlap = overlap; + index = i; + + minArea = area < minArea ? area : minArea; + + } else if (overlap === minOverlap) { + // otherwise choose distribution with minimum area + if (area < minArea) { + minArea = area; + index = i; + } + } + } + + return index; + }, + + // sorts node children by the best axis for split + _chooseSplitAxis: function (node, m, M) { + + var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX, + compareMinY = node.leaf ? this.compareMinY : compareNodeMinY, + xMargin = this._allDistMargin(node, m, M, compareMinX), + yMargin = this._allDistMargin(node, m, M, compareMinY); + + // if total distributions margin value is minimal for x, sort by minX, + // otherwise it's already sorted by minY + if (xMargin < yMargin) node.children.sort(compareMinX); + }, + + // total margin of all possible split distributions where each node is at least m full + _allDistMargin: function (node, m, M, compare) { + + node.children.sort(compare); + + var toBBox = this.toBBox, + leftBBox = distBBox(node, 0, m, toBBox), + rightBBox = distBBox(node, M - m, M, toBBox), + margin = bboxMargin(leftBBox) + bboxMargin(rightBBox), + i, child; + + for (i = m; i < M - m; i++) { + child = node.children[i]; + extend(leftBBox, node.leaf ? toBBox(child) : child.bbox); + margin += bboxMargin(leftBBox); + } + + for (i = M - m - 1; i >= m; i--) { + child = node.children[i]; + extend(rightBBox, node.leaf ? toBBox(child) : child.bbox); + margin += bboxMargin(rightBBox); + } + + return margin; + }, + + _adjustParentBBoxes: function (bbox, path, level) { + // adjust bboxes along the given tree path + for (var i = level; i >= 0; i--) { + extend(path[i].bbox, bbox); + } + }, + + _condense: function (path) { + // go through the path, removing empty nodes and updating bboxes + for (var i = path.length - 1, siblings; i >= 0; i--) { + if (path[i].children.length === 0) { + if (i > 0) { + siblings = path[i - 1].children; + siblings.splice(siblings.indexOf(path[i]), 1); + + } else this.clear(); + + } else calcBBox(path[i], this.toBBox); + } + }, + + _initFormat: function (format) { + // data format (minX, minY, maxX, maxY accessors) + + // uses eval-type function compilation instead of just accepting a toBBox function + // because the algorithms are very sensitive to sorting functions performance, + // so they should be dead simple and without inner calls + + var compareArr = ['return a', ' - b', ';']; + + this.compareMinX = new Function('a', 'b', compareArr.join(format[0])); + this.compareMinY = new Function('a', 'b', compareArr.join(format[1])); + + this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];'); + } +}; + + +// calculate node's bbox from bboxes of its children +function calcBBox(node, toBBox) { + node.bbox = distBBox(node, 0, node.children.length, toBBox); +} + +// min bounding rectangle of node children from k to p-1 +function distBBox(node, k, p, toBBox) { + var bbox = empty(); + + for (var i = k, child; i < p; i++) { + child = node.children[i]; + extend(bbox, node.leaf ? toBBox(child) : child.bbox); + } + + return bbox; +} + +function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; } + +function extend(a, b) { + a[0] = Math.min(a[0], b[0]); + a[1] = Math.min(a[1], b[1]); + a[2] = Math.max(a[2], b[2]); + a[3] = Math.max(a[3], b[3]); + return a; +} + +function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; } +function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; } + +function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); } +function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); } + +function enlargedArea(a, b) { + return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) * + (Math.max(b[3], a[3]) - Math.min(b[1], a[1])); +} + +function intersectionArea(a, b) { + var minX = Math.max(a[0], b[0]), + minY = Math.max(a[1], b[1]), + maxX = Math.min(a[2], b[2]), + maxY = Math.min(a[3], b[3]); + + return Math.max(0, maxX - minX) * + Math.max(0, maxY - minY); +} + +function contains(a, b) { + return a[0] <= b[0] && + a[1] <= b[1] && + b[2] <= a[2] && + b[3] <= a[3]; +} + +function intersects(a, b) { + return b[0] <= a[2] && + b[1] <= a[3] && + b[2] >= a[0] && + b[3] >= a[1]; +} + +// sort an array so that items come in groups of n unsorted items, with groups sorted between each other; +// combines selection algorithm with binary divide & conquer approach + +function multiSelect(arr, left, right, n, compare) { + var stack = [left, right], + mid; + + while (stack.length) { + right = stack.pop(); + left = stack.pop(); + + if (right - left <= n) continue; + + mid = left + Math.ceil((right - left) / n / 2) * n; + select(arr, left, right, mid, compare); + + stack.push(left, mid, mid, right); + } +} + +// Floyd-Rivest selection algorithm: +// sort an array between left and right (inclusive) so that the smallest k elements come first (unordered) +function select(arr, left, right, k, compare) { + var n, i, z, s, sd, newLeft, newRight, t, j; + + while (right > left) { + if (right - left > 600) { + n = right - left + 1; + i = k - left + 1; + z = Math.log(n); + s = 0.5 * Math.exp(2 * z / 3); + sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1); + newLeft = Math.max(left, Math.floor(k - i * s / n + sd)); + newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd)); + select(arr, newLeft, newRight, k, compare); + } + + t = arr[k]; + i = left; + j = right; + + swap(arr, left, k); + if (compare(arr[right], t) > 0) swap(arr, left, right); + + while (i < j) { + swap(arr, i, j); + i++; + j--; + while (compare(arr[i], t) < 0) i++; + while (compare(arr[j], t) > 0) j--; + } + + if (compare(arr[left], t) === 0) swap(arr, left, j); + else { + j++; + swap(arr, j, right); + } + + if (j <= k) left = j + 1; + if (k <= j) right = j - 1; + } +} + +function swap(arr, i, j) { + var tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} + + +// export as AMD/CommonJS module or global variable +if (typeof define === 'function' && define.amd) define('rbush', function () { return rbush; }); +else if (typeof module !== 'undefined') module.exports = rbush; +else if (typeof self !== 'undefined') self.rbush = rbush; +else window.rbush = rbush; + +})(); diff --git a/man/LayerroupCollision.Rd b/man/LayerroupCollision.Rd new file mode 100644 index 00000000..b0b0a4fe --- /dev/null +++ b/man/LayerroupCollision.Rd @@ -0,0 +1,69 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/layergroupcollision.R +\name{LayerroupCollision} +\alias{LayerroupCollision} +\alias{addLayerGroupCollision} +\title{Add LayerGroup Collision Plugin to Leaflet Map} +\usage{ +addLayerGroupCollision( + map, + group = NULL, + className = NULL, + html = NULL, + margin = 5, + data = getMapData(map) +) +} +\arguments{ +\item{map}{the map to add awesome Markers to.} + +\item{group}{the name of the group. It needs to be single string.} + +\item{className}{A single CSS class or a vector of CSS classes.} + +\item{html}{A single HTML string or a vector of HTML strings.} + +\item{margin}{defines the margin between markers, in pixels} + +\item{data}{the data object from which the argument values are derived; by +default, it is the \code{data} object provided to \code{leaflet()} +initially, but can be overridden} +} +\value{ +A leaflet map object with the LayerGroup Collision plugin added. +} +\description{ +Integrates the LayerGroup Collision plugin into a Leaflet map, +which hides overlapping markers and only displays the first added marker in a +collision group. Markers must be static; dynamic changes, dragging, and +deletions are not supported. +The function transforms spatial data into GeoJSON format and uses `L.DivIcon`, +allowing you to pass HTML content and CSS classes to style the markers. +} +\examples{ +library(leaflet) +library(sf) +library(leaflet.extras2) + +df <- sf::st_as_sf(atlStorms2005) +df <- suppressWarnings(st_cast(df, "POINT")) +df <- df[sample(1:nrow(df), 150, replace = FALSE),] +df$classes = sample(x = 1:5, nrow(df), replace = TRUE) + +leaflet() \%>\% + addProviderTiles("CartoDB.Positron") \%>\% + leaflet::addLayersControl(overlayGroups = c("Labels")) \%>\% + addLayerGroupCollision(data = df + , html = ~paste0( + '
', + '
', Name, '
', + '
MaxWind: ', MaxWind, '
', + '
' + ) + , className = ~paste0("my-label my-label-", classes) + , group = "Labels" + ) +} +\references{ +\url{https://github.com/MazeMap/Leaflet.LayerGroup.Collision} +} diff --git a/man/addBuildings.Rd b/man/addBuildings.Rd index 9027a2cd..7aec8839 100644 --- a/man/addBuildings.Rd +++ b/man/addBuildings.Rd @@ -49,7 +49,7 @@ See the OSM Wiki: \href{https://wiki.openstreetmap.org/wiki/Simple_3D_Buildings} library(leaflet) library(leaflet.extras2) -leaflet() \%>\% +leaflet() \%>\% addProviderTiles("CartoDB") \%>\% addBuildings(group = "Buildings") \%>\% addLayersControl(overlayGroups = "Buildings") \%>\% diff --git a/man/addClusterCharts.Rd b/man/addClusterCharts.Rd index 4b15b2a6..52e151df 100644 --- a/man/addClusterCharts.Rd +++ b/man/addClusterCharts.Rd @@ -111,31 +111,38 @@ data$category <- sample(categories, size = nrow(data), replace = TRUE) leaflet() \%>\% addProviderTiles("CartoDB.Positron") \%>\% leaflet::addLayersControl(overlayGroups = "clustermarkers") \%>\% - addClusterCharts(data = data - , categoryField = "category" - , categoryMap = data.frame(labels = categories, - colors = c("#F88", "#FA0", "#FF3", "#BFB"), - strokes = "gray") - , group = "clustermarkers" - , popupFields = c("brewery", "address", "zipcode", "category") - , popupLabels = c("Brauerei", "Adresse", "PLZ", "Art") - , label = "brewery" + addClusterCharts( + data = data, + categoryField = "category", + categoryMap = data.frame( + labels = categories, + colors = c("#F88", "#FA0", "#FF3", "#BFB"), + strokes = "gray" + ), + group = "clustermarkers", + popupFields = c("brewery", "address", "zipcode", "category"), + popupLabels = c("Brauerei", "Adresse", "PLZ", "Art"), + label = "brewery" ) ## Bar Chart leaflet() \%>\% addProviderTiles("CartoDB.Positron") \%>\% leaflet::addLayersControl(overlayGroups = "clustermarkers") \%>\% - addClusterCharts(data = data - , type = "bar" - , categoryField = "category" - , categoryMap = data.frame(labels = categories, - colors = c("#F88", "#FA0", "#FF3", "#BFB"), - strokes = "gray") - , group = "clustermarkers" - , popupFields = c("brewery", "address", "zipcode", "category") - , popupLabels = c("Brauerei", "Adresse", "PLZ", "Art") - , label = "brewery") + addClusterCharts( + data = data, + type = "bar", + categoryField = "category", + categoryMap = data.frame( + labels = categories, + colors = c("#F88", "#FA0", "#FF3", "#BFB"), + strokes = "gray" + ), + group = "clustermarkers", + popupFields = c("brewery", "address", "zipcode", "category"), + popupLabels = c("Brauerei", "Adresse", "PLZ", "Art"), + label = "brewery" + ) ## Custom Pie Chart with "mean" aggregation on column "value" data <- sf::st_as_sf(breweries91) @@ -146,19 +153,22 @@ data$value <- round(runif(nrow(data), 0, 100), 0) leaflet() \%>\% addProviderTiles("CartoDB.Positron") \%>\% leaflet::addLayersControl(overlayGroups = "clustermarkers") \%>\% - addClusterCharts(data = data - , type = "custom" - , valueField = "value" - , aggregation = "mean" - , categoryField = "category" - , categoryMap = data.frame(labels = categories, - colors = c("#F88", "#FA0", "#FF3", "#BFB"), - strokes = "gray") - , options = clusterchartOptions(rmax=50, digits=0, innerRadius = 20) - , group = "clustermarkers" - , popupFields = c("brewery", "address", "zipcode", "category","value") - , popupLabels = c("Brauerei", "Adresse", "PLZ", "Art", "Value") - , label = "brewery" + addClusterCharts( + data = data, + type = "custom", + valueField = "value", + aggregation = "mean", + categoryField = "category", + categoryMap = data.frame( + labels = categories, + colors = c("#F88", "#FA0", "#FF3", "#BFB"), + strokes = "gray" + ), + options = clusterchartOptions(rmax = 50, digits = 0, innerRadius = 20), + group = "clustermarkers", + popupFields = c("brewery", "address", "zipcode", "category", "value"), + popupLabels = c("Brauerei", "Adresse", "PLZ", "Art", "Value"), + label = "brewery" ) ## For Shiny examples, please run: diff --git a/man/addContextmenu.Rd b/man/addContextmenu.Rd index cb58fb39..92df003f 100644 --- a/man/addContextmenu.Rd +++ b/man/addContextmenu.Rd @@ -49,27 +49,33 @@ If the selected contextmenu item is triggered from: \examples{ library(leaflet) leaflet(options = leafletOptions( - contextmenu = TRUE, - contextmenuWidth = 200, - contextmenuItems = - context_mapmenuItems( - context_menuItem("Zoom Out", "function(e) {this.zoomOut()}", disabled=FALSE), - "-", - context_menuItem("Zoom In", "function(e) {this.zoomIn()}")))) \%>\% + contextmenu = TRUE, + contextmenuWidth = 200, + contextmenuItems = + context_mapmenuItems( + context_menuItem("Zoom Out", "function(e) {this.zoomOut()}", disabled = FALSE), + "-", + context_menuItem("Zoom In", "function(e) {this.zoomIn()}") + ) +)) \%>\% addTiles(group = "base") \%>\% addContextmenu() \%>\% - addMarkers(data = breweries91, label = ~brewery, - layerId = ~founded, group = "marker", - options = markerOptions( - contextmenu = TRUE, - contextmenuWidth = 200, - contextmenuItems = - context_markermenuItems( - context_menuItem(text = "Show Marker Coords", - callback = "function(e) {alert(e.latlng);}", - index = 1) - ) - )) + addMarkers( + data = breweries91, label = ~brewery, + layerId = ~founded, group = "marker", + options = markerOptions( + contextmenu = TRUE, + contextmenuWidth = 200, + contextmenuItems = + context_markermenuItems( + context_menuItem( + text = "Show Marker Coords", + callback = "function(e) {alert(e.latlng);}", + index = 1 + ) + ) + ) + ) } \references{ diff --git a/man/addDivicon.Rd b/man/addDivicon.Rd index 3fe99f4f..ef22b11d 100644 --- a/man/addDivicon.Rd +++ b/man/addDivicon.Rd @@ -24,7 +24,7 @@ addDivicon( ) } \arguments{ -\item{map}{The Leaflet map object to which the DivIcon markers will be added.} +\item{map}{the map to add awesome Markers to.} \item{lng}{a numeric vector of longitudes, or a one-sided formula of the form \code{~x} where \code{x} is a variable in \code{data}; by default (if not @@ -55,12 +55,12 @@ for security reasons)} \item{labelOptions}{A Vector of \code{\link[leaflet]{labelOptions}} to provide label options for each label. Default \code{NULL}} -\item{className}{A single CSS class or a vector of CSS classes to apply to the DivIcon markers.} +\item{className}{A single CSS class or a vector of CSS classes.} -\item{html}{A single HTML string or a vector of HTML strings to display within the DivIcon markers.} +\item{html}{A single HTML string or a vector of HTML strings.} -\item{options}{A list of extra options for the markers. -See \code{\link[leaflet]{markerOptions}} for more details.} +\item{options}{a list of extra options for tile layers, popups, paths +(circles, rectangles, polygons, ...), or other map elements} \item{clusterOptions}{if not \code{NULL}, markers will be clustered using \href{https://github.com/Leaflet/Leaflet.markercluster}{Leaflet.markercluster}; @@ -92,27 +92,30 @@ library(leaflet.extras2) # Sample data df <- sf::st_as_sf(atlStorms2005) df <- suppressWarnings(st_cast(df, "POINT")) -df <- df[sample(1:nrow(df), 50, replace = FALSE),] -df$classes = sample(x = c("myclass1","myclass2","myclass3"), nrow(df), replace = TRUE) +df <- df[sample(1:nrow(df), 50, replace = FALSE), ] +df$classes <- sample(x = c("myclass1", "myclass2", "myclass3"), nrow(df), replace = TRUE) df$ID <- paste0("ID_", 1:nrow(df)) -leaflet() \%>\% +leaflet() \%>\% addTiles() \%>\% - addDivicon(data = df - , html = ~paste0( - '
', - '
', Name, '
', - '
MaxWind: ', MaxWind, '
', - '
' - ) - , label = ~Name - , layerId = ~ID - , group = "Divicons" - , popup = ~paste("ID: ", ID, "
", - "Name: ", Name, "
", - "MaxWind:", MaxWind, "
", - "MinPress:", MinPress) - , options = markerOptions(draggable = TRUE) + addDivicon( + data = df, + html = ~ paste0( + '
', + '
', Name, "
", + '
MaxWind: ', MaxWind, "
", + "
" + ), + label = ~Name, + layerId = ~ID, + group = "Divicons", + popup = ~ paste( + "ID: ", ID, "
", + "Name: ", Name, "
", + "MaxWind:", MaxWind, "
", + "MinPress:", MinPress + ), + options = markerOptions(draggable = TRUE) ) } \concept{DivIcon Functions} diff --git a/man/addEasyprint.Rd b/man/addEasyprint.Rd index ca80f693..45d60229 100644 --- a/man/addEasyprint.Rd +++ b/man/addEasyprint.Rd @@ -19,12 +19,13 @@ Add a control, which allows to print or export a map as .PNG. } \examples{ library(leaflet) -leaflet() \%>\% +leaflet() \%>\% addTiles() \%>\% addEasyprint(options = easyprintOptions( - title = 'Print map', - position = 'bottomleft', - exportOnly = TRUE)) + title = "Print map", + position = "bottomleft", + exportOnly = TRUE + )) } \references{ \url{https://github.com/rowanwins/leaflet-easyPrint} diff --git a/man/addGIBS.Rd b/man/addGIBS.Rd index ba72d9ae..2f7a6f04 100644 --- a/man/addGIBS.Rd +++ b/man/addGIBS.Rd @@ -47,12 +47,14 @@ library(leaflet.extras2) layers <- gibs_layers$title[c(35, 128, 185)] -leaflet() \%>\% +leaflet() \%>\% addTiles() \%>\% setView(9, 50, 4) \%>\% - addGIBS(layers = layers, - dates = Sys.Date() - 1, - group = layers) \%>\% + addGIBS( + layers = layers, + dates = Sys.Date() - 1, + group = layers + ) \%>\% addLayersControl(overlayGroups = layers) } \references{ diff --git a/man/addHeightgraph.Rd b/man/addHeightgraph.Rd index 866aeb3b..ec72689f 100644 --- a/man/addHeightgraph.Rd +++ b/man/addHeightgraph.Rd @@ -81,7 +81,7 @@ library(leaflet) library(leaflet.extras2) library(sf) -data <- st_cast(st_as_sf(leaflet::atlStorms2005[4,]), "LINESTRING") +data <- st_cast(st_as_sf(leaflet::atlStorms2005[4, ]), "LINESTRING") data <- st_transform(data, 4326) data <- data.frame(st_coordinates(data)) data$elev <- round(runif(nrow(data), 10, 500), 2) @@ -98,9 +98,11 @@ data$popup <- apply(data, 1, function(x) { leaflet() \%>\% addTiles(group = "base") \%>\% - addHeightgraph(color = "red", columns = c("steepness", "suitability"), - opacity = 1, data = data, group = "heightgraph", - options = heightgraphOptions(width = 400)) + addHeightgraph( + color = "red", columns = c("steepness", "suitability"), + opacity = 1, data = data, group = "heightgraph", + options = heightgraphOptions(width = 400) + ) } \references{ \url{https://github.com/GIScience/Leaflet.Heightgraph} diff --git a/man/addHexbin.Rd b/man/addHexbin.Rd index c31cc064..ac7538a3 100644 --- a/man/addHexbin.Rd +++ b/man/addHexbin.Rd @@ -63,16 +63,20 @@ library(leaflet) library(leaflet.extras2) n <- 1000 -df <- data.frame(lat = rnorm(n, 42.0285, .01), - lng = rnorm(n, -93.65, .01)) +df <- data.frame( + lat = rnorm(n, 42.0285, .01), + lng = rnorm(n, -93.65, .01) +) -leaflet() \%>\% +leaflet() \%>\% addTiles() \%>\% - addHexbin(lng = df$lng, lat = df$lat, - options = hexbinOptions( - colorRange = c("red", "yellow", "blue"), - radiusRange = c(10, 20) - )) + addHexbin( + lng = df$lng, lat = df$lat, + options = hexbinOptions( + colorRange = c("red", "yellow", "blue"), + radiusRange = c(10, 20) + ) + ) } \references{ \url{https://github.com/bluehalo/leaflet-d3#hexbins-api} diff --git a/man/addHistory.Rd b/man/addHistory.Rd index 4853dc2f..e2d23ea0 100644 --- a/man/addHistory.Rd +++ b/man/addHistory.Rd @@ -22,7 +22,7 @@ browser. By default, it is a simple pair of buttons -- back and forward. } \examples{ library(leaflet) -leaflet() \%>\% +leaflet() \%>\% addTiles() \%>\% addHistory() } diff --git a/man/addLabelgun.Rd b/man/addLabelgun.Rd index 4fbb9b58..e6b89fca 100644 --- a/man/addLabelgun.Rd +++ b/man/addLabelgun.Rd @@ -40,10 +40,12 @@ library(leaflet.extras2) leaflet() \%>\% addTiles() \%>\% - addMarkers(data = breweries91, - label = ~brewery, - group = "markers", - labelOptions = labelOptions(permanent = TRUE)) \%>\% + addMarkers( + data = breweries91, + label = ~brewery, + group = "markers", + labelOptions = labelOptions(permanent = TRUE) + ) \%>\% addLabelgun("markers", 1) } \references{ diff --git a/man/addMapkeyMarkers.Rd b/man/addMapkeyMarkers.Rd index 513ff7ca..cf097a88 100644 --- a/man/addMapkeyMarkers.Rd +++ b/man/addMapkeyMarkers.Rd @@ -78,15 +78,19 @@ Add Mapkey Markers \examples{ library(leaflet) -leaflet() \%>\% +leaflet() \%>\% addTiles() \%>\% - addMapkeyMarkers(data = breweries91, - icon = makeMapkeyIcon(icon = "mapkey", - iconSize = 30, - boxShadow = FALSE, - background = "transparent"), - group = "mapkey", - label = ~state, popup = ~village) + addMapkeyMarkers( + data = breweries91, + icon = makeMapkeyIcon( + icon = "mapkey", + iconSize = 30, + boxShadow = FALSE, + background = "transparent" + ), + group = "mapkey", + label = ~state, popup = ~village + ) } \references{ \url{https://github.com/mapshakers/leaflet-mapkey-icon} diff --git a/man/addMovingMarker.Rd b/man/addMovingMarker.Rd index 37bb5a1b..1facd689 100644 --- a/man/addMovingMarker.Rd +++ b/man/addMovingMarker.Rd @@ -82,20 +82,27 @@ library(sf) library(leaflet) library(leaflet.extras2) -crds <- data.frame(structure(c(-67.5, -68.5, -69.6, -70.5, -71.3, -72.2, -72.7, - -72.9, -73, -72.4, -70.8, 15.8, 16.5, 17.3, 17.8, 18.3, 18.6, - 19.8, 21.6, 23.5, 25.1, 27.9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), - dim = c(11L, 3L), dimnames = list(NULL, c("X", "Y", "L1")))) -df <- st_sf(st_sfc(st_linestring(as.matrix(crds), dim="XYZ"), crs = 4326)) -st_geometry(df) <- "geometry"; df <- st_zm(df) +crds <- data.frame(structure( + c( + -67.5, -68.5, -69.6, -70.5, -71.3, -72.2, -72.7, + -72.9, -73, -72.4, -70.8, 15.8, 16.5, 17.3, 17.8, 18.3, 18.6, + 19.8, 21.6, 23.5, 25.1, 27.9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + ), + dim = c(11L, 3L), dimnames = list(NULL, c("X", "Y", "L1")) +)) +df <- st_sf(st_sfc(st_linestring(as.matrix(crds), dim = "XYZ"), crs = 4326)) +st_geometry(df) <- "geometry" +df <- st_zm(df) -leaflet() \%>\% +leaflet() \%>\% addTiles() \%>\% addPolylines(data = df) \%>\% - addMovingMarker(data = df, - movingOptions = movingMarkerOptions(autostart = TRUE, loop = TRUE), - label="I am a pirate!", - popup="Arrr") + addMovingMarker( + data = df, + movingOptions = movingMarkerOptions(autostart = TRUE, loop = TRUE), + label = "I am a pirate!", + popup = "Arrr" + ) } \references{ \url{https://github.com/ewoken/Leaflet.MovingMarker} diff --git a/man/addOpenweatherCurrent.Rd b/man/addOpenweatherCurrent.Rd index 5b841510..5f2ca2d6 100644 --- a/man/addOpenweatherCurrent.Rd +++ b/man/addOpenweatherCurrent.Rd @@ -44,12 +44,14 @@ and if used in Shiny, a click on an icon will update a Shiny input at library(leaflet) library(leaflet.extras2) -Sys.setenv("OPENWEATHERMAP" = 'Your_API_Key') +Sys.setenv("OPENWEATHERMAP" = "Your_API_Key") -leaflet() \%>\% - addTiles() \%>\% setView(9, 50, 9) \%>\% +leaflet() \%>\% + addTiles() \%>\% + setView(9, 50, 9) \%>\% addOpenweatherCurrent(options = openweatherCurrentOptions( - lang = "en", popup = TRUE)) + lang = "en", popup = TRUE + )) } } \references{ diff --git a/man/addOpenweatherTiles.Rd b/man/addOpenweatherTiles.Rd index 9540810f..7b9d8d65 100644 --- a/man/addOpenweatherTiles.Rd +++ b/man/addOpenweatherTiles.Rd @@ -52,10 +52,11 @@ Out of the box a legend image is only available for Pressure, library(leaflet) library(leaflet.extras2) -Sys.setenv("OPENWEATHERMAP" = 'Your_API_Key') +Sys.setenv("OPENWEATHERMAP" = "Your_API_Key") -leaflet() \%>\% - addTiles() \%>\% setView(9, 50, 6) \%>\% +leaflet() \%>\% + addTiles() \%>\% + setView(9, 50, 6) \%>\% addOpenweatherTiles(layers = "wind") } } diff --git a/man/addPlayback.Rd b/man/addPlayback.Rd index 00c4521d..db8e5f3e 100644 --- a/man/addPlayback.Rd +++ b/man/addPlayback.Rd @@ -68,56 +68,71 @@ library(leaflet.extras2) library(sf) ## Single Elements -data <- sf::st_as_sf(leaflet::atlStorms2005[1,]) +data <- sf::st_as_sf(leaflet::atlStorms2005[1, ]) data <- st_cast(data, "POINT") -data$time = as.POSIXct( - seq.POSIXt(Sys.time() - 1000, Sys.time(), length.out = nrow(data))) +data$time <- as.POSIXct( + seq.POSIXt(Sys.time() - 1000, Sys.time(), length.out = nrow(data)) +) data$label <- as.character(data$time) leaflet() \%>\% addTiles() \%>\% - addPlayback(data = data, label = ~label, - popup = ~sprintf("I am a popup for \%s and \%s", - Name, label), - popupOptions = popupOptions(offset = c(0, -35)), - options = playbackOptions(radius = 3, - tickLen = 36000, - speed = 50, - maxInterpolationTime = 1000), - pathOpts = pathOptions(weight = 5)) + addPlayback( + data = data, label = ~label, + popup = ~ sprintf( + "I am a popup for \%s and \%s", + Name, label + ), + popupOptions = popupOptions(offset = c(0, -35)), + options = playbackOptions( + radius = 3, + tickLen = 36000, + speed = 50, + maxInterpolationTime = 1000 + ), + pathOpts = pathOptions(weight = 5) + ) ## Multiple Elements -data <- sf::st_as_sf(leaflet::atlStorms2005[1:5,]) +data <- sf::st_as_sf(leaflet::atlStorms2005[1:5, ]) data$Name <- as.character(data$Name) data <- st_cast(data, "POINT") data$time <- unlist(lapply(rle(data$Name)$lengths, function(x) { - seq.POSIXt(as.POSIXct(Sys.Date()-2), as.POSIXct(Sys.Date()), length.out = x) + seq.POSIXt(as.POSIXct(Sys.Date() - 2), as.POSIXct(Sys.Date()), length.out = x) })) -data$time <- as.POSIXct(data$time, origin="1970-01-01") +data$time <- as.POSIXct(data$time, origin = "1970-01-01") data$label <- paste0("Time: ", data$time) -data$popup = sprintf("

Customized Popup

Name: \%s
Time: \%s", - data$Name, data$time) +data$popup <- sprintf( + "

Customized Popup

Name: \%s
Time: \%s", + data$Name, data$time +) data <- split(data, f = data$Name) leaflet() \%>\% addTiles() \%>\% - addPlayback(data = data, - popup = ~popup, - label = ~label, - popupOptions = popupOptions(offset=c(0,-35)), - labelOptions = labelOptions(noHide = TRUE), - options = playbackOptions(radius = 3, - tickLen = 1000000, - speed = 5000, - maxInterpolationTime = 10000, - transitionpopup = FALSE, - transitionlabel = FALSE, - playCommand = "Let's go", - stopCommand = "Stop it!", - color = c("red","green","blue", - "orange","yellow")), - pathOpts = pathOptions(weight = 5)) + addPlayback( + data = data, + popup = ~popup, + label = ~label, + popupOptions = popupOptions(offset = c(0, -35)), + labelOptions = labelOptions(noHide = TRUE), + options = playbackOptions( + radius = 3, + tickLen = 1000000, + speed = 5000, + maxInterpolationTime = 10000, + transitionpopup = FALSE, + transitionlabel = FALSE, + playCommand = "Let's go", + stopCommand = "Stop it!", + color = c( + "red", "green", "blue", + "orange", "yellow" + ) + ), + pathOpts = pathOptions(weight = 5) + ) } \references{ \url{https://github.com/hallahan/LeafletPlayback} diff --git a/man/addReachability.Rd b/man/addReachability.Rd index 3c4bdda6..b4691613 100644 --- a/man/addReachability.Rd +++ b/man/addReachability.Rd @@ -37,7 +37,7 @@ When used in Shiny, 3 events update a certain shiny Input: library(leaflet) library(leaflet.extras2) -Sys.setenv("OPRS" = 'Your_API_Key') +Sys.setenv("OPRS" = "Your_API_Key") leaflet() \%>\% addTiles() \%>\% diff --git a/man/addSidebar.Rd b/man/addSidebar.Rd index 9f5043b1..b48a30ac 100644 --- a/man/addSidebar.Rd +++ b/man/addSidebar.Rd @@ -30,12 +30,16 @@ The sidebar HTML must be created with \code{\link{sidebar_tabs}} and library(shiny) # run example app showing a single sidebar -runApp(paste0(system.file("examples", package = "leaflet.extras2"), - "/sidebar_app.R")) +runApp(paste0( + system.file("examples", package = "leaflet.extras2"), + "/sidebar_app.R" +)) # run example app showing two sidebars -runApp(paste0(system.file("examples", package = "leaflet.extras2"), - "/multi_sidebar_app.R")) +runApp(paste0( + system.file("examples", package = "leaflet.extras2"), + "/multi_sidebar_app.R" +)) } } \references{ diff --git a/man/addSidebyside.Rd b/man/addSidebyside.Rd index 963db34e..94c910d0 100644 --- a/man/addSidebyside.Rd +++ b/man/addSidebyside.Rd @@ -44,19 +44,29 @@ library(leaflet.extras2) leaflet(quakes) \%>\% addMapPane("left", zIndex = 0) \%>\% addMapPane("right", zIndex = 0) \%>\% - addTiles(group = "base", layerId = "baseid", - options = pathOptions(pane = "right")) \%>\% - addProviderTiles(providers$CartoDB.DarkMatter, group="carto", layerId = "cartoid", - options = pathOptions(pane = "left")) \%>\% - addCircleMarkers(data = breweries91[1:15,], color = "blue", group = "blue", - options = pathOptions(pane = "left")) \%>\% - addCircleMarkers(data = breweries91[15:20,], color = "yellow", group = "yellow") \%>\% - addCircleMarkers(data = breweries91[15:30,], color = "red", group = "red", - options = pathOptions(pane = "right")) \%>\% - addLayersControl(overlayGroups = c("blue","red", "yellow")) \%>\% - addSidebyside(layerId = "sidecontrols", - rightId = "baseid", - leftId = "cartoid") + addTiles( + group = "base", layerId = "baseid", + options = pathOptions(pane = "right") + ) \%>\% + addProviderTiles(providers$CartoDB.DarkMatter, + group = "carto", layerId = "cartoid", + options = pathOptions(pane = "left") + ) \%>\% + addCircleMarkers( + data = breweries91[1:15, ], color = "blue", group = "blue", + options = pathOptions(pane = "left") + ) \%>\% + addCircleMarkers(data = breweries91[15:20, ], color = "yellow", group = "yellow") \%>\% + addCircleMarkers( + data = breweries91[15:30, ], color = "red", group = "red", + options = pathOptions(pane = "right") + ) \%>\% + addLayersControl(overlayGroups = c("blue", "red", "yellow")) \%>\% + addSidebyside( + layerId = "sidecontrols", + rightId = "baseid", + leftId = "cartoid" + ) } \references{ \url{https://github.com/digidem/leaflet-side-by-side} diff --git a/man/addSpinner.Rd b/man/addSpinner.Rd index 678748d1..261781bd 100644 --- a/man/addSpinner.Rd +++ b/man/addSpinner.Rd @@ -31,7 +31,7 @@ leaflet(data = quakes) \%>\% addTiles() \%>\% addSpinner() \%>\% startSpinner(options = list("lines" = 7, "length" = 20)) \%>\% - addMarkers(~long, ~lat, popup = ~as.character(mag), label = ~as.character(mag)) \%>\% + addMarkers(~long, ~lat, popup = ~ as.character(mag), label = ~ as.character(mag)) \%>\% stopSpinner() } \references{ diff --git a/man/addTangram.Rd b/man/addTangram.Rd index 082e9b77..345c874c 100644 --- a/man/addTangram.Rd +++ b/man/addTangram.Rd @@ -56,8 +56,10 @@ server <- function(input, output, session) { addTangram(scene = scene, group = "tangram") \%>\% addCircleMarkers(data = breweries91, group = "brews") \%>\% setView(11, 49.4, 14) \%>\% - addLayersControl(baseGroups = c("tangram", "base"), - overlayGroups = c("brews")) + addLayersControl( + baseGroups = c("tangram", "base"), + overlayGroups = c("brews") + ) }) } diff --git a/man/addTimeslider.Rd b/man/addTimeslider.Rd index 05d4497d..a19dab78 100644 --- a/man/addTimeslider.Rd +++ b/man/addTimeslider.Rd @@ -84,18 +84,22 @@ library(leaflet) library(leaflet.extras2) library(sf) -data <- sf::st_as_sf(leaflet::atlStorms2005[1,]) +data <- sf::st_as_sf(leaflet::atlStorms2005[1, ]) data <- st_cast(data, "POINT") -data$time = as.POSIXct( - seq.POSIXt(Sys.time() - 1000, Sys.time(), length.out = nrow(data))) +data$time <- as.POSIXct( + seq.POSIXt(Sys.time() - 1000, Sys.time(), length.out = nrow(data)) +) leaflet() \%>\% addTiles() \%>\% - addTimeslider(data = data, - options = timesliderOptions( - position = "topright", - timeAttribute = "time", - range = TRUE)) \%>\% + addTimeslider( + data = data, + options = timesliderOptions( + position = "topright", + timeAttribute = "time", + range = TRUE + ) + ) \%>\% setView(-72, 22, 4) } \references{ diff --git a/man/addVelocity.Rd b/man/addVelocity.Rd index 97e776b0..ddc3a62f 100644 --- a/man/addVelocity.Rd +++ b/man/addVelocity.Rd @@ -24,8 +24,8 @@ identifier-style names. Any number of layers and even different types of layers (e.g. markers and polygons) can share the same group name.} \item{content}{the path or URL to a JSON file representing the velocity data -or a data.frame which can be transformed to such a JSON file. Please see the -\href{https://github.com/onaci/leaflet-velocity/tree/master/demo}{demo +or a data.frame which can be transformed to such a JSON file. Please see +the \href{https://github.com/onaci/leaflet-velocity/tree/master/demo}{demo files} for some example data.} \item{options}{List of further options. See \code{\link{velocityOptions}}} diff --git a/man/addWMS.Rd b/man/addWMS.Rd index fc119873..feafadfe 100644 --- a/man/addWMS.Rd +++ b/man/addWMS.Rd @@ -55,7 +55,8 @@ A Leaflet plugin for working with Web Map services, providing: single-tile/untiled/nontiled layers, shared WMS sources, and \bold{GetFeatureInfo}-powered identify. -You can also use \bold{CQL-Filters} by appending a string to the \code{'baseUrl'}. +You can also use \bold{CQL-Filters} by appending a string +to the \code{'baseUrl'}. Something like \code{'http://server/wms?cql_filter=attribute=value'} } @@ -66,14 +67,17 @@ library(leaflet.extras2) leaflet() \%>\% addTiles(group = "base") \%>\% setView(9, 50, 5) \%>\% - addWMS(baseUrl = "https://maps.dwd.de/geoserver/dwd/wms", - layers = "dwd:BRD_1km_winddaten_10m", - popupOptions = popupOptions(maxWidth = 600), - checkempty = TRUE, - options = WMSTileOptions( - transparent = TRUE, - format = "image/png", - info_format = "text/html")) + addWMS( + baseUrl = "https://maps.dwd.de/geoserver/dwd/wms", + layers = "dwd:BRD_1km_winddaten_10m", + popupOptions = popupOptions(maxWidth = 600), + checkempty = TRUE, + options = WMSTileOptions( + transparent = TRUE, + format = "image/png", + info_format = "text/html" + ) + ) } \references{ \url{https://github.com/heigeo/leaflet.wms} diff --git a/man/easyprintMap.Rd b/man/easyprintMap.Rd index 9edd05b9..f0689ba5 100644 --- a/man/easyprintMap.Rd +++ b/man/easyprintMap.Rd @@ -26,33 +26,33 @@ Print or export a map programmatically (e.g. in a Shiny environment). \examples{ ## Only run examples in interactive R sessions if (interactive()) { -library(shiny) -library(leaflet) -library(leaflet.extras2) + library(shiny) + library(leaflet) + library(leaflet.extras2) -ui <- fluidPage( - leafletOutput("map"), - selectInput("scene", "Select Scene", choices = c("CurrentSize", "A4Landscape", "A4Portrait")), - actionButton("print", "Print Map") -) + ui <- fluidPage( + leafletOutput("map"), + selectInput("scene", "Select Scene", choices = c("CurrentSize", "A4Landscape", "A4Portrait")), + actionButton("print", "Print Map") + ) -server <- function(input, output, session) { - output$map <- renderLeaflet({ - input$print - leaflet() \%>\% - addTiles() \%>\% - setView(10, 50, 9) \%>\% - addEasyprint(options = easyprintOptions( - exportOnly = TRUE - )) -}) - observeEvent(input$print, { - leafletProxy("map") \%>\% - easyprintMap(sizeModes = input$scene) -}) -} + server <- function(input, output, session) { + output$map <- renderLeaflet({ + input$print + leaflet() \%>\% + addTiles() \%>\% + setView(10, 50, 9) \%>\% + addEasyprint(options = easyprintOptions( + exportOnly = TRUE + )) + }) + observeEvent(input$print, { + leafletProxy("map") \%>\% + easyprintMap(sizeModes = input$scene) + }) + } -shinyApp(ui, server) + shinyApp(ui, server) } } \seealso{ diff --git a/man/historyOptions.Rd b/man/historyOptions.Rd index 4f10f985..83afcc81 100644 --- a/man/historyOptions.Rd +++ b/man/historyOptions.Rd @@ -63,14 +63,15 @@ History Options } \examples{ library(leaflet) -leaflet() \%>\% +leaflet() \%>\% addTiles() \%>\% - addHistory(options = historyOptions(position = "bottomright", + addHistory(options = historyOptions( + position = "bottomright", maxMovesToSave = 20, - backText = "Go back", + backText = "Go back", forwardText = "Go forward", orientation = "vertical" - )) + )) } \references{ \url{https://github.com/cscott530/leaflet-history} diff --git a/man/makeMapkeyIcon.Rd b/man/makeMapkeyIcon.Rd index d91941b6..3703af33 100644 --- a/man/makeMapkeyIcon.Rd +++ b/man/makeMapkeyIcon.Rd @@ -50,11 +50,13 @@ A list of mapkey-icon data that can be passed to the argument \code{icon} Make Mapkey Icon } \examples{ -makeMapkeyIcon(icon = "traffic_signal", - color = "#0000ff", - iconSize = 12, - boxShadow = FALSE, - background="transparent") +makeMapkeyIcon( + icon = "traffic_signal", + color = "#0000ff", + iconSize = 12, + boxShadow = FALSE, + background = "transparent" +) } \references{ \url{https://github.com/mapshakers/leaflet-mapkey-icon} diff --git a/man/mapkeyIconList.Rd b/man/mapkeyIconList.Rd index 90e1ceee..6a1d1d99 100644 --- a/man/mapkeyIconList.Rd +++ b/man/mapkeyIconList.Rd @@ -16,7 +16,7 @@ A list of class \code{"leaflet_mapkey_icon_set"} Make Mapkey-icon set } \examples{ -iconSet = mapkeyIconList( +iconSet <- mapkeyIconList( red = makeMapkeyIcon(color = "#ff0000"), blue = makeMapkeyIcon(color = "#0000ff") ) diff --git a/man/mapkeyIcons.Rd b/man/mapkeyIcons.Rd index 9edcaacb..18036d25 100644 --- a/man/mapkeyIcons.Rd +++ b/man/mapkeyIcons.Rd @@ -55,12 +55,15 @@ these arguments will be ignored. \examples{ \dontrun{ library(leaflet) -leaflet() \%>\% - addMapkeyMarkers(data = breweries91, - icon = mapkeyIcons( - color = "red", - borderRadius = 0, - iconSize = 25)) +leaflet() \%>\% + addMapkeyMarkers( + data = breweries91, + icon = mapkeyIcons( + color = "red", + borderRadius = 0, + iconSize = 25 + ) + ) } } \references{ diff --git a/man/setBuildingStyle.Rd b/man/setBuildingStyle.Rd index 713c498f..4bb1f2b7 100644 --- a/man/setBuildingStyle.Rd +++ b/man/setBuildingStyle.Rd @@ -27,7 +27,7 @@ leaflet() \%>\% addTiles() \%>\% addBuildings() \%>\% setBuildingStyle(style) \%>\% - setView(13.40, 52.51836,15) + setView(13.40, 52.51836, 15) } \seealso{ Other OSM-Buildings Plugin: diff --git a/man/sidebar_tabs.Rd b/man/sidebar_tabs.Rd index c215f4cf..da386611 100644 --- a/man/sidebar_tabs.Rd +++ b/man/sidebar_tabs.Rd @@ -26,12 +26,16 @@ Create a Sidebar library(shiny) # run example app showing a single sidebar -runApp(paste0(system.file("examples", package = "leaflet.extras2"), - "/sidebar_app.R")) +runApp(paste0( + system.file("examples", package = "leaflet.extras2"), + "/sidebar_app.R" +)) # run example app showing two sidebars -runApp(paste0(system.file("examples", package = "leaflet.extras2"), - "/multi_sidebar_app.R")) +runApp(paste0( + system.file("examples", package = "leaflet.extras2"), + "/multi_sidebar_app.R" +)) } } \references{ diff --git a/man/updateBuildingTime.Rd b/man/updateBuildingTime.Rd index 7838c312..ec3ccb17 100644 --- a/man/updateBuildingTime.Rd +++ b/man/updateBuildingTime.Rd @@ -22,7 +22,7 @@ leaflet() \%>\% addTiles() \%>\% addBuildings() \%>\% updateBuildingTime(as.POSIXct("2024-09-01 19:00:00 CET")) \%>\% - setView(13.40, 52.51836,15) + setView(13.40, 52.51836, 15) } \seealso{ Other OSM-Buildings Plugin: diff --git a/man/velocityOptions.Rd b/man/velocityOptions.Rd index c6f94957..c03da992 100644 --- a/man/velocityOptions.Rd +++ b/man/velocityOptions.Rd @@ -26,7 +26,8 @@ per hour or 'kt' for knots} \item{colorScale}{A vector of hex colors or an RGB matrix} \item{...}{Further arguments passed to the Velocity layer and Windy.js. -For more information, please visit \href{https://github.com/onaci/leaflet-velocity}{leaflet-velocity plugin}} +For more information, please visit +\href{https://github.com/onaci/leaflet-velocity}{leaflet-velocity plugin}} } \value{ A list of further options for \code{addVelocity} diff --git a/package-lock.json b/package-lock.json index bbc4ce3d..630bd259 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "leaflet-arrowheads": "^1.4.0", "leaflet-easyprint": "^2.1.9", "leaflet-geometryutil": "^0.10.1", - "leaflet.heightgraph": "^1.4.0" + "leaflet.heightgraph": "^1.4.0", + "rbush": "^2.0.2" } }, "node_modules/commander": { diff --git a/package.json b/package.json index fd03ebeb..03b82524 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "leaflet-arrowheads": "^1.4.0", "leaflet-easyprint": "^2.1.9", "leaflet-geometryutil": "^0.10.1", - "leaflet.heightgraph": "^1.4.0" + "leaflet.heightgraph": "^1.4.0", + "rbush": "^2.0.2" } } diff --git a/tests/testthat/test-arrowhead.R b/tests/testthat/test-arrowhead.R index bd61f538..74935c4d 100644 --- a/tests/testthat/test-arrowhead.R +++ b/tests/testthat/test-arrowhead.R @@ -10,7 +10,7 @@ test_that("arrowhead", { "addArrowhead" ) expect_true(all(names(m$x$calls[[1]]$args[[10]]) %in% - c("yawn", "size", "frequency", "proportionalToTotal"))) + c("yawn", "size", "frequency", "proportionalToTotal"))) m <- leaflet() %>% clearArrowhead("groupname") m$x$calls[[length(m$x$calls)]]$method == "clearArrowhead" diff --git a/tests/testthat/test-clustercharts.R b/tests/testthat/test-clustercharts.R index 7267b764..e272d99d 100644 --- a/tests/testthat/test-clustercharts.R +++ b/tests/testthat/test-clustercharts.R @@ -1,19 +1,25 @@ test_that("clustercharts", { - ## data ########## data <- sf::st_as_sf(breweries91) - data$category <- sample(c("Schwer", "Mäßig", - "Leicht", "kein Schaden"), - size = nrow(data), replace = TRUE) + data$category <- sample( + c( + "Schwer", "Mäßig", + "Leicht", "kein Schaden" + ), + size = nrow(data), replace = TRUE + ) data$label <- paste0(data$brewery, "
", data$address) data$id <- paste0("ID", seq.int(nrow(data))) - data$popup <- paste0("
", data$brewery, - "
", data$address, "
") + data$popup <- paste0( + "
", data$brewery, + "
", data$address, "
" + ) data$tosum <- sample(1:100, nrow(data), replace = TRUE) data$tosumlabel <- paste("Sum: ", data$tosum) data$web <- gsub(">(.*?)<", ">", data$tosum, "<", data$web) data$web <- ifelse(is.na(data$web), "", - paste0("
", data$web, "
")) + paste0("
", data$web, "
") + ) ## simple example ########## m <- leaflet() %>% @@ -62,8 +68,10 @@ test_that("clustercharts", { labels = c("Schwer", "Mäßig", "Leicht", "kein Schaden"), colors = c("lightblue", "orange", "lightyellow", "lightgreen") ), - popupFields = c("id", "brewery", "address", - "zipcode", "category", "tosum"), + popupFields = c( + "id", "brewery", "address", + "zipcode", "category", "tosum" + ), popupLabels = c("id", "Brauerei", "Addresse", "PLZ", "Art", "tosum") ) deps <- findDependencies(m) @@ -82,8 +90,10 @@ test_that("clustercharts", { labels = c("Schwer", "Mäßig", "Leicht", "kein Schaden"), colors = c("lightblue", "orange", "lightyellow", "lightgreen") ), - popupFields = c("id", "brewery", "address", - "zipcode", "category", "tosum") + popupFields = c( + "id", "brewery", "address", + "zipcode", "category", "tosum" + ) ) deps <- findDependencies(m) expect_equal(deps[[length(deps)]]$name, "lfx-clustercharts") @@ -108,8 +118,10 @@ test_that("clustercharts", { addClusterCharts( data = data, categoryMap = - data.frame(colors = c("lightblue", "orange", - "lightyellow", "lightgreen")) + data.frame(colors = c( + "lightblue", "orange", + "lightyellow", "lightgreen" + )) ) ) @@ -141,8 +153,10 @@ test_that("clustercharts", { data = data, categoryField = "category", categoryMap = - data.frame(colors = c("lightblue", "orange", - "lightyellow", "lightgreen")) + data.frame(colors = c( + "lightblue", "orange", + "lightyellow", "lightgreen" + )) ) ) deps <- findDependencies(m) @@ -187,10 +201,14 @@ test_that("clustercharts", { labels = c("Schwer", "Mäßig", "Leicht", "kein Schaden"), colors = c("lightblue", "orange", "lightyellow", "lightgreen") ), - popupFields = c("id", "brewery", "address", - "zipcode", "category", "tosum", "tosum2"), - popupLabels = c("id", "Brauerei", "Addresse", - "PLZ", "Art", "tosum", "tosum2"), + popupFields = c( + "id", "brewery", "address", + "zipcode", "category", "tosum", "tosum2" + ), + popupLabels = c( + "id", "Brauerei", "Addresse", + "PLZ", "Art", "tosum", "tosum2" + ), label = "label", options = clusterchartOptions(size = 50) ) @@ -226,10 +244,14 @@ test_that("clustercharts", { labels = c("Schwer", "Mäßig", "Leicht", "kein Schaden"), colors = c("lightblue", "orange", "lightyellow", "lightgreen") ), - popupFields = c("id", "brewery", "address", - "zipcode", "category", "tosum", "tosum2"), - popupLabels = c("id", "Brauerei", "Addresse", - "PLZ", "Art", "tosum", "tosum2"), + popupFields = c( + "id", "brewery", "address", + "zipcode", "category", "tosum", "tosum2" + ), + popupLabels = c( + "id", "Brauerei", "Addresse", + "PLZ", "Art", "tosum", "tosum2" + ), label = "label", options = clusterchartOptions(size = c(30, 35)) ) @@ -258,10 +280,14 @@ test_that("clustercharts", { icons = iconvec ), options = clusterchartOptions(size = 50), - popupFields = c("id", "brewery", "address", - "zipcode", "category", "tosum", "tosum2"), - popupLabels = c("id", "Brauerei", "Addresse", - "PLZ", "Art", "tosum", "tosum2"), + popupFields = c( + "id", "brewery", "address", + "zipcode", "category", "tosum", "tosum2" + ), + popupLabels = c( + "id", "Brauerei", "Addresse", + "PLZ", "Art", "tosum", "tosum2" + ), label = "label" ) deps <- findDependencies(m) @@ -303,10 +329,14 @@ test_that("clustercharts", { group = "clustermarkers", layerId = "id", clusterId = "id", - popupFields = c("id", "brewery", "address", - "zipcode", "category", "tosum", "tosum2"), - popupLabels = c("id", "Brauerei", "Addresse", - "PLZ", "Art", "tosum", "tosum2"), + popupFields = c( + "id", "brewery", "address", + "zipcode", "category", "tosum", "tosum2" + ), + popupLabels = c( + "id", "Brauerei", "Addresse", + "PLZ", "Art", "tosum", "tosum2" + ), label = "label", markerOptions = markerOptions( interactive = TRUE, @@ -318,21 +348,27 @@ test_that("clustercharts", { riseOnHover = TRUE, riseOffset = 400 ), - legendOptions = list(position = "bottomright", - title = "Unfälle im Jahr 2003"), + legendOptions = list( + position = "bottomright", + title = "Unfälle im Jahr 2003" + ), clusterOptions = markerClusterOptions( showCoverageOnHover = TRUE, zoomToBoundsOnClick = TRUE, spiderfyOnMaxZoom = TRUE, removeOutsideVisibleBounds = TRUE, - spiderLegPolylineOptions = list(weight = 1.5, - color = "#222", opacity = 0.5), + spiderLegPolylineOptions = list( + weight = 1.5, + color = "#222", opacity = 0.5 + ), freezeAtZoom = TRUE, clusterPane = "clusterpane", spiderfyDistanceMultiplier = 2 ), labelOptions = labelOptions(opacity = 0.8, textsize = "14px"), - popupOptions = popupOptions(maxWidth = 900, - minWidth = 200, keepInView = TRUE) + popupOptions = popupOptions( + maxWidth = 900, + minWidth = 200, keepInView = TRUE + ) ) }) diff --git a/tests/testthat/test-contextmenu.R b/tests/testthat/test-contextmenu.R index adcb4dc1..7a7ab7f7 100644 --- a/tests/testthat/test-contextmenu.R +++ b/tests/testthat/test-contextmenu.R @@ -5,7 +5,8 @@ test_that("contextmenu", { contextmenuItems = context_mapmenuItems( context_menuItem("Zoom Out", "function(e) {this.zoomOut()}", - disabled = FALSE), + disabled = FALSE + ), "-", context_menuItem("Zoom In", "function(e) {this.zoomIn()}") ) @@ -44,7 +45,8 @@ test_that("contextmenu", { "showContextmenu" ) expect_true(all( - colnames(m$x$calls[[length(m$x$calls)]]$args[[1]]) %in% c("lng", "lat"))) + colnames(m$x$calls[[length(m$x$calls)]]$args[[1]]) %in% c("lng", "lat") + )) m <- m %>% showContextmenu(lat = 49.79433, lng = 11.50941) expect_equal( @@ -52,7 +54,8 @@ test_that("contextmenu", { "showContextmenu" ) expect_true(all( - colnames(m$x$calls[[length(m$x$calls)]]$args[[1]]) %in% c("lng", "lat"))) + colnames(m$x$calls[[length(m$x$calls)]]$args[[1]]) %in% c("lng", "lat") + )) m <- m %>% hideContextmenu() expect_equal( diff --git a/tests/testthat/test-divicon.R b/tests/testthat/test-divicon.R index 9078599f..1a567de5 100644 --- a/tests/testthat/test-divicon.R +++ b/tests/testthat/test-divicon.R @@ -4,8 +4,10 @@ library(sf) df <- sf::st_as_sf(atlStorms2005) df <- suppressWarnings(st_cast(df, "POINT")) df <- df[sample(1:nrow(df), 50, replace = FALSE), ] -df$classes <- sample(x = c("myclass1", "myclass2", "myclass3"), - nrow(df), replace = TRUE) +df$classes <- sample( + x = c("myclass1", "myclass2", "myclass3"), + nrow(df), replace = TRUE +) df$ID <- paste0("ID_", 1:nrow(df)) df$lon <- st_coordinates(df)[, 1] df$lat <- st_coordinates(df)[, 2] @@ -27,16 +29,20 @@ test_that("addDivicon works", { className = ~ paste("globalclass", classes), html = ~ paste0("
", Name, "
") ) - expect_true(any(sapply(map$dependencies, - function(dep) dep$name == "lfx-divicon"))) + expect_true(any(sapply( + map$dependencies, + function(dep) dep$name == "lfx-divicon" + ))) expect_is(map, "leaflet") expect_identical(map$x$calls[[2]]$method, "addDivicon") expect_identical(map$x$calls[[2]]$args[[3]], df$ID) expect_identical(map$x$calls[[2]]$args[[4]], NULL) expect_identical(map$x$calls[[2]]$args[[5]], leaflet::markerOptions()) expect_identical(map$x$calls[[2]]$args[[6]], paste("globalclass", df$classes)) - expect_identical(map$x$calls[[2]]$args[[7]], - paste0("
", df$Name, "
")) + expect_identical( + map$x$calls[[2]]$args[[7]], + paste0("
", df$Name, "
") + ) expect_identical(map$x$calls[[2]]$args[[8]], NULL) expect_identical(map$x$calls[[2]]$args[[9]], NULL) expect_identical(map$x$calls[[2]]$args[[10]], NULL) @@ -45,8 +51,10 @@ test_that("addDivicon works", { expect_identical(map$x$calls[[2]]$args[[13]], NULL) # Test 2: Passing a group - df$groups <- sample(x = c("myclass1", "myclass2", "myclass3"), - nrow(df), replace = TRUE) + df$groups <- sample( + x = c("myclass1", "myclass2", "myclass3"), + nrow(df), replace = TRUE + ) map <- generate_test_map() %>% addDivicon( data = df, @@ -61,8 +69,10 @@ test_that("addDivicon works", { expect_identical(map$x$calls[[2]]$args[[4]], df$groups) expect_identical(map$x$calls[[2]]$args[[5]], leaflet::markerOptions()) expect_identical(map$x$calls[[2]]$args[[6]], paste("globalclass", df$classes)) - expect_identical(map$x$calls[[2]]$args[[7]], - paste0("
", df$Name, "
")) + expect_identical( + map$x$calls[[2]]$args[[7]], + paste0("
", df$Name, "
") + ) expect_identical(map$x$calls[[2]]$args[[8]], NULL) expect_identical(map$x$calls[[2]]$args[[9]], NULL) expect_identical(map$x$calls[[2]]$args[[10]], NULL) @@ -89,8 +99,10 @@ test_that("addDivicon works", { expect_identical(map$x$calls[[2]]$args[[4]], df$groups) expect_identical(map$x$calls[[2]]$args[[5]], leaflet::markerOptions()) expect_identical(map$x$calls[[2]]$args[[6]], paste("globalclass", df$classes)) - expect_identical(map$x$calls[[2]]$args[[7]], - paste0("
", df$Name, "
")) + expect_identical( + map$x$calls[[2]]$args[[7]], + paste0("
", df$Name, "
") + ) expect_identical(map$x$calls[[2]]$args[[8]], paste0(df$ID, ": ", df$Name)) expect_identical(map$x$calls[[2]]$args[[9]], popupOptions(minWidth = 400)) expect_identical(map$x$calls[[2]]$args[[10]], df$groups) @@ -119,8 +131,10 @@ test_that("addDivicon works", { expect_identical(map$x$calls[[2]]$args[[4]], df$groups) expect_identical(map$x$calls[[2]]$args[[5]], leaflet::markerOptions()) expect_identical(map$x$calls[[2]]$args[[6]], paste("globalclass", df$classes)) - expect_identical(map$x$calls[[2]]$args[[7]], - paste0("
", df$Name, "
")) + expect_identical( + map$x$calls[[2]]$args[[7]], + paste0("
", df$Name, "
") + ) expect_identical(map$x$calls[[2]]$args[[8]], paste0(df$ID, ": ", df$Name)) expect_identical(map$x$calls[[2]]$args[[9]], popupOptions(minWidth = 400)) expect_identical(map$x$calls[[2]]$args[[10]], df$groups) diff --git a/tests/testthat/test-gibs.R b/tests/testthat/test-gibs.R index 1e41622f..d5b53c19 100644 --- a/tests/testthat/test-gibs.R +++ b/tests/testthat/test-gibs.R @@ -29,7 +29,7 @@ test_that("gibs", { Sys.Date() - 5 ) - m <- m %>% setTransparent(layers, transparent = FFALSE) + m <- m %>% setTransparent(layers, transparent = FALSE) expect_equal( m$x$calls[[length(m$x$calls)]]$method, "setTransparent" diff --git a/tests/testthat/test-heightgraph.R b/tests/testthat/test-heightgraph.R index e483d1bf..386022f3 100644 --- a/tests/testthat/test-heightgraph.R +++ b/tests/testthat/test-heightgraph.R @@ -34,8 +34,11 @@ data <- structure( ) ), row.names = 4L, class = c("sf", "data.frame"), sf_column = "geometry", - agr = structure(c(Name = NA_integer_, - MaxWind = NA_integer_, MinPress = NA_integer_), + agr = structure( + c( + Name = NA_integer_, + MaxWind = NA_integer_, MinPress = NA_integer_ + ), levels = c("constant", "aggregate", "identity"), class = "factor" ) ) diff --git a/tests/testthat/test-layergroupcollision.R b/tests/testthat/test-layergroupcollision.R new file mode 100644 index 00000000..d6e569b3 --- /dev/null +++ b/tests/testthat/test-layergroupcollision.R @@ -0,0 +1,99 @@ +library(testthat) +library(sf) +library(leaflet) + +# Sample data for testing +df <- sf::st_as_sf(atlStorms2005) +df <- suppressWarnings(st_cast(df, "POINT")) +df <- df[sample(1:nrow(df), 50, replace = FALSE), ] +df$classes <- sample( + x = c("myclass1", "myclass2", "myclass3"), + nrow(df), replace = TRUE +) +df$ID <- paste0("ID_", 1:nrow(df)) +df$lon <- st_coordinates(df)[, 1] +df$lat <- st_coordinates(df)[, 2] + +# Function to generate map object for reuse in tests +generate_test_map <- function() { + leaflet() %>% + addTiles() +} + +# Test 1: Basic functionality of addLayerGroupCollision +test_that("addLayerGroupCollision works", { + map <- generate_test_map() %>% + addLayerGroupCollision( + data = df, + group = "Myclass", + className = ~ paste("class", classes), + html = ~ paste0("
", ID, "
") + ) + + expect_is(map, "leaflet") + expect_true(any(sapply( + map$dependencies, + function(dep) dep$name == "lfx-layergroupcollision" + ))) + expect_length(map$dependencies[[length(map$dependencies)]]$script, 3) + expect_identical(map$x$calls[[2]]$method, "addLayerGroupCollision") + expect_is(map$x$calls[[2]]$args[[1]], "geojson") + expect_identical(map$x$calls[[2]]$args[[2]], "Myclass") + expect_identical(map$x$calls[[2]]$args[[3]], 5) # Default margin +}) + +# Test 2: Handling of custom margin +test_that("addLayerGroupCollision handles custom margin", { + map <- generate_test_map() %>% + addLayerGroupCollision( + data = df, + margin = 10 + ) + + expect_is(map, "leaflet") + expect_identical(map$x$calls[[2]]$method, "addLayerGroupCollision") + expect_identical(map$x$calls[[2]]$args[[3]], 10) # Custom margin +}) + +# Test 3: Adding HTML and className with custom values +test_that("addLayerGroupCollision assigns HTML and className correctly", { + map <- generate_test_map() %>% + addLayerGroupCollision( + data = df, + className = ~ paste("myclass", classes), + html = ~ paste0("
", ID, "
") + ) + + expect_is(map, "leaflet") + expect_identical(map$x$calls[[2]]$method, "addLayerGroupCollision") + expect_null(map$x$calls[[2]]$args[[2]]) + expect_identical(map$x$calls[[2]]$args[[3]], 5) +}) + +# Test 4: Verifying map data transformation to GeoJSON +test_that("addLayerGroupCollision transforms spatial data to GeoJSON", { + map <- generate_test_map() %>% + addLayerGroupCollision( + data = df + ) + + geojson <- map$x$calls[[2]]$args[[1]] + expect_true(inherits(geojson, "geojson")) +}) + +# Test 5: Error handling for invalid data +test_that("addLayerGroupCollision handles invalid data gracefully", { + expect_error({ + map <- generate_test_map() %>% + addLayerGroupCollision( + data = NULL + ) + }) + + expect_error({ + map <- generate_test_map() %>% + addLayerGroupCollision( + data = data.frame() + ) + }) +}) diff --git a/tests/testthat/test-leafletsync.R b/tests/testthat/test-leafletsync.R index cb157eb7..2d21e458 100644 --- a/tests/testthat/test-leafletsync.R +++ b/tests/testthat/test-leafletsync.R @@ -5,7 +5,8 @@ test_that("Leaflet Sync works", { deps <- findDependencies(m) expect_equal(deps[[length(deps)]]$name, "lfx-leafletsync") expect_true(all(deps[[length(deps)]]$script %in% c( - "L.Map.Sync.js", "leafletsync-bindings.js"))) + "L.Map.Sync.js", "leafletsync-bindings.js" + ))) m <- leaflet() %>% diff --git a/tests/testthat/test-movingmarker.R b/tests/testthat/test-movingmarker.R index 23286c31..c733b21e 100644 --- a/tests/testthat/test-movingmarker.R +++ b/tests/testthat/test-movingmarker.R @@ -1,14 +1,16 @@ library(sf) ## DATA ####################### df <- new("SpatialLinesDataFrame", - data = structure(list(Name = structure(1L, levels = c( - "ALPHA", - "ARLENE", "BRET", "CINDY", "DELTA", "DENNIS", "EMILY", "EPSILON", - "FRANKLIN", "GAMMA", "GERT", "HARVEY", "IRENE", "JOSE", "KATRINA", - "LEE", "MARIA", "NATE", "OPHELIA", "PHILIPPE", "RITA", "TEN", - "TWENTY-TWO", "WILMA" - ), class = "factor"), MaxWind = 45, MinPress = 998), - row.names = 1L, class = "data.frame"), + data = structure( + list(Name = structure(1L, levels = c( + "ALPHA", + "ARLENE", "BRET", "CINDY", "DELTA", "DENNIS", "EMILY", "EPSILON", + "FRANKLIN", "GAMMA", "GERT", "HARVEY", "IRENE", "JOSE", "KATRINA", + "LEE", "MARIA", "NATE", "OPHELIA", "PHILIPPE", "RITA", "TEN", + "TWENTY-TWO", "WILMA" + ), class = "factor"), MaxWind = 45, MinPress = 998), + row.names = 1L, class = "data.frame" + ), lines = list(new("Lines", Lines = list(new("Line", coords = structure(c( -67.5, -68.5, -69.6, -70.5, -71.3, -72.2, -72.7, -72.9, -73, -72.4, @@ -22,7 +24,8 @@ df <- new("SpatialLinesDataFrame", "y" ), c("min", "max"))), proj4string = new( "CRS", - projargs = "+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs") + projargs = "+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs" + ) ) ## TESTS ####################### diff --git a/tests/testthat/test-osmbuildings.R b/tests/testthat/test-osmbuildings.R index 64501aee..eaf3d9c6 100644 --- a/tests/testthat/test-osmbuildings.R +++ b/tests/testthat/test-osmbuildings.R @@ -1,4 +1,3 @@ - create_test_map <- function() { leaflet() %>% addTiles() } @@ -11,14 +10,17 @@ test_that("addBuildings adds dependencies and invokes method correctly", { map <- addBuildings(map) # Check if the dependencies are added - expect_true(any(sapply(map$dependencies, - function(dep) dep$name) == "lfx-building")) + expect_true(any(sapply( + map$dependencies, + function(dep) dep$name + ) == "lfx-building")) # Check if invokeMethod is called with correct arguments expect_equal(map$x$calls[[2]]$method, "addBuilding") expect_equal( map$x$calls[[2]]$args[[1]], - "https://{s}.data.osmbuildings.org/0.2/59fcc2e8/tile/{z}/{x}/{y}.json") + "https://{s}.data.osmbuildings.org/0.2/59fcc2e8/tile/{z}/{x}/{y}.json" + ) }) test_that("addBuildings handles custom eachFn, clickFn, and data", { @@ -51,8 +53,10 @@ test_that("addBuildings handles custom eachFn, clickFn, and data", { ) ) - map <- addBuildings(map, eachFn = each_fn, - clickFn = click_fn, data = geojson_data) + map <- addBuildings(map, + eachFn = each_fn, + clickFn = click_fn, data = geojson_data + ) # Check if the JavaScript functions and data are passed correctly expect_equal(map$x$calls[[2]]$args[[3]], each_fn) @@ -77,8 +81,10 @@ test_that("updateBuildingTime updates the time correctly", { # Test suite for setBuildingStyle test_that("setBuildingStyle applies styles correctly", { map <- create_test_map() - style <- list(color = "#0000ff", wallColor = "#0000ff", - roofColor = "blue", shadows = FALSE) + style <- list( + color = "#0000ff", wallColor = "#0000ff", + roofColor = "blue", shadows = FALSE + ) map <- addBuildings(map) %>% setBuildingStyle(style) %>% @@ -98,8 +104,10 @@ test_that("setBuildingStyle uses default styles if not provided", { # map # Check if invokeMethod is called with the default styles - default_style <- list(color = "#ffcc00", wallColor = "#ffcc00", - roofColor = "orange", shadows = TRUE) + default_style <- list( + color = "#ffcc00", wallColor = "#ffcc00", + roofColor = "orange", shadows = TRUE + ) expect_equal(map$x$calls[[3]]$"method", "setBuildingStyle") expect_equal(map$x$calls[[3]]$args[[1]], default_style) }) diff --git a/tests/testthat/test-playback.R b/tests/testthat/test-playback.R index f597177d..c21e9d3a 100644 --- a/tests/testthat/test-playback.R +++ b/tests/testthat/test-playback.R @@ -134,15 +134,19 @@ test_that("playback", { structure(c(11.5772056036448, 49.9436206656224), class = c("XY", "POINT", "sfg")) ), precision = 0, - bbox = structure(c(xmin = 11.5772056036448, - ymin = 49.9434124224934, - xmax = 11.5779536762059, - ymax = 49.9447628006851), + bbox = structure( + c( + xmin = 11.5772056036448, + ymin = 49.9434124224934, + xmax = 11.5779536762059, + ymax = 49.9447628006851 + ), class = "bbox" ), crs = structure(list( epsg = 4326L, - proj4string = "+proj=longlat +datum=WGS84 +no_defs"), class = "crs"), + proj4string = "+proj=longlat +datum=WGS84 +no_defs" + ), class = "crs"), n_empty = 0L, class = c("sfc_POINT", "sfc"), ids = 100L ) ), diff --git a/tests/testthat/test-sidebar.R b/tests/testthat/test-sidebar.R index 437e7fa2..40d8ba4e 100644 --- a/tests/testthat/test-sidebar.R +++ b/tests/testthat/test-sidebar.R @@ -83,12 +83,18 @@ test_that("sidebar-error", { expect_error( sidebar_tabs( list(tags$i(class = "person"), tags$i(class = "person")), - sidebar_pane(id = "home_id", - icon = tags$i(class = "person"), tagList()), - sidebar_pane(id = "profile_id", - icon = tags$i(class = "person"), tagList()), - sidebar_pane(id = "messages_id", - icon = tags$i(class = "person"), tagList()) + sidebar_pane( + id = "home_id", + icon = tags$i(class = "person"), tagList() + ), + sidebar_pane( + id = "profile_id", + icon = tags$i(class = "person"), tagList() + ), + sidebar_pane( + id = "messages_id", + icon = tags$i(class = "person"), tagList() + ) ) ) }) diff --git a/tests/testthat/test-sidebyside.R b/tests/testthat/test-sidebyside.R index 58cd953d..ddeb4cc2 100644 --- a/tests/testthat/test-sidebyside.R +++ b/tests/testthat/test-sidebyside.R @@ -14,8 +14,10 @@ test_that("sidebyside", { data = breweries91[1:15, ], color = "blue", group = "blue", options = pathOptions(pane = "left") ) %>% - addCircleMarkers(data = breweries91[15:20, ], - color = "yellow", group = "yellow") %>% + addCircleMarkers( + data = breweries91[15:20, ], + color = "yellow", group = "yellow" + ) %>% addCircleMarkers( data = breweries91[15:30, ], color = "red", group = "red", options = pathOptions(pane = "right") diff --git a/tests/testthat/test-spin.R b/tests/testthat/test-spin.R index e92ce77d..fa1f14c5 100644 --- a/tests/testthat/test-spin.R +++ b/tests/testthat/test-spin.R @@ -15,6 +15,8 @@ test_that("spin", { expect_false(m$x$calls[[length(m$x$calls)]]$args[[1]]) m <- m %>% startSpinner(options = list("lines" = 7, "width" = 12)) - expect_equal(m$x$calls[[length(m$x$calls)]]$args[[2]], - list("lines" = 7, "width" = 12)) + expect_equal( + m$x$calls[[length(m$x$calls)]]$args[[2]], + list("lines" = 7, "width" = 12) + ) }) diff --git a/tests/testthat/test-tangram.R b/tests/testthat/test-tangram.R index 24d56606..f5697a3e 100644 --- a/tests/testthat/test-tangram.R +++ b/tests/testthat/test-tangram.R @@ -1,6 +1,7 @@ test_that("tangram", { scene <- system.file("examples/tangram/www/scene.yaml", - package = "leaflet.extras2") + package = "leaflet.extras2" + ) m <- leaflet() %>% addTangram(scene = scene, group = "tangram") %>% diff --git a/tests/testthat/test-wms.R b/tests/testthat/test-wms.R index 4055aca4..99d8a911 100644 --- a/tests/testthat/test-wms.R +++ b/tests/testthat/test-wms.R @@ -20,5 +20,5 @@ test_that("wms", { test_that("wms-error", { expect_error(leaflet() %>% - addWMS(baseUrl = "https://maps.dwd.de/geoserver/dwd/wms")) + addWMS(baseUrl = "https://maps.dwd.de/geoserver/dwd/wms")) })