From 88ea86caf20450acbbb1bd768e0ce476cb98f982 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Mon, 3 Jun 2024 21:11:03 +0200 Subject: [PATCH 01/14] add args popup/labelOptions, fix labels, add dotlist to glify (sensitivity, hoverWait, etc), expose mouseover to Shiny, dont reassign ... --- DESCRIPTION | 2 +- NEWS | 8 + R/glify-lines.R | 65 +++---- R/glify-points.R | 130 +++++++------ R/glify-polygons.R | 67 +++---- .../Leaflet.glify/addGlifyPoints.js | 36 ++-- .../Leaflet.glify/addGlifyPolygons.js | 58 ++++-- .../Leaflet.glify/addGlifyPolylines.js | 56 ++++-- leafgl.Rproj | 2 +- man/addGlPoints.Rd | 171 +++++++++++------- 10 files changed, 354 insertions(+), 241 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 1da2f81..241eea0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -29,7 +29,7 @@ Description: Provides bindings to the 'Leaflet.glify' JavaScript library which e License: MIT + file LICENSE Encoding: UTF-8 LazyData: false -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 Imports: geojsonsf, htmltools, diff --git a/NEWS b/NEWS index 30fca91..5a9e0e9 100644 --- a/NEWS +++ b/NEWS @@ -5,9 +5,17 @@ features and improvements bug fixes * src version now works also in shiny. #71 + * added `popupOptions` and `labelOptions`. #83 + * added `stroke` (default=TRUE) in `addGlPolygons` and `addGlPolygonsSrc` for drawing borders. #3 + * Labels work similar to `leaflet`. `leafgl` accepts a single string, a vector of strings or a formula. #78 + * The `...` arguments are now passed to all methods in the underlying library. This allows us to set + additional arguments like `fragmentShaderSource`, sensitivity` or `sensitivityHover`. documentation etc + * Added some @details for Shiny click and mouseover events and their corresponding input. #77 + * Using `@inheritParams leaflet::addPolylines` instead of writing the documentation on our own. + miscellaneous diff --git a/R/glify-lines.R b/R/glify-lines.R index 2daf92d..c48b475 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -1,26 +1,14 @@ -#' add polylines to a leaflet map using Leaflet.glify -#' -#' @details -#' MULTILINESTRINGs are currently not supported! Make sure you cast your data -#' to LINETSRING first (e.g. using \code{sf::st_cast(data, "LINESTRING")}. -#' #' @examples -#' if (interactive()) { -#' library(leaflet) -#' library(leafgl) -#' library(sf) -#' #' storms = st_as_sf(atlStorms2005) -#' #' cols = heat.colors(nrow(storms)) #' #' leaflet() %>% #' addProviderTiles(provider = providers$CartoDB.Positron) %>% #' addGlPolylines(data = storms, color = cols, popup = TRUE, opacity = 1) -#' } #' -#' @describeIn addGlPoints add polylines to a leaflet map using Leaflet.glify +#' @describeIn addGlPoints Add Lines to a leaflet map using Leaflet.glify #' @aliases addGlPolylines +#' @order 2 #' @export addGlPolylines addGlPolylines = function(map, data, @@ -33,8 +21,15 @@ addGlPolylines = function(map, layerId = NULL, src = FALSE, pane = "overlayPane", + popupOptions = NULL, + labelOptions = NULL, ...) { + if (missing(labelOptions)) labelOptions <- labelOptions() + if (missing(popupOptions)) popupOptions <- popupOptions() + + dotopts = list(...) + if (isTRUE(src)) { m = addGlPolylinesSrc( map = map @@ -45,7 +40,8 @@ addGlPolylines = function(map, , popup = popup , weight = weight , layerId = layerId - , pane = pane + , popupOptions = popupOptions + , labelOptions = labelOptions , ... ) return(m) @@ -64,26 +60,24 @@ addGlPolylines = function(map, bounds = as.numeric(sf::st_bbox(data)) # color - args <- list(...) palette = "viridis" - if ("palette" %in% names(args)) { - palette <- args$palette - args$palette = NULL + if ("palette" %in% names(dotopts)) { + palette <- dotopts$palette + dotopts$palette = NULL } color <- makeColorMatrix(color, data, palette = palette) if (ncol(color) != 3) stop("only 3 column color matrix supported so far") color = as.data.frame(color, stringsAsFactors = FALSE) colnames(color) = c("r", "g", "b") - cols = jsonify::to_json(color, digits = 3) - # popup + # label / popup + labels <- leaflet::evalFormula(label, data) if (is.null(popup)) { - # geom = sf::st_transform(sf::st_geometry(data), crs = 4326) geom = sf::st_geometry(data) data = sf::st_sf(id = 1:length(geom), geometry = geom) } else if (isTRUE(popup)) { - data = data[, popup] + ## Don't do anything. Pass all columns to JS } else { htmldeps <- htmltools::htmlDependencies(popup) if (length(htmldeps) != 0) { @@ -99,12 +93,12 @@ addGlPolylines = function(map, } # data - if (length(args) == 0) { + if (length(dotopts) == 0) { geojsonsf_args = NULL } else { geojsonsf_args = try( match.arg( - names(args) + names(dotopts) , names(as.list(args(geojsonsf::sf_geojson))) , several.ok = TRUE ) @@ -113,17 +107,12 @@ addGlPolylines = function(map, if (inherits(geojsonsf_args, "try-error")) geojsonsf_args = NULL if (identical(geojsonsf_args, "sf")) geojsonsf_args = NULL } - data = do.call(geojsonsf::sf_geojson, c(list(data), args[geojsonsf_args])) - # data = geojsonsf::sf_geojson(data, ...) + data = do.call(geojsonsf::sf_geojson, c(list(data), dotopts[geojsonsf_args])) # dependencies - map$dependencies = c( - map$dependencies - , glifyDependencies() - ) - - # weight is about double the weight of svg, so / 2 + map$dependencies = c(map$dependencies, glifyDependencies()) + # invoke leaflet method and zoom to bounds map = leaflet::invokeMethod( map , leaflet::getMapData(map) @@ -131,12 +120,15 @@ addGlPolylines = function(map, , data , cols , popup - , label + , labels , opacity , group , weight , layerId + , dotopts , pane + , popupOptions + , labelOptions ) leaflet::expandLimits( @@ -157,6 +149,8 @@ addGlPolylinesSrc = function(map, weight = 1, layerId = NULL, pane = "overlayPane", + popupOptions = NULL, + labelOptions = NULL, ...) { if (is.null(group)) group = deparse(substitute(data)) @@ -281,6 +275,8 @@ addGlPolylinesSrc = function(map, , group , layerId , pane + , popupOptions + , labelOptions ) leaflet::expandLimits( @@ -288,7 +284,6 @@ addGlPolylinesSrc = function(map, c(bounds[2], bounds[4]), c(bounds[1], bounds[3]) ) - } diff --git a/R/glify-points.R b/R/glify-points.R index 78aaa44..e2eb3f3 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -1,60 +1,88 @@ -#' add points to a leaflet map using Leaflet.glify +#' @title Add Data to a leaflet map using Leaflet.glify #' #' @description -#' Leaflet.glify is a web gl renderer plugin for leaflet. See +#' Leaflet.glify is a WebGL renderer plugin for leaflet. See #' \url{https://github.com/robertleeplummerjr/Leaflet.glify} for details #' and documentation. #' -#' @param map a leaflet map to add points/polygons to. -#' @param data sf/sp point/polygon data to add to the map. +#' @inheritParams leaflet::addPolylines +#' @param data sf/sp point/polygon/line data to add to the map. #' @param color Object representing the color. Can be of class integer, character with #' color names, HEX codes or random characters, factor, matrix, data.frame, list, json or formula. #' See the examples or \link{makeColorMatrix} for more information. -#' @param fillColor fill color. #' @param opacity feature opacity. Numeric between 0 and 1. #' Note: expect funny results if you set this to < 1. -#' @param fillOpacity fill opacity. #' @param radius point size in pixels. -#' @param group a group name for the feature layer. #' @param popup Object representing the popup. Can be of type character with column names, #' formula, logical, data.frame or matrix, Spatial, list or JSON. If the length does not -#' match the number of rows in the dataset, the popup vector is repeated to match the dimension. -#' @param label either a column name (currently only supported for polygons and polylines) -#' or a character vector to be used as label. -#' @param layerId the layer id -#' @param weight line width/thicknes in pixels for \code{addGlPolylines}. +#' match the number of rows in the data, the popup vector is repeated to match the dimension. +#' @param weight line width/thickness in pixels for \code{addGlPolylines}. #' @param src whether to pass data to the widget via file attachments. #' @param pane A string which defines the pane of the layer. The default is \code{"overlayPane"}. #' @param ... Used to pass additional named arguments to \code{\link[jsonify]{to_json}} #' & to pass additional arguments to the underlying JavaScript functions. Typical -#' use-cases include setting 'digits' to round the point coordinates or to pass -#' a different 'fragmentShaderSource' to control the shape of the points. Use -#' 'point' (default) to render circles with a thin black outline, -#' 'simpleCircle' for circles without outline or -#' 'sqaure' for squares (without outline). +#' use-cases include setting \code{'digits'} to round the point coordinates or to pass +#' a different \code{'fragmentShaderSource'} to control the shape of the points. Use +#' \itemize{ +#' \item{\code{'point'} (default) to render circles with a thin black outline} +#' \item{\code{'simpleCircle'} for circles without outline} +#' \item{\code{'square'} for squares without outline} +#' } +#' Additional arguments could be \code{'sensitivity'}, \code{'sensitivityHover'} or +#' \code{'vertexShaderSource'}. See a full list at the +#' \href{https://github.com/robertleeplummerjr/Leaflet.glify}{Leaflet.glify} +#' repository. #' -#' @describeIn addGlPoints add points to a leaflet map using Leaflet.glify -#' @examples -#' if (interactive()) { +#' +#' @note +#' MULTILINESTRINGs and MULTIPOLYGONs are currently not supported! +#' Make sure you cast your data to LINESTRING or POLYGON first using: +#' \itemize{ +#' \item{\code{sf::st_cast(data, "LINESTRING")}} +#' \item{\code{sf::st_cast(data, "POLYGON")}} +#' } +#' +#' @section Shiny Inputs: +#' The objects created with \code{leafgl} send input values to Shiny as the +#' user interacts with them. These events follow the pattern +#' \code{input$MAPID_glify_EVENTNAME}. +#' The following events are available: +#' +#' \itemize{ +#' \item \strong{Click Events:} +#' \code{input$MAPID_glify_click} +#' \item \strong{Mouseover Events:} +#' \code{input$MAPID_glify_mouseover} +#' } +#' +#' +#' Each event returns a list containing: +#' \itemize{ +#' \item \code{lat}: Latitude of the object or mouse cursor +#' \item \code{lng}: Longitude of the object or mouse cursor +#' \item \code{id}: The layerId, if any +#' \item \code{group}: The group name of the object +#' \item \code{data}: The properties of the feature +#' } +#' +#' @describeIn addGlPoints Add Points to a leaflet map using Leaflet.glify +#' @order 1 +#' @examples \donttest #' library(leaflet) #' library(leafgl) #' library(sf) #' #' n = 1e5 -#' #' df1 = data.frame(id = 1:n, #' x = rnorm(n, 10, 1), #' y = rnorm(n, 49, 0.8)) #' pts = st_as_sf(df1, coords = c("x", "y"), crs = 4326) -#' #' cols = topo.colors(nrow(pts)) #' #' leaflet() %>% #' addProviderTiles(provider = providers$CartoDB.DarkMatter) %>% #' addGlPoints(data = pts, fillColor = cols, popup = TRUE) #' -#' } -#' #' @export addGlPoints addGlPoints = function(map, data, @@ -67,8 +95,13 @@ addGlPoints = function(map, layerId = NULL, src = FALSE, pane = "overlayPane", + popupOptions = NULL, + labelOptions = NULL, ...) { + if (missing(labelOptions)) labelOptions <- labelOptions() + if (missing(popupOptions)) popupOptions <- popupOptions() + dotopts = list(...) if (isTRUE(src)) { @@ -82,6 +115,8 @@ addGlPoints = function(map, , popup = popup , layerId = layerId , pane = pane + , popupOptions = popupOptions + , labelOptions = labelOptions , ... ) return(m) @@ -97,20 +132,19 @@ addGlPoints = function(map, bounds = as.numeric(sf::st_bbox(data)) # fillColor - args <- list(...) palette = "viridis" - if ("palette" %in% names(args)) { - palette <- args$palette - args$palette = NULL + if ("palette" %in% names(dotopts)) { + palette <- dotopts$palette + dotopts$palette = NULL } fillColor <- makeColorMatrix(fillColor, data, palette = palette) if (ncol(fillColor) != 3) stop("only 3 column fillColor matrix supported so far") fillColor = as.data.frame(fillColor, stringsAsFactors = FALSE) colnames(fillColor) = c("r", "g", "b") - fillColor = jsonify::to_json(fillColor) - # popup + # label / popup + labels <- leaflet::evalFormula(label, data) if (!is.null(popup)) { htmldeps <- htmltools::htmlDependencies(popup) if (length(htmldeps) != 0) { @@ -126,15 +160,13 @@ addGlPoints = function(map, } # data - # data = sf::st_transform(data, 4326) crds = sf::st_coordinates(data)[, c(2, 1)] - # convert data to json - if (length(args) == 0) { + if (length(dotopts) == 0) { jsonify_args = NULL } else { jsonify_args = try( match.arg( - names(args) + names(dotopts) , names(as.list(args(jsonify::to_json))) , several.ok = TRUE ) @@ -142,15 +174,12 @@ addGlPoints = function(map, ) } if (inherits(jsonify_args, "try-error")) jsonify_args = NULL - data = do.call(jsonify::to_json, c(list(crds), args[jsonify_args])) + data = do.call(jsonify::to_json, c(list(crds), dotopts[jsonify_args])) # dependencies - map$dependencies = c( - map$dependencies - , glifyDependencies() - ) - + map$dependencies = c(map$dependencies, glifyDependencies()) + # invoke leaflet method and zoom to bounds map = leaflet::invokeMethod( map , leaflet::getMapData(map) @@ -158,13 +187,15 @@ addGlPoints = function(map, , data , fillColor , popup - , label + , labels , fillOpacity , radius , group , layerId , dotopts , pane + , popupOptions + , labelOptions ) leaflet::expandLimits( @@ -185,6 +216,8 @@ addGlPointsSrc = function(map, popup = NULL, layerId = NULL, pane = "overlayPane", + popupOptions = NULL, + labelOptions = NULL, ...) { ## currently leaflet.glify only supports single (fill)opacity! @@ -298,16 +331,6 @@ addGlPointsSrc = function(map, radius = NULL } - # leaflet::invokeMethod( - # map - # , leaflet::getMapData(map) - # , 'addGlifyPointsSrc' - # , fillOpacity - # , radius - # , group - # , layerId - # ) - map = leaflet::invokeMethod( map , leaflet::getMapData(map) @@ -318,6 +341,8 @@ addGlPointsSrc = function(map, , group , layerId , pane + , popupOptions + , labelOptions ) leaflet::expandLimits( @@ -325,11 +350,10 @@ addGlPointsSrc = function(map, c(bounds[2], bounds[4]), c(bounds[1], bounds[3]) ) - } -# ### via src +# ### via src ############## # addGlPointsSrc2 = function(map, # data, # color = cbind(0, 0.2, 1), diff --git a/R/glify-polygons.R b/R/glify-polygons.R index 7c6d4d8..56947ee 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -1,15 +1,4 @@ -#' add polygons to a leaflet map using Leaflet.glify -#' -#' @details -#' MULTIPOLYGONs are currently not supported! Make sure you cast your data -#' to POLYGON first (e.g. using \code{sf::st_cast(data, "POLYGON")}. -#' #' @examples -#' if (interactive()) { -#' library(leaflet) -#' library(leafgl) -#' library(sf) -#' #' gadm = st_as_sf(gadmCHE) #' gadm = st_cast(gadm, "POLYGON") #' cols = grey.colors(nrow(gadm)) @@ -17,10 +6,10 @@ #' leaflet() %>% #' addProviderTiles(provider = providers$CartoDB.DarkMatter) %>% #' addGlPolygons(data = gadm, color = cols, popup = TRUE) -#' } #' -#' @describeIn addGlPoints add polygons to a leaflet map using Leaflet.glify +#' @describeIn addGlPoints Add Polygons to a leaflet map using Leaflet.glify #' @aliases addGlPolygons +#' @order 3 #' @export addGlPolygons addGlPolygons = function(map, data, @@ -33,8 +22,16 @@ addGlPolygons = function(map, layerId = NULL, src = FALSE, pane = "overlayPane", + stroke = TRUE, + popupOptions = NULL, + labelOptions = NULL, ...) { + if (missing(labelOptions)) labelOptions <- labelOptions() + if (missing(popupOptions)) popupOptions <- popupOptions() + + dotopts = list(...) + if (isTRUE(src)) { m = addGlPolygonsSrc( map = map @@ -46,6 +43,9 @@ addGlPolygons = function(map, , popup = popup , layerId = layerId , pane = pane + , stroke = stroke + , popupOptions = popupOptions + , labelOptions = labelOptions , ... ) return(m) @@ -64,26 +64,25 @@ addGlPolygons = function(map, bounds = as.numeric(sf::st_bbox(data)) # fillColor - args <- list(...) palette = "viridis" - if ("palette" %in% names(args)) { - palette <- args$palette - args$palette = NULL + if ("palette" %in% names(dotopts)) { + palette <- dotopts$palette + dotopts$palette = NULL } fillColor <- makeColorMatrix(fillColor, data, palette = palette) if (ncol(fillColor) != 3) stop("only 3 column fillColor matrix supported so far") fillColor = as.data.frame(fillColor, stringsAsFactors = FALSE) colnames(fillColor) = c("r", "g", "b") - cols = jsonify::to_json(fillColor, digits = 3) - # popup + # label / popup + labels <- leaflet::evalFormula(label, data) if (is.null(popup)) { # geom = sf::st_transform(sf::st_geometry(data), crs = 4326) geom = sf::st_geometry(data) data = sf::st_sf(id = 1:length(geom), geometry = geom) } else if (isTRUE(popup)) { - data = data[, popup] + ## Don't do anything. Pass all columns to JS } else { htmldeps <- htmltools::htmlDependencies(popup) if (length(htmldeps) != 0) { @@ -99,12 +98,12 @@ addGlPolygons = function(map, } # data - if (length(args) == 0) { + if (length(dotopts) == 0) { geojsonsf_args = NULL } else { geojsonsf_args = try( match.arg( - names(args) + names(dotopts) , names(as.list(args(geojsonsf::sf_geojson))) , several.ok = TRUE ) @@ -113,15 +112,12 @@ addGlPolygons = function(map, if (inherits(geojsonsf_args, "try-error")) geojsonsf_args = NULL if (identical(geojsonsf_args, "sf")) geojsonsf_args = NULL } - data = do.call(geojsonsf::sf_geojson, c(list(data), args[geojsonsf_args])) - # data = geojsonsf::sf_geojson(data, ...) + data = do.call(geojsonsf::sf_geojson, c(list(data), dotopts[geojsonsf_args])) # dependencies - map$dependencies = c( - map$dependencies - , glifyDependencies() - ) + map$dependencies = c(map$dependencies, glifyDependencies()) + # invoke leaflet method and zoom to bounds map = leaflet::invokeMethod( map , leaflet::getMapData(map) @@ -129,11 +125,15 @@ addGlPolygons = function(map, , data , cols , popup - , label + , labels , fillOpacity , group , layerId + , dotopts , pane + , stroke + , popupOptions + , labelOptions ) leaflet::expandLimits( @@ -155,6 +155,9 @@ addGlPolygonsSrc = function(map, popup = NULL, layerId = NULL, pane = "overlayPane", + stroke = TRUE, + popupOptions = NULL, + labelOptions = NULL, ...) { if (is.null(group)) group = deparse(substitute(data)) @@ -248,7 +251,6 @@ addGlPolygonsSrc = function(map, map$dependencies, glifyPopupAttachmentSrc(fl_popup, layerId) ) - } map = leaflet::invokeMethod( @@ -260,6 +262,9 @@ addGlPolygonsSrc = function(map, , group , layerId , pane + , stroke + , popupOptions + , labelOptions ) leaflet::expandLimits( @@ -271,7 +276,7 @@ addGlPolygonsSrc = function(map, } -# ### via attachments +# ### via attachments ############ # addGlPolygonsFl = function(map, # data, # color = cbind(0, 0.2, 1), diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js index 9cc6325..9eaf563 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js @@ -1,4 +1,6 @@ -LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacity, radius, group, layerId, dotOptions, pane) { +LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacity, + radius, group, layerId, dotOptions, pane, + popupOptions, labelOptions) { const map = this; @@ -18,11 +20,11 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit rad = function(index, point) { return radius[index]; }; } - // click function + // click & hover function let clickFun = (e, point, xy) => { - var idx = data.findIndex(k => k==point); //set up a standalone popup (use a popup as a layer) if (map.hasLayer(pointslayer.layer)) { + var idx = data.findIndex(k => k==point); var content = popup ? popup[idx].toString() : null; if (HTMLWidgets.shinyMode) { Shiny.setInputValue(map.id + "_glify_click", { @@ -34,7 +36,7 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit }); } if (popup !== null) { - L.popup() + L.popup(popupOptions) .setLatLng(point) .setContent(content) .openOn(map); @@ -42,13 +44,22 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit } }; - let tooltip = new L.Tooltip(); - + let tooltip = new L.Tooltip(labelOptions); var hover_event = function(e, point, addlabel, label) { var idx = data.findIndex(k => k==point); //set up a standalone label (use a label as a layer) if (map.hasLayer(pointslayer.layer)) { - var content = label ? label[idx].toString() : null; + var content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : + typeof label === 'string' ? label : null; + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_mouseover", { + id: layerId ? layerId[idx] : idx+1, + group: pointslayer.settings.className, + lat: point[0], + lng: point[1], + data: content + }); + } if (label !== null) { tooltip .setLatLng(point) @@ -57,13 +68,12 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit } } } - var hvr = function(e, feature) { hover_event(e, feature, label !== null, label); } // arguments for gl layer - var pointsArgs = { + var layerArgs = { map: map, click: clickFun, hover: hvr, @@ -84,12 +94,12 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit } // append dotOptions to layer arguments - Object.entries(dotOptions).forEach(([key,value]) => { pointsArgs[key] = value }); + Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); - // initialze layer - var pointslayer = L.glify.points(pointsArgs); + // initialize Glify Layer + var pointslayer = L.glify.points(layerArgs); - // add layer to map using RStudio leaflet's layerManager + // add layer to map using leaflet's layerManager map.layerManager.addLayer(pointslayer.layer, "glify", layerId, group); }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js index 71116dc..44bfa3c 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js @@ -1,7 +1,10 @@ -LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, opacity, group, layerId, pane) { +LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, + opacity, group, layerId, dotOptions, pane, + stroke, popupOptions, labelOptions) { var map = this; + // colors var clrs; if (cols.length === 1) { clrs = cols[0]; @@ -9,6 +12,7 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, opac clrs = function(index, feature) { return cols[index]; }; } + // click & hover function var click_event = function(e, feature, addpopup, popup) { if (map.hasLayer(shapeslayer.layer)) { var idx = data.features.findIndex(k => k==feature); @@ -24,50 +28,64 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, opac if (addpopup) { var content = popup === true ? json2table(feature.properties) : popup[idx].toString(); - L.popup({ maxWidth: 2000 }) - .setLatLng(e.latlng) - .setContent(content) - .openOn(map); - //.openPopup(); + L.popup(popupOptions) + .setLatLng(e.latlng) + .setContent(content) + .openOn(map); } } }; - - var pop = function (e, feature) { + var clickFun = function (e, feature) { click_event(e, feature, popup !== null, popup); }; - // var label = "testtest"; - let tooltip = new L.Tooltip(); - + let tooltip = new L.Tooltip(labelOptions); var hover_event = function(e, feature, addlabel, label) { if (map.hasLayer(shapeslayer.layer)) { + var idx = data.features.findIndex(k => k==feature); + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_mouseover", { + id: layerId ? layerId[idx] : idx+1, + group: Object.values(shapeslayer.layer._eventParents)[0].groupname, + lat: e.latlng.lat, + lng: e.latlng.lng, + data: feature.properties + }); + } if (addlabel) { + var content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : + typeof label === 'string' ? label : null; tooltip - .setLatLng(e.latlng) - .setContent(feature.properties[[label]].toString()) - .addTo(map); + .setLatLng(e.latlng) + .setContent(content) + .addTo(map); } } } - var hvr = function(e, feature) { hover_event(e, feature, label !== null, label); } - - var shapeslayer = L.glify.shapes({ + // arguments for gl layer + var layerArgs = { map: map, - click: pop, + click: clickFun, hover: hvr, data: data, color: clrs, opacity: opacity, className: group, - border: true, + border: stroke, pane: pane - }); + }; + + // append dotOptions to layer arguments + Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); + + // initialize Glify Layer + var shapeslayer = L.glify.shapes(layerArgs); + // add layer to map using leaflet's layerManager map.layerManager.addLayer(shapeslayer.layer, "glify", layerId, group); }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js index 3e58f03..240f5a3 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js @@ -1,7 +1,10 @@ -LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, opacity, group, weight, layerId, pane) { +LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, + opacity, group, weight, layerId, dotOptions, pane, + popupOptions, labelOptions) { var map = this; + // colors var clrs; if (cols.length === 1) { clrs = cols[0]; @@ -9,6 +12,7 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, opa clrs = function(index, feature) { return cols[index]; }; } + // weight var wght; if (weight.length === undefined) { wght = weight; @@ -16,6 +20,7 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, opa wght = function(index, feature) { return weight[index]; }; } + // click & hover function var click_event = function(e, feature, addpopup, popup) { if (map.hasLayer(lineslayer.layer)) { var idx = data.features.findIndex(k => k==feature); @@ -31,40 +36,48 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, opa if (addpopup) { var content = popup === true ? json2table(feature.properties) : popup[idx].toString(); - L.popup({ maxWidth: 2000 }) - .setLatLng(e.latlng) - .setContent(content) - .openOn(map); + L.popup(popupOptions) + .setLatLng(e.latlng) + .setContent(content) + .openOn(map); } } }; - - var pop = function (e, feature) { + var clickFun = function (e, feature) { click_event(e, feature, popup !== null, popup); }; - // var label = "testtest"; - let tooltip = new L.Tooltip(); - + let tooltip = new L.Tooltip(labelOptions); var hover_event = function(e, feature, addlabel, label) { if (map.hasLayer(lineslayer.layer)) { + var idx = data.features.findIndex(k => k==feature); + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_mouseover", { + id: layerId ? layerId[idx] : idx+1, + group: Object.values(lineslayer.layer._eventParents)[0].groupname, + lat: e.latlng.lat, + lng: e.latlng.lng, + data: feature.properties + }); + } if (addlabel) { + var content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : + typeof label === 'string' ? label : null; tooltip - .setLatLng(e.latlng) - .setContent(feature.properties[[label]].toString()) - .addTo(map); + .setLatLng(e.latlng) + .setContent(content) + .addTo(map); } } } - var hvr = function(e, feature) { hover_event(e, feature, label !== null, label); } - - var lineslayer = L.glify.lines({ + // arguments for gl layer + var layerArgs = { map: map, - click: pop, + click: clickFun, hover: hvr, latitudeKey: 1, longitudeKey: 0, @@ -74,8 +87,15 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, opa className: group, weight: wght, pane: pane - }); + }; + + // append dotOptions to layer arguments + Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); + + // initialize Glify Layer + var lineslayer = L.glify.lines(layerArgs); + // add layer to map using leaflet's layerManager map.layerManager.addLayer(lineslayer.layer, "glify", layerId, group); }; diff --git a/leafgl.Rproj b/leafgl.Rproj index 60ab68b..f167af7 100644 --- a/leafgl.Rproj +++ b/leafgl.Rproj @@ -16,5 +16,5 @@ StripTrailingWhitespace: Yes BuildType: Package PackageInstallArgs: --no-multiarch --with-keep.source -PackageCheckArgs: --as-cran +PackageCheckArgs: --as-cran --no-manual PackageRoxygenize: rd,collate,namespace diff --git a/man/addGlPoints.Rd b/man/addGlPoints.Rd index b26d0d8..2238e81 100644 --- a/man/addGlPoints.Rd +++ b/man/addGlPoints.Rd @@ -1,39 +1,43 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/glify-lines.R, R/glify-points.R, +% Please edit documentation in R/glify-points.R, R/glify-lines.R, % R/glify-polygons.R -\name{addGlPolylines} -\alias{addGlPolylines} +\name{addGlPoints} \alias{addGlPoints} +\alias{addGlPolylines} \alias{addGlPolygons} -\title{add polylines to a leaflet map using Leaflet.glify} +\title{Add Data to a leaflet map using Leaflet.glify} \usage{ -addGlPolylines( +addGlPoints( map, data, - color = cbind(0, 0.2, 1), - opacity = 0.6, - group = "glpolylines", + fillColor = "#0033ff", + fillOpacity = 0.8, + radius = 10, + group = "glpoints", popup = NULL, label = NULL, - weight = 1, layerId = NULL, src = FALSE, pane = "overlayPane", + popupOptions = NULL, + labelOptions = NULL, ... ) -addGlPoints( +addGlPolylines( map, data, - fillColor = "#0033ff", - fillOpacity = 0.8, - radius = 10, - group = "glpoints", + color = cbind(0, 0.2, 1), + opacity = 0.6, + group = "glpolylines", popup = NULL, label = NULL, + weight = 1, layerId = NULL, src = FALSE, pane = "overlayPane", + popupOptions = NULL, + labelOptions = NULL, ... ) @@ -49,31 +53,34 @@ addGlPolygons( layerId = NULL, src = FALSE, pane = "overlayPane", + stroke = TRUE, + popupOptions = NULL, + labelOptions = NULL, ... ) } \arguments{ -\item{map}{a leaflet map to add points/polygons to.} +\item{map}{a map widget object created from \code{\link[leaflet:leaflet]{leaflet()}}} -\item{data}{sf/sp point/polygon data to add to the map.} +\item{data}{sf/sp point/polygon/line data to add to the map.} -\item{color}{Object representing the color. Can be of class integer, character with -color names, HEX codes or random characters, factor, matrix, data.frame, list, json or formula. -See the examples or \link{makeColorMatrix} for more information.} +\item{fillColor}{fill color} -\item{opacity}{feature opacity. Numeric between 0 and 1. -Note: expect funny results if you set this to < 1.} +\item{fillOpacity}{fill opacity} + +\item{radius}{point size in pixels.} -\item{group}{a group name for the feature layer.} +\item{group}{the name of the group the newly created layers should belong to +(for \code{\link[leaflet:clearGroup]{clearGroup()}} and \code{\link[leaflet:addLayersControl]{addLayersControl()}} purposes). +Human-friendly group names are permitted--they need not be short, +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{popup}{Object representing the popup. Can be of type character with column names, formula, logical, data.frame or matrix, Spatial, list or JSON. If the length does not -match the number of rows in the dataset, the popup vector is repeated to match the dimension.} - -\item{label}{either a column name (currently only supported for polygons and polylines) -or a character vector to be used as label.} +match the number of rows in the data, the popup vector is repeated to match the dimension.} -\item{weight}{line width/thicknes in pixels for \code{addGlPolylines}.} +\item{label}{a character vector of the HTML content for the labels} \item{layerId}{the layer id} @@ -81,80 +88,107 @@ or a character vector to be used as label.} \item{pane}{A string which defines the pane of the layer. The default is \code{"overlayPane"}.} +\item{popupOptions}{A Vector of \code{\link[leaflet:popupOptions]{popupOptions()}} to provide popups} + +\item{labelOptions}{A Vector of \code{\link[leaflet:labelOptions]{labelOptions()}} to provide label +options for each label. Default \code{NULL}} + \item{...}{Used to pass additional named arguments to \code{\link[jsonify]{to_json}} & to pass additional arguments to the underlying JavaScript functions. Typical -use-cases include setting 'digits' to round the point coordinates or to pass -a different 'fragmentShaderSource' to control the shape of the points. Use -'point' (default) to render circles with a thin black outline, -'simpleCircle' for circles without outline or -'sqaure' for squares (without outline).} +use-cases include setting \code{'digits'} to round the point coordinates or to pass +a different \code{'fragmentShaderSource'} to control the shape of the points. Use +\itemize{ + \item{\code{'point'} (default) to render circles with a thin black outline} + \item{\code{'simpleCircle'} for circles without outline} + \item{\code{'square'} for squares without outline} +} +Additional arguments could be \code{'sensitivity'}, \code{'sensitivityHover'} or +\code{'vertexShaderSource'}. See a full list at the +\href{https://github.com/robertleeplummerjr/Leaflet.glify}{Leaflet.glify} +repository.} -\item{fillColor}{fill color.} +\item{color}{Object representing the color. Can be of class integer, character with +color names, HEX codes or random characters, factor, matrix, data.frame, list, json or formula. +See the examples or \link{makeColorMatrix} for more information.} -\item{fillOpacity}{fill opacity.} +\item{opacity}{feature opacity. Numeric between 0 and 1. +Note: expect funny results if you set this to < 1.} -\item{radius}{point size in pixels.} +\item{weight}{line width/thickness in pixels for \code{addGlPolylines}.} + +\item{stroke}{whether to draw stroke along the path (e.g. the borders of +polygons or circles)} } \description{ -Leaflet.glify is a web gl renderer plugin for leaflet. See +Leaflet.glify is a WebGL renderer plugin for leaflet. See \url{https://github.com/robertleeplummerjr/Leaflet.glify} for details and documentation. } -\details{ -MULTILINESTRINGs are currently not supported! Make sure you cast your data - to LINETSRING first (e.g. using \code{sf::st_cast(data, "LINESTRING")}. - -MULTIPOLYGONs are currently not supported! Make sure you cast your data - to POLYGON first (e.g. using \code{sf::st_cast(data, "POLYGON")}. -} \section{Functions}{ \itemize{ -\item \code{addGlPolylines()}: add polylines to a leaflet map using Leaflet.glify +\item \code{addGlPoints()}: Add Points to a leaflet map using Leaflet.glify -\item \code{addGlPoints()}: add points to a leaflet map using Leaflet.glify +\item \code{addGlPolylines()}: Add Lines to a leaflet map using Leaflet.glify -\item \code{addGlPolygons()}: add polygons to a leaflet map using Leaflet.glify +\item \code{addGlPolygons()}: Add Polygons to a leaflet map using Leaflet.glify }} -\examples{ -if (interactive()) { -library(leaflet) -library(leafgl) -library(sf) - -storms = st_as_sf(atlStorms2005) - -cols = heat.colors(nrow(storms)) - -leaflet() \%>\% - addProviderTiles(provider = providers$CartoDB.Positron) \%>\% - addGlPolylines(data = storms, color = cols, popup = TRUE, opacity = 1) +\note{ +MULTILINESTRINGs and MULTIPOLYGONs are currently not supported! + Make sure you cast your data to LINESTRING or POLYGON first using: + \itemize{ + \item{\code{sf::st_cast(data, "LINESTRING")}} + \item{\code{sf::st_cast(data, "POLYGON")}} + } +} +\section{Shiny Inputs}{ + + The objects created with \code{leafgl} send input values to Shiny as the + user interacts with them. These events follow the pattern + \code{input$MAPID_glify_EVENTNAME}. + The following events are available: + + \itemize{ + \item \strong{Click Events:} + \code{input$MAPID_glify_click} + \item \strong{Mouseover Events:} + \code{input$MAPID_glify_mouseover} + } + + + Each event returns a list containing: + \itemize{ + \item \code{lat}: Latitude of the object or mouse cursor + \item \code{lng}: Longitude of the object or mouse cursor + \item \code{id}: The layerId, if any + \item \code{group}: The group name of the object + \item \code{data}: The properties of the feature + } } -if (interactive()) { +\examples{ +\donttest library(leaflet) library(leafgl) library(sf) n = 1e5 - df1 = data.frame(id = 1:n, x = rnorm(n, 10, 1), y = rnorm(n, 49, 0.8)) pts = st_as_sf(df1, coords = c("x", "y"), crs = 4326) - cols = topo.colors(nrow(pts)) leaflet() \%>\% addProviderTiles(provider = providers$CartoDB.DarkMatter) \%>\% addGlPoints(data = pts, fillColor = cols, popup = TRUE) -} +storms = st_as_sf(atlStorms2005) +cols = heat.colors(nrow(storms)) -if (interactive()) { -library(leaflet) -library(leafgl) -library(sf) +leaflet() \%>\% + addProviderTiles(provider = providers$CartoDB.Positron) \%>\% + addGlPolylines(data = storms, color = cols, popup = TRUE, opacity = 1, preseveDrawingBuffer=TRUE) gadm = st_as_sf(gadmCHE) gadm = st_cast(gadm, "POLYGON") @@ -162,7 +196,6 @@ cols = grey.colors(nrow(gadm)) leaflet() \%>\% addProviderTiles(provider = providers$CartoDB.DarkMatter) \%>\% - addGlPolygons(data = gadm, color = cols, popup = TRUE) -} + addGlPolygons(data = gadm, color = cols, popup = TRUE, preseveDrawingBuffer=TRUE) } From ca4213aaeb689ee812413e7e93c1f50b31fbb167 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Mon, 3 Jun 2024 22:23:16 +0200 Subject: [PATCH 02/14] move JS helper functions to sep file use const/let --- R/glify-helpers.R | 11 ++- inst/htmlwidgets/Leaflet.glify/GlifyUtils.js | 78 +++++++++++++++++ .../Leaflet.glify/addGlifyPoints.js | 30 +++---- .../Leaflet.glify/addGlifyPolygons.js | 86 +++---------------- .../Leaflet.glify/addGlifyPolylines.js | 73 +++------------- man/addGlPoints.Rd | 4 +- 6 files changed, 126 insertions(+), 156 deletions(-) create mode 100644 inst/htmlwidgets/Leaflet.glify/GlifyUtils.js diff --git a/R/glify-helpers.R b/R/glify-helpers.R index 5e33ad0..2d9411c 100644 --- a/R/glify-helpers.R +++ b/R/glify-helpers.R @@ -6,7 +6,8 @@ glifyDependencies = function() { '3.2.0', system.file("htmlwidgets/Leaflet.glify", package = "leafgl"), script = c( - "addGlifyPoints.js" + "GlifyUtils.js" + , "addGlifyPoints.js" , "addGlifyPolygons.js" , "addGlifyPolylines.js" , "glify-browser.js" @@ -23,7 +24,8 @@ glifyDependenciesSrc = function() { '3.2.0', system.file("htmlwidgets/Leaflet.glify", package = "leafgl"), script = c( - "addGlifyPointsSrc.js" + "GlifyUtils.js" + , "addGlifyPointsSrc.js" , "addGlifyPolygonsSrc.js" , "addGlifyPolylinesSrc.js" , "glify-browser.js" @@ -146,10 +148,11 @@ glifyDependenciesFl = function() { '2.2.0', system.file("htmlwidgets/Leaflet.glify", package = "leafgl"), script = c( - "addGlifyPoints.js" + "GlifyUtils.js" + , "addGlifyPoints.js" , "addGlifyPolygonsFl.js" , "addGlifyPolylines.js" - , "glify.js" + , "glify-browser.js" ) ) ) diff --git a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js new file mode 100644 index 0000000..97f07c6 --- /dev/null +++ b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js @@ -0,0 +1,78 @@ +/* global LeafletWidget, Shiny, L */ + +LeafletWidget.methods.removeGlPolylines = function(layerId) { + this.layerManager.removeLayer("glify", layerId); +}; + +LeafletWidget.methods.removeGlPolygons = function(layerId) { + this.layerManager.removeLayer("glify", layerId); +}; + +LeafletWidget.methods.removeGlPoints = function(layerId) { + this.layerManager.removeLayer("glify", layerId); +}; + + +LeafletWidget.methods.clearGlLayers = function() { + this.layerManager.clearLayers("glify"); +}; + +function click_event(e, feature, addpopup, popup, popupOptions, layer, layerId, data, map) { + if (map.hasLayer(layer.layer)) { + const idx = data.features.findIndex(k => k==feature); + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_click", { + id: layerId ? layerId[idx] : idx+1, + group: Object.values(layer.layer._eventParents)[0].groupname, + lat: e.latlng.lat, + lng: e.latlng.lng, + data: feature.properties + }); + } + if (addpopup) { + const content = popup === true ? json2table(feature.properties) : popup[idx].toString(); + + L.popup(popupOptions) + .setLatLng(e.latlng) + .setContent(content) + .openOn(map); + } + } +}; + +function hover_event(e, feature, addlabel, label, layer, tooltip, layerId, data, map) { + if (map.hasLayer(layer.layer)) { + const idx = data.features.findIndex(k => k==feature); + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_mouseover", { + id: layerId ? layerId[idx] : idx+1, + group: Object.values(layer.layer._eventParents)[0].groupname, + lat: e.latlng.lat, + lng: e.latlng.lng, + data: feature.properties + }); + } + if (addlabel) { + const content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : + typeof label === 'string' ? label : null; + tooltip + .setLatLng(e.latlng) + .setContent(content) + .addTo(map); + } + } +} + + +function json2table(json, cls) { + const cols = Object.keys(json); + const vals = Object.values(json); + + let tab = ""; + for (let i = 0; i < cols.length; i++) { + tab += "" + cols[i] + " " + + "" + vals[i] + " "; + } + + return "" + tab + "
"; +} diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js index 9eaf563..6d1fa09 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js @@ -1,3 +1,5 @@ +/* global LeafletWidget, L */ + LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacity, radius, group, layerId, dotOptions, pane, popupOptions, labelOptions) { @@ -5,7 +7,7 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit const map = this; // colors - var clrs; + let clrs; if (cols.length === 1) { clrs = cols[0]; } else { @@ -13,7 +15,7 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit } // radius - var rad; + let rad; if (typeof(radius) === "number") { rad = radius; } else { @@ -21,7 +23,7 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit } // click & hover function - let clickFun = (e, point, xy) => { + const clickFun = (e, point, xy) => { //set up a standalone popup (use a popup as a layer) if (map.hasLayer(pointslayer.layer)) { var idx = data.findIndex(k => k==point); @@ -44,11 +46,11 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit } }; - let tooltip = new L.Tooltip(labelOptions); - var hover_event = function(e, point, addlabel, label) { - var idx = data.findIndex(k => k==point); + const tooltip = new L.Tooltip(labelOptions); + const hover_event = function(e, point, addlabel, label) { //set up a standalone label (use a label as a layer) if (map.hasLayer(pointslayer.layer)) { + var idx = data.findIndex(k => k==point); var content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : typeof label === 'string' ? label : null; if (HTMLWidgets.shinyMode) { @@ -68,15 +70,15 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit } } } - var hvr = function(e, feature) { + const mouseoverFun = function(e, feature) { hover_event(e, feature, label !== null, label); } // arguments for gl layer - var layerArgs = { + const layerArgs = { map: map, click: clickFun, - hover: hvr, + hover: mouseoverFun, data: data, color: clrs, opacity: opacity, @@ -97,17 +99,9 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); // initialize Glify Layer - var pointslayer = L.glify.points(layerArgs); + const pointslayer = L.glify.points(layerArgs); // add layer to map using leaflet's layerManager map.layerManager.addLayer(pointslayer.layer, "glify", layerId, group); }; - -LeafletWidget.methods.removeGlPoints = function(layerId) { - this.layerManager.removeLayer("glify", layerId); -}; - -LeafletWidget.methods.clearGlLayers = function() { - this.layerManager.clearLayers("glify"); -}; \ No newline at end of file diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js index 44bfa3c..86d0f8e 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js @@ -1,11 +1,13 @@ +/* global LeafletWidget, L */ + LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, opacity, group, layerId, dotOptions, pane, stroke, popupOptions, labelOptions) { - var map = this; + const map = this; // colors - var clrs; + let clrs; if (cols.length === 1) { clrs = cols[0]; } else { @@ -13,64 +15,21 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, } // click & hover function - var click_event = function(e, feature, addpopup, popup) { - if (map.hasLayer(shapeslayer.layer)) { - var idx = data.features.findIndex(k => k==feature); - if (HTMLWidgets.shinyMode) { - Shiny.setInputValue(map.id + "_glify_click", { - id: layerId ? layerId[idx] : idx+1, - group: Object.values(shapeslayer.layer._eventParents)[0].groupname, - lat: e.latlng.lat, - lng: e.latlng.lng, - data: feature.properties - }); - } - if (addpopup) { - var content = popup === true ? json2table(feature.properties) : popup[idx].toString(); - - L.popup(popupOptions) - .setLatLng(e.latlng) - .setContent(content) - .openOn(map); - } - } - }; - var clickFun = function (e, feature) { - click_event(e, feature, popup !== null, popup); + const clickFun = function (e, feature) { + click_event(e, feature, popup !== null, popup, popupOptions, shapeslayer, layerId, data, map); }; - let tooltip = new L.Tooltip(labelOptions); - var hover_event = function(e, feature, addlabel, label) { - if (map.hasLayer(shapeslayer.layer)) { - var idx = data.features.findIndex(k => k==feature); - if (HTMLWidgets.shinyMode) { - Shiny.setInputValue(map.id + "_glify_mouseover", { - id: layerId ? layerId[idx] : idx+1, - group: Object.values(shapeslayer.layer._eventParents)[0].groupname, - lat: e.latlng.lat, - lng: e.latlng.lng, - data: feature.properties - }); - } - if (addlabel) { - var content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : - typeof label === 'string' ? label : null; - tooltip - .setLatLng(e.latlng) - .setContent(content) - .addTo(map); - } - } - } - var hvr = function(e, feature) { - hover_event(e, feature, label !== null, label); + const tooltip = new L.Tooltip(labelOptions); + const mouseoverFun = function(e, feature) { + hover_event(e, feature, label !== null, label, shapeslayer, tooltip, + layerId, data, map); } // arguments for gl layer - var layerArgs = { + const layerArgs = { map: map, click: clickFun, - hover: hvr, + hover: mouseoverFun, data: data, color: clrs, opacity: opacity, @@ -83,30 +42,11 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); // initialize Glify Layer - var shapeslayer = L.glify.shapes(layerArgs); + const shapeslayer = L.glify.shapes(layerArgs); // add layer to map using leaflet's layerManager map.layerManager.addLayer(shapeslayer.layer, "glify", layerId, group); }; -LeafletWidget.methods.removeGlPolygons = function(layerId) { - this.layerManager.removeLayer("glify", layerId); -}; - - - -function json2table(json, cls) { - var cols = Object.keys(json); - var vals = Object.values(json); - - var tab = ""; - - for (let i = 0; i < cols.length; i++) { - tab += "" + cols[i] + " " + - "" + vals[i] + " "; - } - - return "" + tab + "
"; -} diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js index 240f5a3..ce53089 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js @@ -1,11 +1,13 @@ +/* global LeafletWidget, L */ + LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, opacity, group, weight, layerId, dotOptions, pane, popupOptions, labelOptions) { - var map = this; + const map = this; // colors - var clrs; + let clrs; if (cols.length === 1) { clrs = cols[0]; } else { @@ -13,7 +15,7 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, } // weight - var wght; + let wght; if (weight.length === undefined) { wght = weight; } else { @@ -21,64 +23,21 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, } // click & hover function - var click_event = function(e, feature, addpopup, popup) { - if (map.hasLayer(lineslayer.layer)) { - var idx = data.features.findIndex(k => k==feature); - if (HTMLWidgets.shinyMode) { - Shiny.setInputValue(map.id + "_glify_click", { - id: layerId ? layerId[idx] : idx+1, - group: Object.values(lineslayer.layer._eventParents)[0].groupname, - lat: e.latlng.lat, - lng: e.latlng.lng, - data: feature.properties - }); - } - if (addpopup) { - var content = popup === true ? json2table(feature.properties) : popup[idx].toString(); - - L.popup(popupOptions) - .setLatLng(e.latlng) - .setContent(content) - .openOn(map); - } - } - }; - var clickFun = function (e, feature) { - click_event(e, feature, popup !== null, popup); + const clickFun = function (e, feature) { + click_event(e, feature, popup !== null, popup, popupOptions, lineslayer, layerId, data, map); }; - let tooltip = new L.Tooltip(labelOptions); - var hover_event = function(e, feature, addlabel, label) { - if (map.hasLayer(lineslayer.layer)) { - var idx = data.features.findIndex(k => k==feature); - if (HTMLWidgets.shinyMode) { - Shiny.setInputValue(map.id + "_glify_mouseover", { - id: layerId ? layerId[idx] : idx+1, - group: Object.values(lineslayer.layer._eventParents)[0].groupname, - lat: e.latlng.lat, - lng: e.latlng.lng, - data: feature.properties - }); - } - if (addlabel) { - var content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : - typeof label === 'string' ? label : null; - tooltip - .setLatLng(e.latlng) - .setContent(content) - .addTo(map); - } - } - } - var hvr = function(e, feature) { - hover_event(e, feature, label !== null, label); + const tooltip = new L.Tooltip(labelOptions); + const mouseoverFun = function(e, feature) { + hover_event(e, feature, label !== null, label, lineslayer, tooltip, + layerId, data, map); } // arguments for gl layer - var layerArgs = { + const layerArgs = { map: map, click: clickFun, - hover: hvr, + hover: mouseoverFun, latitudeKey: 1, longitudeKey: 0, data: data, @@ -93,14 +52,10 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); // initialize Glify Layer - var lineslayer = L.glify.lines(layerArgs); + const lineslayer = L.glify.lines(layerArgs); // add layer to map using leaflet's layerManager map.layerManager.addLayer(lineslayer.layer, "glify", layerId, group); }; -LeafletWidget.methods.removeGlPolylines = function(layerId) { - this.layerManager.removeLayer("glify", layerId); -}; - diff --git a/man/addGlPoints.Rd b/man/addGlPoints.Rd index 2238e81..868c92b 100644 --- a/man/addGlPoints.Rd +++ b/man/addGlPoints.Rd @@ -188,7 +188,7 @@ cols = heat.colors(nrow(storms)) leaflet() \%>\% addProviderTiles(provider = providers$CartoDB.Positron) \%>\% - addGlPolylines(data = storms, color = cols, popup = TRUE, opacity = 1, preseveDrawingBuffer=TRUE) + addGlPolylines(data = storms, color = cols, popup = TRUE, opacity = 1) gadm = st_as_sf(gadmCHE) gadm = st_cast(gadm, "POLYGON") @@ -196,6 +196,6 @@ cols = grey.colors(nrow(gadm)) leaflet() \%>\% addProviderTiles(provider = providers$CartoDB.DarkMatter) \%>\% - addGlPolygons(data = gadm, color = cols, popup = TRUE, preseveDrawingBuffer=TRUE) + addGlPolygons(data = gadm, color = cols, popup = TRUE) } From a100d370880a5027a6a1060e4c92a7d48676bbed Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Wed, 5 Jun 2024 14:31:12 +0200 Subject: [PATCH 03/14] fix remove/clear methods by layerId/group/all Glify, expose new method "clearGlGroup", set active = TRUE/FALSE when hiding/showing, refactor docs --- NAMESPACE | 1 + NEWS | 9 +- R/glify-lines.R | 3 + R/glify-points.R | 4 +- R/glify-polygons.R | 3 + R/glify-remove-clear.R | 33 ++-- inst/htmlwidgets/Leaflet.glify/GlifyUtils.js | 152 ++++++++++++++++-- .../Leaflet.glify/addGlifyPoints.js | 5 +- .../Leaflet.glify/addGlifyPolygons.js | 5 +- .../Leaflet.glify/addGlifyPolylines.js | 5 +- man/addGlPoints.Rd | 8 +- man/clearGlLayers.Rd | 14 -- man/remove.Rd | 36 +++++ man/removeGlPoints.Rd | 16 -- man/removeGlPolygons.Rd | 16 -- man/removeGlPolylines.Rd | 16 -- 16 files changed, 232 insertions(+), 94 deletions(-) delete mode 100644 man/clearGlLayers.Rd create mode 100644 man/remove.Rd delete mode 100644 man/removeGlPoints.Rd delete mode 100644 man/removeGlPolygons.Rd delete mode 100644 man/removeGlPolylines.Rd diff --git a/NAMESPACE b/NAMESPACE index 3af5d6b..a313b03 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -26,6 +26,7 @@ S3method(makePopup,shiny.tag) export(addGlPoints) export(addGlPolygons) export(addGlPolylines) +export(clearGlGroup) export(clearGlLayers) export(leafglOutput) export(makeColorMatrix) diff --git a/NEWS b/NEWS index 5a9e0e9..921bd22 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,11 @@ leafgl 0.2.1.9005 (2023-09-08) features and improvements + * New method *clearGlGroup* removes a group from leaflet and the Leaflet.Glify instances. + * The JavaScript methods of the `removeGl**` functions was rewritten to correctly remove an element identified by `layerId` + * `clearGlLayers` now correctly removes all Leaflet.Glify instances + * When showing/hiding Leaflet.Glify layers, they are set to active = TRUE/FALSE to make mouseevents work again. #48, #50 + bug fixes * src version now works also in shiny. #71 @@ -9,12 +14,12 @@ bug fixes * added `stroke` (default=TRUE) in `addGlPolygons` and `addGlPolygonsSrc` for drawing borders. #3 * Labels work similar to `leaflet`. `leafgl` accepts a single string, a vector of strings or a formula. #78 * The `...` arguments are now passed to all methods in the underlying library. This allows us to set - additional arguments like `fragmentShaderSource`, sensitivity` or `sensitivityHover`. + additional arguments like `fragmentShaderSource`, `sensitivity` or `sensitivityHover`. documentation etc * Added some @details for Shiny click and mouseover events and their corresponding input. #77 - * Using `@inheritParams leaflet::addPolylines` instead of writing the documentation on our own. + * Use `@inheritParams leaflet::**` for identical function arguments miscellaneous diff --git a/R/glify-lines.R b/R/glify-lines.R index c48b475..9c3a4f4 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -1,4 +1,7 @@ #' @examples +#' library(leaflet) +#' library(sf) +#' #' storms = st_as_sf(atlStorms2005) #' cols = heat.colors(nrow(storms)) #' diff --git a/R/glify-points.R b/R/glify-points.R index e2eb3f3..c80947c 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -67,7 +67,7 @@ #' #' @describeIn addGlPoints Add Points to a leaflet map using Leaflet.glify #' @order 1 -#' @examples \donttest +#' @examples \donttest{ #' library(leaflet) #' library(leafgl) #' library(sf) @@ -82,7 +82,7 @@ #' leaflet() %>% #' addProviderTiles(provider = providers$CartoDB.DarkMatter) %>% #' addGlPoints(data = pts, fillColor = cols, popup = TRUE) -#' +#' } #' @export addGlPoints addGlPoints = function(map, data, diff --git a/R/glify-polygons.R b/R/glify-polygons.R index 56947ee..be06093 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -1,4 +1,7 @@ #' @examples +#' library(leaflet) +#' library(sf) +#' #' gadm = st_as_sf(gadmCHE) #' gadm = st_cast(gadm, "POLYGON") #' cols = grey.colors(nrow(gadm)) diff --git a/R/glify-remove-clear.R b/R/glify-remove-clear.R index 291444f..534009c 100644 --- a/R/glify-remove-clear.R +++ b/R/glify-remove-clear.R @@ -1,35 +1,38 @@ -#' removeGlPoints -#' @description Remove points from a map, identified by layerId; -#' @param map The map widget -#' @param layerId The layerId to remove +#' Remove Leaflet.Glify elements from a map +#' +#' Remove one or more features from a map, identified by `layerId`; +#' or, clear all features of the given group. +#' +#' @inheritParams leaflet::removeShape +#' @return the new `map` object +#' +#' @name remove #' @export removeGlPoints <- function(map, layerId) { leaflet::invokeMethod(map, NULL, "removeGlPoints", layerId) } -#' removeGlPolylines -#' @description Remove lines from a map, identified by layerId; -#' @param map The map widget -#' @param layerId The layerId to remove +#' @rdname remove #' @export removeGlPolylines <- function(map, layerId) { leaflet::invokeMethod(map, NULL, "removeGlPolylines", layerId) } -#' removeGlPolygons -#' @description Remove polygons from a map, identified by layerId; -#' @param map The map widget -#' @param layerId The layerId to remove +#' @rdname remove #' @export removeGlPolygons <- function(map, layerId) { leaflet::invokeMethod(map, NULL, "removeGlPolygons", layerId) } -#' clearGlLayers -#' @description Clear all Glify features -#' @param map The map widget +#' @rdname remove #' @export clearGlLayers <- function(map) { leaflet::invokeMethod(map, NULL, "clearGlLayers") } +#' @rdname remove +#' @export +clearGlGroup <- function(map, group) { + leaflet::invokeMethod(map, NULL, "clearGlGroup", group) +} + diff --git a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js index 97f07c6..30bb5bf 100644 --- a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js +++ b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js @@ -1,22 +1,153 @@ /* global LeafletWidget, Shiny, L */ + +// Remove elements by `layerId` LeafletWidget.methods.removeGlPolylines = function(layerId) { - this.layerManager.removeLayer("glify", layerId); + let insts = L.glify.linesInstances; + for(i in insts){ + let layId = insts[i].settings.layerId; + if (layId) { + let idx = layId.findIndex(k => k==layerId); + if (idx !== -1) { + insts[i].remove(idx); + insts[i].settings.layerId.splice(idx, 1); + } + } + } }; - LeafletWidget.methods.removeGlPolygons = function(layerId) { - this.layerManager.removeLayer("glify", layerId); + let insts = L.glify.shapesInstances; + for (i in insts) { + let layId = insts[i].settings.layerId; + if (layId) { + let idx = layId.findIndex(k => k==layerId); + if (idx !== -1) { + insts[i].remove(idx); + insts[i].settings.layerId.splice(idx, 1); + } + } + } }; - LeafletWidget.methods.removeGlPoints = function(layerId) { - this.layerManager.removeLayer("glify", layerId); + let insts = L.glify.pointsInstances; + for(i in insts){ + let layId = insts[i].settings.layerId; + if (layId) { + let idx = layId.findIndex(k => k==layerId); + if (idx !== -1) { + insts[i].remove(idx); + insts[i].settings.layerId.splice(idx, 1); + } + } + } }; - +// Remove all Glify elements or by Group LeafletWidget.methods.clearGlLayers = function() { + let arr = L.glify.shapesInstances; + for( let i = 0; i < arr.length; i++){ + arr[i].settings.map.off("mousemove"); + arr[i].remove(); + } + arr.splice(0, arr.length) + + arr = L.glify.linesInstances; + for( let i = 0; i < arr.length; i++){ + arr[i].settings.map.off("mousemove"); + arr[i].remove(); + } + arr.splice(0, arr.length) + + arr = L.glify.pointsInstances; + for( let i = 0; i < arr.length; i++){ + arr[i].settings.map.off("mousemove"); + arr[i].remove(); + } + arr.splice(0, arr.length) + this.layerManager.clearLayers("glify"); }; +LeafletWidget.methods.clearGlGroup = function(group) { + const formats = ['linesInstances', 'pointsInstances', 'shapesInstances']; + $.each(asArray(group), (j, v) => { + formats.forEach(format => { + let arr = L.glify[format]; + for( let i = 0; i < arr.length; i++){ + if ( arr[i].settings.className === group) { + arr[i].settings.map.off("mousemove"); + arr[i].remove(); + arr.splice(i, 1); + } + } + }); + this.layerManager.clearGroup(v); + }); +}; + + +// Workaround to set 'active' to TRUE / FALSE, when a layer is shown/hidden via the layerControl +function addGlifyEventListeners (map) { + if (!map.hasEventListeners("overlayadd")) { + map.on("overlayadd", function(e) { + let leafid = Object.keys(e.layer._layers)[0]; // L.stamp(e.layer) is not the same; + let glifylayer = this.layerManager._byCategory.glify[leafid] + if (glifylayer) { + let glifyinstance = L.glify.instances.find(e => e.layer._leaflet_id == leafid); + if (glifyinstance) { + //console.log("glifyinstance TRUE"); console.log(glifyinstance) + glifyinstance.active = true; + } + } + }); + } + if (!map.hasEventListeners("overlayremove")) { + map.on("overlayremove", function(e) { + let leafid = Object.keys(e.layer._layers)[0]; // L.stamp(e.layer) is not the same; + let glifylayer = this.layerManager._byCategory.glify[leafid] + if (glifylayer) { + let glifyinstance = L.glify.instances.find(e => e.layer._leaflet_id == leafid); + if (glifyinstance) { + //console.log("glifyinstance FALSE"); console.log(glifyinstance) + glifyinstance.active = false; + } + } + }); + } +}; + +// Adapt Leaflet hide/showGroup methods, to set active = TRUE/FALSE for Glify objects. +var origHideFun = LeafletWidget.methods.hideGroup; +LeafletWidget.methods.hideGroup = function(group) { + const map = this; + $.each(asArray(group), (i, g) => { + // Set Glify Instances to false + L.glify.instances.forEach(e => { + if (e.settings.className === g) { + e.active = false; + } + }); + // Remove Layer from Leaflet + origHideFun.call(this, group) + }); +}; +var origShowFun = LeafletWidget.methods.showGroup; +LeafletWidget.methods.showGroup = function(group) { + const map = this; + $.each(asArray(group), (i, g) => { + // Set Glify Instances to true + L.glify.instances.forEach(e => { + if (e.settings.className === g) { + e.active = true; + } + }); + // Add Layer to Leaflet + origShowFun.call(this, group) + }); +}; + + +// Helper Functions function click_event(e, feature, addpopup, popup, popupOptions, layer, layerId, data, map) { if (map.hasLayer(layer.layer)) { const idx = data.features.findIndex(k => k==feature); @@ -39,7 +170,6 @@ function click_event(e, feature, addpopup, popup, popupOptions, layer, layerId, } } }; - function hover_event(e, feature, addlabel, label, layer, tooltip, layerId, data, map) { if (map.hasLayer(layer.layer)) { const idx = data.features.findIndex(k => k==feature); @@ -62,8 +192,6 @@ function hover_event(e, feature, addlabel, label, layer, tooltip, layerId, data, } } } - - function json2table(json, cls) { const cols = Object.keys(json); const vals = Object.values(json); @@ -76,3 +204,9 @@ function json2table(json, cls) { return "" + tab + "
"; } +function asArray(value) { + if (value instanceof Array) + return value; + else + return [value]; +} diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js index 6d1fa09..e7afc85 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js @@ -84,7 +84,8 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit opacity: opacity, size: rad, className: group, - pane: pane + pane: pane, + layerId: layerId }; // extract correct fragmentShaderSource if provided via dotOptions @@ -103,5 +104,7 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit // add layer to map using leaflet's layerManager map.layerManager.addLayer(pointslayer.layer, "glify", layerId, group); + + addGlifyEventListeners(map) }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js index 86d0f8e..c0b0f54 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js @@ -35,7 +35,8 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, opacity: opacity, className: group, border: stroke, - pane: pane + pane: pane, + layerId: layerId }; // append dotOptions to layer arguments @@ -46,6 +47,8 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, // add layer to map using leaflet's layerManager map.layerManager.addLayer(shapeslayer.layer, "glify", layerId, group); + + addGlifyEventListeners(map) }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js index ce53089..954b0f2 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js @@ -45,7 +45,8 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, opacity: opacity, className: group, weight: wght, - pane: pane + pane: pane, + layerId: layerId }; // append dotOptions to layer arguments @@ -56,6 +57,8 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, // add layer to map using leaflet's layerManager map.layerManager.addLayer(lineslayer.layer, "glify", layerId, group); + + addGlifyEventListeners(map) }; diff --git a/man/addGlPoints.Rd b/man/addGlPoints.Rd index 868c92b..bc6b477 100644 --- a/man/addGlPoints.Rd +++ b/man/addGlPoints.Rd @@ -167,7 +167,7 @@ MULTILINESTRINGs and MULTIPOLYGONs are currently not supported! } \examples{ -\donttest +\donttest{ library(leaflet) library(leafgl) library(sf) @@ -182,6 +182,9 @@ cols = topo.colors(nrow(pts)) leaflet() \%>\% addProviderTiles(provider = providers$CartoDB.DarkMatter) \%>\% addGlPoints(data = pts, fillColor = cols, popup = TRUE) +} +library(leaflet) +library(sf) storms = st_as_sf(atlStorms2005) cols = heat.colors(nrow(storms)) @@ -190,6 +193,9 @@ leaflet() \%>\% addProviderTiles(provider = providers$CartoDB.Positron) \%>\% addGlPolylines(data = storms, color = cols, popup = TRUE, opacity = 1) +library(leaflet) +library(sf) + gadm = st_as_sf(gadmCHE) gadm = st_cast(gadm, "POLYGON") cols = grey.colors(nrow(gadm)) diff --git a/man/clearGlLayers.Rd b/man/clearGlLayers.Rd deleted file mode 100644 index 9426cef..0000000 --- a/man/clearGlLayers.Rd +++ /dev/null @@ -1,14 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/glify-remove-clear.R -\name{clearGlLayers} -\alias{clearGlLayers} -\title{clearGlLayers} -\usage{ -clearGlLayers(map) -} -\arguments{ -\item{map}{The map widget} -} -\description{ -Clear all Glify features -} diff --git a/man/remove.Rd b/man/remove.Rd new file mode 100644 index 0000000..c1421e2 --- /dev/null +++ b/man/remove.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/glify-remove-clear.R +\name{remove} +\alias{remove} +\alias{removeGlPoints} +\alias{removeGlPolylines} +\alias{removeGlPolygons} +\alias{clearGlLayers} +\alias{clearGlGroup} +\title{Remove Leaflet.Glify elements from a map} +\usage{ +removeGlPoints(map, layerId) + +removeGlPolylines(map, layerId) + +removeGlPolygons(map, layerId) + +clearGlLayers(map) + +clearGlGroup(map, group) +} +\arguments{ +\item{map}{a map widget object, possibly created from \code{\link[leaflet:leaflet]{leaflet()}} +but more likely from \code{\link[leaflet:leafletProxy]{leafletProxy()}}} + +\item{layerId}{character vector; the layer id(s) of the item to remove} + +\item{group}{the name of the group whose members should be removed} +} +\value{ +the new `map` object +} +\description{ +Remove one or more features from a map, identified by `layerId`; +or, clear all features of the given group. +} diff --git a/man/removeGlPoints.Rd b/man/removeGlPoints.Rd deleted file mode 100644 index 8599f4d..0000000 --- a/man/removeGlPoints.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/glify-remove-clear.R -\name{removeGlPoints} -\alias{removeGlPoints} -\title{removeGlPoints} -\usage{ -removeGlPoints(map, layerId) -} -\arguments{ -\item{map}{The map widget} - -\item{layerId}{The layerId to remove} -} -\description{ -Remove points from a map, identified by layerId; -} diff --git a/man/removeGlPolygons.Rd b/man/removeGlPolygons.Rd deleted file mode 100644 index c72c3e2..0000000 --- a/man/removeGlPolygons.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/glify-remove-clear.R -\name{removeGlPolygons} -\alias{removeGlPolygons} -\title{removeGlPolygons} -\usage{ -removeGlPolygons(map, layerId) -} -\arguments{ -\item{map}{The map widget} - -\item{layerId}{The layerId to remove} -} -\description{ -Remove polygons from a map, identified by layerId; -} diff --git a/man/removeGlPolylines.Rd b/man/removeGlPolylines.Rd deleted file mode 100644 index 437c580..0000000 --- a/man/removeGlPolylines.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/glify-remove-clear.R -\name{removeGlPolylines} -\alias{removeGlPolylines} -\title{removeGlPolylines} -\usage{ -removeGlPolylines(map, layerId) -} -\arguments{ -\item{map}{The map widget} - -\item{layerId}{The layerId to remove} -} -\description{ -Remove lines from a map, identified by layerId; -} From 11358587b86cce4550b41e062888e100c627105f Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Wed, 5 Jun 2024 15:03:20 +0200 Subject: [PATCH 04/14] fix: allow layerId to be formula --- NAMESPACE | 1 + R/glify-lines.R | 3 +++ R/glify-points.R | 3 +++ R/glify-polygons.R | 3 +++ R/glify-shiny.R | 4 +--- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index a313b03..75bad7e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -38,5 +38,6 @@ export(renderLeafgl) importFrom(htmltools,htmlDependencies) importFrom(htmltools,tagList) importFrom(htmltools,tags) +importFrom(leaflet,evalFormula) importFrom(leaflet,leafletOutput) importFrom(leaflet,renderLeaflet) diff --git a/R/glify-lines.R b/R/glify-lines.R index 9c3a4f4..0fe02d1 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -33,6 +33,9 @@ addGlPolylines = function(map, dotopts = list(...) + if (!is.null(layerId) && inherits(layerId, "formula")) + layerId <- evalFormula(layerId, data) + if (isTRUE(src)) { m = addGlPolylinesSrc( map = map diff --git a/R/glify-points.R b/R/glify-points.R index c80947c..2040828 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -104,6 +104,9 @@ addGlPoints = function(map, dotopts = list(...) + if (!is.null(layerId) && inherits(layerId, "formula")) + layerId <- evalFormula(layerId, data) + if (isTRUE(src)) { m = addGlPointsSrc( map = map diff --git a/R/glify-polygons.R b/R/glify-polygons.R index be06093..2f12375 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -35,6 +35,9 @@ addGlPolygons = function(map, dotopts = list(...) + if (!is.null(layerId) && inherits(layerId, "formula")) + layerId <- evalFormula(layerId, data) + if (isTRUE(src)) { m = addGlPolygonsSrc( map = map diff --git a/R/glify-shiny.R b/R/glify-shiny.R index 90ee686..82d06d1 100644 --- a/R/glify-shiny.R +++ b/R/glify-shiny.R @@ -11,7 +11,7 @@ #' #' @return A UI for rendering leafgl #' -#' @importFrom leaflet leafletOutput +#' @importFrom leaflet leafletOutput renderLeaflet evalFormula #' @importFrom htmltools tagList tags htmlDependencies #' @rdname glify-shiny #' @export @@ -56,8 +56,6 @@ leafglOutput <- function(outputId, width = "100%", height = 400){ # Just for consistency # -#' @importFrom leaflet renderLeaflet -#' #' @param expr An expression that generates an HTML widget #' @param env The environment in which to evaluate expr. #' @param quoted Is expr a quoted expression (with quote())? From e6dbde3f56ff83cad86a3098686e890683489074 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Wed, 5 Jun 2024 15:11:40 +0200 Subject: [PATCH 05/14] move imports to separate pkg-file --- R/glify-shiny.R | 2 -- R/leafgl_package.R | 9 +++++++++ man/leafgl-package.Rd | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 R/leafgl_package.R create mode 100644 man/leafgl-package.Rd diff --git a/R/glify-shiny.R b/R/glify-shiny.R index 82d06d1..2f3fdd5 100644 --- a/R/glify-shiny.R +++ b/R/glify-shiny.R @@ -11,8 +11,6 @@ #' #' @return A UI for rendering leafgl #' -#' @importFrom leaflet leafletOutput renderLeaflet evalFormula -#' @importFrom htmltools tagList tags htmlDependencies #' @rdname glify-shiny #' @export #' diff --git a/R/leafgl_package.R b/R/leafgl_package.R new file mode 100644 index 0000000..b103af3 --- /dev/null +++ b/R/leafgl_package.R @@ -0,0 +1,9 @@ + +#' @keywords internal +"_PACKAGE" + +## usethis namespace: start +#' @importFrom leaflet leafletOutput renderLeaflet evalFormula +#' @importFrom htmltools tagList tags htmlDependencies +## usethis namespace: end +NULL diff --git a/man/leafgl-package.Rd b/man/leafgl-package.Rd new file mode 100644 index 0000000..fa79b79 --- /dev/null +++ b/man/leafgl-package.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/leafgl_package.R +\docType{package} +\name{leafgl-package} +\alias{leafgl} +\alias{leafgl-package} +\title{leafgl: High-Performance 'WebGl' Rendering for Package 'leaflet'} +\description{ +Provides bindings to the 'Leaflet.glify' JavaScript library which extends the 'leaflet' JavaScript library to render large data in the browser using 'WebGl'. +} +\author{ +\strong{Maintainer}: Tim Appelhans \email{tim.appelhans@gmail.com} [copyright holder] + +Other contributors: +\itemize{ + \item Colin Fay \email{colin@thinkr.fr} (\href{https://orcid.org/0000-0001-7343-1846}{ORCID}) [contributor] + \item Robert Plummer (Leaflet.glify plugin) [contributor] + \item Kent Johnson \email{kjohnson@akoyabio.com} [contributor] + \item Sebastian Gatscha \email{sebastian_gatscha@gmx.at} [contributor] +} + +} +\keyword{internal} From 806bb8fc47ea726c440192b9c6649a2ffc83b04c Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Sat, 8 Jun 2024 10:42:38 +0200 Subject: [PATCH 06/14] fix labels/popup for *Src functions, move Point click/Hover Functions, refactor --- R/glify-helpers.R | 12 ++ R/glify-lines.R | 121 ++++++++++-------- R/glify-points.R | 104 ++++++++------- R/glify-polygons.R | 101 +++++++++------ inst/htmlwidgets/Leaflet.glify/GlifyUtils.js | 46 ++++++- .../Leaflet.glify/addGlifyPoints.js | 58 ++------- .../Leaflet.glify/addGlifyPointsSrc.js | 90 ++++++++----- .../Leaflet.glify/addGlifyPolygons.js | 1 - .../Leaflet.glify/addGlifyPolygonsSrc.js | 77 ++++++----- .../Leaflet.glify/addGlifyPolylines.js | 1 - .../Leaflet.glify/addGlifyPolylinesSrc.js | 78 ++++++----- 11 files changed, 406 insertions(+), 283 deletions(-) diff --git a/R/glify-helpers.R b/R/glify-helpers.R index 2d9411c..e92cb8b 100644 --- a/R/glify-helpers.R +++ b/R/glify-helpers.R @@ -83,6 +83,18 @@ glifyPopupAttachmentSrc = function(fl_popup, group) { ) ) } +glifyLabelAttachmentSrc = function(fl_popup, group) { + data_dir <- dirname(fl_popup) + data_file <- basename(fl_popup) + list( + htmltools::htmlDependency( + name = paste0(group, "lab"), + version = 1, + src = c(file = data_dir), + script = list(data_file) + ) + ) +} glifyRadiusAttachmentSrc = function(fl_radius, group) { data_dir <- dirname(fl_radius) diff --git a/R/glify-lines.R b/R/glify-lines.R index 0fe02d1..6f94b11 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -28,14 +28,24 @@ addGlPolylines = function(map, labelOptions = NULL, ...) { + # check data ########## if (missing(labelOptions)) labelOptions <- labelOptions() if (missing(popupOptions)) popupOptions <- popupOptions() - dotopts = list(...) + if (is.null(group)) group = deparse(substitute(data)) + if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) + stopifnot(inherits(sf::st_geometry(data), c("sfc_LINESTRING", "sfc_MULTILINESTRING"))) + if (inherits(sf::st_geometry(data), "sfc_MULTILINESTRING")) + stop("Can only handle LINESTRINGs, please cast your MULTILINESTRING to LINESTRING using sf::st_cast", + call. = FALSE) if (!is.null(layerId) && inherits(layerId, "formula")) layerId <- evalFormula(layerId, data) + ## currently leaflet.glify only supports single (fill)opacity! + opacity = opacity[1] + + # call SRC function ############## if (isTRUE(src)) { m = addGlPolylinesSrc( map = map @@ -44,8 +54,10 @@ addGlPolylines = function(map, , opacity = opacity , group = group , popup = popup + , label = label , weight = weight , layerId = layerId + , pane = pane , popupOptions = popupOptions , labelOptions = labelOptions , ... @@ -53,19 +65,11 @@ addGlPolylines = function(map, return(m) } - ## currently leaflet.glify only supports single (fill)opacity! - opacity = opacity[1] - - if (is.null(group)) group = deparse(substitute(data)) - if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) - stopifnot(inherits(sf::st_geometry(data), c("sfc_LINESTRING", "sfc_MULTILINESTRING"))) - if (inherits(sf::st_geometry(data), "sfc_MULTILINESTRING")) - stop("Can only handle LINESTRINGs, please cast your MULTILINESTRING to LINESTRING using sf::st_cast", - call. = FALSE) - + # get Bounds and ... ################# + dotopts = list(...) bounds = as.numeric(sf::st_bbox(data)) - # color + # color ######## palette = "viridis" if ("palette" %in% names(dotopts)) { palette <- dotopts$palette @@ -77,7 +81,7 @@ addGlPolylines = function(map, colnames(color) = c("r", "g", "b") cols = jsonify::to_json(color, digits = 3) - # label / popup + # label / popup ######## labels <- leaflet::evalFormula(label, data) if (is.null(popup)) { geom = sf::st_geometry(data) @@ -98,7 +102,7 @@ addGlPolylines = function(map, data = sf::st_sf(id = 1:length(geom), geometry = geom) } - # data + # data ######## if (length(dotopts) == 0) { geojsonsf_args = NULL } else { @@ -118,7 +122,7 @@ addGlPolylines = function(map, # dependencies map$dependencies = c(map$dependencies, glifyDependencies()) - # invoke leaflet method and zoom to bounds + # invoke leaflet method and zoom to bounds ######## map = leaflet::invokeMethod( map , leaflet::getMapData(map) @@ -152,6 +156,7 @@ addGlPolylinesSrc = function(map, opacity = 0.8, group = "glpolygons", popup = NULL, + label = NULL, weight = 1, layerId = NULL, pane = "overlayPane", @@ -159,38 +164,33 @@ addGlPolylinesSrc = function(map, labelOptions = NULL, ...) { - if (is.null(group)) group = deparse(substitute(data)) - if (is.null(layerId)) layerId = paste0(group, "-lns") - if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) - stopifnot(inherits(sf::st_geometry(data), c("sfc_LINESTRING", "sfc_MULTILINESTRING"))) - if (inherits(sf::st_geometry(data), "sfc_MULTILINESTRING")) - stop("Can only handle LINESTRINGs, please cast your MULTILINESTRING ", - "to LINESTRING using e.g. sf::st_cast") - + # get Bounds and ... ################# + dotopts = list(...) bounds = as.numeric(sf::st_bbox(data)) - # temp directories + # temp directories ############ dir_data = tempfile(pattern = "glify_polylines_dat") dir.create(dir_data) dir_color = tempfile(pattern = "glify_polylines_col") dir.create(dir_color) - dir_popup = tempfile(pattern = "glify_polylines_pop") - dir.create(dir_popup) dir_weight = tempfile(pattern = "glify_polylines_wgt") dir.create(dir_weight) + dir_popup = tempfile(pattern = "glify_polylines_pop") + dir.create(dir_popup) + dir_labels = tempfile(pattern = "glify_polylines_labl") + dir.create(dir_labels) - # data + # data ############ data_orig <- data geom = sf::st_geometry(data) data = sf::st_sf(id = 1:length(geom), geometry = geom) - ell_args <- list(...) - fl_data = paste0(dir_data, "/", layerId, "_data.js") - pre = paste0('var data = data || {}; data["', layerId, '"] = ') + fl_data = paste0(dir_data, "/", group, "_data.js") + pre = paste0('var data = data || {}; data["', group, '"] = ') writeLines(pre, fl_data) jsonify_args = try( match.arg( - names(ell_args) + names(dotopts) , names(as.list(args(geojsonsf::sf_geojson))) , several.ok = TRUE ) @@ -198,41 +198,56 @@ addGlPolylinesSrc = function(map, ) if (inherits(jsonify_args, "try-error")) jsonify_args = NULL if (identical(jsonify_args, "sf")) jsonify_args = NULL - cat('[', do.call(geojsonsf::sf_geojson, c(list(data), ell_args[jsonify_args])), '];', + cat('[', do.call(geojsonsf::sf_geojson, c(list(data), dotopts[jsonify_args])), '];', file = fl_data, sep = "", append = TRUE) map$dependencies = c( map$dependencies, glifyDependenciesSrc(), - glifyDataAttachmentSrc(fl_data, layerId) + glifyDataAttachmentSrc(fl_data, group) ) - # color + # color ############ palette = "viridis" - if ("palette" %in% names(ell_args)) { - palette <- ell_args$palette + if ("palette" %in% names(dotopts)) { + palette <- dotopts$palette + dotopts$palette = NULL } color <- makeColorMatrix(color, data_orig, palette = palette) if (ncol(color) != 3) stop("only 3 column color matrix supported so far") color = as.data.frame(color, stringsAsFactors = FALSE) colnames(color) = c("r", "g", "b") - if (nrow(color) > 1) { - fl_color = paste0(dir_color, "/", layerId, "_color.js") - pre = paste0('var col = col || {}; col["', layerId, '"] = ') + fl_color = paste0(dir_color, "/", group, "_color.js") + pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) cat('[', jsonify::to_json(color), '];', file = fl_color, append = TRUE) map$dependencies = c( map$dependencies, - glifyColorAttachmentSrc(fl_color, layerId) + glifyColorAttachmentSrc(fl_color, group) ) - color = NULL } - # popup + # labels ############ + if (!is.null(label)) { + labels <- leaflet::evalFormula(label, data_orig) + fl_label = paste0(dir_labels, "/", group, "_label.js") + pre = paste0('var labs = labs || {}; labs["', group, '"] = ') + writeLines(pre, fl_label) + cat('[', jsonify::to_json(labels), '];', + file = fl_label, append = TRUE) + + map$dependencies = c( + map$dependencies, + glifyLabelAttachmentSrc(fl_label, group) + ) + label = NULL + } + + # popup ############ if (!is.null(popup)) { htmldeps <- htmltools::htmlDependencies(popup) if (length(htmldeps) != 0) { @@ -242,44 +257,45 @@ addGlPolylinesSrc = function(map, ) } popup = makePopup(popup, data_orig) - fl_popup = paste0(dir_popup, "/", layerId, "_popup.js") - pre = paste0('var popup = popup || {}; popup["', layerId, '"] = ') + fl_popup = paste0(dir_popup, "/", group, "_popup.js") + pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) cat('[', jsonify::to_json(popup), '];', file = fl_popup, append = TRUE) map$dependencies = c( map$dependencies, - glifyPopupAttachmentSrc(fl_popup, layerId) + glifyPopupAttachmentSrc(fl_popup, group) ) - + popup = NULL } - # weight + # weight ############ if (length(unique(weight)) > 1) { - fl_weight = paste0(dir_weight, "/", layerId, "_weight.js") - pre = paste0('var wgt = wgt || {}; wgt["', layerId, '"] = ') + fl_weight = paste0(dir_weight, "/", group, "_weight.js") + pre = paste0('var wgt = wgt || {}; wgt["', group, '"] = ') writeLines(pre, fl_weight) cat('[', jsonify::to_json(weight), '];', file = fl_weight, append = TRUE) map$dependencies = c( map$dependencies, - glifyRadiusAttachmentSrc(fl_weight, layerId) + glifyRadiusAttachmentSrc(fl_weight, group) ) - weight = NULL } + # invoke method ########### map = leaflet::invokeMethod( map , leaflet::getMapData(map) , 'addGlifyPolylinesSrc' , color - , weight , opacity , group + , weight , layerId + , dotopts , pane , popupOptions , labelOptions @@ -292,4 +308,3 @@ addGlPolylinesSrc = function(map, ) } - diff --git a/R/glify-points.R b/R/glify-points.R index 2040828..e192be3 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -99,14 +99,21 @@ addGlPoints = function(map, labelOptions = NULL, ...) { + # check data ########## if (missing(labelOptions)) labelOptions <- labelOptions() if (missing(popupOptions)) popupOptions <- popupOptions() - dotopts = list(...) + if (is.null(group)) group = deparse(substitute(data)) + if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) + stopifnot(inherits(sf::st_geometry(data), c("sfc_POINT", "sfc_MULTIPOINT"))) if (!is.null(layerId) && inherits(layerId, "formula")) layerId <- evalFormula(layerId, data) + ## currently leaflet.glify only supports single (fill)opacity! + fillOpacity = fillOpacity[1] + + # call SRC function ############## if (isTRUE(src)) { m = addGlPointsSrc( map = map @@ -116,6 +123,7 @@ addGlPoints = function(map, , radius = radius , group = group , popup = popup + , label = label , layerId = layerId , pane = pane , popupOptions = popupOptions @@ -125,16 +133,11 @@ addGlPoints = function(map, return(m) } - ## currently leaflet.glify only supports single (fill)opacity! - fillOpacity = fillOpacity[1] - - if (is.null(group)) group = deparse(substitute(data)) - if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) - stopifnot(inherits(sf::st_geometry(data), c("sfc_POINT", "sfc_MULTIPOINT"))) - + # get Bounds and ... ################# + dotopts = list(...) bounds = as.numeric(sf::st_bbox(data)) - # fillColor + # fillColor ########### palette = "viridis" if ("palette" %in% names(dotopts)) { palette <- dotopts$palette @@ -146,7 +149,7 @@ addGlPoints = function(map, colnames(fillColor) = c("r", "g", "b") fillColor = jsonify::to_json(fillColor) - # label / popup + # label / popup ########### labels <- leaflet::evalFormula(label, data) if (!is.null(popup)) { htmldeps <- htmltools::htmlDependencies(popup) @@ -162,7 +165,7 @@ addGlPoints = function(map, popup = NULL } - # data + # data ########### crds = sf::st_coordinates(data)[, c(2, 1)] if (length(dotopts) == 0) { jsonify_args = NULL @@ -182,7 +185,7 @@ addGlPoints = function(map, # dependencies map$dependencies = c(map$dependencies, glifyDependencies()) - # invoke leaflet method and zoom to bounds + # invoke leaflet method and zoom to bounds ########### map = leaflet::invokeMethod( map , leaflet::getMapData(map) @@ -217,23 +220,18 @@ addGlPointsSrc = function(map, radius = 10, group = "glpoints", popup = NULL, + label = NULL, layerId = NULL, pane = "overlayPane", popupOptions = NULL, labelOptions = NULL, ...) { - ## currently leaflet.glify only supports single (fill)opacity! - fillOpacity = fillOpacity[1] - - if (is.null(group)) group = deparse(substitute(data)) - if (is.null(layerId)) layerId = paste0(group, "-pts") - if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) - stopifnot(inherits(sf::st_geometry(data), c("sfc_POINT", "sfc_MULTIPOINT"))) - + # get Bounds and ... ################# + dotopts = list(...) bounds = as.numeric(sf::st_bbox(data)) - # temp directories + # temp directories ############ dir_data = tempfile(pattern = "glify_points_dat") dir.create(dir_data) dir_color = tempfile(pattern = "glify_points_col") @@ -242,38 +240,40 @@ addGlPointsSrc = function(map, dir.create(dir_popup) dir_radius = tempfile(pattern = "glify_points_rad") dir.create(dir_radius) + dir_labels = tempfile(pattern = "glify_polylines_labl") + dir.create(dir_labels) - # data + # data ############ # data = sf::st_transform(data, 4326) crds = sf::st_coordinates(data)[, c(2, 1)] - ell_args <- list(...) - fl_data = paste0(dir_data, "/", layerId, "_data.js") - pre = paste0('var data = data || {}; data["', layerId, '"] = ') + fl_data = paste0(dir_data, "/", group, "_data.js") + pre = paste0('var data = data || {}; data["', group, '"] = ') writeLines(pre, fl_data) jsonify_args = try( match.arg( - names(ell_args) - , names(as.list(args(jsonify::to_json))) + names(dotopts) + , names(as.list(args(json_funccall))) , several.ok = TRUE ) , silent = TRUE ) if (inherits(jsonify_args, "try-error")) jsonify_args = NULL if (identical(jsonify_args, "x")) jsonify_args = NULL - cat('[', do.call(jsonify::to_json, c(list(crds), ell_args[jsonify_args])), '];', + cat('[', do.call(json_funccall(), c(list(crds), dotopts[jsonify_args])), '];', file = fl_data, sep = "", append = TRUE) map$dependencies = c( map$dependencies, glifyDependenciesSrc(), - glifyDataAttachmentSrc(fl_data, layerId) + glifyDataAttachmentSrc(fl_data, group) ) - # color + # color ############ palette = "viridis" - if ("palette" %in% names(ell_args)) { - palette <- ell_args$palette + if ("palette" %in% names(dotopts)) { + palette <- dotopts$palette + dotopts$palette = NULL } fillColor <- makeColorMatrix(fillColor, data, palette = palette) if (ncol(fillColor) != 3) stop("only 3 column fillColor matrix supported so far") @@ -281,21 +281,36 @@ addGlPointsSrc = function(map, colnames(fillColor) = c("r", "g", "b") if (nrow(fillColor) > 1) { - fl_color = paste0(dir_color, "/", layerId, "_color.js") - pre = paste0('var col = col || {}; col["', layerId, '"] = ') + fl_color = paste0(dir_color, "/", group, "_color.js") + pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) cat('[', jsonify::to_json(fillColor), '];', file = fl_color, append = TRUE) map$dependencies = c( map$dependencies, - glifyColorAttachmentSrc(fl_color, layerId) + glifyColorAttachmentSrc(fl_color, group) ) - fillColor = NULL } - # popup + # labels ############ + if (!is.null(label)) { + labels <- leaflet::evalFormula(label, data) + fl_label = paste0(dir_labels, "/", group, "_label.js") + pre = paste0('var labs = labs || {}; labs["', group, '"] = ') + writeLines(pre, fl_label) + cat('[', jsonify::to_json(labels), '];', + file = fl_label, append = TRUE) + + map$dependencies = c( + map$dependencies, + glifyLabelAttachmentSrc(fl_label, group) + ) + label = NULL + } + + # popup ############ if (!is.null(popup)) { htmldeps <- htmltools::htmlDependencies(popup) if (length(htmldeps) != 0) { @@ -305,20 +320,20 @@ addGlPointsSrc = function(map, ) } popup = makePopup(popup, data) - fl_popup = paste0(dir_popup, "/", layerId, "_popup.js") - pre = paste0('var popup = popup || {}; popup["', layerId, '"] = ') + fl_popup = paste0(dir_popup, "/", group, "_popup.js") + pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) cat('[', jsonify::to_json(popup), '];', file = fl_popup, append = TRUE) map$dependencies = c( map$dependencies, - glifyPopupAttachmentSrc(fl_popup, layerId) + glifyPopupAttachmentSrc(fl_popup, group) ) - + popup = NULL } - # radius + # radius ############ if (length(unique(radius)) > 1) { fl_radius = paste0(dir_radius, "/", layerId, "_radius.js") pre = paste0('var rad = rad || {}; rad["', layerId, '"] = ') @@ -330,19 +345,20 @@ addGlPointsSrc = function(map, map$dependencies, glifyRadiusAttachmentSrc(fl_radius, layerId) ) - radius = NULL } + # invoke method ########### map = leaflet::invokeMethod( map , leaflet::getMapData(map) , 'addGlifyPointsSrc' , fillColor - , radius , fillOpacity + , radius , group , layerId + , dotopts , pane , popupOptions , labelOptions diff --git a/R/glify-polygons.R b/R/glify-polygons.R index 2f12375..6e2b126 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -30,14 +30,24 @@ addGlPolygons = function(map, labelOptions = NULL, ...) { + # check data ########## if (missing(labelOptions)) labelOptions <- labelOptions() if (missing(popupOptions)) popupOptions <- popupOptions() - dotopts = list(...) + if (is.null(group)) group = deparse(substitute(data)) + if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) + stopifnot(inherits(sf::st_geometry(data), c("sfc_POLYGON", "sfc_MULTIPOLYGON"))) + if (inherits(sf::st_geometry(data), "sfc_MULTIPOLYGON")) + stop("Can only handle POLYGONs, please cast your MULTIPOLYGON to POLYGON using sf::st_cast", + call. = FALSE) if (!is.null(layerId) && inherits(layerId, "formula")) layerId <- evalFormula(layerId, data) + ## currently leaflet.glify only supports single (fill)opacity! + fillOpacity = fillOpacity[1] + + # call SRC function ############## if (isTRUE(src)) { m = addGlPolygonsSrc( map = map @@ -47,6 +57,7 @@ addGlPolygons = function(map, , fillOpacity = fillOpacity , group = group , popup = popup + , label = label , layerId = layerId , pane = pane , stroke = stroke @@ -57,19 +68,11 @@ addGlPolygons = function(map, return(m) } - ## currently leaflet.glify only supports single (fill)opacity! - fillOpacity = fillOpacity[1] - - if (is.null(group)) group = deparse(substitute(data)) - if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) - stopifnot(inherits(sf::st_geometry(data), c("sfc_POLYGON", "sfc_MULTIPOLYGON"))) - if (inherits(sf::st_geometry(data), "sfc_MULTIPOLYGON")) - stop("Can only handle POLYGONs, please cast your MULTIPOLYGON to POLYGON using sf::st_cast", - call. = FALSE) - + # get Bounds and ... ################# + dotopts = list(...) bounds = as.numeric(sf::st_bbox(data)) - # fillColor + # fillColor ########### palette = "viridis" if ("palette" %in% names(dotopts)) { palette <- dotopts$palette @@ -81,7 +84,7 @@ addGlPolygons = function(map, colnames(fillColor) = c("r", "g", "b") cols = jsonify::to_json(fillColor, digits = 3) - # label / popup + # label / popup ########### labels <- leaflet::evalFormula(label, data) if (is.null(popup)) { # geom = sf::st_transform(sf::st_geometry(data), crs = 4326) @@ -103,7 +106,7 @@ addGlPolygons = function(map, data = sf::st_sf(id = 1:length(geom), geometry = geom) } - # data + # data ########### if (length(dotopts) == 0) { geojsonsf_args = NULL } else { @@ -123,7 +126,7 @@ addGlPolygons = function(map, # dependencies map$dependencies = c(map$dependencies, glifyDependencies()) - # invoke leaflet method and zoom to bounds + # invoke leaflet method and zoom to bounds ########### map = leaflet::invokeMethod( map , leaflet::getMapData(map) @@ -159,6 +162,7 @@ addGlPolygonsSrc = function(map, fillOpacity = 0.6, group = "glpolygons", popup = NULL, + label = NULL, layerId = NULL, pane = "overlayPane", stroke = TRUE, @@ -166,36 +170,31 @@ addGlPolygonsSrc = function(map, labelOptions = NULL, ...) { - if (is.null(group)) group = deparse(substitute(data)) - if (is.null(layerId)) layerId = paste0(group, "-pls") - if (inherits(data, "Spatial")) data <- sf::st_as_sf(data) - stopifnot(inherits(sf::st_geometry(data), c("sfc_POLYGON", "sfc_MULTIPOLYGON"))) - if (inherits(sf::st_geometry(data), "sfc_MULTIPOLYGON")) - stop("Can only handle POLYGONs, please cast your MULTIPOLYGON ", - "to POLYGON using e.g. sf::st_cast") - + # get Bounds and ... ################# + dotopts = list(...) bounds = as.numeric(sf::st_bbox(data)) - # temp directories + # temp directories ############ dir_data = tempfile(pattern = "glify_polygons_dat") dir.create(dir_data) dir_color = tempfile(pattern = "glify_polygons_col") dir.create(dir_color) dir_popup = tempfile(pattern = "glify_polygons_pop") dir.create(dir_popup) + dir_labels = tempfile(pattern = "glify_polylines_labl") + dir.create(dir_labels) - # data + # data ############ data_orig <- data geom = sf::st_geometry(data) data = sf::st_sf(id = 1:length(geom), geometry = geom) - ell_args <- list(...) - fl_data = paste0(dir_data, "/", layerId, "_data.js") - pre = paste0('var data = data || {}; data["', layerId, '"] = ') + fl_data = paste0(dir_data, "/", group, "_data.js") + pre = paste0('var data = data || {}; data["', group, '"] = ') writeLines(pre, fl_data) jsonify_args = try( match.arg( - names(ell_args) + names(dotopts) , names(as.list(args(geojsonsf::sf_geojson))) , several.ok = TRUE ) @@ -203,19 +202,20 @@ addGlPolygonsSrc = function(map, ) if (inherits(jsonify_args, "try-error")) jsonify_args = NULL if (identical(jsonify_args, "sf")) jsonify_args = NULL - cat('[', do.call(geojsonsf::sf_geojson, c(list(data), ell_args[jsonify_args])), '];', + cat('[', do.call(geojsonsf::sf_geojson, c(list(data), dotopts[jsonify_args])), '];', file = fl_data, sep = "", append = TRUE) map$dependencies = c( map$dependencies, glifyDependenciesSrc(), - glifyDataAttachmentSrc(fl_data, layerId) + glifyDataAttachmentSrc(fl_data, group) ) - # color + # color ############ palette = "viridis" - if ("palette" %in% names(ell_args)) { - palette <- ell_args$palette + if ("palette" %in% names(dotopts)) { + palette <- dotopts$palette + dotopts$palette = NULL } fillColor <- makeColorMatrix(fillColor, data_orig, palette = palette) if (ncol(fillColor) != 3) stop("only 3 column fillColor matrix supported so far") @@ -223,21 +223,37 @@ addGlPolygonsSrc = function(map, colnames(fillColor) = c("r", "g", "b") if (nrow(fillColor) > 1) { - fl_color = paste0(dir_color, "/", layerId, "_color.js") - pre = paste0('var col = col || {}; col["', layerId, '"] = ') + fl_color = paste0(dir_color, "/", group, "_color.js") + pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) cat('[', jsonify::to_json(fillColor), '];', file = fl_color, append = TRUE) map$dependencies = c( map$dependencies, - glifyColorAttachmentSrc(fl_color, layerId) + glifyColorAttachmentSrc(fl_color, group) ) fillColor = NULL } - # popup + # labels ############ + if (!is.null(label)) { + labels <- leaflet::evalFormula(label, data_orig) + fl_label = paste0(dir_labels, "/", group, "_label.js") + pre = paste0('var labs = labs || {}; labs["', group, '"] = ') + writeLines(pre, fl_label) + cat('[', jsonify::to_json(labels), '];', + file = fl_label, append = TRUE) + + map$dependencies = c( + map$dependencies, + glifyLabelAttachmentSrc(fl_label, group) + ) + label = NULL + } + + # popup ############ if (!is.null(popup)) { htmldeps <- htmltools::htmlDependencies(popup) if (length(htmldeps) != 0) { @@ -247,18 +263,20 @@ addGlPolygonsSrc = function(map, ) } popup = makePopup(popup, data_orig) - fl_popup = paste0(dir_popup, "/", layerId, "_popup.js") - pre = paste0('var popup = popup || {}; popup["', layerId, '"] = ') + fl_popup = paste0(dir_popup, "/", group, "_popup.js") + pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) cat('[', jsonify::to_json(popup), '];', file = fl_popup, append = TRUE) map$dependencies = c( map$dependencies, - glifyPopupAttachmentSrc(fl_popup, layerId) + glifyPopupAttachmentSrc(fl_popup, group) ) + popup = NULL } + # invoke method ########### map = leaflet::invokeMethod( map , leaflet::getMapData(map) @@ -267,6 +285,7 @@ addGlPolygonsSrc = function(map, , fillOpacity , group , layerId + , dotopts , pane , stroke , popupOptions diff --git a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js index 30bb5bf..e8eb41a 100644 --- a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js +++ b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js @@ -94,7 +94,6 @@ function addGlifyEventListeners (map) { if (glifylayer) { let glifyinstance = L.glify.instances.find(e => e.layer._leaflet_id == leafid); if (glifyinstance) { - //console.log("glifyinstance TRUE"); console.log(glifyinstance) glifyinstance.active = true; } } @@ -107,7 +106,6 @@ function addGlifyEventListeners (map) { if (glifylayer) { let glifyinstance = L.glify.instances.find(e => e.layer._leaflet_id == leafid); if (glifyinstance) { - //console.log("glifyinstance FALSE"); console.log(glifyinstance) glifyinstance.active = false; } } @@ -148,6 +146,49 @@ LeafletWidget.methods.showGroup = function(group) { // Helper Functions +function click_event_pts(e, point, addpopup, popup, popupOptions, layer, layerId, data, map) { + if (map.hasLayer(layer.layer)) { + var idx = data.findIndex(k => k==point); + var content = popup ? popup[idx].toString() : null; + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_click", { + id: layerId ? layerId[idx] : idx+1, + group: layer.settings.className, + lat: point[0], + lng: point[1], + data: content + }); + } + if (addpopup) { + L.popup(popupOptions) + .setLatLng(point) + .setContent(content) + .openOn(map); + } + } +}; +function hover_event_pts(e, point, addlabel, label, layer, tooltip, layerId, data, map) { + if (map.hasLayer(layer.layer)) { + var idx = data.findIndex(k => k==point); + var content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : + typeof label === 'string' ? label : null; + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_mouseover", { + id: layerId ? layerId[idx] : idx+1, + group: layer.settings.className, + lat: point[0], + lng: point[1], + data: content + }); + } + if (addlabel) { + tooltip + .setLatLng(point) + .setContent(content) + .addTo(map); + } + } +} function click_event(e, feature, addpopup, popup, popupOptions, layer, layerId, data, map) { if (map.hasLayer(layer.layer)) { const idx = data.features.findIndex(k => k==feature); @@ -162,7 +203,6 @@ function click_event(e, feature, addpopup, popup, popupOptions, layer, layerId, } if (addpopup) { const content = popup === true ? json2table(feature.properties) : popup[idx].toString(); - L.popup(popupOptions) .setLatLng(e.latlng) .setContent(content) diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js index e7afc85..39cbf6d 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js @@ -1,7 +1,6 @@ /* global LeafletWidget, L */ - -LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacity, - radius, group, layerId, dotOptions, pane, +LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacity, radius, + group, layerId, dotOptions, pane, popupOptions, labelOptions) { const map = this; @@ -23,55 +22,14 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit } // click & hover function - const clickFun = (e, point, xy) => { - //set up a standalone popup (use a popup as a layer) - if (map.hasLayer(pointslayer.layer)) { - var idx = data.findIndex(k => k==point); - var content = popup ? popup[idx].toString() : null; - if (HTMLWidgets.shinyMode) { - Shiny.setInputValue(map.id + "_glify_click", { - id: layerId ? layerId[idx] : idx+1, - group: pointslayer.settings.className, - lat: point[0], - lng: point[1], - data: content - }); - } - if (popup !== null) { - L.popup(popupOptions) - .setLatLng(point) - .setContent(content) - .openOn(map); - } - } - }; + const clickFun = function(e, point) { + click_event_pts(e, point, popup !== null, popup, popupOptions, pointslayer, layerId, data, map); + }; const tooltip = new L.Tooltip(labelOptions); - const hover_event = function(e, point, addlabel, label) { - //set up a standalone label (use a label as a layer) - if (map.hasLayer(pointslayer.layer)) { - var idx = data.findIndex(k => k==point); - var content = Array.isArray(label) ? (label[idx] ? label[idx].toString() : null) : - typeof label === 'string' ? label : null; - if (HTMLWidgets.shinyMode) { - Shiny.setInputValue(map.id + "_glify_mouseover", { - id: layerId ? layerId[idx] : idx+1, - group: pointslayer.settings.className, - lat: point[0], - lng: point[1], - data: content - }); - } - if (label !== null) { - tooltip - .setLatLng(point) - .setContent(content) - .addTo(map); - } - } - } - const mouseoverFun = function(e, feature) { - hover_event(e, feature, label !== null, label); + const mouseoverFun = function(e, point) { + hover_event_pts(e, point, label !== null, label, pointslayer, tooltip, + layerId, data, map); } // arguments for gl layer diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPointsSrc.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPointsSrc.js index b1be16b..ca220e9 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPointsSrc.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPointsSrc.js @@ -1,52 +1,78 @@ -LeafletWidget.methods.addGlifyPointsSrc = function(fillColor, radius, fillOpacity, group, layerId, pane) { +/* global LeafletWidget, L */ +LeafletWidget.methods.addGlifyPointsSrc = function(cols, opacity, radius, group, + layerId, dotOptions, pane, + popupOptions, labelOptions) { - var map = this; + const map = this; // color - var clrs; - if (fillColor === null) { - clrs = function(index, feature) { return col[layerId][0][index]; }; + let clrs; + if (cols === null) { + clrs = function(index, feature) { return col[group][0][index]; }; } else { - clrs = fillColor; + clrs = cols; } // radius - var size; + let rad; if (radius === null) { - size = function(index, point) { return rad[layerId][0][index]; }; + rad = function(index, point) { return rad[group][0][index]; }; } else { - size = radius; + rad = radius; } - var pointslayer = L.glify.points({ + // click & hover function + const clickFun = function(e, point) { + if (typeof pops !== 'undefined' && pops?.[group]?.[0]) { + let popsrc = pops[group][0]; + popsrc = popsrc.length == 1 ? popsrc[0] : popsrc; + click_event_pts(e, point, popsrc !== null, popsrc, popupOptions, + pointslayer, layerId, data[group][0], map); + } + }; + + const tooltip = new L.Tooltip(labelOptions); + const mouseoverFun = function(e, point) { + if (typeof labs !== 'undefined' && labs?.[group]?.[0]) { + let labsrc = labs[group][0]; + labsrc = labsrc.length == 1 ? labsrc[0] : labsrc; + hover_event_pts(e, point, labsrc !== null, labsrc, pointslayer, tooltip, + layerId, data[group][0], map); + } + } + + // arguments for gl layer + const layerArgs = { map: map, - click: function (e, point, xy) { - if (typeof(popup) === "undefined") { - return; - } else if (typeof(popup[layerId]) === "undefined") { - return; - } else { - //var idx = data[layerId][0].indexOf(point); - var idx = data[layerId][0].findIndex(k => k==point); - //set up a standalone popup (use a popup as a layer) - if (map.hasLayer(pointslayer.layer)) { - L.popup() - .setLatLng(point) - .setContent(popup[layerId][0][idx].toString()) - .openOn(map); - } - } - }, - data: data[layerId][0], + click: clickFun, + hover: mouseoverFun, + data: data[group][0], color: clrs, - opacity: fillOpacity, - size: size, + opacity: opacity, + size: rad, className: group, - pane: pane - }); + pane: pane, + layerId: layerId + }; + + // extract correct fragmentShaderSource if provided via dotOptions + if (dotOptions.fragmentShaderSource !== undefined && dotOptions.fragmentShaderSource !== null) { + let fragmentShader = dotOptions.fragmentShaderSource; + dotOptions.fragmentShaderSource = () => { + return L.glify.shader.fragment[fragmentShader]; + }; + } + + // append dotOptions to layer arguments + Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); + + // initialize Glify Layer + const pointslayer = L.glify.points(layerArgs); + // add layer to map using leaflet's layerManager map.layerManager.addLayer(pointslayer.layer, "glify", layerId, group); + addGlifyEventListeners(map) }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js index c0b0f54..468a46e 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js @@ -1,5 +1,4 @@ /* global LeafletWidget, L */ - LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, opacity, group, layerId, dotOptions, pane, stroke, popupOptions, labelOptions) { diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygonsSrc.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygonsSrc.js index b2f7fa1..c601c91 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygonsSrc.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygonsSrc.js @@ -1,41 +1,60 @@ -LeafletWidget.methods.addGlifyPolygonsSrc = function(fillColor, fillOpacity, group, layerId, pane) { +/* global LeafletWidget, L */ +LeafletWidget.methods.addGlifyPolygonsSrc = function(cols, opacity, group, + layerId, dotOptions, pane, stroke, + popupOptions, labelOptions) { - var map = this; - -// FIX ME clrs, pop need to be layer specificly named!!!!! + const map = this; // color - var clrs; - if (fillColor === null) { - clrs = function(index, feature) { return col[layerId][0][index]; }; + let clrs; + if (cols === null) { + clrs = function(index, feature) { return col[group][0][index]; }; } else { - clrs = fillColor; + clrs = cols; + } + + // click & hover function + const clickFun = function (e, feature) { + if (typeof pops !== 'undefined' && pops?.[group]?.[0]) { + let popsrc = pops[group][0]; + popsrc = popsrc.length == 1 ? popsrc[0] : popsrc; + click_event(e, feature, popsrc !== null, popsrc, popupOptions, + shapeslayer, layerId, data[group][0], map); + } + }; + + const tooltip = new L.Tooltip(labelOptions); + const mouseoverFun = function(e, feature) { + if (typeof labs !== 'undefined' && labs?.[group]?.[0]) { + let labsrc = labs[group][0]; + labsrc = labsrc.length == 1 ? labsrc[0] : labsrc; + hover_event(e, feature, labsrc !== null, labsrc, shapeslayer, tooltip, + layerId, data[group][0], map); + } } - var shapeslayer = L.glify.shapes({ + // arguments for gl layer + const layerArgs = { map: map, - click: function (e, feature) { - if (typeof(popup) === "undefined") { - return; - } else if (typeof(popup[layerId]) === "undefined") { - return; - } else { - if (map.hasLayer(shapeslayer.layer)) { - var idx = data[layerId][0].features.findIndex(k => k==feature); - L.popup() - .setLatLng(e.latlng) - .setContent(popup[layerId][0][idx].toString()) - .openOn(map); - } - } - }, - data: data[layerId][0], + click: clickFun, + hover: mouseoverFun, + data: data[group][0], color: clrs, - opacity: fillOpacity, + opacity: opacity, className: group, - pane: pane - }); + border: stroke, + pane: pane, + layerId: layerId + }; + + // append dotOptions to layer arguments + Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); + + // initialize Glify Layer + const shapeslayer = L.glify.shapes(layerArgs); - map.layerManager.addLayer(shapeslayer.layer, "glify", null, group); + // add layer to map using leaflet's layerManager + map.layerManager.addLayer(shapeslayer.layer, "glify", layerId, group); + addGlifyEventListeners(map) }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js index 954b0f2..ec1d573 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js @@ -1,5 +1,4 @@ /* global LeafletWidget, L */ - LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, opacity, group, weight, layerId, dotOptions, pane, popupOptions, labelOptions) { diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylinesSrc.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylinesSrc.js index b1de87b..9cf5e5d 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylinesSrc.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylinesSrc.js @@ -1,50 +1,70 @@ -LeafletWidget.methods.addGlifyPolylinesSrc = function(color, weight, opacity, group, layerId, pane) { +/* global LeafletWidget, L */ +LeafletWidget.methods.addGlifyPolylinesSrc = function(cols, opacity, + group, weight, layerId, dotOptions, pane, + popupOptions, labelOptions) { - var map = this; + const map = this; // color - var clrs; - if (color === null) { - clrs = function(index, feature) { return col[layerId][0][index]; }; + let clrs; + if (cols === null) { + clrs = function(index, feature) { return col[group][0][index]; }; } else { - clrs = color; + clrs = cols; } // radius - var wght; + let wght; if (weight === null) { - wght = function(index, feature) { return wgt[layerId][0][index]; }; + wght = function(index, feature) { return wgt[group][0][index]; }; } else { wght = weight; } - var lineslayer = L.glify.lines({ + // click & hover function + const clickFun = function (e, feature) { + if (typeof pops !== 'undefined' && pops?.[group]?.[0]) { + let popsrc = pops[group][0]; + popsrc = popsrc.length == 1 ? popsrc[0] : popsrc; + click_event(e, feature, popsrc !== null, popsrc, popupOptions, + lineslayer, layerId, data[group][0], map); + } + }; + + const tooltip = new L.Tooltip(labelOptions); + const mouseoverFun = function(e, feature) { + if (typeof labs !== 'undefined' && labs?.[group]?.[0]) { + let labsrc = labs[group][0]; + labsrc = labsrc.length == 1 ? labsrc[0] : labsrc; + hover_event(e, feature, labsrc !== null, labsrc, lineslayer, tooltip, + layerId, data[group][0], map); + } + } + + // arguments for gl layer + const layerArgs = { map: map, - click: function (e, feature) { - if (typeof(popup) === "undefined") { - return; - } else if (typeof(popup[layerId]) === "undefined") { - return; - } else { - if (map.hasLayer(lineslayer.layer)) { - var idx = data[layerId][0].features.findIndex(k => k==feature); - L.popup() - .setLatLng(e.latlng) - .setContent(popup[layerId][0][idx].toString()) - .openOn(map); - } - } - }, + click: clickFun, + hover: mouseoverFun, latitudeKey: 1, longitudeKey: 0, - data: data[layerId][0], + data: data[group][0], color: clrs, opacity: opacity, - weight: wght, className: group, - pane: pane - }); + weight: wght, + pane: pane, + layerId: layerId + }; + + // append dotOptions to layer arguments + Object.entries(dotOptions).forEach(([key,value]) => { layerArgs[key] = value }); + + // initialize Glify Layer + const lineslayer = L.glify.lines(layerArgs); - map.layerManager.addLayer(lineslayer.layer, "glify", null, group); + // add layer to map using leaflet's layerManager + map.layerManager.addLayer(lineslayer.layer, "glify", layerId, group); + addGlifyEventListeners(map) }; From c5c9f372252f7dfe3caa23d2c62729eda8c1aabf Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Sat, 8 Jun 2024 14:43:04 +0200 Subject: [PATCH 07/14] convert_to_json function to try yyjsonr::write_json_str or jsonify::to_json --- R/glify-helpers.R | 39 +++++++++++++++++++++++++++++++++++++++ R/glify-lines.R | 15 ++++++--------- R/glify-points.R | 22 ++++++++++------------ R/glify-polygons.R | 13 +++++-------- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/R/glify-helpers.R b/R/glify-helpers.R index e92cb8b..b064515 100644 --- a/R/glify-helpers.R +++ b/R/glify-helpers.R @@ -169,3 +169,42 @@ glifyDependenciesFl = function() { ) ) } + + + +json_funccall <- function() { + json_parser <- getOption("leafgl_json_parser", "jsonify") # Default to jsonify + if (json_parser == "yyjsonr") { + yyjsonr::write_json_str + } else { + jsonify::to_json + } +} +convert_to_json <- function(data, ...) { + json_parser <- getOption("leafgl_json_parser", "jsonify") # Default to jsonify + if (json_parser == "yyjsonr") { + print("I am using yyjsonr") + json_data <- yyjsonr::write_json_str(data, ...) + class(json_data) <- "json" + } else { + print("I am using jsonify") + json_data <- jsonify::to_json(data, ...) + } + return(json_data) +} + +## Not used as its not faster - Needs geometries to be the last column and be named geometry +yyjsonr_2_geojson <- function(sfdata) { + # sfdata <- data + geom <- st_geometry(sfdata) + sfdata <- st_drop_geometry(sfdata) + sfdata$geometry <- geom + sfdata <- sf::st_as_sf(sfdata) + json_data <- yyjsonr::write_json_str(sfdata, digits=4) + json_data <- gsub("]}]", "]}}]}", fixed = TRUE, + paste0('{"type":"FeatureCollection","features":[{"type":"Feature","properties":', + gsub('","geometry":', '"},"geometry":{"type":"Polygon","coordinates":', + substr(json_data, 2, nchar(json_data)), fixed = TRUE))) + class(json_data) <- "geojson" + json_data +} \ No newline at end of file diff --git a/R/glify-lines.R b/R/glify-lines.R index 6f94b11..f8a9655 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -79,7 +79,7 @@ addGlPolylines = function(map, if (ncol(color) != 3) stop("only 3 column color matrix supported so far") color = as.data.frame(color, stringsAsFactors = FALSE) colnames(color) = c("r", "g", "b") - cols = jsonify::to_json(color, digits = 3) + cols = convert_to_json(color, digits = 3) # label / popup ######## labels <- leaflet::evalFormula(label, data) @@ -96,8 +96,7 @@ addGlPolylines = function(map, htmldeps ) } - popup = makePopup(popup, data) - popup = jsonify::to_json(popup) + popup = convert_to_json(makePopup(popup, data)) geom = sf::st_geometry(data) data = sf::st_sf(id = 1:length(geom), geometry = geom) } @@ -221,7 +220,7 @@ addGlPolylinesSrc = function(map, fl_color = paste0(dir_color, "/", group, "_color.js") pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) - cat('[', jsonify::to_json(color), '];', + cat('[', convert_to_json(color, digits = 3), '];', file = fl_color, append = TRUE) map$dependencies = c( @@ -233,11 +232,10 @@ addGlPolylinesSrc = function(map, # labels ############ if (!is.null(label)) { - labels <- leaflet::evalFormula(label, data_orig) fl_label = paste0(dir_labels, "/", group, "_label.js") pre = paste0('var labs = labs || {}; labs["', group, '"] = ') writeLines(pre, fl_label) - cat('[', jsonify::to_json(labels), '];', + cat('[', convert_to_json(leaflet::evalFormula(label, data_orig)), '];', file = fl_label, append = TRUE) map$dependencies = c( @@ -256,11 +254,10 @@ addGlPolylinesSrc = function(map, htmldeps ) } - popup = makePopup(popup, data_orig) fl_popup = paste0(dir_popup, "/", group, "_popup.js") pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) - cat('[', jsonify::to_json(popup), '];', + cat('[', convert_to_json(makePopup(popup, data_orig)), '];', file = fl_popup, append = TRUE) map$dependencies = c( @@ -275,7 +272,7 @@ addGlPolylinesSrc = function(map, fl_weight = paste0(dir_weight, "/", group, "_weight.js") pre = paste0('var wgt = wgt || {}; wgt["', group, '"] = ') writeLines(pre, fl_weight) - cat('[', jsonify::to_json(weight), '];', + cat('[', convert_to_json(weight), '];', file = fl_weight, append = TRUE) map$dependencies = c( diff --git a/R/glify-points.R b/R/glify-points.R index e192be3..c99182a 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -137,7 +137,7 @@ addGlPoints = function(map, dotopts = list(...) bounds = as.numeric(sf::st_bbox(data)) - # fillColor ########### + # color ########### palette = "viridis" if ("palette" %in% names(dotopts)) { palette <- dotopts$palette @@ -147,7 +147,7 @@ addGlPoints = function(map, if (ncol(fillColor) != 3) stop("only 3 column fillColor matrix supported so far") fillColor = as.data.frame(fillColor, stringsAsFactors = FALSE) colnames(fillColor) = c("r", "g", "b") - fillColor = jsonify::to_json(fillColor) + fillColor = convert_to_json(fillColor, digits = 3) # label / popup ########### labels <- leaflet::evalFormula(label, data) @@ -159,8 +159,7 @@ addGlPoints = function(map, htmldeps ) } - popup = makePopup(popup, data) - popup = jsonify::to_json(popup) + popup = convert_to_json(makePopup(popup, data)) } else { popup = NULL } @@ -173,14 +172,15 @@ addGlPoints = function(map, jsonify_args = try( match.arg( names(dotopts) - , names(as.list(args(jsonify::to_json))) + , names(as.list(args(json_funccall))) , several.ok = TRUE ) , silent = TRUE ) } if (inherits(jsonify_args, "try-error")) jsonify_args = NULL - data = do.call(jsonify::to_json, c(list(crds), dotopts[jsonify_args])) + data = do.call(json_funccall(), c(list(crds), dotopts[jsonify_args])) + class(data) <- "json" # dependencies map$dependencies = c(map$dependencies, glifyDependencies()) @@ -284,7 +284,7 @@ addGlPointsSrc = function(map, fl_color = paste0(dir_color, "/", group, "_color.js") pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) - cat('[', jsonify::to_json(fillColor), '];', + cat('[', convert_to_json(fillColor, digits = 3), '];', file = fl_color, append = TRUE) map$dependencies = c( @@ -296,11 +296,10 @@ addGlPointsSrc = function(map, # labels ############ if (!is.null(label)) { - labels <- leaflet::evalFormula(label, data) fl_label = paste0(dir_labels, "/", group, "_label.js") pre = paste0('var labs = labs || {}; labs["', group, '"] = ') writeLines(pre, fl_label) - cat('[', jsonify::to_json(labels), '];', + cat('[', convert_to_json(leaflet::evalFormula(label, data)), '];', file = fl_label, append = TRUE) map$dependencies = c( @@ -319,11 +318,10 @@ addGlPointsSrc = function(map, htmldeps ) } - popup = makePopup(popup, data) fl_popup = paste0(dir_popup, "/", group, "_popup.js") pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) - cat('[', jsonify::to_json(popup), '];', + cat('[', convert_to_json(makePopup(popup, data)), '];', file = fl_popup, append = TRUE) map$dependencies = c( @@ -338,7 +336,7 @@ addGlPointsSrc = function(map, fl_radius = paste0(dir_radius, "/", layerId, "_radius.js") pre = paste0('var rad = rad || {}; rad["', layerId, '"] = ') writeLines(pre, fl_radius) - cat('[', jsonify::to_json(radius), '];', + cat('[', convert_to_json(radius), '];', file = fl_radius, append = TRUE) map$dependencies = c( diff --git a/R/glify-polygons.R b/R/glify-polygons.R index 6e2b126..7c80030 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -82,7 +82,7 @@ addGlPolygons = function(map, if (ncol(fillColor) != 3) stop("only 3 column fillColor matrix supported so far") fillColor = as.data.frame(fillColor, stringsAsFactors = FALSE) colnames(fillColor) = c("r", "g", "b") - cols = jsonify::to_json(fillColor, digits = 3) + cols = convert_to_json(fillColor, digits = 3) # label / popup ########### labels <- leaflet::evalFormula(label, data) @@ -100,8 +100,7 @@ addGlPolygons = function(map, htmldeps ) } - popup = makePopup(popup, data) - popup = jsonify::to_json(popup) + popup = convert_to_json(makePopup(popup, data)) geom = sf::st_geometry(data) data = sf::st_sf(id = 1:length(geom), geometry = geom) } @@ -226,7 +225,7 @@ addGlPolygonsSrc = function(map, fl_color = paste0(dir_color, "/", group, "_color.js") pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) - cat('[', jsonify::to_json(fillColor), '];', + cat('[', convert_to_json(fillColor, digits = 3), '];', file = fl_color, append = TRUE) map$dependencies = c( @@ -239,11 +238,10 @@ addGlPolygonsSrc = function(map, # labels ############ if (!is.null(label)) { - labels <- leaflet::evalFormula(label, data_orig) fl_label = paste0(dir_labels, "/", group, "_label.js") pre = paste0('var labs = labs || {}; labs["', group, '"] = ') writeLines(pre, fl_label) - cat('[', jsonify::to_json(labels), '];', + cat('[', convert_to_json(leaflet::evalFormula(label, data_orig)), '];', file = fl_label, append = TRUE) map$dependencies = c( @@ -262,11 +260,10 @@ addGlPolygonsSrc = function(map, htmldeps ) } - popup = makePopup(popup, data_orig) fl_popup = paste0(dir_popup, "/", group, "_popup.js") pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) - cat('[', jsonify::to_json(popup), '];', + cat('[', convert_to_json(makePopup(popup, data_orig)), '];', file = fl_popup, append = TRUE) map$dependencies = c( From efb51c0989767020049db502f77f1532a42c8ca8 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Sat, 8 Jun 2024 14:54:51 +0200 Subject: [PATCH 08/14] simplify/unify dependency calls --- DESCRIPTION | 1 + R/glify-helpers.R | 224 +++++++++-------------- R/glify-lines.R | 21 +-- R/glify-points.R | 31 +--- R/glify-polygons.R | 17 +- tests/testthat/test-leafgl-addGlPoints.R | 12 +- 6 files changed, 108 insertions(+), 198 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 241eea0..b0fb391 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -40,4 +40,5 @@ Imports: Suggests: colourvalues, shiny, + yyjsonr, testthat (>= 2.1.0) diff --git a/R/glify-helpers.R b/R/glify-helpers.R index b064515..e3df374 100644 --- a/R/glify-helpers.R +++ b/R/glify-helpers.R @@ -1,5 +1,6 @@ -# helpers -glifyDependencies = function() { +# dependencies +glifyDependencies = function(src = FALSE) { + src <- ifelse(src, "Src", "") list( htmltools::htmlDependency( "Leaflet.glify", @@ -7,27 +8,9 @@ glifyDependencies = function() { system.file("htmlwidgets/Leaflet.glify", package = "leafgl"), script = c( "GlifyUtils.js" - , "addGlifyPoints.js" - , "addGlifyPolygons.js" - , "addGlifyPolylines.js" - , "glify-browser.js" - ) - ) - ) -} - -# helpers -glifyDependenciesSrc = function() { - list( - htmltools::htmlDependency( - "Leaflet.glifySrc", - '3.2.0', - system.file("htmlwidgets/Leaflet.glify", package = "leafgl"), - script = c( - "GlifyUtils.js" - , "addGlifyPointsSrc.js" - , "addGlifyPolygonsSrc.js" - , "addGlifyPolylinesSrc.js" + , paste0("addGlifyPoints", src, ".js") + , paste0("addGlifyPolygons", src, ".js") + , paste0("addGlifyPolylines", src, ".js") , "glify-browser.js" ) ) @@ -58,37 +41,16 @@ glifyDataAttachmentSrc = function(fl_data, group, async = FALSE) { } } -glifyColorAttachmentSrc = function(fl_color, group) { - data_dir <- dirname(fl_color) - data_file <- basename(fl_color) - list( - htmltools::htmlDependency( - name = paste0(group, "col"), - version = 1, - src = c(file = data_dir), - script = list(data_file) - ) - ) -} - -glifyPopupAttachmentSrc = function(fl_popup, group) { - data_dir <- dirname(fl_popup) - data_file <- basename(fl_popup) - list( - htmltools::htmlDependency( - name = paste0(group, "pop"), - version = 1, - src = c(file = data_dir), - script = list(data_file) - ) - ) -} -glifyLabelAttachmentSrc = function(fl_popup, group) { - data_dir <- dirname(fl_popup) - data_file <- basename(fl_popup) +glifyAttachmentSrc <- function(fl, group, type) { + valid_types <- c("col", "pop", "lab", "rad") + if (!type %in% valid_types) { + stop("Invalid type. Valid types are: col, pop, lab, rad.") + } + data_dir <- dirname(fl) + data_file <- basename(fl) list( htmltools::htmlDependency( - name = paste0(group, "lab"), + name = paste0(group, type), version = 1, src = c(file = data_dir), script = list(data_file) @@ -96,82 +58,8 @@ glifyLabelAttachmentSrc = function(fl_popup, group) { ) } -glifyRadiusAttachmentSrc = function(fl_radius, group) { - data_dir <- dirname(fl_radius) - data_file <- basename(fl_radius) - list( - htmltools::htmlDependency( - name = paste0(group, "rad"), - version = 1, - src = c(file = data_dir), - script = list(data_file) - ) - ) -} - -glifyDataAttachment = function(fl_data, group) { - data_dir <- dirname(fl_data) - data_file <- basename(fl_data) - list( - htmltools::htmlDependency( - name = paste0(group, "dt"), - version = 1, - src = c(file = data_dir), - attachment = list(data_file) - ) - ) -} - - -glifyColorAttachment = function(fl_color, group) { - data_dir <- dirname(fl_color) - data_file <- basename(fl_color) - list( - htmltools::htmlDependency( - name = paste0(group, "cl"), - version = 1, - src = c(file = data_dir), - attachment = list(data_file) - ) - ) -} - -glifyPopupAttachment = function(fl_popup, group) { - data_dir <- dirname(fl_popup) - data_file <- basename(fl_popup) - list( - htmltools::htmlDependency( - name = paste0(group, "pop"), - version = 1, - src = c(file = data_dir), - attachment = list(data_file) - ) - ) -} - - - # helpers -glifyDependenciesFl = function() { - list( - htmltools::htmlDependency( - "Leaflet.glify", - '2.2.0', - system.file("htmlwidgets/Leaflet.glify", package = "leafgl"), - script = c( - "GlifyUtils.js" - , "addGlifyPoints.js" - , "addGlifyPolygonsFl.js" - , "addGlifyPolylines.js" - , "glify-browser.js" - ) - ) - ) -} - - - json_funccall <- function() { json_parser <- getOption("leafgl_json_parser", "jsonify") # Default to jsonify if (json_parser == "yyjsonr") { @@ -193,18 +81,74 @@ convert_to_json <- function(data, ...) { return(json_data) } + + +## Not used ########## +# glifyDependenciesFl = function() { +# list( +# htmltools::htmlDependency( +# "Leaflet.glify", +# '2.2.0', +# system.file("htmlwidgets/Leaflet.glify", package = "leafgl"), +# script = c( +# "GlifyUtils.js" +# , "addGlifyPoints.js" +# , "addGlifyPolygonsFl.js" +# , "addGlifyPolylines.js" +# , "glify-browser.js" +# ) +# ) +# ) +# } +# glifyDataAttachment = function(fl_data, group) { +# data_dir <- dirname(fl_data) +# data_file <- basename(fl_data) +# list( +# htmltools::htmlDependency( +# name = paste0(group, "dt"), +# version = 1, +# src = c(file = data_dir), +# attachment = list(data_file) +# ) +# ) +# } +# glifyColorAttachment = function(fl_color, group) { +# data_dir <- dirname(fl_color) +# data_file <- basename(fl_color) +# list( +# htmltools::htmlDependency( +# name = paste0(group, "cl"), +# version = 1, +# src = c(file = data_dir), +# attachment = list(data_file) +# ) +# ) +# } +# glifyPopupAttachment = function(fl_popup, group) { +# data_dir <- dirname(fl_popup) +# data_file <- basename(fl_popup) +# list( +# htmltools::htmlDependency( +# name = paste0(group, "pop"), +# version = 1, +# src = c(file = data_dir), +# attachment = list(data_file) +# ) +# ) +# } + ## Not used as its not faster - Needs geometries to be the last column and be named geometry -yyjsonr_2_geojson <- function(sfdata) { - # sfdata <- data - geom <- st_geometry(sfdata) - sfdata <- st_drop_geometry(sfdata) - sfdata$geometry <- geom - sfdata <- sf::st_as_sf(sfdata) - json_data <- yyjsonr::write_json_str(sfdata, digits=4) - json_data <- gsub("]}]", "]}}]}", fixed = TRUE, - paste0('{"type":"FeatureCollection","features":[{"type":"Feature","properties":', - gsub('","geometry":', '"},"geometry":{"type":"Polygon","coordinates":', - substr(json_data, 2, nchar(json_data)), fixed = TRUE))) - class(json_data) <- "geojson" - json_data -} \ No newline at end of file +# yyjsonr_2_geojson <- function(sfdata) { +# # sfdata <- data +# geom <- st_geometry(sfdata) +# sfdata <- st_drop_geometry(sfdata) +# sfdata$geometry <- geom +# sfdata <- sf::st_as_sf(sfdata) +# json_data <- yyjsonr::write_json_str(sfdata, digits=4) +# json_data <- gsub("]}]", "]}}]}", fixed = TRUE, +# paste0('{"type":"FeatureCollection","features":[{"type":"Feature","properties":', +# gsub('","geometry":', '"},"geometry":{"type":"Polygon","coordinates":', +# substr(json_data, 2, nchar(json_data)), fixed = TRUE))) +# class(json_data) <- "geojson" +# json_data +# } \ No newline at end of file diff --git a/R/glify-lines.R b/R/glify-lines.R index f8a9655..32b4c57 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -202,7 +202,7 @@ addGlPolylinesSrc = function(map, map$dependencies = c( map$dependencies, - glifyDependenciesSrc(), + glifyDependencies(TRUE), glifyDataAttachmentSrc(fl_data, group) ) @@ -223,10 +223,7 @@ addGlPolylinesSrc = function(map, cat('[', convert_to_json(color, digits = 3), '];', file = fl_color, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyColorAttachmentSrc(fl_color, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_color, group, "col")) color = NULL } @@ -238,10 +235,7 @@ addGlPolylinesSrc = function(map, cat('[', convert_to_json(leaflet::evalFormula(label, data_orig)), '];', file = fl_label, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyLabelAttachmentSrc(fl_label, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_label, group, "lab")) label = NULL } @@ -260,10 +254,7 @@ addGlPolylinesSrc = function(map, cat('[', convert_to_json(makePopup(popup, data_orig)), '];', file = fl_popup, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyPopupAttachmentSrc(fl_popup, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_popup, group, "pop")) popup = NULL } @@ -276,9 +267,7 @@ addGlPolylinesSrc = function(map, file = fl_weight, append = TRUE) map$dependencies = c( - map$dependencies, - glifyRadiusAttachmentSrc(fl_weight, group) - ) + map$dependencies, glifyAttachmentSrc(fl_weight, group, "rad")) weight = NULL } diff --git a/R/glify-points.R b/R/glify-points.R index c99182a..71045d6 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -265,7 +265,7 @@ addGlPointsSrc = function(map, map$dependencies = c( map$dependencies, - glifyDependenciesSrc(), + glifyDependencies(TRUE), glifyDataAttachmentSrc(fl_data, group) ) @@ -287,10 +287,7 @@ addGlPointsSrc = function(map, cat('[', convert_to_json(fillColor, digits = 3), '];', file = fl_color, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyColorAttachmentSrc(fl_color, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_color, group, "col")) fillColor = NULL } @@ -302,10 +299,7 @@ addGlPointsSrc = function(map, cat('[', convert_to_json(leaflet::evalFormula(label, data)), '];', file = fl_label, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyLabelAttachmentSrc(fl_label, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_label, group, "lab")) label = NULL } @@ -324,10 +318,7 @@ addGlPointsSrc = function(map, cat('[', convert_to_json(makePopup(popup, data)), '];', file = fl_popup, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyPopupAttachmentSrc(fl_popup, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_popup, group, "pop")) popup = NULL } @@ -339,10 +330,7 @@ addGlPointsSrc = function(map, cat('[', convert_to_json(radius), '];', file = fl_radius, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyRadiusAttachmentSrc(fl_radius, layerId) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_radius, group, "rad")) radius = NULL } @@ -436,17 +424,14 @@ addGlPointsSrc = function(map, # # dependencies # map$dependencies = c( # map$dependencies, -# glifyDependenciesSrc(), +# glifyDependenciesSrc(TRUE), # glifyDataAttachmentSrc(fl_data1, grp1), # glifyDataAttachmentSrc(fl_data2, grp1, TRUE), -# glifyColorAttachmentSrc(fl_color, group) +# glifyAttachmentSrc(fl_color, group, "col") # ) # # if (!is.null(popup)) { -# map$dependencies = c( -# map$dependencies, -# glifyPopupAttachmentSrc(fl_popup, group) -# ) +# map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_color, group, "col")) # } # # leaflet::invokeMethod(map, leaflet::getMapData(map), 'addGlifyPointsSrc2', diff --git a/R/glify-polygons.R b/R/glify-polygons.R index 7c80030..fa383c0 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -206,7 +206,7 @@ addGlPolygonsSrc = function(map, map$dependencies = c( map$dependencies, - glifyDependenciesSrc(), + glifyDependencies(TRUE), glifyDataAttachmentSrc(fl_data, group) ) @@ -228,10 +228,7 @@ addGlPolygonsSrc = function(map, cat('[', convert_to_json(fillColor, digits = 3), '];', file = fl_color, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyColorAttachmentSrc(fl_color, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_color, group, "col")) fillColor = NULL } @@ -244,10 +241,7 @@ addGlPolygonsSrc = function(map, cat('[', convert_to_json(leaflet::evalFormula(label, data_orig)), '];', file = fl_label, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyLabelAttachmentSrc(fl_label, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_label, group, "lab")) label = NULL } @@ -266,10 +260,7 @@ addGlPolygonsSrc = function(map, cat('[', convert_to_json(makePopup(popup, data_orig)), '];', file = fl_popup, append = TRUE) - map$dependencies = c( - map$dependencies, - glifyPopupAttachmentSrc(fl_popup, group) - ) + map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_popup, group, "pop")) popup = NULL } diff --git a/tests/testthat/test-leafgl-addGlPoints.R b/tests/testthat/test-leafgl-addGlPoints.R index b2f51f4..b7ecbc7 100644 --- a/tests/testthat/test-leafgl-addGlPoints.R +++ b/tests/testthat/test-leafgl-addGlPoints.R @@ -26,8 +26,8 @@ test_that("addGlPoints works", { m = leaflet() %>% addGlPoints(data = pts, layerId = "someid", src = TRUE) expect_is(m, "leaflet") - expect_identical(m$dependencies[[length(m$dependencies)-1]]$name, paste0("someid","dat")) - expect_identical(m$dependencies[[length(m$dependencies)]]$name, paste0("someid","col")) + expect_identical(m$dependencies[[length(m$dependencies)-1]]$name, "glpointsdat") + expect_identical(m$dependencies[[length(m$dependencies)]]$name, "glpointscol") m = leaflet() %>% addGlPoints(data = pts, group = NULL) @@ -36,14 +36,14 @@ test_that("addGlPoints works", { m = leaflet() %>% addGlPoints(data = pts, layerId = NULL, group = NULL, src = TRUE) expect_is(m, "leaflet") - expect_identical(m$dependencies[[length(m$dependencies)-1]]$name, "data-ptsdat") - expect_identical(m$dependencies[[length(m$dependencies)]]$name, "data-ptscol") + expect_identical(m$dependencies[[length(m$dependencies)-1]]$name, "ptsdat") + expect_identical(m$dependencies[[length(m$dependencies)]]$name, "ptscol") m = leaflet() %>% addGlPoints(data = breweries91, src = TRUE) expect_is(m, "leaflet") - expect_identical(m$dependencies[[length(m$dependencies)-1]]$name, "glpoints-ptsdat") - expect_identical(m$dependencies[[length(m$dependencies)]]$name, "glpoints-ptscol") + expect_identical(m$dependencies[[length(m$dependencies)-1]]$name, "glpointsdat") + expect_identical(m$dependencies[[length(m$dependencies)]]$name, "glpointscol") m = leaflet() %>% addGlPoints(data = breweries91, src = TRUE, radius = 5) From 1e95b5509c6824dcca466f4e54c488dcc9a40335 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Sat, 8 Jun 2024 15:22:04 +0200 Subject: [PATCH 09/14] allow custom json_parser_function --- R/glify-helpers.R | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/R/glify-helpers.R b/R/glify-helpers.R index e3df374..1912dcd 100644 --- a/R/glify-helpers.R +++ b/R/glify-helpers.R @@ -62,7 +62,9 @@ glifyAttachmentSrc <- function(fl, group, type) { # helpers json_funccall <- function() { json_parser <- getOption("leafgl_json_parser", "jsonify") # Default to jsonify - if (json_parser == "yyjsonr") { + if (is.function(json_parser)) { + json_parser + } else if (json_parser == "yyjsonr") { yyjsonr::write_json_str } else { jsonify::to_json @@ -70,12 +72,15 @@ json_funccall <- function() { } convert_to_json <- function(data, ...) { json_parser <- getOption("leafgl_json_parser", "jsonify") # Default to jsonify - if (json_parser == "yyjsonr") { - print("I am using yyjsonr") + if (is.function(json_parser)) { + # print("I am using a custom JSON parser function") + json_data <- json_parser(data, ...) + } else if (json_parser == "yyjsonr") { + # print("I am using yyjsonr") json_data <- yyjsonr::write_json_str(data, ...) class(json_data) <- "json" } else { - print("I am using jsonify") + # print("I am using jsonify") json_data <- jsonify::to_json(data, ...) } return(json_data) From 706e10e8ca476498d32c286a4dcb6cf7f36f77ff Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Sun, 9 Jun 2024 15:38:40 +0200 Subject: [PATCH 10/14] fixed hoverwait: 10, docs --- NEWS | 6 ++ R/glify-helpers.R | 20 +++--- R/glify-lines.R | 2 +- R/glify-points.R | 1 - R/glify-polygons.R | 2 +- .../Leaflet.glify/addGlifyPoints.js | 1 + .../Leaflet.glify/addGlifyPointsSrc.js | 1 + .../Leaflet.glify/addGlifyPolygons.js | 1 + .../Leaflet.glify/addGlifyPolygonsSrc.js | 1 + .../Leaflet.glify/addGlifyPolylines.js | 1 + .../Leaflet.glify/addGlifyPolylinesSrc.js | 1 + man/addGlPoints.Rd | 72 ++++++++++--------- 12 files changed, 63 insertions(+), 46 deletions(-) diff --git a/NEWS b/NEWS index 921bd22..63895ad 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,12 @@ documentation etc miscellaneous + * unified / simplified the dependency functions/calls + * add option `leafgl_json_parser` to change JSON-parser via options. Possible values are: + - `jsonify` (default) + - `yyjsonr` + - Custom JSON converter like `jsonlite::toJSON` for example. + leafgl 0.2.1 diff --git a/R/glify-helpers.R b/R/glify-helpers.R index 1912dcd..ddc6f25 100644 --- a/R/glify-helpers.R +++ b/R/glify-helpers.R @@ -144,16 +144,20 @@ convert_to_json <- function(data, ...) { ## Not used as its not faster - Needs geometries to be the last column and be named geometry # yyjsonr_2_geojson <- function(sfdata) { -# # sfdata <- data -# geom <- st_geometry(sfdata) -# sfdata <- st_drop_geometry(sfdata) -# sfdata$geometry <- geom -# sfdata <- sf::st_as_sf(sfdata) +# geom_col <- attr(sfdata, "sf_column") +# # Rename the geometry column to "geometry" if it's not already named "geometry" +# colndat <- names(sfdata) +# if (geom_col != "geometry") { +# colndat[colndat == geom_col] <- "geometry" +# } +# # Move the geometry column to the last position if it's not already the last column +# col_order <- setdiff(colndat, "geometry") +# sfdata <- sfdata[, c(col_order, "geometry")] # json_data <- yyjsonr::write_json_str(sfdata, digits=4) # json_data <- gsub("]}]", "]}}]}", fixed = TRUE, -# paste0('{"type":"FeatureCollection","features":[{"type":"Feature","properties":', -# gsub('","geometry":', '"},"geometry":{"type":"Polygon","coordinates":', -# substr(json_data, 2, nchar(json_data)), fixed = TRUE))) +# paste0('{"type":"FeatureCollection","features":[{"type":"Feature","properties":', +# gsub('","geometry":', '"},"geometry":{"type":"Polygon","coordinates":', +# substr(json_data, 2, nchar(json_data)), fixed = TRUE))) # class(json_data) <- "geojson" # json_data # } \ No newline at end of file diff --git a/R/glify-lines.R b/R/glify-lines.R index 32b4c57..aaae827 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -1,5 +1,6 @@ #' @examples #' library(leaflet) +#' library(leafgl) #' library(sf) #' #' storms = st_as_sf(atlStorms2005) @@ -11,7 +12,6 @@ #' #' @describeIn addGlPoints Add Lines to a leaflet map using Leaflet.glify #' @aliases addGlPolylines -#' @order 2 #' @export addGlPolylines addGlPolylines = function(map, data, diff --git a/R/glify-points.R b/R/glify-points.R index 71045d6..2c23831 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -66,7 +66,6 @@ #' } #' #' @describeIn addGlPoints Add Points to a leaflet map using Leaflet.glify -#' @order 1 #' @examples \donttest{ #' library(leaflet) #' library(leafgl) diff --git a/R/glify-polygons.R b/R/glify-polygons.R index fa383c0..9e069de 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -1,5 +1,6 @@ #' @examples #' library(leaflet) +#' library(leafgl) #' library(sf) #' #' gadm = st_as_sf(gadmCHE) @@ -12,7 +13,6 @@ #' #' @describeIn addGlPoints Add Polygons to a leaflet map using Leaflet.glify #' @aliases addGlPolygons -#' @order 3 #' @export addGlPolygons addGlPolygons = function(map, data, diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js index 39cbf6d..fdba854 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js @@ -43,6 +43,7 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit size: rad, className: group, pane: pane, + hoverWait: 10, layerId: layerId }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPointsSrc.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPointsSrc.js index ca220e9..3d3936b 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPointsSrc.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPointsSrc.js @@ -52,6 +52,7 @@ LeafletWidget.methods.addGlifyPointsSrc = function(cols, opacity, radius, group, size: rad, className: group, pane: pane, + hoverWait: 10, layerId: layerId }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js index 468a46e..b9fcbfa 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js @@ -35,6 +35,7 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, className: group, border: stroke, pane: pane, + hoverWait: 10, layerId: layerId }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygonsSrc.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygonsSrc.js index c601c91..a2443eb 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygonsSrc.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygonsSrc.js @@ -44,6 +44,7 @@ LeafletWidget.methods.addGlifyPolygonsSrc = function(cols, opacity, group, className: group, border: stroke, pane: pane, + hoverWait: 10, layerId: layerId }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js index ec1d573..72b9aa7 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js @@ -45,6 +45,7 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, className: group, weight: wght, pane: pane, + hoverWait: 10, layerId: layerId }; diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylinesSrc.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylinesSrc.js index 9cf5e5d..dd8a00e 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylinesSrc.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylinesSrc.js @@ -54,6 +54,7 @@ LeafletWidget.methods.addGlifyPolylinesSrc = function(cols, opacity, className: group, weight: wght, pane: pane, + hoverWait: 10, layerId: layerId }; diff --git a/man/addGlPoints.Rd b/man/addGlPoints.Rd index bc6b477..5de9147 100644 --- a/man/addGlPoints.Rd +++ b/man/addGlPoints.Rd @@ -1,21 +1,21 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/glify-points.R, R/glify-lines.R, +% Please edit documentation in R/glify-lines.R, R/glify-points.R, % R/glify-polygons.R -\name{addGlPoints} -\alias{addGlPoints} +\name{addGlPolylines} \alias{addGlPolylines} +\alias{addGlPoints} \alias{addGlPolygons} \title{Add Data to a leaflet map using Leaflet.glify} \usage{ -addGlPoints( +addGlPolylines( map, data, - fillColor = "#0033ff", - fillOpacity = 0.8, - radius = 10, - group = "glpoints", + color = cbind(0, 0.2, 1), + opacity = 0.6, + group = "glpolylines", popup = NULL, label = NULL, + weight = 1, layerId = NULL, src = FALSE, pane = "overlayPane", @@ -24,15 +24,15 @@ addGlPoints( ... ) -addGlPolylines( +addGlPoints( map, data, - color = cbind(0, 0.2, 1), - opacity = 0.6, - group = "glpolylines", + fillColor = "#0033ff", + fillOpacity = 0.8, + radius = 10, + group = "glpoints", popup = NULL, label = NULL, - weight = 1, layerId = NULL, src = FALSE, pane = "overlayPane", @@ -64,11 +64,12 @@ addGlPolygons( \item{data}{sf/sp point/polygon/line data to add to the map.} -\item{fillColor}{fill color} - -\item{fillOpacity}{fill opacity} +\item{color}{Object representing the color. Can be of class integer, character with +color names, HEX codes or random characters, factor, matrix, data.frame, list, json or formula. +See the examples or \link{makeColorMatrix} for more information.} -\item{radius}{point size in pixels.} +\item{opacity}{feature opacity. Numeric between 0 and 1. +Note: expect funny results if you set this to < 1.} \item{group}{the name of the group the newly created layers should belong to (for \code{\link[leaflet:clearGroup]{clearGroup()}} and \code{\link[leaflet:addLayersControl]{addLayersControl()}} purposes). @@ -82,6 +83,8 @@ match the number of rows in the data, the popup vector is repeated to match the \item{label}{a character vector of the HTML content for the labels} +\item{weight}{line width/thickness in pixels for \code{addGlPolylines}.} + \item{layerId}{the layer id} \item{src}{whether to pass data to the widget via file attachments.} @@ -107,14 +110,11 @@ Additional arguments could be \code{'sensitivity'}, \code{'sensitivityHover'} or \href{https://github.com/robertleeplummerjr/Leaflet.glify}{Leaflet.glify} repository.} -\item{color}{Object representing the color. Can be of class integer, character with -color names, HEX codes or random characters, factor, matrix, data.frame, list, json or formula. -See the examples or \link{makeColorMatrix} for more information.} +\item{fillColor}{fill color} -\item{opacity}{feature opacity. Numeric between 0 and 1. -Note: expect funny results if you set this to < 1.} +\item{fillOpacity}{fill opacity} -\item{weight}{line width/thickness in pixels for \code{addGlPolylines}.} +\item{radius}{point size in pixels.} \item{stroke}{whether to draw stroke along the path (e.g. the borders of polygons or circles)} @@ -126,10 +126,10 @@ Leaflet.glify is a WebGL renderer plugin for leaflet. See } \section{Functions}{ \itemize{ -\item \code{addGlPoints()}: Add Points to a leaflet map using Leaflet.glify - \item \code{addGlPolylines()}: Add Lines to a leaflet map using Leaflet.glify +\item \code{addGlPoints()}: Add Points to a leaflet map using Leaflet.glify + \item \code{addGlPolygons()}: Add Polygons to a leaflet map using Leaflet.glify }} @@ -167,6 +167,17 @@ MULTILINESTRINGs and MULTIPOLYGONs are currently not supported! } \examples{ +library(leaflet) +library(leafgl) +library(sf) + +storms = st_as_sf(atlStorms2005) +cols = heat.colors(nrow(storms)) + +leaflet() \%>\% + addProviderTiles(provider = providers$CartoDB.Positron) \%>\% + addGlPolylines(data = storms, color = cols, popup = TRUE, opacity = 1) + \donttest{ library(leaflet) library(leafgl) @@ -184,16 +195,7 @@ leaflet() \%>\% addGlPoints(data = pts, fillColor = cols, popup = TRUE) } library(leaflet) -library(sf) - -storms = st_as_sf(atlStorms2005) -cols = heat.colors(nrow(storms)) - -leaflet() \%>\% - addProviderTiles(provider = providers$CartoDB.Positron) \%>\% - addGlPolylines(data = storms, color = cols, popup = TRUE, opacity = 1) - -library(leaflet) +library(leafgl) library(sf) gadm = st_as_sf(gadmCHE) From c3c3a9743eb00fb7590f24b9338823b3ef4f63e7 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Tue, 11 Jun 2024 09:03:07 +0200 Subject: [PATCH 11/14] use yyjsonr for geojson, expose new option "leafgl_geojson_parser" --- R/glify-helpers.R | 39 +++++++++++++++------------------------ R/glify-lines.R | 8 ++++---- R/glify-polygons.R | 8 ++++---- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/R/glify-helpers.R b/R/glify-helpers.R index ddc6f25..1eff00a 100644 --- a/R/glify-helpers.R +++ b/R/glify-helpers.R @@ -73,19 +73,30 @@ json_funccall <- function() { convert_to_json <- function(data, ...) { json_parser <- getOption("leafgl_json_parser", "jsonify") # Default to jsonify if (is.function(json_parser)) { - # print("I am using a custom JSON parser function") json_data <- json_parser(data, ...) } else if (json_parser == "yyjsonr") { - # print("I am using yyjsonr") json_data <- yyjsonr::write_json_str(data, ...) class(json_data) <- "json" } else { - # print("I am using jsonify") json_data <- jsonify::to_json(data, ...) } return(json_data) } - +geojson_funccall <- function() { + json_parser <- getOption("leafgl_geojson_parser", "geojsonsf") # Default to geojsonsf + if (is.function(json_parser)) { + json_parser + } else if (json_parser == "yyjsonr") { + yyson_geojson_str + } else { + geojsonsf::sf_geojson + } +} +yyson_geojson_str <- function(x, ...) { + dt <- yyjsonr::write_geojson_str(x, ...) + class(dt) <- "json" + dt +} ## Not used ########## @@ -141,23 +152,3 @@ convert_to_json <- function(data, ...) { # ) # ) # } - -## Not used as its not faster - Needs geometries to be the last column and be named geometry -# yyjsonr_2_geojson <- function(sfdata) { -# geom_col <- attr(sfdata, "sf_column") -# # Rename the geometry column to "geometry" if it's not already named "geometry" -# colndat <- names(sfdata) -# if (geom_col != "geometry") { -# colndat[colndat == geom_col] <- "geometry" -# } -# # Move the geometry column to the last position if it's not already the last column -# col_order <- setdiff(colndat, "geometry") -# sfdata <- sfdata[, c(col_order, "geometry")] -# json_data <- yyjsonr::write_json_str(sfdata, digits=4) -# json_data <- gsub("]}]", "]}}]}", fixed = TRUE, -# paste0('{"type":"FeatureCollection","features":[{"type":"Feature","properties":', -# gsub('","geometry":', '"},"geometry":{"type":"Polygon","coordinates":', -# substr(json_data, 2, nchar(json_data)), fixed = TRUE))) -# class(json_data) <- "geojson" -# json_data -# } \ No newline at end of file diff --git a/R/glify-lines.R b/R/glify-lines.R index aaae827..95c4c64 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -108,7 +108,7 @@ addGlPolylines = function(map, geojsonsf_args = try( match.arg( names(dotopts) - , names(as.list(args(geojsonsf::sf_geojson))) + , names(as.list(args(geojson_funccall))) , several.ok = TRUE ) , silent = TRUE @@ -116,7 +116,7 @@ addGlPolylines = function(map, if (inherits(geojsonsf_args, "try-error")) geojsonsf_args = NULL if (identical(geojsonsf_args, "sf")) geojsonsf_args = NULL } - data = do.call(geojsonsf::sf_geojson, c(list(data), dotopts[geojsonsf_args])) + data = do.call(geojson_funccall(), c(list(data), dotopts[geojsonsf_args])) # dependencies map$dependencies = c(map$dependencies, glifyDependencies()) @@ -190,14 +190,14 @@ addGlPolylinesSrc = function(map, jsonify_args = try( match.arg( names(dotopts) - , names(as.list(args(geojsonsf::sf_geojson))) + , names(as.list(args(geojson_funccall))) , several.ok = TRUE ) , silent = TRUE ) if (inherits(jsonify_args, "try-error")) jsonify_args = NULL if (identical(jsonify_args, "sf")) jsonify_args = NULL - cat('[', do.call(geojsonsf::sf_geojson, c(list(data), dotopts[jsonify_args])), '];', + cat('[', do.call(geojson_funccall(), c(list(data), dotopts[jsonify_args])), '];', file = fl_data, sep = "", append = TRUE) map$dependencies = c( diff --git a/R/glify-polygons.R b/R/glify-polygons.R index 9e069de..b245965 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -112,7 +112,7 @@ addGlPolygons = function(map, geojsonsf_args = try( match.arg( names(dotopts) - , names(as.list(args(geojsonsf::sf_geojson))) + , names(as.list(args(geojson_funccall))) , several.ok = TRUE ) , silent = TRUE @@ -120,7 +120,7 @@ addGlPolygons = function(map, if (inherits(geojsonsf_args, "try-error")) geojsonsf_args = NULL if (identical(geojsonsf_args, "sf")) geojsonsf_args = NULL } - data = do.call(geojsonsf::sf_geojson, c(list(data), dotopts[geojsonsf_args])) + data = do.call(geojson_funccall(), c(list(data), dotopts[geojsonsf_args])) # dependencies map$dependencies = c(map$dependencies, glifyDependencies()) @@ -194,14 +194,14 @@ addGlPolygonsSrc = function(map, jsonify_args = try( match.arg( names(dotopts) - , names(as.list(args(geojsonsf::sf_geojson))) + , names(as.list(args(geojson_funccall))) , several.ok = TRUE ) , silent = TRUE ) if (inherits(jsonify_args, "try-error")) jsonify_args = NULL if (identical(jsonify_args, "sf")) jsonify_args = NULL - cat('[', do.call(geojsonsf::sf_geojson, c(list(data), dotopts[jsonify_args])), '];', + cat('[', do.call(geojson_funccall(), c(list(data), dotopts[jsonify_args])), '];', file = fl_data, sep = "", append = TRUE) map$dependencies = c( From b509362ccf01984168c577406010297d1e34a244 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Tue, 11 Jun 2024 10:22:02 +0200 Subject: [PATCH 12/14] use yyjonsr instead of jsonify/geojsonsf, use correct options, fix tests for popup = FALSE --- DESCRIPTION | 4 +- NEWS | 5 +- R/glify-helpers.R | 35 +----- R/glify-lines.R | 20 ++-- R/glify-points.R | 43 ++++---- R/glify-polygons.R | 18 ++-- R/utils-color.R | 5 +- R/utils-popup.R | 2 +- man/addGlPoints.Rd | 9 +- man/makeColorMatrix.Rd | 3 +- tests/testthat/test-leafgl-colors.R | 116 ++++++++++---------- tests/testthat/test-leafgl-popup.R | 159 ++++++++++++++-------------- tests/testthat/test-remove_clear.R | 1 - 13 files changed, 193 insertions(+), 227 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b0fb391..db80696 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -31,14 +31,12 @@ Encoding: UTF-8 LazyData: false RoxygenNote: 7.3.1 Imports: - geojsonsf, htmltools, - jsonify, leaflet, sf, + yyjsonr, grDevices Suggests: colourvalues, shiny, - yyjsonr, testthat (>= 2.1.0) diff --git a/NEWS b/NEWS index 63895ad..c09dee3 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ leafgl 0.2.1.9005 (2023-09-08) features and improvements + * Switched from `jsonify` and `geojsonsf` to `yyjsonr` * New method *clearGlGroup* removes a group from leaflet and the Leaflet.Glify instances. * The JavaScript methods of the `removeGl**` functions was rewritten to correctly remove an element identified by `layerId` * `clearGlLayers` now correctly removes all Leaflet.Glify instances @@ -24,10 +25,6 @@ documentation etc miscellaneous * unified / simplified the dependency functions/calls - * add option `leafgl_json_parser` to change JSON-parser via options. Possible values are: - - `jsonify` (default) - - `yyjsonr` - - Custom JSON converter like `jsonlite::toJSON` for example. leafgl 0.2.1 diff --git a/R/glify-helpers.R b/R/glify-helpers.R index 1eff00a..376fef8 100644 --- a/R/glify-helpers.R +++ b/R/glify-helpers.R @@ -60,37 +60,10 @@ glifyAttachmentSrc <- function(fl, group, type) { # helpers -json_funccall <- function() { - json_parser <- getOption("leafgl_json_parser", "jsonify") # Default to jsonify - if (is.function(json_parser)) { - json_parser - } else if (json_parser == "yyjsonr") { - yyjsonr::write_json_str - } else { - jsonify::to_json - } -} -convert_to_json <- function(data, ...) { - json_parser <- getOption("leafgl_json_parser", "jsonify") # Default to jsonify - if (is.function(json_parser)) { - json_data <- json_parser(data, ...) - } else if (json_parser == "yyjsonr") { - json_data <- yyjsonr::write_json_str(data, ...) - class(json_data) <- "json" - } else { - json_data <- jsonify::to_json(data, ...) - } - return(json_data) -} -geojson_funccall <- function() { - json_parser <- getOption("leafgl_geojson_parser", "geojsonsf") # Default to geojsonsf - if (is.function(json_parser)) { - json_parser - } else if (json_parser == "yyjsonr") { - yyson_geojson_str - } else { - geojsonsf::sf_geojson - } +yyson_json_str <- function(x, ...) { + dt <- yyjsonr::write_json_str(x, ...) + class(dt) <- "json" + dt } yyson_geojson_str <- function(x, ...) { dt <- yyjsonr::write_geojson_str(x, ...) diff --git a/R/glify-lines.R b/R/glify-lines.R index 95c4c64..5d6289c 100644 --- a/R/glify-lines.R +++ b/R/glify-lines.R @@ -79,7 +79,7 @@ addGlPolylines = function(map, if (ncol(color) != 3) stop("only 3 column color matrix supported so far") color = as.data.frame(color, stringsAsFactors = FALSE) colnames(color) = c("r", "g", "b") - cols = convert_to_json(color, digits = 3) + cols = yyson_json_str(color, digits = 3) # label / popup ######## labels <- leaflet::evalFormula(label, data) @@ -96,7 +96,7 @@ addGlPolylines = function(map, htmldeps ) } - popup = convert_to_json(makePopup(popup, data)) + popup = yyson_json_str(makePopup(popup, data)) geom = sf::st_geometry(data) data = sf::st_sf(id = 1:length(geom), geometry = geom) } @@ -108,7 +108,7 @@ addGlPolylines = function(map, geojsonsf_args = try( match.arg( names(dotopts) - , names(as.list(args(geojson_funccall))) + , names(as.list(args(yyjsonr::opts_write_json))) , several.ok = TRUE ) , silent = TRUE @@ -116,7 +116,7 @@ addGlPolylines = function(map, if (inherits(geojsonsf_args, "try-error")) geojsonsf_args = NULL if (identical(geojsonsf_args, "sf")) geojsonsf_args = NULL } - data = do.call(geojson_funccall(), c(list(data), dotopts[geojsonsf_args])) + data = do.call(yyson_geojson_str, c(list(data), dotopts[geojsonsf_args])) # dependencies map$dependencies = c(map$dependencies, glifyDependencies()) @@ -190,14 +190,14 @@ addGlPolylinesSrc = function(map, jsonify_args = try( match.arg( names(dotopts) - , names(as.list(args(geojson_funccall))) + , names(as.list(args(yyjsonr::opts_write_json))) , several.ok = TRUE ) , silent = TRUE ) if (inherits(jsonify_args, "try-error")) jsonify_args = NULL if (identical(jsonify_args, "sf")) jsonify_args = NULL - cat('[', do.call(geojson_funccall(), c(list(data), dotopts[jsonify_args])), '];', + cat('[', do.call(yyson_geojson_str, c(list(data), dotopts[jsonify_args])), '];', file = fl_data, sep = "", append = TRUE) map$dependencies = c( @@ -220,7 +220,7 @@ addGlPolylinesSrc = function(map, fl_color = paste0(dir_color, "/", group, "_color.js") pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) - cat('[', convert_to_json(color, digits = 3), '];', + cat('[', yyson_json_str(color, digits = 3), '];', file = fl_color, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_color, group, "col")) @@ -232,7 +232,7 @@ addGlPolylinesSrc = function(map, fl_label = paste0(dir_labels, "/", group, "_label.js") pre = paste0('var labs = labs || {}; labs["', group, '"] = ') writeLines(pre, fl_label) - cat('[', convert_to_json(leaflet::evalFormula(label, data_orig)), '];', + cat('[', yyson_json_str(leaflet::evalFormula(label, data_orig)), '];', file = fl_label, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_label, group, "lab")) @@ -251,7 +251,7 @@ addGlPolylinesSrc = function(map, fl_popup = paste0(dir_popup, "/", group, "_popup.js") pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) - cat('[', convert_to_json(makePopup(popup, data_orig)), '];', + cat('[', yyson_json_str(makePopup(popup, data_orig)), '];', file = fl_popup, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_popup, group, "pop")) @@ -263,7 +263,7 @@ addGlPolylinesSrc = function(map, fl_weight = paste0(dir_weight, "/", group, "_weight.js") pre = paste0('var wgt = wgt || {}; wgt["', group, '"] = ') writeLines(pre, fl_weight) - cat('[', convert_to_json(weight), '];', + cat('[', yyson_json_str(weight), '];', file = fl_weight, append = TRUE) map$dependencies = c( diff --git a/R/glify-points.R b/R/glify-points.R index 2c23831..c7ed8fa 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -19,10 +19,11 @@ #' @param weight line width/thickness in pixels for \code{addGlPolylines}. #' @param src whether to pass data to the widget via file attachments. #' @param pane A string which defines the pane of the layer. The default is \code{"overlayPane"}. -#' @param ... Used to pass additional named arguments to \code{\link[jsonify]{to_json}} -#' & to pass additional arguments to the underlying JavaScript functions. Typical -#' use-cases include setting \code{'digits'} to round the point coordinates or to pass -#' a different \code{'fragmentShaderSource'} to control the shape of the points. Use +#' @param ... Used to pass additional named arguments to \code{\link[yyjsonr]{write_json_str}} or +#' \code{\link[yyjsonr]{write_geojson_str}} & to pass additional arguments to the +#' underlying JavaScript functions. Typical use-cases include setting \code{'digits'} to +#' round the point coordinates or to pass a different \code{'fragmentShaderSource'} to +#' control the shape of the points. Use #' \itemize{ #' \item{\code{'point'} (default) to render circles with a thin black outline} #' \item{\code{'simpleCircle'} for circles without outline} @@ -146,7 +147,7 @@ addGlPoints = function(map, if (ncol(fillColor) != 3) stop("only 3 column fillColor matrix supported so far") fillColor = as.data.frame(fillColor, stringsAsFactors = FALSE) colnames(fillColor) = c("r", "g", "b") - fillColor = convert_to_json(fillColor, digits = 3) + fillColor = yyson_json_str(fillColor, digits = 3) # label / popup ########### labels <- leaflet::evalFormula(label, data) @@ -158,7 +159,7 @@ addGlPoints = function(map, htmldeps ) } - popup = convert_to_json(makePopup(popup, data)) + popup = yyson_json_str(makePopup(popup, data)) } else { popup = NULL } @@ -171,14 +172,14 @@ addGlPoints = function(map, jsonify_args = try( match.arg( names(dotopts) - , names(as.list(args(json_funccall))) + , names(as.list(args(yyjsonr::opts_write_json))) , several.ok = TRUE ) , silent = TRUE ) } if (inherits(jsonify_args, "try-error")) jsonify_args = NULL - data = do.call(json_funccall(), c(list(crds), dotopts[jsonify_args])) + data = do.call(yyson_json_str, c(list(crds), dotopts[jsonify_args])) class(data) <- "json" # dependencies @@ -252,14 +253,14 @@ addGlPointsSrc = function(map, jsonify_args = try( match.arg( names(dotopts) - , names(as.list(args(json_funccall))) + , names(as.list(args(yyjsonr::opts_write_json))) , several.ok = TRUE ) , silent = TRUE ) if (inherits(jsonify_args, "try-error")) jsonify_args = NULL if (identical(jsonify_args, "x")) jsonify_args = NULL - cat('[', do.call(json_funccall(), c(list(crds), dotopts[jsonify_args])), '];', + cat('[', do.call(yyson_json_str, c(list(crds), dotopts[jsonify_args])), '];', file = fl_data, sep = "", append = TRUE) map$dependencies = c( @@ -283,7 +284,7 @@ addGlPointsSrc = function(map, fl_color = paste0(dir_color, "/", group, "_color.js") pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) - cat('[', convert_to_json(fillColor, digits = 3), '];', + cat('[', yyson_json_str(fillColor, digits = 3), '];', file = fl_color, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_color, group, "col")) @@ -295,7 +296,7 @@ addGlPointsSrc = function(map, fl_label = paste0(dir_labels, "/", group, "_label.js") pre = paste0('var labs = labs || {}; labs["', group, '"] = ') writeLines(pre, fl_label) - cat('[', convert_to_json(leaflet::evalFormula(label, data)), '];', + cat('[', yyson_json_str(leaflet::evalFormula(label, data)), '];', file = fl_label, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_label, group, "lab")) @@ -314,7 +315,7 @@ addGlPointsSrc = function(map, fl_popup = paste0(dir_popup, "/", group, "_popup.js") pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) - cat('[', convert_to_json(makePopup(popup, data)), '];', + cat('[', yyson_json_str(makePopup(popup, data)), '];', file = fl_popup, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_popup, group, "pop")) @@ -326,7 +327,7 @@ addGlPointsSrc = function(map, fl_radius = paste0(dir_radius, "/", layerId, "_radius.js") pre = paste0('var rad = rad || {}; rad["', layerId, '"] = ') writeLines(pre, fl_radius) - cat('[', convert_to_json(radius), '];', + cat('[', yyson_json_str(radius), '];', file = fl_radius, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_radius, group, "rad")) @@ -391,11 +392,11 @@ addGlPointsSrc = function(map, # fl_data2 = paste0(dir_data, "/", grp2, "_data.json") # pre1 = paste0('var data = data || {}; data["', grp1, '"] = ') # writeLines(pre1, fl_data1) -# cat('[', jsonify::to_json(crds[1:100, ], ...), '];', +# cat('[', yyson_json_str(crds[1:100, ], ...), '];', # file = fl_data1, sep = "", append = TRUE) # pre2 = paste0('var data = data || {}; data["', grp2, '"] = ') # writeLines(pre2, fl_data2) -# cat('[', jsonify::to_json(crds[101:nrow(crds), ], ...), '];', +# cat('[', yyson_json_str(crds[101:nrow(crds), ], ...), '];', # file = fl_data2, sep = "", append = TRUE) # # # color @@ -406,7 +407,7 @@ addGlPointsSrc = function(map, # fl_color = paste0(dir_color, "/", group, "_color.json") # pre = paste0('var col = col || {}; col["', group, '"] = ') # writeLines(pre, fl_color) -# cat('[', jsonify::to_json(color), '];', +# cat('[', yyson_json_str(color), '];', # file = fl_color, append = TRUE) # # # popup @@ -414,7 +415,7 @@ addGlPointsSrc = function(map, # fl_popup = paste0(dir_popup, "/", group, "_popup.json") # pre = paste0('var popup = popup || {}; popup["', group, '"] = ') # writeLines(pre, fl_popup) -# cat('[', jsonify::to_json(data[[popup]]), '];', +# cat('[', yyson_json_str(data[[popup]]), '];', # file = fl_popup, append = TRUE) # } else { # popup = NULL @@ -468,7 +469,7 @@ addGlPointsSrc = function(map, # crds = sf::st_coordinates(data)[, c(2, 1)] # # fl_data = paste0(dir_data, "/", group, "_data.json") -# cat(jsonify::to_json(crds, digits = 7), file = fl_data, append = FALSE) +# cat(yyson_json_str(crds, digits = 7), file = fl_data, append = FALSE) # data_var = paste0(group, "dt") # # # color @@ -476,14 +477,14 @@ addGlPointsSrc = function(map, # color = as.data.frame(color, stringsAsFactors = FALSE) # colnames(color) = c("r", "g", "b") # -# jsn = jsonify::to_json(color) +# jsn = yyson_json_str(color) # fl_color = paste0(dir_color, "/", group, "_color.json") # color_var = paste0(group, "cl") # cat(jsn, file = fl_color, append = FALSE) # # # popup # if (!is.null(popup)) { -# pop = jsonify::to_json(data[[popup]]) +# pop = yyson_json_str(data[[popup]]) # fl_popup = paste0(dir_popup, "/", group, "_popup.json") # popup_var = paste0(group, "pop") # cat(pop, file = fl_popup, append = FALSE) diff --git a/R/glify-polygons.R b/R/glify-polygons.R index b245965..cddf5f8 100644 --- a/R/glify-polygons.R +++ b/R/glify-polygons.R @@ -82,7 +82,7 @@ addGlPolygons = function(map, if (ncol(fillColor) != 3) stop("only 3 column fillColor matrix supported so far") fillColor = as.data.frame(fillColor, stringsAsFactors = FALSE) colnames(fillColor) = c("r", "g", "b") - cols = convert_to_json(fillColor, digits = 3) + cols = yyson_json_str(fillColor, digits = 3) # label / popup ########### labels <- leaflet::evalFormula(label, data) @@ -100,7 +100,7 @@ addGlPolygons = function(map, htmldeps ) } - popup = convert_to_json(makePopup(popup, data)) + popup = yyson_json_str(makePopup(popup, data)) geom = sf::st_geometry(data) data = sf::st_sf(id = 1:length(geom), geometry = geom) } @@ -112,7 +112,7 @@ addGlPolygons = function(map, geojsonsf_args = try( match.arg( names(dotopts) - , names(as.list(args(geojson_funccall))) + , names(as.list(args(yyjsonr::opts_write_json))) , several.ok = TRUE ) , silent = TRUE @@ -120,7 +120,7 @@ addGlPolygons = function(map, if (inherits(geojsonsf_args, "try-error")) geojsonsf_args = NULL if (identical(geojsonsf_args, "sf")) geojsonsf_args = NULL } - data = do.call(geojson_funccall(), c(list(data), dotopts[geojsonsf_args])) + data = do.call(yyson_geojson_str, c(list(data), dotopts[geojsonsf_args])) # dependencies map$dependencies = c(map$dependencies, glifyDependencies()) @@ -194,14 +194,14 @@ addGlPolygonsSrc = function(map, jsonify_args = try( match.arg( names(dotopts) - , names(as.list(args(geojson_funccall))) + , names(as.list(args(yyjsonr::opts_write_json))) , several.ok = TRUE ) , silent = TRUE ) if (inherits(jsonify_args, "try-error")) jsonify_args = NULL if (identical(jsonify_args, "sf")) jsonify_args = NULL - cat('[', do.call(geojson_funccall(), c(list(data), dotopts[jsonify_args])), '];', + cat('[', do.call(yyson_geojson_str, c(list(data), dotopts[jsonify_args])), '];', file = fl_data, sep = "", append = TRUE) map$dependencies = c( @@ -225,7 +225,7 @@ addGlPolygonsSrc = function(map, fl_color = paste0(dir_color, "/", group, "_color.js") pre = paste0('var col = col || {}; col["', group, '"] = ') writeLines(pre, fl_color) - cat('[', convert_to_json(fillColor, digits = 3), '];', + cat('[', yyson_json_str(fillColor, digits = 3), '];', file = fl_color, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_color, group, "col")) @@ -238,7 +238,7 @@ addGlPolygonsSrc = function(map, fl_label = paste0(dir_labels, "/", group, "_label.js") pre = paste0('var labs = labs || {}; labs["', group, '"] = ') writeLines(pre, fl_label) - cat('[', convert_to_json(leaflet::evalFormula(label, data_orig)), '];', + cat('[', yyson_json_str(leaflet::evalFormula(label, data_orig)), '];', file = fl_label, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_label, group, "lab")) @@ -257,7 +257,7 @@ addGlPolygonsSrc = function(map, fl_popup = paste0(dir_popup, "/", group, "_popup.js") pre = paste0('var pops = pops || {}; pops["', group, '"] = ') writeLines(pre, fl_popup) - cat('[', convert_to_json(makePopup(popup, data_orig)), '];', + cat('[', yyson_json_str(makePopup(popup, data_orig)), '];', file = fl_popup, append = TRUE) map$dependencies = c(map$dependencies, glifyAttachmentSrc(fl_popup, group, "pop")) diff --git a/R/utils-color.R b/R/utils-color.R index 0cec6d3..36b3e44 100644 --- a/R/utils-color.R +++ b/R/utils-color.R @@ -44,8 +44,7 @@ #' makeColorMatrix(~vals1, testdf) #' #' ## For JSON -#' library(jsonify) -#' makeColorMatrix(jsonify::to_json(data.frame(r = 54, g = 186, b = 1)), NULL) +#' makeColorMatrix(leafgl:::yyson_json_str(data.frame(r = 54, g = 186, b = 1)), NULL) #' #' ## For Lists #' makeColorMatrix(list(1,2), data.frame(x=c(1,2))) @@ -140,7 +139,7 @@ makeColorMatrix.list <- function(x, data = NULL, palette = "viridis", ...) { #' @export makeColorMatrix.json <- function(x, data = NULL, palette = "viridis", ...) { - x <- jsonify::from_json(x) + x <- yyjsonr::read_json_str(x) makeColorMatrix(x, data, palette, ...) } diff --git a/R/utils-popup.R b/R/utils-popup.R index c86f1ed..00b2d87 100644 --- a/R/utils-popup.R +++ b/R/utils-popup.R @@ -84,7 +84,7 @@ makePopup.list <- function(x, data) { #' @export makePopup.json <- function(x, data) { - x <- jsonify::from_json(x) + x <- yyjsonr::read_json_str(x) makePopup(x, data) } diff --git a/man/addGlPoints.Rd b/man/addGlPoints.Rd index 5de9147..28854a7 100644 --- a/man/addGlPoints.Rd +++ b/man/addGlPoints.Rd @@ -96,10 +96,11 @@ match the number of rows in the data, the popup vector is repeated to match the \item{labelOptions}{A Vector of \code{\link[leaflet:labelOptions]{labelOptions()}} to provide label options for each label. Default \code{NULL}} -\item{...}{Used to pass additional named arguments to \code{\link[jsonify]{to_json}} -& to pass additional arguments to the underlying JavaScript functions. Typical -use-cases include setting \code{'digits'} to round the point coordinates or to pass -a different \code{'fragmentShaderSource'} to control the shape of the points. Use +\item{...}{Used to pass additional named arguments to \code{\link[yyjsonr]{write_json_str}} or +\code{\link[yyjsonr]{write_geojson_str}} & to pass additional arguments to the +underlying JavaScript functions. Typical use-cases include setting \code{'digits'} to +round the point coordinates or to pass a different \code{'fragmentShaderSource'} to +control the shape of the points. Use \itemize{ \item{\code{'point'} (default) to render circles with a thin black outline} \item{\code{'simpleCircle'} for circles without outline} diff --git a/man/makeColorMatrix.Rd b/man/makeColorMatrix.Rd index 1a646b2..c0c4ced 100644 --- a/man/makeColorMatrix.Rd +++ b/man/makeColorMatrix.Rd @@ -56,8 +56,7 @@ makeColorMatrix(~vals, testdf) makeColorMatrix(~vals1, testdf) ## For JSON -library(jsonify) -makeColorMatrix(jsonify::to_json(data.frame(r = 54, g = 186, b = 1)), NULL) +makeColorMatrix(leafgl:::yyson_json_str(data.frame(r = 54, g = 186, b = 1)), NULL) ## For Lists makeColorMatrix(list(1,2), data.frame(x=c(1,2))) diff --git a/tests/testthat/test-leafgl-colors.R b/tests/testthat/test-leafgl-colors.R index 0c25e92..d7b299b 100644 --- a/tests/testthat/test-leafgl-colors.R +++ b/tests/testthat/test-leafgl-colors.R @@ -1,7 +1,7 @@ context("test-leafgl-color_utils") library(leaflet) library(sf) -library(jsonify) +library(yyjsonr) n = 1e2 df1 = data.frame(id = 1:n, id2 = n:1, @@ -47,7 +47,7 @@ test_that("Character as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -65,7 +65,7 @@ test_that("Character as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -74,7 +74,7 @@ test_that("Character as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -83,7 +83,7 @@ test_that("Character as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## Character - Column Name ################### @@ -93,7 +93,7 @@ test_that("Character as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -102,7 +102,7 @@ test_that("Character as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -111,7 +111,7 @@ test_that("Character as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## Character - HEX-Code ################### @@ -121,7 +121,7 @@ test_that("Character as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -130,7 +130,7 @@ test_that("Character as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -139,7 +139,7 @@ test_that("Character as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## Character - Character Column Name ############# @@ -149,7 +149,7 @@ test_that("Character as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## Character - Character Column Name with Palette ############# @@ -160,7 +160,7 @@ test_that("Character as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) }) @@ -172,7 +172,7 @@ test_that("Formula as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -182,7 +182,7 @@ test_that("Formula as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -201,7 +201,7 @@ test_that("Formula as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -211,7 +211,7 @@ test_that("Formula as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -230,7 +230,7 @@ test_that("Formula as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -240,7 +240,7 @@ test_that("Formula as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -262,7 +262,7 @@ test_that("Tables as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -271,7 +271,7 @@ test_that("Tables as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -280,7 +280,7 @@ test_that("Tables as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -289,7 +289,7 @@ test_that("Tables as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -298,7 +298,7 @@ test_that("Tables as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) @@ -309,7 +309,7 @@ test_that("Tables as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -318,7 +318,7 @@ test_that("Tables as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -327,7 +327,7 @@ test_that("Tables as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## data.frame with nrow = 1 ################### @@ -337,7 +337,7 @@ test_that("Tables as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -346,7 +346,7 @@ test_that("Tables as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) }) @@ -359,7 +359,7 @@ test_that("Numeric as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -368,7 +368,7 @@ test_that("Numeric as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -377,7 +377,7 @@ test_that("Numeric as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## Numeric ################### @@ -387,7 +387,7 @@ test_that("Numeric as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -396,7 +396,7 @@ test_that("Numeric as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -405,7 +405,7 @@ test_that("Numeric as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## Factor ################### @@ -415,7 +415,7 @@ test_that("Numeric as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -424,7 +424,7 @@ test_that("Numeric as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -433,7 +433,7 @@ test_that("Numeric as color", { group = "pts") expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) @@ -443,7 +443,7 @@ test_that("Numeric as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -452,7 +452,7 @@ test_that("Numeric as color", { group = "lns"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) }) @@ -465,7 +465,7 @@ test_that("List as color", { group = "pts") expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -474,7 +474,7 @@ test_that("List as color", { group = "pts") expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) @@ -484,7 +484,7 @@ test_that("List as color", { group = "pts") expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -493,7 +493,7 @@ test_that("List as color", { group = "pts") expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -502,7 +502,7 @@ test_that("List as color", { group = "pts") expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- expect_warning(leaflet() %>% @@ -512,7 +512,7 @@ test_that("List as color", { group = "pts")) expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) }) @@ -521,33 +521,33 @@ test_that("JSON as color", { ## JSON with same dimensions ################### m <- leaflet() %>% addGlPoints(data = pts, - fillColor = jsonify::to_json(list(matrix(sample(1:255, nrow(pts)*3, replace = T), ncol = 3))), + fillColor = leafgl:::yyson_json_str(list(matrix(sample(1:255, nrow(pts)*3, replace = T), ncol = 3))), group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## JSON with 1 color ################### m <- leaflet() %>% addGlPoints(data = pts, - fillColor = jsonify::to_json(data.frame(r = 54, g = 186, b = 1)), + fillColor = leafgl:::yyson_json_str(data.frame(r = 54, g = 186, b = 1)), group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## JSON with wrong dimension - Warning ################### m <- expect_warning(leaflet() %>% addGlPoints(data = pts, - fillColor = jsonify::to_json(data.frame(r = c(54, 123), + fillColor = leafgl:::yyson_json_str(data.frame(r = c(54, 123), g = c(1, 186), b = c(1, 123))), group = "pts")) expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) }) @@ -560,7 +560,7 @@ test_that("Date/POSIX* as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## POSIXct ################### @@ -570,7 +570,7 @@ test_that("Date/POSIX* as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## Date ################### @@ -580,7 +580,7 @@ test_that("Date/POSIX* as color", { group = "pts"); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) }) @@ -592,7 +592,7 @@ test_that("Warnings / Errors", { group = "pts")) expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- expect_warning(leaflet() %>% @@ -601,7 +601,7 @@ test_that("Warnings / Errors", { group = "pts")); expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% @@ -610,7 +610,7 @@ test_that("Warnings / Errors", { group = "pts") expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) ## Errors + Warnings ################### diff --git a/tests/testthat/test-leafgl-popup.R b/tests/testthat/test-leafgl-popup.R index cf4f4ff..9b16bc4 100644 --- a/tests/testthat/test-leafgl-popup.R +++ b/tests/testthat/test-leafgl-popup.R @@ -1,7 +1,7 @@ context("test-leafgl-popup") library(leaflet) -library(jsonify) +library(yyjsonr) library(sf) ## makePopup solo ####### @@ -28,8 +28,8 @@ test_that("popup-points-character", { popup = "state", group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), breweries91$state) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), breweries91$state) rm(m) sfpoints <- sf::st_as_sf(breweries91) @@ -39,7 +39,7 @@ test_that("popup-points-character", { group = "grp") expect_is(m, "leaflet") expect_is(m$x$calls[[1]]$args[[2]], "json") - expect_true(validate_json(m$x$calls[[1]]$args[[2]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[1]]$args[[2]])) rm(m) m <- leaflet() %>% addTiles() %>% @@ -47,8 +47,8 @@ test_that("popup-points-character", { popup = breweries91$state, group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), breweries91$state) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), breweries91$state) rm(m) ## Column Names ############## @@ -57,8 +57,8 @@ test_that("popup-points-character", { popup = c("state", "address"), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - # expect_identical(from_json(m$x$calls[[2]]$args[[3]]), breweries91$state) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + # expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), breweries91$state) rm(m) ## Single Random Character ############## @@ -67,8 +67,8 @@ test_that("popup-points-character", { popup = "Text 1", group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(breweries91))) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(breweries91))) rm(m) ## Multiple Random Characters - (wrong length) ############## @@ -77,8 +77,8 @@ test_that("popup-points-character", { popup = c("Text 1", "Text 2"), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep(c("Text 1","Text 2"), nrow(breweries91))[1:nrow(breweries91)]) rm(m) @@ -88,8 +88,8 @@ test_that("popup-points-character", { popup = rep("Text 1", nrow(breweries91)), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(breweries91))) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(breweries91))) }) test_that("popup-points-table", { @@ -99,7 +99,7 @@ test_that("popup-points-table", { popup = as.data.frame(breweries91), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, @@ -114,7 +114,7 @@ test_that("popup-points-table", { popup = as.data.frame(breweries91)[1:4,], group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## Matrix ############## m <- leaflet() %>% addTiles() %>% @@ -122,7 +122,7 @@ test_that("popup-points-table", { popup = as.matrix(as.data.frame(breweries91)), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) @@ -133,7 +133,7 @@ test_that("popup-points-spatial", { popup = breweries91, group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, @@ -149,7 +149,7 @@ test_that("popup-points-spatial", { popup = st_as_sf(breweries91), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) test_that("popup-points-formula", { @@ -162,7 +162,7 @@ test_that("popup-points-formula", { state, address, brewery), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, @@ -183,7 +183,7 @@ test_that("popup-points-list", { district=5029, stringsAsFactors = F)), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## List with length >1 ############## m <- leaflet() %>% addTiles() %>% @@ -193,7 +193,7 @@ test_that("popup-points-list", { stringsAsFactors = F)), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## List with same length ############## @@ -202,7 +202,7 @@ test_that("popup-points-list", { popup = as.list(as.data.frame(breweries91)), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) @@ -210,40 +210,40 @@ test_that("popup-points-json", { ## JSON - 1 column ############## m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, - popup = jsonify::to_json(as.list(as.data.frame(breweries91[,1]))), + popup = yyson_json_str(as.list(as.data.frame(breweries91[,1]))), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, - popup = jsonify::to_json(as.data.frame(breweries91[,1])), + popup = yyson_json_str(as.data.frame(breweries91[,1])), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## JSON - multiple columns ############## m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, - popup = jsonify::to_json(as.list(as.data.frame(breweries91[,1:5]))), + popup = yyson_json_str(as.list(as.data.frame(breweries91[,1:5]))), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, - popup = jsonify::to_json(as.data.frame(breweries91[1,])), + popup = yyson_json_str(as.data.frame(breweries91[1,])), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## JSON with same length ############## m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, - popup = jsonify::to_json(as.list(as.data.frame(breweries91))), + popup = yyson_json_str(as.list(as.data.frame(breweries91))), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) test_that("popup-points-logical", { @@ -253,7 +253,7 @@ test_that("popup-points-logical", { popup = TRUE, group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, @@ -268,8 +268,8 @@ test_that("popup-points-logical", { popup = FALSE, group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_true(m$x$calls[[2]]$args[[3]] == "{}") + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_true(m$x$calls[[2]]$args[[3]] == "[]") ## NULL ################# m <- leaflet() %>% addTiles() %>% @@ -289,7 +289,7 @@ test_that("popup-points-shiny.tag", { popup = shiny::icon("car"), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m <- leaflet() %>% addTiles() %>% addGlPoints(data = breweries91, @@ -306,7 +306,7 @@ test_that("popup-points-shiny.tag", { # ), # group = "grp")) # expect_is(m, "leaflet") - # expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + # expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) test_that("popup-points-default", { @@ -316,7 +316,7 @@ test_that("popup-points-default", { popup = Sys.time(), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## POSIX* - same length############## m <- leaflet() %>% addTiles() %>% @@ -325,7 +325,7 @@ test_that("popup-points-default", { length.out = nrow(breweries91)), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## Date ############## m <- leaflet() %>% addTiles() %>% @@ -333,7 +333,7 @@ test_that("popup-points-default", { popup = Sys.Date(), group = "grp") expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) ## LINES ################################# @@ -348,8 +348,8 @@ test_that("popup-lines-character", { popup = "Name", opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), as.character(storms$Name)) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), as.character(storms$Name)) rm(m) m <- leaflet() %>% addTiles() %>% @@ -357,8 +357,8 @@ test_that("popup-lines-character", { popup = storms$Name, opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), as.character(storms$Name)) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), as.character(storms$Name)) rm(m) @@ -368,7 +368,7 @@ test_that("popup-lines-character", { popup = c("Name", "MaxWind"), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) rm(m) ## Buttons / Icons / Emojis ?? ############## @@ -427,8 +427,8 @@ test_that("popup-lines-character", { popup = "Text 1", opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(storms))) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(storms))) rm(m) ## Multiple Random Characters - (wrong length) ############## @@ -437,8 +437,8 @@ test_that("popup-lines-character", { popup = c("Text 1", "Text 2"), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep(c("Text 1","Text 2"), nrow(storms))[1:nrow(storms)]) rm(m) @@ -448,8 +448,8 @@ test_that("popup-lines-character", { popup = rep("Text 1", nrow(storms)), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(storms))) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(storms))) }) test_that("popup-lines-table", { @@ -459,7 +459,7 @@ test_that("popup-lines-table", { popup = as.data.frame(storms), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m$x$calls[[2]]$args[[3]] m <- leaflet() %>% addTiles() %>% @@ -475,7 +475,7 @@ test_that("popup-lines-table", { popup = as.data.frame(storms)[1:4,], opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) m <- leaflet() %>% addTiles() %>% addGlPolylines(data = storms, @@ -500,7 +500,7 @@ test_that("popup-lines-table", { popup = as.matrix(as.data.frame(storms)), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) test_that("popup-lines-spatial", { @@ -511,7 +511,7 @@ test_that("popup-lines-spatial", { popup = popups, opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## Simple Feature ############## library(sf) @@ -521,7 +521,7 @@ test_that("popup-lines-spatial", { opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) test_that("popup-lines-formula", { @@ -535,7 +535,7 @@ test_that("popup-lines-formula", { opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) test_that("popup-lines-logical", { @@ -553,8 +553,8 @@ test_that("popup-lines-logical", { popup = FALSE, opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_true(m$x$calls[[2]]$args[[3]] == "{}") + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_true(m$x$calls[[2]]$args[[3]] == "[]") ## NULL ################# m <- leaflet() %>% addTiles() %>% @@ -576,8 +576,8 @@ test_that("popup-polygon-character", { popup = "HASC_1", opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), gadm$HASC_1) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), gadm$HASC_1) rm(m) m <- leaflet() %>% addTiles() %>% @@ -593,8 +593,8 @@ test_that("popup-polygon-character", { popup = gadm$HASC_1, opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), gadm$HASC_1) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), gadm$HASC_1) rm(m) m <- leaflet() %>% addTiles() %>% @@ -611,7 +611,7 @@ test_that("popup-polygon-character", { popup = c("HASC_1", "NAME_0"), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) rm(m) m <- leaflet() %>% addTiles() %>% @@ -664,8 +664,8 @@ test_that("popup-polygon-character", { popup = "Text 1", opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(gadm))) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(gadm))) rm(m) ## Multiple Random Characters - (wrong length) ############## @@ -674,8 +674,8 @@ test_that("popup-polygon-character", { popup = c("Text 1", "Text 2"), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep(c("Text 1","Text 2"), nrow(gadm))[1:nrow(gadm)]) rm(m) @@ -685,8 +685,8 @@ test_that("popup-polygon-character", { popup = rep("Text 1", nrow(gadm)), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_identical(from_json(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(gadm))) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_identical(read_json_str(m$x$calls[[2]]$args[[3]]), rep("Text 1", nrow(gadm))) }) test_that("popup-polygon-table", { @@ -696,7 +696,7 @@ test_that("popup-polygon-table", { popup = as.data.frame(gadm)[1:6], opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## Data.frame - wrong length ############## m <- leaflet() %>% addTiles() %>% @@ -704,7 +704,7 @@ test_that("popup-polygon-table", { popup = as.data.frame(gadm)[1, 1:4], opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## Matrix ############## m <- leaflet() %>% addTiles() %>% @@ -712,7 +712,7 @@ test_that("popup-polygon-table", { popup = as.matrix(as.data.frame(gadm)[1:6]), opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) @@ -724,7 +724,7 @@ test_that("popup-polygon-spatial", { popup = popups, opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) ## Simple Feature ############## library(sf) @@ -734,7 +734,7 @@ test_that("popup-polygon-spatial", { opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) test_that("popup-polygon-formula", { @@ -748,7 +748,7 @@ test_that("popup-polygon-formula", { opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) }) test_that("popup-polygon-logical", { @@ -766,15 +766,14 @@ test_that("popup-polygon-logical", { popup = FALSE, opacity = 1) expect_is(m, "leaflet") - expect_true(jsonify::validate_json(m$x$calls[[2]]$args[[3]])) - expect_true(m$x$calls[[2]]$args[[3]] == "{}") + expect_true(yyjsonr::validate_json_str(m$x$calls[[2]]$args[[3]])) + expect_true(m$x$calls[[2]]$args[[3]] == "[]") ## NULL ################# m <- leaflet() %>% addTiles() %>% addGlPolygons(data = gadm, popup = NULL, opacity = 1) - expect_is(m, "leaflet") expect_true(is.null(m$x$calls[[2]]$args[[3]])) }) diff --git a/tests/testthat/test-remove_clear.R b/tests/testthat/test-remove_clear.R index 7fc5f96..ffb4aef 100644 --- a/tests/testthat/test-remove_clear.R +++ b/tests/testthat/test-remove_clear.R @@ -2,7 +2,6 @@ context("test-leafgl-remove_clear") library(leaflet) library(sf) -library(jsonify) n = 1e2 df1 = data.frame(id = 1:n, id2 = n:1, From af381ddc03ccba03e0172f49e5d61b7122184749 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Sun, 23 Jun 2024 00:29:40 +0200 Subject: [PATCH 13/14] update Glify to 3.3.0, remove arr.splice workaround, remove tooltip in hoverOff --- NEWS | 15 +++++---- NEWS.md | 32 +++++++++++++++---- inst/htmlwidgets/Leaflet.glify/GlifyUtils.js | 4 --- .../Leaflet.glify/addGlifyPoints.js | 6 ++++ .../Leaflet.glify/addGlifyPolygons.js | 7 ++++ .../Leaflet.glify/addGlifyPolylines.js | 6 ++++ .../Leaflet.glify/glify-browser.js | 11 ++----- man/addGlPoints.Rd | 8 ++--- man/remove.Rd | 4 +-- 9 files changed, 61 insertions(+), 32 deletions(-) diff --git a/NEWS b/NEWS index c09dee3..1cd51ca 100644 --- a/NEWS +++ b/NEWS @@ -6,15 +6,16 @@ features and improvements * New method *clearGlGroup* removes a group from leaflet and the Leaflet.Glify instances. * The JavaScript methods of the `removeGl**` functions was rewritten to correctly remove an element identified by `layerId` * `clearGlLayers` now correctly removes all Leaflet.Glify instances - * When showing/hiding Leaflet.Glify layers, they are set to active = TRUE/FALSE to make mouseevents work again. #48, #50 + * When showing/hiding Leaflet.Glify layers, they are set to active = TRUE/FALSE to make mouseevents work again. #48 #50 bug fixes - * src version now works also in shiny. #71 - * added `popupOptions` and `labelOptions`. #83 - * added `stroke` (default=TRUE) in `addGlPolygons` and `addGlPolygonsSrc` for drawing borders. #3 - * Labels work similar to `leaflet`. `leafgl` accepts a single string, a vector of strings or a formula. #78 - * The `...` arguments are now passed to all methods in the underlying library. This allows us to set + * Increase precision of points, lines and shapes by translating them closer to the Pixel Origin. Thanks @RayLarone #93 + * src version now works also in shiny. #71 + * added `popupOptions` and `labelOptions`. #83 + * added `stroke` (default=TRUE) in `addGlPolygons` and `addGlPolygonsSrc` for drawing borders. #3 #68 + * Labels work similar to `leaflet`. `leafgl` accepts a single string, a vector of strings or a formula. #78 + * The `...` arguments are now passed to all methods in the underlying library. This allows us to set additional arguments like `fragmentShaderSource`, `sensitivity` or `sensitivityHover`. documentation etc @@ -24,6 +25,8 @@ documentation etc miscellaneous + * update upstream javascript dependency to 3.3.0. #49 + Note: If you previously used the workaround `L.glify.Shapes.instances.splice(0, 1)`, please remove it with this new version. * unified / simplified the dependency functions/calls diff --git a/NEWS.md b/NEWS.md index f36e145..51bbf35 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,37 +2,55 @@ #### ✨ features and improvements +- Switched from `jsonify` and `geojsonsf` to `yyjsonr` +- New method `clearGlGroup` removes a group from leaflet and the Leaflet.Glify instances. +- The JavaScript methods of the `removeGl**` functions was rewritten to correctly remove an element identified by `layerId` +- `clearGlLayers` now correctly removes all Leaflet.Glify instances +- When showing/hiding Leaflet.Glify layers, they are set to active = TRUE/FALSE to make mouseevents work again. [#48](https://github.com/r-spatial/leafgl/issues/48) [#50](https://github.com/r-spatial/leafgl/issues/50) + #### 🐛 bug fixes - * src version now works also in shiny. #71 +- Increase precision of points, lines and shapes by translating them closer to the Pixel Origin. Thanks @RayLarone [#93](https://github.com/r-spatial/leafgl/issues/93) +- src version now works also in shiny. [#71](https://github.com/r-spatial/leafgl/issues/71) +- added `popupOptions` and `labelOptions`. [#83](https://github.com/r-spatial/leafgl/issues/83) +- added `stroke` (default=TRUE) in `addGlPolygons` and `addGlPolygonsSrc` for drawing borders. [#3](https://github.com/r-spatial/leafgl/issues/3) [#68](https://github.com/r-spatial/leafgl/issues/68) +- Labels work similar to `leaflet`. `leafgl` accepts a single string, a vector of strings or a formula. [#78](https://github.com/r-spatial/leafgl/issues/78) +- The `...` arguments are now passed to all methods in the underlying library. This allows us to set additional arguments like `fragmentShaderSource`, `sensitivity` or `sensitivityHover`. [#81](https://github.com/r-spatial/leafgl/issues/81) #### 💬 documentation etc +- Added some @details for Shiny click and mouseover events and their corresponding input. [#77](https://github.com/r-spatial/leafgl/issues/77) +- Use `@inheritParams leaflet::**` for identical function arguments + #### 🍬 miscellaneous +- update upstream javascript dependency to 3.3.0. [#49](https://github.com/r-spatial/leafgl/issues/49) + + ⚠️If you previously used the workaround `L.glify.Shapes.instances.splice(0, 1)`, please remove it with this new version. + +- unified / simplified the dependency functions/calls ## leafgl 0.2.1 new features: - * all methods can now have labels/tooltips. Currently only lines and polygons support passing of a column name, points need a predefined label vector. +- all methods can now have labels/tooltips. Currently only lines and polygons support passing of a column name, points need a predefined label vector. miscallaneous: - * all methods now have a pane argument to control layer ordering (thanks to @trafficonese). #67 #64 - +- all methods now have a pane argument to control layer ordering (thanks to @trafficonese). [#67](https://github.com/r-spatial/leafgl/issues/67) [#64](https://github.com/r-spatial/leafgl/issues/64) + ## leafgl 0.2.0 miscallaneous: - * update upstream javascript dependency to 3.2.0 +- update upstream javascript dependency to 3.2.0 ## leafgl 0.1.2 new features: - * expose additional JavaScript arguments in addGlPoints via magic dots. #54 & #60 - +- expose additional JavaScript arguments in addGlPoints via magic dots. [#54](https://github.com/r-spatial/leafgl/issues/54) & [#60](https://github.com/r-spatial/leafgl/issues/60) ## leafgl 0.1.1 diff --git a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js index e8eb41a..15ce3a7 100644 --- a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js +++ b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js @@ -49,21 +49,18 @@ LeafletWidget.methods.clearGlLayers = function() { arr[i].settings.map.off("mousemove"); arr[i].remove(); } - arr.splice(0, arr.length) arr = L.glify.linesInstances; for( let i = 0; i < arr.length; i++){ arr[i].settings.map.off("mousemove"); arr[i].remove(); } - arr.splice(0, arr.length) arr = L.glify.pointsInstances; for( let i = 0; i < arr.length; i++){ arr[i].settings.map.off("mousemove"); arr[i].remove(); } - arr.splice(0, arr.length) this.layerManager.clearLayers("glify"); }; @@ -76,7 +73,6 @@ LeafletWidget.methods.clearGlGroup = function(group) { if ( arr[i].settings.className === group) { arr[i].settings.map.off("mousemove"); arr[i].remove(); - arr.splice(i, 1); } } }); diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js index fdba854..ccff2a3 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js @@ -37,6 +37,12 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit map: map, click: clickFun, hover: mouseoverFun, + hoverOff: function(e, feat) { + tooltip.remove(); + //if (HTMLWidgets.shinyMode) { + // Shiny.setInputValue(map.id + "_glify_mouseover", null); + //} + }, data: data, color: clrs, opacity: opacity, diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js index b9fcbfa..2fa9045 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js @@ -29,6 +29,12 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, map: map, click: clickFun, hover: mouseoverFun, + hoverOff: function(e, feat) { + tooltip.remove(); + //if (HTMLWidgets.shinyMode) { + // Shiny.setInputValue(map.id + "_glify_mouseover", null); + //} + }, data: data, color: clrs, opacity: opacity, @@ -53,3 +59,4 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, + diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js index 72b9aa7..ee3a999 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js @@ -37,6 +37,12 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, map: map, click: clickFun, hover: mouseoverFun, + hoverOff: function(e, feat) { + tooltip.remove(); + //if (HTMLWidgets.shinyMode) { + // Shiny.setInputValue(map.id + "_glify_mouseover", null); + //} + }, latitudeKey: 1, longitudeKey: 0, data: data, diff --git a/inst/htmlwidgets/Leaflet.glify/glify-browser.js b/inst/htmlwidgets/Leaflet.glify/glify-browser.js index 39c1505..f3297d6 100644 --- a/inst/htmlwidgets/Leaflet.glify/glify-browser.js +++ b/inst/htmlwidgets/Leaflet.glify/glify-browser.js @@ -1,10 +1,3 @@ -!function(t,n){if("object"==typeof exports&&"object"==typeof module)module.exports=n(require("leaflet"));else if("function"==typeof define&&define.amd)define(["leaflet"],n);else{var r="object"==typeof exports?n(require("leaflet")):n(t.L);for(var e in r)("object"==typeof exports?exports:t)[e]=r[e]}}(window,(function(t){return function(t){var n={};function r(e){if(n[e])return n[e].exports;var i=n[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=t,r.c=n,r.d=function(t,n,e){r.o(t,n)||Object.defineProperty(t,n,{enumerable:!0,get:e})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,n){if(1&n&&(t=r(t)),8&n)return t;if(4&n&&"object"==typeof t&&t&&t.__esModule)return t;var e=Object.create(null);if(r.r(e),Object.defineProperty(e,"default",{enumerable:!0,value:t}),2&n&&"string"!=typeof t)for(var i in t)r.d(e,i,function(n){return t[n]}.bind(null,i));return e},r.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(n,"a",n),n},r.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},r.p="",r(r.s=10)}([function(n,r){n.exports=t},function(t,n,r){"use strict";function e(t,n,r){r=r||2;var e,a,s,c,f,v,d,g=n&&n.length,y=g?n[0]*r:t.length,_=i(t,0,y,r,!0),m=[];if(!_||_.next===_.prev)return m;if(g&&(_=function(t,n,r,e){var u,a,s,c,f,v=[];for(u=0,a=n.length;u80*r){e=s=t[0],a=c=t[1];for(var x=r;xs&&(s=f),v>c&&(c=v);d=0!==(d=Math.max(s-e,c-a))?1/d:0}return u(_,m,r,e,a,d),m}function i(t,n,r,e,i){var o,u;if(i===L(t,n,r,e)>0)for(o=n;o=n;o-=e)u=w(o,t[o],t[o+1],u);return u&&_(u,u.next)&&(S(u),u=u.next),u}function o(t,n){if(!t)return t;n||(n=t);var r,e=t;do{if(r=!1,e.steiner||!_(e,e.next)&&0!==y(e.prev,e,e.next))e=e.next;else{if(S(e),(e=n=e.prev)===e.next)break;r=!0}}while(r||e!==n);return n}function u(t,n,r,e,i,l,h){if(t){!h&&l&&function(t,n,r,e){var i=t;do{null===i.z&&(i.z=v(i.x,i.y,n,r,e)),i.prevZ=i.prev,i.nextZ=i.next,i=i.next}while(i!==t);i.prevZ.nextZ=null,i.prevZ=null,function(t){var n,r,e,i,o,u,a,s,c=1;do{for(r=t,t=null,o=null,u=0;r;){for(u++,e=r,a=0,n=0;n0||s>0&&e;)0!==a&&(0===s||!e||r.z<=e.z)?(i=r,r=r.nextZ,a--):(i=e,e=e.nextZ,s--),o?o.nextZ=i:t=i,i.prevZ=o,o=i;r=e}o.nextZ=null,c*=2}while(u>1)}(i)}(t,e,i,l);for(var p,d,g=t;t.prev!==t.next;)if(p=t.prev,d=t.next,l?s(t,e,i,l):a(t))n.push(p.i/r),n.push(t.i/r),n.push(d.i/r),S(t),t=d.next,g=d.next;else if((t=d)===g){h?1===h?u(t=c(t,n,r),n,r,e,i,l,2):2===h&&f(t,n,r,e,i,l):u(o(t),n,r,e,i,l,1);break}}}function a(t){var n=t.prev,r=t,e=t.next;if(y(n,r,e)>=0)return!1;for(var i=t.next.next;i!==t.prev;){if(d(n.x,n.y,r.x,r.y,e.x,e.y,i.x,i.y)&&y(i.prev,i,i.next)>=0)return!1;i=i.next}return!0}function s(t,n,r,e){var i=t.prev,o=t,u=t.next;if(y(i,o,u)>=0)return!1;for(var a=i.xo.x?i.x>u.x?i.x:u.x:o.x>u.x?o.x:u.x,f=i.y>o.y?i.y>u.y?i.y:u.y:o.y>u.y?o.y:u.y,l=v(a,s,n,r,e),h=v(c,f,n,r,e),p=t.prevZ,g=t.nextZ;p&&p.z>=l&&g&&g.z<=h;){if(p!==t.prev&&p!==t.next&&d(i.x,i.y,o.x,o.y,u.x,u.y,p.x,p.y)&&y(p.prev,p,p.next)>=0)return!1;if(p=p.prevZ,g!==t.prev&&g!==t.next&&d(i.x,i.y,o.x,o.y,u.x,u.y,g.x,g.y)&&y(g.prev,g,g.next)>=0)return!1;g=g.nextZ}for(;p&&p.z>=l;){if(p!==t.prev&&p!==t.next&&d(i.x,i.y,o.x,o.y,u.x,u.y,p.x,p.y)&&y(p.prev,p,p.next)>=0)return!1;p=p.prevZ}for(;g&&g.z<=h;){if(g!==t.prev&&g!==t.next&&d(i.x,i.y,o.x,o.y,u.x,u.y,g.x,g.y)&&y(g.prev,g,g.next)>=0)return!1;g=g.nextZ}return!0}function c(t,n,r){var e=t;do{var i=e.prev,o=e.next.next;!_(i,o)&&m(i,e,e.next,o)&&x(i,o)&&x(o,i)&&(n.push(i.i/r),n.push(e.i/r),n.push(o.i/r),S(e),S(e.next),e=t=o),e=e.next}while(e!==t);return e}function f(t,n,r,e,i,a){var s=t;do{for(var c=s.next.next;c!==s.prev;){if(s.i!==c.i&&g(s,c)){var f=b(s,c);return s=o(s,s.next),f=o(f,f.next),u(s,n,r,e,i,a),void u(f,n,r,e,i,a)}c=c.next}s=s.next}while(s!==t)}function l(t,n){return t.x-n.x}function h(t,n){if(n=function(t,n){var r,e=n,i=t.x,o=t.y,u=-1/0;do{if(o<=e.y&&o>=e.next.y&&e.next.y!==e.y){var a=e.x+(o-e.y)*(e.next.x-e.x)/(e.next.y-e.y);if(a<=i&&a>u){if(u=a,a===i){if(o===e.y)return e;if(o===e.next.y)return e.next}r=e.x=e.x&&e.x>=f&&i!==e.x&&d(or.x)&&x(e,t)&&(r=e,h=s),e=e.next;return r}(t,n)){var r=b(n,t);o(r,r.next)}}function v(t,n,r,e,i){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=32767*(t-r)*i)|t<<8))|t<<4))|t<<2))|t<<1))|(n=1431655765&((n=858993459&((n=252645135&((n=16711935&((n=32767*(n-e)*i)|n<<8))|n<<4))|n<<2))|n<<1))<<1}function p(t){var n=t,r=t;do{(n.x=0&&(t-u)*(e-a)-(r-u)*(n-a)>=0&&(r-u)*(o-a)-(i-u)*(e-a)>=0}function g(t,n){return t.next.i!==n.i&&t.prev.i!==n.i&&!function(t,n){var r=t;do{if(r.i!==t.i&&r.next.i!==t.i&&r.i!==n.i&&r.next.i!==n.i&&m(r,r.next,t,n))return!0;r=r.next}while(r!==t);return!1}(t,n)&&x(t,n)&&x(n,t)&&function(t,n){var r=t,e=!1,i=(t.x+n.x)/2,o=(t.y+n.y)/2;do{r.y>o!=r.next.y>o&&r.next.y!==r.y&&i<(r.next.x-r.x)*(o-r.y)/(r.next.y-r.y)+r.x&&(e=!e),r=r.next}while(r!==t);return e}(t,n)}function y(t,n,r){return(n.y-t.y)*(r.x-n.x)-(n.x-t.x)*(r.y-n.y)}function _(t,n){return t.x===n.x&&t.y===n.y}function m(t,n,r,e){return!!(_(t,n)&&_(r,e)||_(t,e)&&_(r,n))||y(t,n,r)>0!=y(t,n,e)>0&&y(r,e,t)>0!=y(r,e,n)>0}function x(t,n){return y(t.prev,t,t.next)<0?y(t,n,t.next)>=0&&y(t,t.prev,n)>=0:y(t,n,t.prev)<0||y(t,t.next,n)<0}function b(t,n){var r=new A(t.i,t.x,t.y),e=new A(n.i,n.x,n.y),i=t.next,o=n.prev;return t.next=n,n.prev=t,r.next=i,i.prev=r,e.next=r,r.prev=e,o.next=e,e.prev=o,e}function w(t,n,r,e){var i=new A(t,n,r);return e?(i.next=e.next,i.prev=e,e.next.prev=i,e.next=i):(i.prev=i,i.next=i),i}function S(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function A(t,n,r){this.i=t,this.x=n,this.y=r,this.prev=null,this.next=null,this.z=null,this.prevZ=null,this.nextZ=null,this.steiner=!1}function L(t,n,r,e){for(var i=0,o=n,u=r-e;o0&&(e+=t[i-1].length,r.holes.push(e))}return r}},function(t,n,r){"use strict";var e=r(3),i=r(5),o=r(6),u=r(7);function a(t){void 0!==t&&this.loadFeatureCollection(t)}function s(t,n){var r=n.geometry.coordinates[0];if(i(t,r)){for(var e=1;e=r)&&(!!s(e,t)&&(u++,!0))}))}},a.prototype.search=function(t,n,r){return void 0===r?this.searchForOnePolygon(t,n):this.searchForMultiplePolygons(t,n,r)},a.prototype.loadFeatureCollection=function(t){var n=[],r=[],i=0;function u(t){r.push(t);var e=o.getBoundingBox(t.geometry.coordinates[0]);e.polyId=i++,n.push(e)}t.features.forEach((function(t){if(t.geometry&&void 0!==t.geometry.coordinates[0]&&t.geometry.coordinates[0].length>0)switch(t.geometry.type){case"Polygon":u(t);break;case"MultiPolygon":for(var n=t.geometry.coordinates,r=0;r=t.minX&&n.maxY>=t.minY}function d(t){return{children:t,height:1,leaf:!0,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0}}function g(t,n,r,i,o){for(var u,a=[n,r];a.length;)(r=a.pop())-(n=a.pop())<=i||(u=n+Math.ceil((r-n)/i/2)*i,e(t,u,n,r,o),a.push(n,u,u,r))}i.prototype={all:function(){return this._all(this.data,[])},search:function(t){var n=this.data,r=[],e=this.toBBox;if(!p(t,n))return r;for(var i,o,u,a,s=[];n;){for(i=0,o=n.children.length;i=0&&o[n].children.length>this._maxEntries;)this._split(o,n),n--;this._adjustParentBBoxes(i,o,n)},_split:function(t,n){var r=t[n],e=r.children.length,i=this._minEntries;this._chooseSplitAxis(r,i,e);var o=this._chooseSplitIndex(r,i,e),a=d(r.children.splice(o,r.children.length-o));a.height=r.height,a.leaf=r.leaf,u(r,this.toBBox),u(a,this.toBBox),n?t[n-1].children.push(a):this._splitRoot(r,a)},_splitRoot:function(t,n){this.data=d([t,n]),this.data.height=t.height+1,this.data.leaf=!1,u(this.data,this.toBBox)},_chooseSplitIndex:function(t,n,r){var e,i,o,u,s,c,f,h,v,p,d,g,y,_;for(c=f=1/0,e=n;e<=r-n;e++)i=a(t,0,e,this.toBBox),o=a(t,e,r,this.toBBox),v=i,p=o,d=void 0,g=void 0,y=void 0,_=void 0,d=Math.max(v.minX,p.minX),g=Math.max(v.minY,p.minY),y=Math.min(v.maxX,p.maxX),_=Math.min(v.maxY,p.maxY),u=Math.max(0,y-d)*Math.max(0,_-g),s=l(i)+l(o),u=n;i--)o=t.children[i],s(f,t.leaf?u(o):o),l+=h(f);return l},_adjustParentBBoxes:function(t,n,r){for(var e=r;e>=0;e--)s(n[e],t)},_condense:function(t){for(var n,r=t.length-1;r>=0;r--)0===t[r].children.length?r>0?(n=t[r-1].children).splice(n.indexOf(t[r]),1):this.clear():u(t[r],this.toBBox)},_initFormat:function(t){var n=["return a"," - b",";"];this.compareMinX=new Function("a","b",n.join(t[0])),this.compareMinY=new Function("a","b",n.join(t[1])),this.toBBox=new Function("a","return {minX: a"+t[0]+", minY: a"+t[1]+", maxX: a"+t[2]+", maxY: a"+t[3]+"};")}}},function(t,n,r){t.exports=function(){"use strict";function t(t,n,r){var e=t[n];t[n]=t[r],t[r]=e}function n(t,n){return tn?1:0}return function(r,e,i,o,u){!function n(r,e,i,o,u){for(;o>i;){if(o-i>600){var a=o-i+1,s=e-i+1,c=Math.log(a),f=.5*Math.exp(2*c/3),l=.5*Math.sqrt(c*f*(a-f)/a)*(s-a/2<0?-1:1),h=Math.max(i,Math.floor(e-s*f/a+l)),v=Math.min(o,Math.floor(e+(a-s)*f/a+l));n(r,e,h,v,u)}var p=r[e],d=i,g=o;for(t(r,i,e),u(r[o],p)>0&&t(r,i,o);d0;)g--}0===u(r[i],p)?t(r,i,g):(g++,t(r,g,o)),g<=e&&(i=g+1),e<=g&&(o=g-1)}}(r,e,i||0,o||r.length-1,u||n)}}()},function(t,n){t.exports=function(t,n){for(var r=t[0],e=t[1],i=!1,o=0,u=n.length-1;oe!=f>e&&r<(c-a)*(e-s)/(f-s)+a&&(i=!i)}return i}},function(t,n,r){"use strict";t.exports={getBoundingBox:function(t){for(var n=t[0],r={minX:n[0],minY:n[1],maxX:n[0],maxY:n[1]},e=1;er.maxX&&(r.maxX=o);var u=i[1];ur.maxY&&(r.maxY=u)}return r}}},function(t,n,r){(function(t,e){var i; -/** - * @license - * Lodash - * Copyright OpenJS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */(function(){var o="Expected a function",u="__lodash_placeholder__",a=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],s="[object Arguments]",c="[object Array]",f="[object Boolean]",l="[object Date]",h="[object Error]",v="[object Function]",p="[object GeneratorFunction]",d="[object Map]",g="[object Number]",y="[object Object]",_="[object RegExp]",m="[object Set]",x="[object String]",b="[object Symbol]",w="[object WeakMap]",S="[object ArrayBuffer]",A="[object DataView]",L="[object Float32Array]",E="[object Float64Array]",M="[object Int8Array]",k="[object Int16Array]",F="[object Int32Array]",B="[object Uint8Array]",C="[object Uint16Array]",j="[object Uint32Array]",z=/\b__p \+= '';/g,R=/\b(__p \+=) '' \+/g,O=/(__e\(.*?\)|\b__t\)) \+\n'';/g,P=/&(?:amp|lt|gt|quot|#39);/g,T=/[&<>"']/g,I=RegExp(P.source),N=RegExp(T.source),Y=/<%-([\s\S]+?)%>/g,U=/<%([\s\S]+?)%>/g,D=/<%=([\s\S]+?)%>/g,W=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Z=/^\w*$/,X=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,K=/[\\^$.*+?()[\]{}|]/g,V=RegExp(K.source),H=/^\s+/,q=/\s/,$=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,G=/\{\n\/\* \[wrapped with (.+)\] \*/,J=/,? & /,Q=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,tt=/[()=,{}\[\]\/\s]/,nt=/\\(\\)?/g,rt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,et=/\w*$/,it=/^[-+]0x[0-9a-f]+$/i,ot=/^0b[01]+$/i,ut=/^\[object .+?Constructor\]$/,at=/^0o[0-7]+$/i,st=/^(?:0|[1-9]\d*)$/,ct=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,ft=/($^)/,lt=/['\n\r\u2028\u2029\\]/g,ht="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",vt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",pt="[\\ud800-\\udfff]",dt="["+vt+"]",gt="["+ht+"]",yt="\\d+",_t="[\\u2700-\\u27bf]",mt="[a-z\\xdf-\\xf6\\xf8-\\xff]",xt="[^\\ud800-\\udfff"+vt+yt+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",bt="\\ud83c[\\udffb-\\udfff]",wt="[^\\ud800-\\udfff]",St="(?:\\ud83c[\\udde6-\\uddff]){2}",At="[\\ud800-\\udbff][\\udc00-\\udfff]",Lt="[A-Z\\xc0-\\xd6\\xd8-\\xde]",Et="(?:"+mt+"|"+xt+")",Mt="(?:"+Lt+"|"+xt+")",kt="(?:"+gt+"|"+bt+")"+"?",Ft="[\\ufe0e\\ufe0f]?"+kt+("(?:\\u200d(?:"+[wt,St,At].join("|")+")[\\ufe0e\\ufe0f]?"+kt+")*"),Bt="(?:"+[_t,St,At].join("|")+")"+Ft,Ct="(?:"+[wt+gt+"?",gt,St,At,pt].join("|")+")",jt=RegExp("['’]","g"),zt=RegExp(gt,"g"),Rt=RegExp(bt+"(?="+bt+")|"+Ct+Ft,"g"),Ot=RegExp([Lt+"?"+mt+"+(?:['’](?:d|ll|m|re|s|t|ve))?(?="+[dt,Lt,"$"].join("|")+")",Mt+"+(?:['’](?:D|LL|M|RE|S|T|VE))?(?="+[dt,Lt+Et,"$"].join("|")+")",Lt+"?"+Et+"+(?:['’](?:d|ll|m|re|s|t|ve))?",Lt+"+(?:['’](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",yt,Bt].join("|"),"g"),Pt=RegExp("[\\u200d\\ud800-\\udfff"+ht+"\\ufe0e\\ufe0f]"),Tt=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,It=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Nt=-1,Yt={};Yt[L]=Yt[E]=Yt[M]=Yt[k]=Yt[F]=Yt[B]=Yt["[object Uint8ClampedArray]"]=Yt[C]=Yt[j]=!0,Yt[s]=Yt[c]=Yt[S]=Yt[f]=Yt[A]=Yt[l]=Yt[h]=Yt[v]=Yt[d]=Yt[g]=Yt[y]=Yt[_]=Yt[m]=Yt[x]=Yt[w]=!1;var Ut={};Ut[s]=Ut[c]=Ut[S]=Ut[A]=Ut[f]=Ut[l]=Ut[L]=Ut[E]=Ut[M]=Ut[k]=Ut[F]=Ut[d]=Ut[g]=Ut[y]=Ut[_]=Ut[m]=Ut[x]=Ut[b]=Ut[B]=Ut["[object Uint8ClampedArray]"]=Ut[C]=Ut[j]=!0,Ut[h]=Ut[v]=Ut[w]=!1;var Dt={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Wt=parseFloat,Zt=parseInt,Xt="object"==typeof t&&t&&t.Object===Object&&t,Kt="object"==typeof self&&self&&self.Object===Object&&self,Vt=Xt||Kt||Function("return this")(),Ht=n&&!n.nodeType&&n,qt=Ht&&"object"==typeof e&&e&&!e.nodeType&&e,$t=qt&&qt.exports===Ht,Gt=$t&&Xt.process,Jt=function(){try{var t=qt&&qt.require&&qt.require("util").types;return t||Gt&&Gt.binding&&Gt.binding("util")}catch(t){}}(),Qt=Jt&&Jt.isArrayBuffer,tn=Jt&&Jt.isDate,nn=Jt&&Jt.isMap,rn=Jt&&Jt.isRegExp,en=Jt&&Jt.isSet,on=Jt&&Jt.isTypedArray;function un(t,n,r){switch(r.length){case 0:return t.call(n);case 1:return t.call(n,r[0]);case 2:return t.call(n,r[0],r[1]);case 3:return t.call(n,r[0],r[1],r[2])}return t.apply(n,r)}function an(t,n,r,e){for(var i=-1,o=null==t?0:t.length;++i-1}function vn(t,n,r){for(var e=-1,i=null==t?0:t.length;++e-1;);return r}function Pn(t,n){for(var r=t.length;r--&&wn(n,t[r],0)>-1;);return r}function Tn(t,n){for(var r=t.length,e=0;r--;)t[r]===n&&++e;return e}var In=Mn({"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss","Ā":"A","Ă":"A","Ą":"A","ā":"a","ă":"a","ą":"a","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","ć":"c","ĉ":"c","ċ":"c","č":"c","Ď":"D","Đ":"D","ď":"d","đ":"d","Ē":"E","Ĕ":"E","Ė":"E","Ę":"E","Ě":"E","ē":"e","ĕ":"e","ė":"e","ę":"e","ě":"e","Ĝ":"G","Ğ":"G","Ġ":"G","Ģ":"G","ĝ":"g","ğ":"g","ġ":"g","ģ":"g","Ĥ":"H","Ħ":"H","ĥ":"h","ħ":"h","Ĩ":"I","Ī":"I","Ĭ":"I","Į":"I","İ":"I","ĩ":"i","ī":"i","ĭ":"i","į":"i","ı":"i","Ĵ":"J","ĵ":"j","Ķ":"K","ķ":"k","ĸ":"k","Ĺ":"L","Ļ":"L","Ľ":"L","Ŀ":"L","Ł":"L","ĺ":"l","ļ":"l","ľ":"l","ŀ":"l","ł":"l","Ń":"N","Ņ":"N","Ň":"N","Ŋ":"N","ń":"n","ņ":"n","ň":"n","ŋ":"n","Ō":"O","Ŏ":"O","Ő":"O","ō":"o","ŏ":"o","ő":"o","Ŕ":"R","Ŗ":"R","Ř":"R","ŕ":"r","ŗ":"r","ř":"r","Ś":"S","Ŝ":"S","Ş":"S","Š":"S","ś":"s","ŝ":"s","ş":"s","š":"s","Ţ":"T","Ť":"T","Ŧ":"T","ţ":"t","ť":"t","ŧ":"t","Ũ":"U","Ū":"U","Ŭ":"U","Ů":"U","Ű":"U","Ų":"U","ũ":"u","ū":"u","ŭ":"u","ů":"u","ű":"u","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","Ż":"Z","Ž":"Z","ź":"z","ż":"z","ž":"z","IJ":"IJ","ij":"ij","Œ":"Oe","œ":"oe","ʼn":"'n","ſ":"s"}),Nn=Mn({"&":"&","<":"<",">":">",'"':""","'":"'"});function Yn(t){return"\\"+Dt[t]}function Un(t){return Pt.test(t)}function Dn(t){var n=-1,r=Array(t.size);return t.forEach((function(t,e){r[++n]=[e,t]})),r}function Wn(t,n){return function(r){return t(n(r))}}function Zn(t,n){for(var r=-1,e=t.length,i=0,o=[];++r",""":'"',"'":"'"});var Gn=function t(n){var r,e=(n=null==n?Vt:Gn.defaults(Vt.Object(),n,Gn.pick(Vt,It))).Array,i=n.Date,q=n.Error,ht=n.Function,vt=n.Math,pt=n.Object,dt=n.RegExp,gt=n.String,yt=n.TypeError,_t=e.prototype,mt=ht.prototype,xt=pt.prototype,bt=n["__core-js_shared__"],wt=mt.toString,St=xt.hasOwnProperty,At=0,Lt=(r=/[^.]+$/.exec(bt&&bt.keys&&bt.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"",Et=xt.toString,Mt=wt.call(pt),kt=Vt._,Ft=dt("^"+wt.call(St).replace(K,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bt=$t?n.Buffer:void 0,Ct=n.Symbol,Rt=n.Uint8Array,Pt=Bt?Bt.allocUnsafe:void 0,Dt=Wn(pt.getPrototypeOf,pt),Xt=pt.create,Kt=xt.propertyIsEnumerable,Ht=_t.splice,qt=Ct?Ct.isConcatSpreadable:void 0,Gt=Ct?Ct.iterator:void 0,Jt=Ct?Ct.toStringTag:void 0,mn=function(){try{var t=to(pt,"defineProperty");return t({},"",{}),t}catch(t){}}(),Mn=n.clearTimeout!==Vt.clearTimeout&&n.clearTimeout,Jn=i&&i.now!==Vt.Date.now&&i.now,Qn=n.setTimeout!==Vt.setTimeout&&n.setTimeout,tr=vt.ceil,nr=vt.floor,rr=pt.getOwnPropertySymbols,er=Bt?Bt.isBuffer:void 0,ir=n.isFinite,or=_t.join,ur=Wn(pt.keys,pt),ar=vt.max,sr=vt.min,cr=i.now,fr=n.parseInt,lr=vt.random,hr=_t.reverse,vr=to(n,"DataView"),pr=to(n,"Map"),dr=to(n,"Promise"),gr=to(n,"Set"),yr=to(n,"WeakMap"),_r=to(pt,"create"),mr=yr&&new yr,xr={},br=ko(vr),wr=ko(pr),Sr=ko(dr),Ar=ko(gr),Lr=ko(yr),Er=Ct?Ct.prototype:void 0,Mr=Er?Er.valueOf:void 0,kr=Er?Er.toString:void 0;function Fr(t){if(Xu(t)&&!Ru(t)&&!(t instanceof zr)){if(t instanceof jr)return t;if(St.call(t,"__wrapped__"))return Fo(t)}return new jr(t)}var Br=function(){function t(){}return function(n){if(!Zu(n))return{};if(Xt)return Xt(n);t.prototype=n;var r=new t;return t.prototype=void 0,r}}();function Cr(){}function jr(t,n){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!n,this.__index__=0,this.__values__=void 0}function zr(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Rr(t){var n=-1,r=null==t?0:t.length;for(this.clear();++n=n?t:n)),t}function Gr(t,n,r,e,i,o){var u,a=1&n,c=2&n,h=4&n;if(r&&(u=i?r(t,e,i,o):r(t)),void 0!==u)return u;if(!Zu(t))return t;var w=Ru(t);if(w){if(u=function(t){var n=t.length,r=new t.constructor(n);n&&"string"==typeof t[0]&&St.call(t,"index")&&(r.index=t.index,r.input=t.input);return r}(t),!a)return _i(t,u)}else{var z=eo(t),R=z==v||z==p;if(Iu(t))return hi(t,a);if(z==y||z==s||R&&!i){if(u=c||R?{}:oo(t),!a)return c?function(t,n){return mi(t,ro(t),n)}(t,function(t,n){return t&&mi(n,wa(n),t)}(u,t)):function(t,n){return mi(t,no(t),n)}(t,Vr(u,t))}else{if(!Ut[z])return i?t:{};u=function(t,n,r){var e=t.constructor;switch(n){case S:return vi(t);case f:case l:return new e(+t);case A:return function(t,n){var r=n?vi(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)}(t,r);case L:case E:case M:case k:case F:case B:case"[object Uint8ClampedArray]":case C:case j:return pi(t,r);case d:return new e;case g:case x:return new e(t);case _:return function(t){var n=new t.constructor(t.source,et.exec(t));return n.lastIndex=t.lastIndex,n}(t);case m:return new e;case b:return i=t,Mr?pt(Mr.call(i)):{}}var i}(t,z,a)}}o||(o=new Ir);var O=o.get(t);if(O)return O;o.set(t,u),$u(t)?t.forEach((function(e){u.add(Gr(e,n,r,e,t,o))})):Ku(t)&&t.forEach((function(e,i){u.set(i,Gr(e,n,r,i,t,o))}));var P=w?void 0:(h?c?Vi:Ki:c?wa:ba)(t);return sn(P||t,(function(e,i){P&&(e=t[i=e]),Zr(u,i,Gr(e,n,r,i,t,o))})),u}function Jr(t,n,r){var e=r.length;if(null==t)return!e;for(t=pt(t);e--;){var i=r[e],o=n[i],u=t[i];if(void 0===u&&!(i in t)||!o(u))return!1}return!0}function Qr(t,n,r){if("function"!=typeof t)throw new yt(o);return bo((function(){t.apply(void 0,r)}),n)}function te(t,n,r,e){var i=-1,o=hn,u=!0,a=t.length,s=[],c=n.length;if(!a)return s;r&&(n=pn(n,jn(r))),e?(o=vn,u=!1):n.length>=200&&(o=Rn,u=!1,n=new Tr(n));t:for(;++i-1},Or.prototype.set=function(t,n){var r=this.__data__,e=Xr(r,t);return e<0?(++this.size,r.push([t,n])):r[e][1]=n,this},Pr.prototype.clear=function(){this.size=0,this.__data__={hash:new Rr,map:new(pr||Or),string:new Rr}},Pr.prototype.delete=function(t){var n=Ji(this,t).delete(t);return this.size-=n?1:0,n},Pr.prototype.get=function(t){return Ji(this,t).get(t)},Pr.prototype.has=function(t){return Ji(this,t).has(t)},Pr.prototype.set=function(t,n){var r=Ji(this,t),e=r.size;return r.set(t,n),this.size+=r.size==e?0:1,this},Tr.prototype.add=Tr.prototype.push=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this},Tr.prototype.has=function(t){return this.__data__.has(t)},Ir.prototype.clear=function(){this.__data__=new Or,this.size=0},Ir.prototype.delete=function(t){var n=this.__data__,r=n.delete(t);return this.size=n.size,r},Ir.prototype.get=function(t){return this.__data__.get(t)},Ir.prototype.has=function(t){return this.__data__.has(t)},Ir.prototype.set=function(t,n){var r=this.__data__;if(r instanceof Or){var e=r.__data__;if(!pr||e.length<199)return e.push([t,n]),this.size=++r.size,this;r=this.__data__=new Pr(e)}return r.set(t,n),this.size=r.size,this};var ne=wi(ce),re=wi(fe,!0);function ee(t,n){var r=!0;return ne(t,(function(t,e,i){return r=!!n(t,e,i)})),r}function ie(t,n,r){for(var e=-1,i=t.length;++e0&&r(a)?n>1?ue(a,n-1,r,e,i):dn(i,a):e||(i[i.length]=a)}return i}var ae=Si(),se=Si(!0);function ce(t,n){return t&&ae(t,n,ba)}function fe(t,n){return t&&se(t,n,ba)}function le(t,n){return ln(n,(function(n){return Uu(t[n])}))}function he(t,n){for(var r=0,e=(n=si(n,t)).length;null!=t&&rn}function ge(t,n){return null!=t&&St.call(t,n)}function ye(t,n){return null!=t&&n in pt(t)}function _e(t,n,r){for(var i=r?vn:hn,o=t[0].length,u=t.length,a=u,s=e(u),c=1/0,f=[];a--;){var l=t[a];a&&n&&(l=pn(l,jn(n))),c=sr(l.length,c),s[a]=!r&&(n||o>=120&&l.length>=120)?new Tr(a&&l):void 0}l=t[0];var h=-1,v=s[0];t:for(;++h=a)return s;var c=r[e];return s*("desc"==c?-1:1)}}return t.index-n.index}(t,n,r)}))}function Re(t,n,r){for(var e=-1,i=n.length,o={};++e-1;)a!==t&&Ht.call(a,s,1),Ht.call(t,s,1);return t}function Pe(t,n){for(var r=t?n.length:0,e=r-1;r--;){var i=n[r];if(r==e||i!==o){var o=i;ao(i)?Ht.call(t,i,1):ti(t,i)}}return t}function Te(t,n){return t+nr(lr()*(n-t+1))}function Ie(t,n){var r="";if(!t||n<1||n>9007199254740991)return r;do{n%2&&(r+=t),(n=nr(n/2))&&(t+=t)}while(n);return r}function Ne(t,n){return wo(go(t,n,Va),t+"")}function Ye(t){return Yr(Ba(t))}function Ue(t,n){var r=Ba(t);return Lo(r,$r(n,0,r.length))}function De(t,n,r,e){if(!Zu(t))return t;for(var i=-1,o=(n=si(n,t)).length,u=o-1,a=t;null!=a&&++io?0:o+n),(r=r>o?o:r)<0&&(r+=o),o=n>r?0:r-n>>>0,n>>>=0;for(var u=e(o);++i>>1,u=t[o];null!==u&&!Ju(u)&&(r?u<=n:u=200){var c=n?null:Ii(t);if(c)return Xn(c);u=!1,i=Rn,s=new Tr}else s=n?[]:a;t:for(;++e=e?t:Ke(t,n,r)}var li=Mn||function(t){return Vt.clearTimeout(t)};function hi(t,n){if(n)return t.slice();var r=t.length,e=Pt?Pt(r):new t.constructor(r);return t.copy(e),e}function vi(t){var n=new t.constructor(t.byteLength);return new Rt(n).set(new Rt(t)),n}function pi(t,n){var r=n?vi(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}function di(t,n){if(t!==n){var r=void 0!==t,e=null===t,i=t==t,o=Ju(t),u=void 0!==n,a=null===n,s=n==n,c=Ju(n);if(!a&&!c&&!o&&t>n||o&&u&&s&&!a&&!c||e&&u&&s||!r&&s||!i)return 1;if(!e&&!o&&!c&&t1?r[i-1]:void 0,u=i>2?r[2]:void 0;for(o=t.length>3&&"function"==typeof o?(i--,o):void 0,u&&so(r[0],r[1],u)&&(o=i<3?void 0:o,i=1),n=pt(n);++e-1?i[o?n[u]:u]:void 0}}function ki(t){return Xi((function(n){var r=n.length,e=r,i=jr.prototype.thru;for(t&&n.reverse();e--;){var u=n[e];if("function"!=typeof u)throw new yt(o);if(i&&!a&&"wrapper"==qi(u))var a=new jr([],!0)}for(e=a?e:r;++e1&&m.reverse(),l&&c<_&&(m.length=c),this&&this!==Vt&&this instanceof y&&(L=g||Ei(L)),L.apply(A,m)}}function Bi(t,n){return function(r,e){return function(t,n,r,e){return ce(t,(function(t,i,o){n(e,r(t),i,o)})),e}(r,t,n(e),{})}}function Ci(t,n){return function(r,e){var i;if(void 0===r&&void 0===e)return n;if(void 0!==r&&(i=r),void 0!==e){if(void 0===i)return e;"string"==typeof r||"string"==typeof e?(r=Je(r),e=Je(e)):(r=Ge(r),e=Ge(e)),i=t(r,e)}return i}}function ji(t){return Xi((function(n){return n=pn(n,jn(Gi())),Ne((function(r){var e=this;return t(n,(function(t){return un(t,e,r)}))}))}))}function zi(t,n){var r=(n=void 0===n?" ":Je(n)).length;if(r<2)return r?Ie(n,t):n;var e=Ie(n,tr(t/Vn(n)));return Un(n)?fi(Hn(e),0,t).join(""):e.slice(0,t)}function Ri(t){return function(n,r,i){return i&&"number"!=typeof i&&so(n,r,i)&&(r=i=void 0),n=ea(n),void 0===r?(r=n,n=0):r=ea(r),function(t,n,r,i){for(var o=-1,u=ar(tr((n-t)/(r||1)),0),a=e(u);u--;)a[i?u:++o]=t,t+=r;return a}(n,r,i=void 0===i?na))return!1;var c=o.get(t),f=o.get(n);if(c&&f)return c==n&&f==t;var l=-1,h=!0,v=2&r?new Tr:void 0;for(o.set(t,n),o.set(n,t);++l-1&&t%1==0&&t1?"& ":"")+n[e],n=n.join(r>2?", ":" "),t.replace($,"{\n/* [wrapped with "+n+"] */\n")}(e,function(t,n){return sn(a,(function(r){var e="_."+r[0];n&r[1]&&!hn(t,e)&&t.push(e)})),t.sort()}(function(t){var n=t.match(G);return n?n[1].split(J):[]}(e),r)))}function Ao(t){var n=0,r=0;return function(){var e=cr(),i=16-(e-r);if(r=e,i>0){if(++n>=800)return arguments[0]}else n=0;return t.apply(void 0,arguments)}}function Lo(t,n){var r=-1,e=t.length,i=e-1;for(n=void 0===n?e:n;++r1?t[n-1]:void 0;return r="function"==typeof r?(t.pop(),r):void 0,qo(t,r)}));function ru(t){var n=Fr(t);return n.__chain__=!0,n}function eu(t,n){return n(t)}var iu=Xi((function(t){var n=t.length,r=n?t[0]:0,e=this.__wrapped__,i=function(n){return qr(n,t)};return!(n>1||this.__actions__.length)&&e instanceof zr&&ao(r)?((e=e.slice(r,+r+(n?1:0))).__actions__.push({func:eu,args:[i],thisArg:void 0}),new jr(e,this.__chain__).thru((function(t){return n&&!t.length&&t.push(void 0),t}))):this.thru(i)}));var ou=xi((function(t,n,r){St.call(t,r)?++t[r]:Hr(t,r,1)}));var uu=Mi(zo),au=Mi(Ro);function su(t,n){return(Ru(t)?sn:ne)(t,Gi(n,3))}function cu(t,n){return(Ru(t)?cn:re)(t,Gi(n,3))}var fu=xi((function(t,n,r){St.call(t,r)?t[r].push(n):Hr(t,r,[n])}));var lu=Ne((function(t,n,r){var i=-1,o="function"==typeof n,u=Pu(t)?e(t.length):[];return ne(t,(function(t){u[++i]=o?un(n,t,r):me(t,n,r)})),u})),hu=xi((function(t,n,r){Hr(t,r,n)}));function vu(t,n){return(Ru(t)?pn:ke)(t,Gi(n,3))}var pu=xi((function(t,n,r){t[r?0:1].push(n)}),(function(){return[[],[]]}));var du=Ne((function(t,n){if(null==t)return[];var r=n.length;return r>1&&so(t,n[0],n[1])?n=[]:r>2&&so(n[0],n[1],n[2])&&(n=[n[0]]),ze(t,ue(n,1),[])})),gu=Jn||function(){return Vt.Date.now()};function yu(t,n,r){return n=r?void 0:n,Yi(t,128,void 0,void 0,void 0,void 0,n=t&&null==n?t.length:n)}function _u(t,n){var r;if("function"!=typeof n)throw new yt(o);return t=ia(t),function(){return--t>0&&(r=n.apply(this,arguments)),t<=1&&(n=void 0),r}}var mu=Ne((function(t,n,r){var e=1;if(r.length){var i=Zn(r,$i(mu));e|=32}return Yi(t,e,n,r,i)})),xu=Ne((function(t,n,r){var e=3;if(r.length){var i=Zn(r,$i(xu));e|=32}return Yi(n,e,t,r,i)}));function bu(t,n,r){var e,i,u,a,s,c,f=0,l=!1,h=!1,v=!0;if("function"!=typeof t)throw new yt(o);function p(n){var r=e,o=i;return e=i=void 0,f=n,a=t.apply(o,r)}function d(t){return f=t,s=bo(y,n),l?p(t):a}function g(t){var r=t-c;return void 0===c||r>=n||r<0||h&&t-f>=u}function y(){var t=gu();if(g(t))return _(t);s=bo(y,function(t){var r=n-(t-c);return h?sr(r,u-(t-f)):r}(t))}function _(t){return s=void 0,v&&e?p(t):(e=i=void 0,a)}function m(){var t=gu(),r=g(t);if(e=arguments,i=this,c=t,r){if(void 0===s)return d(c);if(h)return li(s),s=bo(y,n),p(c)}return void 0===s&&(s=bo(y,n)),a}return n=ua(n)||0,Zu(r)&&(l=!!r.leading,u=(h="maxWait"in r)?ar(ua(r.maxWait)||0,n):u,v="trailing"in r?!!r.trailing:v),m.cancel=function(){void 0!==s&&li(s),f=0,e=c=i=s=void 0},m.flush=function(){return void 0===s?a:_(gu())},m}var wu=Ne((function(t,n){return Qr(t,1,n)})),Su=Ne((function(t,n,r){return Qr(t,ua(n)||0,r)}));function Au(t,n){if("function"!=typeof t||null!=n&&"function"!=typeof n)throw new yt(o);var r=function(){var e=arguments,i=n?n.apply(this,e):e[0],o=r.cache;if(o.has(i))return o.get(i);var u=t.apply(this,e);return r.cache=o.set(i,u)||o,u};return r.cache=new(Au.Cache||Pr),r}function Lu(t){if("function"!=typeof t)throw new yt(o);return function(){var n=arguments;switch(n.length){case 0:return!t.call(this);case 1:return!t.call(this,n[0]);case 2:return!t.call(this,n[0],n[1]);case 3:return!t.call(this,n[0],n[1],n[2])}return!t.apply(this,n)}}Au.Cache=Pr;var Eu=ci((function(t,n){var r=(n=1==n.length&&Ru(n[0])?pn(n[0],jn(Gi())):pn(ue(n,1),jn(Gi()))).length;return Ne((function(e){for(var i=-1,o=sr(e.length,r);++i=n})),zu=xe(function(){return arguments}())?xe:function(t){return Xu(t)&&St.call(t,"callee")&&!Kt.call(t,"callee")},Ru=e.isArray,Ou=Qt?jn(Qt):function(t){return Xu(t)&&pe(t)==S};function Pu(t){return null!=t&&Wu(t.length)&&!Uu(t)}function Tu(t){return Xu(t)&&Pu(t)}var Iu=er||us,Nu=tn?jn(tn):function(t){return Xu(t)&&pe(t)==l};function Yu(t){if(!Xu(t))return!1;var n=pe(t);return n==h||"[object DOMException]"==n||"string"==typeof t.message&&"string"==typeof t.name&&!Hu(t)}function Uu(t){if(!Zu(t))return!1;var n=pe(t);return n==v||n==p||"[object AsyncFunction]"==n||"[object Proxy]"==n}function Du(t){return"number"==typeof t&&t==ia(t)}function Wu(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=9007199254740991}function Zu(t){var n=typeof t;return null!=t&&("object"==n||"function"==n)}function Xu(t){return null!=t&&"object"==typeof t}var Ku=nn?jn(nn):function(t){return Xu(t)&&eo(t)==d};function Vu(t){return"number"==typeof t||Xu(t)&&pe(t)==g}function Hu(t){if(!Xu(t)||pe(t)!=y)return!1;var n=Dt(t);if(null===n)return!0;var r=St.call(n,"constructor")&&n.constructor;return"function"==typeof r&&r instanceof r&&wt.call(r)==Mt}var qu=rn?jn(rn):function(t){return Xu(t)&&pe(t)==_};var $u=en?jn(en):function(t){return Xu(t)&&eo(t)==m};function Gu(t){return"string"==typeof t||!Ru(t)&&Xu(t)&&pe(t)==x}function Ju(t){return"symbol"==typeof t||Xu(t)&&pe(t)==b}var Qu=on?jn(on):function(t){return Xu(t)&&Wu(t.length)&&!!Yt[pe(t)]};var ta=Oi(Me),na=Oi((function(t,n){return t<=n}));function ra(t){if(!t)return[];if(Pu(t))return Gu(t)?Hn(t):_i(t);if(Gt&&t[Gt])return function(t){for(var n,r=[];!(n=t.next()).done;)r.push(n.value);return r}(t[Gt]());var n=eo(t);return(n==d?Dn:n==m?Xn:Ba)(t)}function ea(t){return t?(t=ua(t))===1/0||t===-1/0?17976931348623157e292*(t<0?-1:1):t==t?t:0:0===t?t:0}function ia(t){var n=ea(t),r=n%1;return n==n?r?n-r:n:0}function oa(t){return t?$r(ia(t),0,4294967295):0}function ua(t){if("number"==typeof t)return t;if(Ju(t))return NaN;if(Zu(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=Zu(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=Cn(t);var r=ot.test(t);return r||at.test(t)?Zt(t.slice(2),r?2:8):it.test(t)?NaN:+t}function aa(t){return mi(t,wa(t))}function sa(t){return null==t?"":Je(t)}var ca=bi((function(t,n){if(ho(n)||Pu(n))mi(n,ba(n),t);else for(var r in n)St.call(n,r)&&Zr(t,r,n[r])})),fa=bi((function(t,n){mi(n,wa(n),t)})),la=bi((function(t,n,r,e){mi(n,wa(n),t,e)})),ha=bi((function(t,n,r,e){mi(n,ba(n),t,e)})),va=Xi(qr);var pa=Ne((function(t,n){t=pt(t);var r=-1,e=n.length,i=e>2?n[2]:void 0;for(i&&so(n[0],n[1],i)&&(e=1);++r1),n})),mi(t,Vi(t),r),e&&(r=Gr(r,7,Wi));for(var i=n.length;i--;)ti(r,n[i]);return r}));var Ea=Xi((function(t,n){return null==t?{}:function(t,n){return Re(t,n,(function(n,r){return ya(t,r)}))}(t,n)}));function Ma(t,n){if(null==t)return{};var r=pn(Vi(t),(function(t){return[t]}));return n=Gi(n),Re(t,r,(function(t,r){return n(t,r[0])}))}var ka=Ni(ba),Fa=Ni(wa);function Ba(t){return null==t?[]:zn(t,ba(t))}var Ca=Li((function(t,n,r){return n=n.toLowerCase(),t+(r?ja(n):n)}));function ja(t){return Ya(sa(t).toLowerCase())}function za(t){return(t=sa(t))&&t.replace(ct,In).replace(zt,"")}var Ra=Li((function(t,n,r){return t+(r?"-":"")+n.toLowerCase()})),Oa=Li((function(t,n,r){return t+(r?" ":"")+n.toLowerCase()})),Pa=Ai("toLowerCase");var Ta=Li((function(t,n,r){return t+(r?"_":"")+n.toLowerCase()}));var Ia=Li((function(t,n,r){return t+(r?" ":"")+Ya(n)}));var Na=Li((function(t,n,r){return t+(r?" ":"")+n.toUpperCase()})),Ya=Ai("toUpperCase");function Ua(t,n,r){return t=sa(t),void 0===(n=r?void 0:n)?function(t){return Tt.test(t)}(t)?function(t){return t.match(Ot)||[]}(t):function(t){return t.match(Q)||[]}(t):t.match(n)||[]}var Da=Ne((function(t,n){try{return un(t,void 0,n)}catch(t){return Yu(t)?t:new q(t)}})),Wa=Xi((function(t,n){return sn(n,(function(n){n=Mo(n),Hr(t,n,mu(t[n],t))})),t}));function Za(t){return function(){return t}}var Xa=ki(),Ka=ki(!0);function Va(t){return t}function Ha(t){return Ae("function"==typeof t?t:Gr(t,1))}var qa=Ne((function(t,n){return function(r){return me(r,t,n)}})),$a=Ne((function(t,n){return function(r){return me(t,r,n)}}));function Ga(t,n,r){var e=ba(n),i=le(n,e);null!=r||Zu(n)&&(i.length||!e.length)||(r=n,n=t,t=this,i=le(n,ba(n)));var o=!(Zu(r)&&"chain"in r&&!r.chain),u=Uu(t);return sn(i,(function(r){var e=n[r];t[r]=e,u&&(t.prototype[r]=function(){var n=this.__chain__;if(o||n){var r=t(this.__wrapped__),i=r.__actions__=_i(this.__actions__);return i.push({func:e,args:arguments,thisArg:t}),r.__chain__=n,r}return e.apply(t,dn([this.value()],arguments))})})),t}function Ja(){}var Qa=ji(pn),ts=ji(fn),ns=ji(_n);function rs(t){return co(t)?En(Mo(t)):function(t){return function(n){return he(n,t)}}(t)}var es=Ri(),is=Ri(!0);function os(){return[]}function us(){return!1}var as=Ci((function(t,n){return t+n}),0),ss=Ti("ceil"),cs=Ci((function(t,n){return t/n}),1),fs=Ti("floor");var ls,hs=Ci((function(t,n){return t*n}),1),vs=Ti("round"),ps=Ci((function(t,n){return t-n}),0);return Fr.after=function(t,n){if("function"!=typeof n)throw new yt(o);return t=ia(t),function(){if(--t<1)return n.apply(this,arguments)}},Fr.ary=yu,Fr.assign=ca,Fr.assignIn=fa,Fr.assignInWith=la,Fr.assignWith=ha,Fr.at=va,Fr.before=_u,Fr.bind=mu,Fr.bindAll=Wa,Fr.bindKey=xu,Fr.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return Ru(t)?t:[t]},Fr.chain=ru,Fr.chunk=function(t,n,r){n=(r?so(t,n,r):void 0===n)?1:ar(ia(n),0);var i=null==t?0:t.length;if(!i||n<1)return[];for(var o=0,u=0,a=e(tr(i/n));oi?0:i+r),(e=void 0===e||e>i?i:ia(e))<0&&(e+=i),e=r>e?0:oa(e);r>>0)?(t=sa(t))&&("string"==typeof n||null!=n&&!qu(n))&&!(n=Je(n))&&Un(t)?fi(Hn(t),0,r):t.split(n,r):[]},Fr.spread=function(t,n){if("function"!=typeof t)throw new yt(o);return n=null==n?0:ar(ia(n),0),Ne((function(r){var e=r[n],i=fi(r,0,n);return e&&dn(i,e),un(t,this,i)}))},Fr.tail=function(t){var n=null==t?0:t.length;return n?Ke(t,1,n):[]},Fr.take=function(t,n,r){return t&&t.length?Ke(t,0,(n=r||void 0===n?1:ia(n))<0?0:n):[]},Fr.takeRight=function(t,n,r){var e=null==t?0:t.length;return e?Ke(t,(n=e-(n=r||void 0===n?1:ia(n)))<0?0:n,e):[]},Fr.takeRightWhile=function(t,n){return t&&t.length?ri(t,Gi(n,3),!1,!0):[]},Fr.takeWhile=function(t,n){return t&&t.length?ri(t,Gi(n,3)):[]},Fr.tap=function(t,n){return n(t),t},Fr.throttle=function(t,n,r){var e=!0,i=!0;if("function"!=typeof t)throw new yt(o);return Zu(r)&&(e="leading"in r?!!r.leading:e,i="trailing"in r?!!r.trailing:i),bu(t,n,{leading:e,maxWait:n,trailing:i})},Fr.thru=eu,Fr.toArray=ra,Fr.toPairs=ka,Fr.toPairsIn=Fa,Fr.toPath=function(t){return Ru(t)?pn(t,Mo):Ju(t)?[t]:_i(Eo(sa(t)))},Fr.toPlainObject=aa,Fr.transform=function(t,n,r){var e=Ru(t),i=e||Iu(t)||Qu(t);if(n=Gi(n,4),null==r){var o=t&&t.constructor;r=i?e?new o:[]:Zu(t)&&Uu(o)?Br(Dt(t)):{}}return(i?sn:ce)(t,(function(t,e,i){return n(r,t,e,i)})),r},Fr.unary=function(t){return yu(t,1)},Fr.union=Xo,Fr.unionBy=Ko,Fr.unionWith=Vo,Fr.uniq=function(t){return t&&t.length?Qe(t):[]},Fr.uniqBy=function(t,n){return t&&t.length?Qe(t,Gi(n,2)):[]},Fr.uniqWith=function(t,n){return n="function"==typeof n?n:void 0,t&&t.length?Qe(t,void 0,n):[]},Fr.unset=function(t,n){return null==t||ti(t,n)},Fr.unzip=Ho,Fr.unzipWith=qo,Fr.update=function(t,n,r){return null==t?t:ni(t,n,ai(r))},Fr.updateWith=function(t,n,r,e){return e="function"==typeof e?e:void 0,null==t?t:ni(t,n,ai(r),e)},Fr.values=Ba,Fr.valuesIn=function(t){return null==t?[]:zn(t,wa(t))},Fr.without=$o,Fr.words=Ua,Fr.wrap=function(t,n){return Mu(ai(n),t)},Fr.xor=Go,Fr.xorBy=Jo,Fr.xorWith=Qo,Fr.zip=tu,Fr.zipObject=function(t,n){return oi(t||[],n||[],Zr)},Fr.zipObjectDeep=function(t,n){return oi(t||[],n||[],De)},Fr.zipWith=nu,Fr.entries=ka,Fr.entriesIn=Fa,Fr.extend=fa,Fr.extendWith=la,Ga(Fr,Fr),Fr.add=as,Fr.attempt=Da,Fr.camelCase=Ca,Fr.capitalize=ja,Fr.ceil=ss,Fr.clamp=function(t,n,r){return void 0===r&&(r=n,n=void 0),void 0!==r&&(r=(r=ua(r))==r?r:0),void 0!==n&&(n=(n=ua(n))==n?n:0),$r(ua(t),n,r)},Fr.clone=function(t){return Gr(t,4)},Fr.cloneDeep=function(t){return Gr(t,5)},Fr.cloneDeepWith=function(t,n){return Gr(t,5,n="function"==typeof n?n:void 0)},Fr.cloneWith=function(t,n){return Gr(t,4,n="function"==typeof n?n:void 0)},Fr.conformsTo=function(t,n){return null==n||Jr(t,n,ba(n))},Fr.deburr=za,Fr.defaultTo=function(t,n){return null==t||t!=t?n:t},Fr.divide=cs,Fr.endsWith=function(t,n,r){t=sa(t),n=Je(n);var e=t.length,i=r=void 0===r?e:$r(ia(r),0,e);return(r-=n.length)>=0&&t.slice(r,i)==n},Fr.eq=Bu,Fr.escape=function(t){return(t=sa(t))&&N.test(t)?t.replace(T,Nn):t},Fr.escapeRegExp=function(t){return(t=sa(t))&&V.test(t)?t.replace(K,"\\$&"):t},Fr.every=function(t,n,r){var e=Ru(t)?fn:ee;return r&&so(t,n,r)&&(n=void 0),e(t,Gi(n,3))},Fr.find=uu,Fr.findIndex=zo,Fr.findKey=function(t,n){return xn(t,Gi(n,3),ce)},Fr.findLast=au,Fr.findLastIndex=Ro,Fr.findLastKey=function(t,n){return xn(t,Gi(n,3),fe)},Fr.floor=fs,Fr.forEach=su,Fr.forEachRight=cu,Fr.forIn=function(t,n){return null==t?t:ae(t,Gi(n,3),wa)},Fr.forInRight=function(t,n){return null==t?t:se(t,Gi(n,3),wa)},Fr.forOwn=function(t,n){return t&&ce(t,Gi(n,3))},Fr.forOwnRight=function(t,n){return t&&fe(t,Gi(n,3))},Fr.get=ga,Fr.gt=Cu,Fr.gte=ju,Fr.has=function(t,n){return null!=t&&io(t,n,ge)},Fr.hasIn=ya,Fr.head=Po,Fr.identity=Va,Fr.includes=function(t,n,r,e){t=Pu(t)?t:Ba(t),r=r&&!e?ia(r):0;var i=t.length;return r<0&&(r=ar(i+r,0)),Gu(t)?r<=i&&t.indexOf(n,r)>-1:!!i&&wn(t,n,r)>-1},Fr.indexOf=function(t,n,r){var e=null==t?0:t.length;if(!e)return-1;var i=null==r?0:ia(r);return i<0&&(i=ar(e+i,0)),wn(t,n,i)},Fr.inRange=function(t,n,r){return n=ea(n),void 0===r?(r=n,n=0):r=ea(r),function(t,n,r){return t>=sr(n,r)&&t=-9007199254740991&&t<=9007199254740991},Fr.isSet=$u,Fr.isString=Gu,Fr.isSymbol=Ju,Fr.isTypedArray=Qu,Fr.isUndefined=function(t){return void 0===t},Fr.isWeakMap=function(t){return Xu(t)&&eo(t)==w},Fr.isWeakSet=function(t){return Xu(t)&&"[object WeakSet]"==pe(t)},Fr.join=function(t,n){return null==t?"":or.call(t,n)},Fr.kebabCase=Ra,Fr.last=Yo,Fr.lastIndexOf=function(t,n,r){var e=null==t?0:t.length;if(!e)return-1;var i=e;return void 0!==r&&(i=(i=ia(r))<0?ar(e+i,0):sr(i,e-1)),n==n?function(t,n,r){for(var e=r+1;e--;)if(t[e]===n)return e;return e}(t,n,i):bn(t,An,i,!0)},Fr.lowerCase=Oa,Fr.lowerFirst=Pa,Fr.lt=ta,Fr.lte=na,Fr.max=function(t){return t&&t.length?ie(t,Va,de):void 0},Fr.maxBy=function(t,n){return t&&t.length?ie(t,Gi(n,2),de):void 0},Fr.mean=function(t){return Ln(t,Va)},Fr.meanBy=function(t,n){return Ln(t,Gi(n,2))},Fr.min=function(t){return t&&t.length?ie(t,Va,Me):void 0},Fr.minBy=function(t,n){return t&&t.length?ie(t,Gi(n,2),Me):void 0},Fr.stubArray=os,Fr.stubFalse=us,Fr.stubObject=function(){return{}},Fr.stubString=function(){return""},Fr.stubTrue=function(){return!0},Fr.multiply=hs,Fr.nth=function(t,n){return t&&t.length?je(t,ia(n)):void 0},Fr.noConflict=function(){return Vt._===this&&(Vt._=kt),this},Fr.noop=Ja,Fr.now=gu,Fr.pad=function(t,n,r){t=sa(t);var e=(n=ia(n))?Vn(t):0;if(!n||e>=n)return t;var i=(n-e)/2;return zi(nr(i),r)+t+zi(tr(i),r)},Fr.padEnd=function(t,n,r){t=sa(t);var e=(n=ia(n))?Vn(t):0;return n&&en){var e=t;t=n,n=e}if(r||t%1||n%1){var i=lr();return sr(t+i*(n-t+Wt("1e-"+((i+"").length-1))),n)}return Te(t,n)},Fr.reduce=function(t,n,r){var e=Ru(t)?gn:kn,i=arguments.length<3;return e(t,Gi(n,4),r,i,ne)},Fr.reduceRight=function(t,n,r){var e=Ru(t)?yn:kn,i=arguments.length<3;return e(t,Gi(n,4),r,i,re)},Fr.repeat=function(t,n,r){return n=(r?so(t,n,r):void 0===n)?1:ia(n),Ie(sa(t),n)},Fr.replace=function(){var t=arguments,n=sa(t[0]);return t.length<3?n:n.replace(t[1],t[2])},Fr.result=function(t,n,r){var e=-1,i=(n=si(n,t)).length;for(i||(i=1,t=void 0);++e9007199254740991)return[];var r=4294967295,e=sr(t,4294967295);t-=4294967295;for(var i=Bn(e,n=Gi(n));++r=o)return t;var a=r-Vn(e);if(a<1)return e;var s=u?fi(u,0,a).join(""):t.slice(0,a);if(void 0===i)return s+e;if(u&&(a+=s.length-a),qu(i)){if(t.slice(a).search(i)){var c,f=s;for(i.global||(i=dt(i.source,sa(et.exec(i))+"g")),i.lastIndex=0;c=i.exec(f);)var l=c.index;s=s.slice(0,void 0===l?a:l)}}else if(t.indexOf(Je(i),a)!=a){var h=s.lastIndexOf(i);h>-1&&(s=s.slice(0,h))}return s+e},Fr.unescape=function(t){return(t=sa(t))&&I.test(t)?t.replace(P,$n):t},Fr.uniqueId=function(t){var n=++At;return sa(t)+n},Fr.upperCase=Na,Fr.upperFirst=Ya,Fr.each=su,Fr.eachRight=cu,Fr.first=Po,Ga(Fr,(ls={},ce(Fr,(function(t,n){St.call(Fr.prototype,n)||(ls[n]=t)})),ls),{chain:!1}),Fr.VERSION="4.17.21",sn(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){Fr[t].placeholder=Fr})),sn(["drop","take"],(function(t,n){zr.prototype[t]=function(r){r=void 0===r?1:ar(ia(r),0);var e=this.__filtered__&&!n?new zr(this):this.clone();return e.__filtered__?e.__takeCount__=sr(r,e.__takeCount__):e.__views__.push({size:sr(r,4294967295),type:t+(e.__dir__<0?"Right":"")}),e},zr.prototype[t+"Right"]=function(n){return this.reverse()[t](n).reverse()}})),sn(["filter","map","takeWhile"],(function(t,n){var r=n+1,e=1==r||3==r;zr.prototype[t]=function(t){var n=this.clone();return n.__iteratees__.push({iteratee:Gi(t,3),type:r}),n.__filtered__=n.__filtered__||e,n}})),sn(["head","last"],(function(t,n){var r="take"+(n?"Right":"");zr.prototype[t]=function(){return this[r](1).value()[0]}})),sn(["initial","tail"],(function(t,n){var r="drop"+(n?"":"Right");zr.prototype[t]=function(){return this.__filtered__?new zr(this):this[r](1)}})),zr.prototype.compact=function(){return this.filter(Va)},zr.prototype.find=function(t){return this.filter(t).head()},zr.prototype.findLast=function(t){return this.reverse().find(t)},zr.prototype.invokeMap=Ne((function(t,n){return"function"==typeof t?new zr(this):this.map((function(r){return me(r,t,n)}))})),zr.prototype.reject=function(t){return this.filter(Lu(Gi(t)))},zr.prototype.slice=function(t,n){t=ia(t);var r=this;return r.__filtered__&&(t>0||n<0)?new zr(r):(t<0?r=r.takeRight(-t):t&&(r=r.drop(t)),void 0!==n&&(r=(n=ia(n))<0?r.dropRight(-n):r.take(n-t)),r)},zr.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},zr.prototype.toArray=function(){return this.take(4294967295)},ce(zr.prototype,(function(t,n){var r=/^(?:filter|find|map|reject)|While$/.test(n),e=/^(?:head|last)$/.test(n),i=Fr[e?"take"+("last"==n?"Right":""):n],o=e||/^find/.test(n);i&&(Fr.prototype[n]=function(){var n=this.__wrapped__,u=e?[1]:arguments,a=n instanceof zr,s=u[0],c=a||Ru(n),f=function(t){var n=i.apply(Fr,dn([t],u));return e&&l?n[0]:n};c&&r&&"function"==typeof s&&1!=s.length&&(a=c=!1);var l=this.__chain__,h=!!this.__actions__.length,v=o&&!l,p=a&&!h;if(!o&&c){n=p?n:new zr(this);var d=t.apply(n,u);return d.__actions__.push({func:eu,args:[f],thisArg:void 0}),new jr(d,l)}return v&&p?t.apply(this,u):(d=this.thru(f),v?e?d.value()[0]:d.value():d)})})),sn(["pop","push","shift","sort","splice","unshift"],(function(t){var n=_t[t],r=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",e=/^(?:pop|shift)$/.test(t);Fr.prototype[t]=function(){var t=arguments;if(e&&!this.__chain__){var i=this.value();return n.apply(Ru(i)?i:[],t)}return this[r]((function(r){return n.apply(Ru(r)?r:[],t)}))}})),ce(zr.prototype,(function(t,n){var r=Fr[n];if(r){var e=r.name+"";St.call(xr,e)||(xr[e]=[]),xr[e].push({name:n,func:r})}})),xr[Fi(void 0,2).name]=[{name:"wrapper",func:void 0}],zr.prototype.clone=function(){var t=new zr(this.__wrapped__);return t.__actions__=_i(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=_i(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=_i(this.__views__),t},zr.prototype.reverse=function(){if(this.__filtered__){var t=new zr(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},zr.prototype.value=function(){var t=this.__wrapped__.value(),n=this.__dir__,r=Ru(t),e=n<0,i=r?t.length:0,o=function(t,n,r){var e=-1,i=r.length;for(;++e=this.__values__.length;return{done:t,value:t?void 0:this.__values__[this.__index__++]}},Fr.prototype.plant=function(t){for(var n,r=this;r instanceof Cr;){var e=Fo(r);e.__index__=0,e.__values__=void 0,n?i.__wrapped__=e:n=e;var i=e;r=r.__wrapped__}return i.__wrapped__=t,n},Fr.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof zr){var n=t;return this.__actions__.length&&(n=new zr(this)),(n=n.reverse()).__actions__.push({func:eu,args:[Zo],thisArg:void 0}),new jr(n,this.__chain__)}return this.thru(Zo)},Fr.prototype.toJSON=Fr.prototype.valueOf=Fr.prototype.value=function(){return ei(this.__wrapped__,this.__actions__)},Fr.prototype.first=Fr.prototype.head,Gt&&(Fr.prototype[Gt]=function(){return this}),Fr}();Vt._=Gn,void 0===(i=function(){return Gn}.call(n,r,n,e))||(e.exports=i)}).call(this)}).call(this,r(8),r(9)(t))},function(t,n){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(t){"object"==typeof window&&(r=window)}t.exports=r},function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,r){"use strict";r.r(n),r.d(n,"Glify",(function(){return M})),r.d(n,"glify",(function(){return k}));var e=r(0);class i extends e.Layer{constructor(t,n){super(),this._userDrawFunc=t,this._frame=null,this._redrawCallbacks=[],this._pane=n}drawing(t){return this._userDrawFunc=t,this}params(t){return e.Util.setOptions(this,t),this}redraw(t){return"function"==typeof t&&this._redrawCallbacks.push(t),null===this._frame&&(this._frame=e.Util.requestAnimFrame(this._redraw,this)),this}isAnimated(){return Boolean(this._map.options.zoomAnimation&&e.Browser.any3d)}onAdd(t){var n;this._map=t;const r=this.canvas=null!==(n=this.canvas)&&void 0!==n?n:document.createElement("canvas"),i=t.getSize(),o=this.isAnimated();r.width=i.x,r.height=i.y,r.className="leaflet-zoom-"+(o?"animated":"hide");const u=t.getPane(this._pane);if(!u)throw new Error("unable to find pane");return u.appendChild(this.canvas),t.on("moveend",this._reset,this),t.on("resize",this._resize,this),o&&t.on("zoomanim",e.Layer?this._animateZoom:this._animateZoomNoLayer,this),this._reset(),this}onRemove(t){if(this.canvas){const n=t.getPane(this._pane);if(!n)throw new Error("unable to find pane");n.removeChild(this.canvas)}return t.off("moveend",this._reset,this),t.off("resize",this._resize,this),this.isAnimated()&&t.off("zoomanim",e.Layer?this._animateZoom:this._animateZoomNoLayer,this),this}addTo(t){return t.addLayer(this),this}get map(){return this._map}set map(t){this._map=t}_resize(t){this.canvas&&(this.canvas.width=t.newSize.x,this.canvas.height=t.newSize.y)}_reset(){if(this.canvas){const t=this._map.containerPointToLayerPoint([0,0]);e.DomUtil.setPosition(this.canvas,t)}this._redraw()}_redraw(){const{_map:t,canvas:n}=this,r=t.getSize(),i=t.getBounds(),o=180*r.x/(20037508.34*(i.getEast()-i.getWest())),u=t.getZoom(),a=new e.LatLng(i.getNorth(),i.getWest()),s=this._unclampedProject(a,0);for(n&&this._userDrawFunc({bounds:i,canvas:n,offset:s,scale:Math.pow(2,u),size:r,zoomScale:o,zoom:u});this._redrawCallbacks.length>0;){const t=this._redrawCallbacks.shift();t&&t(this)}this._frame=null}_animateZoom(t){const{_map:n,canvas:r}=this,i=n.getZoomScale(t.zoom,n.getZoom()),o=this._unclampedLatLngBoundsToNewLayerBounds(n.getBounds(),t.zoom,t.center).min;r&&o&&e.DomUtil.setTransform(r,o,i)}_animateZoomNoLayer(t){const{_map:n,canvas:r}=this;if(r){const i=n.getZoomScale(t.zoom,n.getZoom()),o=n._getCenterOffset(t.center)._multiplyBy(-i).subtract(n._getMapPanePos());e.DomUtil.setTransform(r,o,i)}}_unclampedProject(t,n){var r;const{crs:i}=this._map.options,{R:o}=i.projection,u=Math.PI/180,a=t.lat,s=Math.sin(a*u),c=new e.Point(o*t.lng*u,o*Math.log((1+s)/(1-s))/2),f=null!==(r=null==i?void 0:i.scale(n))&&void 0!==r?r:0;return i.transformation._transform(c,f)}_unclampedLatLngBoundsToNewLayerBounds(t,n,r){const i=this._map._getNewPixelOrigin(r,n);return new e.Bounds([this._unclampedProject(t.getSouthWest(),n).subtract(i),this._unclampedProject(t.getNorthWest(),n).subtract(i),this._unclampedProject(t.getSouthEast(),n).subtract(i),this._unclampedProject(t.getNorthEast(),n).subtract(i)])}}function o(t){return`"${t}" not properly defined`}class u{constructor(){this.array=new Float32Array(16)}setSize(t,n){return this.array.set([2/t,0,0,0,0,-2/n,0,0,0,0,0,0,-1,1,0,1]),this}translateTo(t,n){const{array:r}=this;return r[12]=r[0]*t-1,r[13]=r[5]*n+1,this}scaleTo(t){const{array:n}=this;return n[0]*=t,n[5]*=t,this}}const a={pane:"overlayPane"};class s{constructor(t){var n,r;this.bytes=0,this.buffers={},this.attributeLocations={},this.uniformLocations={},this.settings={...a,...t},this.mapMatrix=new u,this.active=!0,this.vertexShader=null,this.fragmentShader=null,this.program=null,this.matrix=null,this.vertices=null,this.vertexLines=null;const e=Boolean(t.preserveDrawingBuffer),s=this.layer=new i(t=>this.drawOnCanvas(t),this.pane).addTo(this.map);if(!s.canvas)throw new Error(o("layer.canvas"));const c=this.canvas=s.canvas;c.width=c.clientWidth,c.height=c.clientHeight,c.style.position="absolute",this.className&&(c.className+=" "+this.className),this.gl=null!==(r=null!==(n=c.getContext("webgl2",{preserveDrawingBuffer:e}))&&void 0!==n?n:c.getContext("webgl",{preserveDrawingBuffer:e}))&&void 0!==r?r:c.getContext("experimental-webgl",{preserveDrawingBuffer:e})}get data(){if(!this.settings.data)throw new Error(o("settings.data"));return this.settings.data}get pane(){var t;return null!==(t=this.settings.pane)&&void 0!==t?t:"overlayPane"}get className(){var t;return null!==(t=this.settings.className)&&void 0!==t?t:""}get map(){if(!this.settings.map)throw new Error(o("settings.map"));return this.settings.map}get sensitivity(){if("number"!=typeof this.settings.sensitivity)throw new Error(o("settings.sensitivity"));return this.settings.sensitivity}get sensitivityHover(){if("number"!=typeof this.settings.sensitivityHover)throw new Error(o("settings.sensitivityHover"));return this.settings.sensitivityHover}get hoverWait(){var t;return null!==(t=this.settings.hoverWait)&&void 0!==t?t:250}get longitudeKey(){if("number"!=typeof this.settings.longitudeKey)throw new Error(o("settings.longitudeKey"));return this.settings.longitudeKey}get latitudeKey(){if("number"!=typeof this.settings.latitudeKey)throw new Error(o("settings.latitudeKey"));return this.settings.latitudeKey}get opacity(){if("number"!=typeof this.settings.opacity)throw new Error(o("settings.opacity"));return this.settings.opacity}get color(){var t;return null!==(t=this.settings.color)&&void 0!==t?t:null}attachShaderVariables(t){if(0===this.getShaderVariableCount())return this;const{gl:n,settings:r}=this,{shaderVariables:e}=r;let i=0;for(const r in e){if(!e.hasOwnProperty(r))continue;const o=e[r],u=this.getAttributeLocation(r);if(u<0)throw new Error("shader variable "+r+" not found");n.vertexAttribPointer(u,o.size,n[o.type],!!o.normalize,this.bytes*t,i*t),i+=o.size,n.enableVertexAttribArray(u)}return this}getShaderVariableCount(){var t;return Object.keys(null!==(t=this.settings.shaderVariables)&&void 0!==t?t:{}).length}setData(t){return this.settings={...this.settings,data:t},this.render()}setup(){const t=this.settings;return t.click&&t.setupClick&&t.setupClick(this.map),t.hover&&t.setupHover&&t.setupHover(this.map,this.hoverWait),this.setupVertexShader().setupFragmentShader().setupProgram()}setupVertexShader(){const{gl:t,settings:n}=this,r="function"==typeof n.vertexShaderSource?n.vertexShaderSource():n.vertexShaderSource,e=t.createShader(t.VERTEX_SHADER);if(!e)throw new Error("Not able to create vertex");if(!r)throw new Error(o("settings.vertexShaderSource"));return t.shaderSource(e,r),t.compileShader(e),this.vertexShader=e,this}setupFragmentShader(){const t=this.gl,n=this.settings,r="function"==typeof n.fragmentShaderSource?n.fragmentShaderSource():n.fragmentShaderSource,e=t.createShader(t.FRAGMENT_SHADER);if(!e)throw new Error("Not able to create fragment");if(!r)throw new Error(o("settings.fragmentShaderSource"));return t.shaderSource(e,r),t.compileShader(e),this.fragmentShader=e,this}setupProgram(){const{gl:t,vertexShader:n,fragmentShader:r}=this,e=t.createProgram();if(!e)throw new Error("Not able to create program");if(!n)throw new Error(o("this.vertexShader"));if(!r)throw new Error(o("this.fragmentShader"));return t.attachShader(e,n),t.attachShader(e,r),t.linkProgram(e),t.useProgram(e),t.blendFuncSeparate(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA,t.ONE,t.ONE_MINUS_SRC_ALPHA),t.enable(t.BLEND),this.program=e,this}addTo(t){return this.layer.addTo(null!=t?t:this.map),this.active=!0,this.render()}remove(t){if(void 0===t)this.map.removeLayer(this.layer),this.active=!1;else{const n=this.settings.data.features||this.settings.data;"number"==typeof(t=t instanceof Array?t:[t])&&(t=[t]),t.sort((t,n)=>t-n).reverse().forEach(t=>{n.splice(t,1)}),this.render()}return this}insert(t,n){return(this.settings.data.features||this.settings.data).splice(n,0,t),this.render()}update(t,n){return(this.settings.data.features||this.settings.data)[n]=t,this.render()}getBuffer(t){if(!this.buffers[t]){const n=this.gl.createBuffer();if(!n)throw new Error("Not able to create buffer");this.buffers[t]=n}return this.buffers[t]}getAttributeLocation(t){if(!this.program)throw new Error(o("this.program"));return void 0!==this.attributeLocations[t]?this.attributeLocations[t]:this.attributeLocations[t]=this.gl.getAttribLocation(this.program,t)}getUniformLocation(t){if(!this.program)throw new Error(o("this.program"));if(void 0!==this.uniformLocations[t])return this.uniformLocations[t];const n=this.gl.getUniformLocation(this.program,t);if(!n)throw new Error("Cannot find location");return this.uniformLocations[t]=n}click(t,n){if(!this.settings.click)return;const r=this.settings.click(t,n);return void 0!==r?r:void 0}hover(t,n){if(!this.settings.hover)return;const r=this.settings.hover(t,n);return void 0!==r?r:void 0}hoverOff(t,n){this.settings.hoverOff&&this.settings.hoverOff(t,n)}}s.defaults=a;function c(){return{r:Math.random(),g:Math.random(),b:Math.random(),a:Math.random()}}class f{constructor(t){this.pixels=[],this.latLngs=[],this.settings=t,this.vertexCount=0,this.array=[]}get length(){return this.array.length}fillFromCoordinates(t){var n;const{color:r,opacity:i,project:o,latitudeKey:u,longitudeKey:a}=this.settings;for(let s=0;s1?(c=i,f=o):(c=r+l*u,f=e+l*a);const h=t-c,v=n-f;return Math.sqrt(h*h+v*v)}function p(t,n,r){const e=r.latLngToLayerPoint(t),i=r.latLngToLayerPoint(n);return function(t,n){return Math.sqrt(t*t+n*n)}(e.x-i.x,e.y-i.y)}const d={data:{type:"FeatureCollection",features:[]},color:c,className:"",opacity:.5,weight:2,sensitivity:.1,sensitivityHover:.03,shaderVariables:{vertex:{type:"FLOAT",start:0,size:2},color:{type:"FLOAT",start:2,size:4}}};class g extends s{constructor(t){if(super(t),this.scale=1/0,this.bytes=6,this.allVertices=[],this.allVerticesTyped=new Float32Array(0),this.vertices=[],this.aPointSize=-1,this.hoveringFeatures=[],this.settings={...g.defaults,...t},!t.data)throw new Error('"data" is missing');this.active=!0,this.setup().render()}get weight(){if(!this.settings.weight)throw new Error("settings.weight not correctly defined");return this.settings.weight}render(){this.resetVertices();const{canvas:t,gl:n,layer:r,mapMatrix:e}=this,i=this.getBuffer("vertex");n.bindBuffer(n.ARRAY_BUFFER,i);const o=this.allVerticesTyped.BYTES_PER_ELEMENT;n.bufferData(n.ARRAY_BUFFER,this.allVerticesTyped,n.STATIC_DRAW);const u=this.getAttributeLocation("vertex");return n.vertexAttribPointer(u,2,n.FLOAT,!1,o*this.bytes,0),n.enableVertexAttribArray(u),this.matrix=this.getUniformLocation("matrix"),this.aPointSize=this.getAttributeLocation("pointSize"),e.setSize(t.width,t.height),n.viewport(0,0,t.width,t.height),n.uniformMatrix4fv(this.matrix,!1,e.array),this.attachShaderVariables(o),r.redraw(),this}resetVertices(){const{map:t,opacity:n,color:r,weight:e,latitudeKey:i,longitudeKey:o,data:u,bytes:a,settings:s}=this,{eachVertex:c}=s,{features:l}=u,h=l.length;let v,p,d=null,g=null,y=0;"function"==typeof r&&(d=r),"function"==typeof e&&(g=e);const _=t.project.bind(t),m=[];for(;y18)i.translateTo(-h.x,-h.y),n.uniformMatrix4fv(o,!1,i.array),n.drawArrays(n.LINES,0,u.length/f);else if("number"==typeof s)for(let t=-s;t<=s;t+=.5)for(let r=-s;r<=s;r+=.5)i.translateTo(-h.x+r/l,-h.y+t/l),n.uniformMatrix4fv(o,!1,i.array),n.drawArrays(n.LINES,0,u.length/f);else if("function"==typeof s){let t=0;const{features:e}=r;for(let r=0;r{const{latitudeKey:o,longitudeKey:u,sensitivity:a,weight:s,scale:c,active:f}=r;function l(n,s,f,l){v(t.latlng.lng,t.latlng.lat,s[u],s[o],n[u],n[o])<=a+l/c&&(e=f,i=r)}f&&r.map===n&&r.data.features.forEach((t,n)=>{const r="function"==typeof s?s(n,t):s,{coordinates:e,type:i}=t.geometry;if("LineString"===i)for(let n=1;n0){const i=e[n-1];l(i[i.length-1],e[n][o],t,r)}else o>0&&l(e[n][o],e[n][o-1],t,r)}})}),i&&e){const n=i.click(t,e);return void 0!==n?n:void 0}}static tryHover(t,n,r){const i=[];return r.forEach(r=>{const{sensitivityHover:o,latitudeKey:u,longitudeKey:a,data:s,hoveringFeatures:c,weight:f,scale:l}=r;function h(n,r,e,i){return v(t.latlng.lng,t.latlng.lat,r[a],r[u],n[a],n[u])<=o+i/l&&(d.includes(e)||d.push(e),!p.includes(e))}if(!r.active)return;if(n!==r.map)return;const p=c,d=[];r.hoveringFeatures=d;const g=Object(e.geoJSON)(s.features).getBounds();(function(t,n){const r=n.getNorthEast(),e=n.getSouthWest();return r.lat>t.lat&&t.lat>e.lat&&r.lng>t.lng&&t.lng>e.lng})(t.latlng,g)&&s.features.forEach((n,e)=>{const o="function"==typeof f?f(e,n):f,{coordinates:u,type:a}=n.geometry;let s=!1;if("LineString"===a)for(let t=1;t0){const r=u[t-1];if(s=h(r[r.length-1],u[t][e],n,o),s)break}else if(e>0&&(s=h(u[t][e],u[t][e-1],n,o),s))break}if(s){const e=r.hover(t,n);void 0!==e&&i.push(e)}});for(let n=0;n0?e:this.allLatLngLookup,f)}static closest(t,n,r){return n.length<1?null:n.reduce((n,e)=>p(t,n.latLng,r){a=r.settings,r.active&&r.map===n&&(u=r.lookup(t.latlng),null!==u&&(i[u.key]=r,e.push(u)))}),e.length<1)return;if(!a)return;const s=this.closest(t.latlng,e,n);if(!s)return;const c=i[s.key];if(!c)return;const{sensitivity:f}=c,l=s.latLng;return h(n.latLngToLayerPoint(l),t.layerPoint,s.chosenSize*(null!=f?f:1))?(o=c.click(t,s.feature||s.latLng),void 0===o||o):void 0}static tryHover(t,n,r){const e=[];return r.forEach(r=>{if(!r.active)return;if(r.map!==n)return;const i=r.lookup(t.latlng);if(i&&h(n.latLngToLayerPoint(i.latLng),t.layerPoint,i.chosenSize*r.sensitivityHover*30)){const n=r.hover(t,i.feature||i.latLng);void 0!==n&&e.push(n)}}),e}}_.defaults=y,_.maps=[];var m=r(1),x=r.n(m),b=r(2),w=r.n(b);function S(t){switch(t&&t.type||null){case"FeatureCollection":return t.features=t.features.reduce((function(t,n){return t.concat(S(n))}),[]),t;case"Feature":return t.geometry?S(t.geometry).map((function(n){var r={type:"Feature",properties:JSON.parse(JSON.stringify(t.properties)),geometry:n};return void 0!==t.id&&(r.id=t.id),r})):[t];case"MultiPoint":return t.coordinates.map((function(t){return{type:"Point",coordinates:t}}));case"MultiPolygon":return t.coordinates.map((function(t){return{type:"Polygon",coordinates:t}}));case"MultiLineString":return t.coordinates.map((function(t){return{type:"LineString",coordinates:t}}));case"GeometryCollection":return t.geometries.map(S).reduce((function(t,n){return t.concat(n)}),[]);case"Point":case"Polygon":case"LineString":return[t]}}const A={color:c,className:"",opacity:.5,borderOpacity:1,shaderVariables:{vertex:{type:"FLOAT",start:0,size:2},color:{type:"FLOAT",start:2,size:4}},border:!1};class L extends s{constructor(t){if(super(t),this.bytes=6,this.polygonLookup=null,this.settings={...L.defaults,...t},!t.data)throw new Error(o("settings.data"));if(!t.map)throw new Error(o("settings.map"));this.setup().render()}get border(){if("boolean"!=typeof this.settings.border)throw new Error(o("settings.border"));return this.settings.border}get borderOpacity(){if("number"!=typeof this.settings.borderOpacity)throw new Error(o("settings.borderOpacity"));return this.settings.borderOpacity}render(){this.resetVertices();const{canvas:t,gl:n,layer:r,vertices:e,mapMatrix:i}=this,o=this.getBuffer("vertex"),u=new Float32Array(e),a=u.BYTES_PER_ELEMENT,s=this.getAttributeLocation("vertex");return n.bindBuffer(n.ARRAY_BUFFER,o),n.bufferData(n.ARRAY_BUFFER,u,n.STATIC_DRAW),n.vertexAttribPointer(s,2,n.FLOAT,!1,a*this.bytes,0),n.enableVertexAttribArray(s),this.matrix=this.getUniformLocation("matrix"),n.viewport(0,0,t.width,t.height),i.setSize(t.width,t.height),n.uniformMatrix4fv(this.matrix,!1,i.array),this.attachShaderVariables(a),r.redraw(),this}resetVertices(){this.vertices=[],this.vertexLines=[],this.polygonLookup=new w.a;const{vertices:t,vertexLines:n,polygonLookup:r,map:i,border:u,opacity:a,borderOpacity:s,color:c,data:f}=this;let h,v,p,d,g,y,_,m,b,A,L=null,E=0;switch(f.type){case"Feature":r.loadFeatureCollection({type:"FeatureCollection",features:[f]}),p=S(f);break;case"MultiPolygon":{const t={type:"MultiPolygon",coordinates:f.coordinates};r.loadFeatureCollection({type:"FeatureCollection",features:[{type:"Feature",properties:{},geometry:t}]}),p=S(f);break}default:r.loadFeatureCollection(f),p=f.features}const M=p.length;if(!c)throw new Error(o("settings.color"));for("function"==typeof c&&(L=c);E{if(r.active&&r.map===n&&r.polygonLookup&&(i=r.polygonLookup.search(t.latlng.lng,t.latlng.lat),i)){const n=r.hover(t,i);void 0!==n&&e.push(n)}}),e}}L.defaults=A;const E={vertex:"uniform mat4 matrix;\nattribute vec4 vertex;\nattribute vec4 color;\nattribute float pointSize;\nvarying vec4 _color;\n\nvoid main() {\n //set the size of the point\n gl_PointSize = pointSize;\n\n //multiply each vertex by a matrix.\n gl_Position = matrix * vertex;\n\n //pass the color to the fragment shader\n _color = color;\n}\n",fragment:{dot:"precision mediump float;\nuniform vec4 color;\n\nvoid main() {\n float border = 0.05;\n float radius = 0.5;\n vec2 center = vec2(0.5);\n\n vec4 color0 = vec4(0.0);\n vec4 color1 = vec4(color[0], color[1], color[2], color[3]);\n\n vec2 m = gl_PointCoord.xy - center;\n float dist = radius - sqrt(m.x * m.x + m.y * m.y);\n\n float t = 0.0;\n if (dist > border) {\n t = 1.0;\n } else if (dist > 0.0) {\n t = dist / border;\n }\n\n //works for overlapping circles if blending is enabled\n gl_FragColor = mix(color0, color1, t);\n}\n",point:"precision mediump float;\nvarying vec4 _color;\n\nvoid main() {\n float border = 0.1;\n float radius = 0.5;\n vec2 center = vec2(0.5, 0.5);\n\n vec4 pointColor = vec4(\n _color[0],\n _color[1],\n _color[2],\n _color[3]\n );\n\n vec2 m = gl_PointCoord.xy - center;\n float dist1 = radius - sqrt(m.x * m.x + m.y * m.y);\n\n float t1 = 0.0;\n if (dist1 > border) {\n t1 = 1.0;\n } else if (dist1 > 0.0) {\n t1 = dist1 / border;\n }\n\n //works for overlapping circles if blending is enabled\n //gl_FragColor = mix(color0, color1, t);\n\n //border\n float outerBorder = 0.05;\n float innerBorder = 0.8;\n vec4 borderColor = vec4(0, 0, 0, 0.4);\n vec2 uv = gl_PointCoord.xy;\n vec4 clearColor = vec4(0, 0, 0, 0);\n\n // Offset uv with the center of the circle.\n uv -= center;\n\n float dist2 = sqrt(dot(uv, uv));\n\n float t2 = 1.0 + smoothstep(radius, radius + outerBorder, dist2)\n - smoothstep(radius - innerBorder, radius, dist2);\n\n gl_FragColor = mix(mix(borderColor, clearColor, t2), pointColor, t1);\n}\n",puck:"precision mediump float;\nvarying vec4 _color;\n\nvoid main() {\n vec2 center = vec2(0.5);\n vec2 uv = gl_PointCoord.xy - center;\n float smoothing = 0.005;\n vec4 _color1 = vec4(_color[0], _color[1], _color[2], _color[3]);\n float radius1 = 0.3;\n vec4 _color2 = vec4(_color[0], _color[1], _color[2], _color[3]);\n float radius2 = 0.5;\n float dist = length(uv);\n\n //SMOOTH\n float gamma = 2.2;\n color1.rgb = pow(_color1.rgb, vec3(gamma));\n color2.rgb = pow(_color2.rgb, vec3(gamma));\n\n vec4 puck = mix(\n mix(\n _color1,\n _color2,\n smoothstep(\n radius1 - smoothing,\n radius1 + smoothing,\n dist\n )\n ),\n vec4(0,0,0,0),\n smoothstep(\n radius2 - smoothing,\n radius2 + smoothing,\n dist\n )\n );\n\n //Gamma correction (prevents color fringes)\n puck.rgb = pow(puck.rgb, vec3(1.0 / gamma));\n gl_FragColor = puck;\n}\n",simpleCircle:"precision mediump float;\nvarying vec4 _color;\n\nvoid main() {\n vec4 color1 = vec4(_color[0], _color[1], _color[2], _color[3]);\n\n //simple circles\n float d = distance (gl_PointCoord, vec2(0.5, 0.5));\n if (d < 0.5 ){\n gl_FragColor = color1;\n } else {\n discard;\n }\n}\n",square:"precision mediump float;\nvarying vec4 _color;\n\nvoid main() {\n //squares\n gl_FragColor = vec4(_color[0], _color[1], _color[2], _color[3]);\n}\n",polygon:"precision mediump float;\nvarying vec4 _color;\n\nvoid main() {\n gl_FragColor = vec4(\n _color[0],\n _color[1],\n _color[2],\n _color[3]\n );\n}\n"}};class M{constructor(){this.longitudeKey=1,this.latitudeKey=0,this.clickSetupMaps=[],this.hoverSetupMaps=[],this.shader=E,this.Points=_,this.Shapes=L,this.Lines=g,this.pointsInstances=[],this.shapesInstances=[],this.linesInstances=[]}longitudeFirst(){return this.longitudeKey=0,this.latitudeKey=1,this}latitudeFirst(){return this.latitudeKey=0,this.longitudeKey=1,this}get instances(){return[...this.pointsInstances,...this.linesInstances,...this.shapesInstances]}points(t){const n=new this.Points({setupClick:this.setupClick.bind(this),setupHover:this.setupHover.bind(this),latitudeKey:k.latitudeKey,longitudeKey:k.longitudeKey,vertexShaderSource:()=>this.shader.vertex,fragmentShaderSource:()=>this.shader.fragment.point,...t});return this.pointsInstances.push(n),n}lines(t){const n=new this.Lines({setupClick:this.setupClick.bind(this),setupHover:this.setupHover.bind(this),latitudeKey:this.latitudeKey,longitudeKey:this.longitudeKey,vertexShaderSource:()=>this.shader.vertex,fragmentShaderSource:()=>this.shader.fragment.polygon,...t});return this.linesInstances.push(n),n}shapes(t){const n=new this.Shapes({setupClick:this.setupClick.bind(this),setupHover:this.setupHover.bind(this),latitudeKey:this.latitudeKey,longitudeKey:this.longitudeKey,vertexShaderSource:()=>this.shader.vertex,fragmentShaderSource:()=>this.shader.fragment.polygon,...t});return this.shapesInstances.push(n),n}setupClick(t){this.clickSetupMaps.includes(t)||(this.clickSetupMaps.push(t),t.on("click",n=>{let r;return r=this.Points.tryClick(n,t,this.pointsInstances),void 0!==r?r:(r=this.Lines.tryClick(n,t,this.linesInstances),void 0!==r?r:(r=this.Shapes.tryClick(n,t,this.shapesInstances),void 0!==r?r:void 0))}))}setupHover(t,n,r){this.hoverSetupMaps.includes(t)||(this.hoverSetupMaps.push(t),t.on("mousemove",function(t,n,r){let e=null;return function(i){const o=r&&!e;null!==e&&clearTimeout(e),e=setTimeout((function(){e=null,r||t(i)}),n),o&&t(i)}}(n=>{this.Points.tryHover(n,t,this.pointsInstances),this.Lines.tryHover(n,t,this.linesInstances),this.Shapes.tryHover(n,t,this.shapesInstances)},null!=n?n:0,r)))}}const k=new M;n.default=k;"undefined"!=typeof window&&window.L&&(window.L.glify=k,window.L.Glify=M)}])})); +/*! For license information please see glify-browser.js.LICENSE.txt */ +!function(t,n){if("object"==typeof exports&&"object"==typeof module)module.exports=n(require("leaflet"));else if("function"==typeof define&&define.amd)define(["leaflet"],n);else{var r="object"==typeof exports?n(require("leaflet")):n(t.L);for(var e in r)("object"==typeof exports?exports:t)[e]=r[e]}}(self,(t=>(()=>{var n={570:t=>{"use strict";function n(t,n,e){e=e||2;var o,u,a,s,f,h,v,g=n&&n.length,d=g?n[0]*e:t.length,y=r(t,0,d,e,!0),_=[];if(!y||y.next===y.prev)return _;if(g&&(y=function(t,n,e,i){var o,u,a,s=[];for(o=0,u=n.length;o80*e){o=a=t[0],u=s=t[1];for(var m=e;ma&&(a=f),h>s&&(s=h);v=0!==(v=Math.max(a-o,s-u))?32767/v:0}return i(y,_,e,o,u,v,0),_}function r(t,n,r,e,i){var o,u;if(i===E(t,n,r,e)>0)for(o=n;o=n;o-=e)u=S(o,t[o],t[o+1],u);return u&&y(u,u.next)&&(A(u),u=u.next),u}function e(t,n){if(!t)return t;n||(n=t);var r,e=t;do{if(r=!1,e.steiner||!y(e,e.next)&&0!==d(e.prev,e,e.next))e=e.next;else{if(A(e),(e=n=e.prev)===e.next)break;r=!0}}while(r||e!==n);return n}function i(t,n,r,c,l,f,p){if(t){!p&&f&&function(t,n,r,e){var i=t;do{0===i.z&&(i.z=h(i.x,i.y,n,r,e)),i.prevZ=i.prev,i.nextZ=i.next,i=i.next}while(i!==t);i.prevZ.nextZ=null,i.prevZ=null,function(t){var n,r,e,i,o,u,a,s,c=1;do{for(r=t,t=null,o=null,u=0;r;){for(u++,e=r,a=0,n=0;n0||s>0&&e;)0!==a&&(0===s||!e||r.z<=e.z)?(i=r,r=r.nextZ,a--):(i=e,e=e.nextZ,s--),o?o.nextZ=i:t=i,i.prevZ=o,o=i;r=e}o.nextZ=null,c*=2}while(u>1)}(i)}(t,c,l,f);for(var v,g,d=t;t.prev!==t.next;)if(v=t.prev,g=t.next,f?u(t,c,l,f):o(t))n.push(v.i/r|0),n.push(t.i/r|0),n.push(g.i/r|0),A(t),t=g.next,d=g.next;else if((t=g)===d){p?1===p?i(t=a(e(t),n,r),n,r,c,l,f,2):2===p&&s(t,n,r,c,l,f):i(e(t),n,r,c,l,f,1);break}}}function o(t){var n=t.prev,r=t,e=t.next;if(d(n,r,e)>=0)return!1;for(var i=n.x,o=r.x,u=e.x,a=n.y,s=r.y,c=e.y,l=io?i>u?i:u:o>u?o:u,p=a>s?a>c?a:c:s>c?s:c,g=e.next;g!==n;){if(g.x>=l&&g.x<=h&&g.y>=f&&g.y<=p&&v(i,a,o,s,u,c,g.x,g.y)&&d(g.prev,g,g.next)>=0)return!1;g=g.next}return!0}function u(t,n,r,e){var i=t.prev,o=t,u=t.next;if(d(i,o,u)>=0)return!1;for(var a=i.x,s=o.x,c=u.x,l=i.y,f=o.y,p=u.y,g=as?a>c?a:c:s>c?s:c,m=l>f?l>p?l:p:f>p?f:p,x=h(g,y,n,r,e),w=h(_,m,n,r,e),b=t.prevZ,S=t.nextZ;b&&b.z>=x&&S&&S.z<=w;){if(b.x>=g&&b.x<=_&&b.y>=y&&b.y<=m&&b!==i&&b!==u&&v(a,l,s,f,c,p,b.x,b.y)&&d(b.prev,b,b.next)>=0)return!1;if(b=b.prevZ,S.x>=g&&S.x<=_&&S.y>=y&&S.y<=m&&S!==i&&S!==u&&v(a,l,s,f,c,p,S.x,S.y)&&d(S.prev,S,S.next)>=0)return!1;S=S.nextZ}for(;b&&b.z>=x;){if(b.x>=g&&b.x<=_&&b.y>=y&&b.y<=m&&b!==i&&b!==u&&v(a,l,s,f,c,p,b.x,b.y)&&d(b.prev,b,b.next)>=0)return!1;b=b.prevZ}for(;S&&S.z<=w;){if(S.x>=g&&S.x<=_&&S.y>=y&&S.y<=m&&S!==i&&S!==u&&v(a,l,s,f,c,p,S.x,S.y)&&d(S.prev,S,S.next)>=0)return!1;S=S.nextZ}return!0}function a(t,n,r){var i=t;do{var o=i.prev,u=i.next.next;!y(o,u)&&_(o,i,i.next,u)&&w(o,u)&&w(u,o)&&(n.push(o.i/r|0),n.push(i.i/r|0),n.push(u.i/r|0),A(i),A(i.next),i=t=u),i=i.next}while(i!==t);return e(i)}function s(t,n,r,o,u,a){var s=t;do{for(var c=s.next.next;c!==s.prev;){if(s.i!==c.i&&g(s,c)){var l=b(s,c);return s=e(s,s.next),l=e(l,l.next),i(s,n,r,o,u,a,0),void i(l,n,r,o,u,a,0)}c=c.next}s=s.next}while(s!==t)}function c(t,n){return t.x-n.x}function l(t,n){var r=function(t,n){var r,e=n,i=t.x,o=t.y,u=-1/0;do{if(o<=e.y&&o>=e.next.y&&e.next.y!==e.y){var a=e.x+(o-e.y)*(e.next.x-e.x)/(e.next.y-e.y);if(a<=i&&a>u&&(u=a,r=e.x=e.x&&e.x>=l&&i!==e.x&&v(or.x||e.x===r.x&&f(r,e)))&&(r=e,p=s)),e=e.next}while(e!==c);return r}(t,n);if(!r)return n;var i=b(r,t);return e(i,i.next),e(r,r.next)}function f(t,n){return d(t.prev,t,n.prev)<0&&d(n.next,t,t.next)<0}function h(t,n,r,e,i){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-r)*i|0)|t<<8))|t<<4))|t<<2))|t<<1))|(n=1431655765&((n=858993459&((n=252645135&((n=16711935&((n=(n-e)*i|0)|n<<8))|n<<4))|n<<2))|n<<1))<<1}function p(t){var n=t,r=t;do{(n.x=(t-u)*(o-a)&&(t-u)*(e-a)>=(r-u)*(n-a)&&(r-u)*(o-a)>=(i-u)*(e-a)}function g(t,n){return t.next.i!==n.i&&t.prev.i!==n.i&&!function(t,n){var r=t;do{if(r.i!==t.i&&r.next.i!==t.i&&r.i!==n.i&&r.next.i!==n.i&&_(r,r.next,t,n))return!0;r=r.next}while(r!==t);return!1}(t,n)&&(w(t,n)&&w(n,t)&&function(t,n){var r=t,e=!1,i=(t.x+n.x)/2,o=(t.y+n.y)/2;do{r.y>o!=r.next.y>o&&r.next.y!==r.y&&i<(r.next.x-r.x)*(o-r.y)/(r.next.y-r.y)+r.x&&(e=!e),r=r.next}while(r!==t);return e}(t,n)&&(d(t.prev,t,n.prev)||d(t,n.prev,n))||y(t,n)&&d(t.prev,t,t.next)>0&&d(n.prev,n,n.next)>0)}function d(t,n,r){return(n.y-t.y)*(r.x-n.x)-(n.x-t.x)*(r.y-n.y)}function y(t,n){return t.x===n.x&&t.y===n.y}function _(t,n,r,e){var i=x(d(t,n,r)),o=x(d(t,n,e)),u=x(d(r,e,t)),a=x(d(r,e,n));return i!==o&&u!==a||!(0!==i||!m(t,r,n))||!(0!==o||!m(t,e,n))||!(0!==u||!m(r,t,e))||!(0!==a||!m(r,n,e))}function m(t,n,r){return n.x<=Math.max(t.x,r.x)&&n.x>=Math.min(t.x,r.x)&&n.y<=Math.max(t.y,r.y)&&n.y>=Math.min(t.y,r.y)}function x(t){return t>0?1:t<0?-1:0}function w(t,n){return d(t.prev,t,t.next)<0?d(t,n,t.next)>=0&&d(t,t.prev,n)>=0:d(t,n,t.prev)<0||d(t,t.next,n)<0}function b(t,n){var r=new L(t.i,t.x,t.y),e=new L(n.i,n.x,n.y),i=t.next,o=n.prev;return t.next=n,n.prev=t,r.next=i,i.prev=r,e.next=r,r.prev=e,o.next=e,e.prev=o,e}function S(t,n,r,e){var i=new L(t,n,r);return e?(i.next=e.next,i.prev=e,e.next.prev=i,e.next=i):(i.prev=i,i.next=i),i}function A(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function L(t,n,r){this.i=t,this.x=n,this.y=r,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}function E(t,n,r,e){for(var i=0,o=n,u=r-e;o0&&(e+=t[i-1].length,r.holes.push(e))}return r}},543:function(t,n,r){var e;t=r.nmd(t),function(){var i,o="Expected a function",u="__lodash_hash_undefined__",a="__lodash_placeholder__",s=32,c=128,l=1/0,f=9007199254740991,h=NaN,p=4294967295,v=[["ary",c],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",s],["partialRight",64],["rearg",256]],g="[object Arguments]",d="[object Array]",y="[object Boolean]",_="[object Date]",m="[object Error]",x="[object Function]",w="[object GeneratorFunction]",b="[object Map]",S="[object Number]",A="[object Object]",L="[object Promise]",E="[object RegExp]",M="[object Set]",F="[object String]",k="[object Symbol]",C="[object WeakMap]",B="[object ArrayBuffer]",z="[object DataView]",R="[object Float32Array]",O="[object Float64Array]",j="[object Int8Array]",P="[object Int16Array]",I="[object Int32Array]",T="[object Uint8Array]",Y="[object Uint8ClampedArray]",N="[object Uint16Array]",U="[object Uint32Array]",D=/\b__p \+= '';/g,W=/\b(__p \+=) '' \+/g,X=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Z=/&(?:amp|lt|gt|quot|#39);/g,K=/[&<>"']/g,V=RegExp(Z.source),H=RegExp(K.source),q=/<%-([\s\S]+?)%>/g,$=/<%([\s\S]+?)%>/g,G=/<%=([\s\S]+?)%>/g,J=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Q=/^\w*$/,tt=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,nt=/[\\^$.*+?()[\]{}|]/g,rt=RegExp(nt.source),et=/^\s+/,it=/\s/,ot=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,ut=/\{\n\/\* \[wrapped with (.+)\] \*/,at=/,? & /,st=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,ct=/[()=,{}\[\]\/\s]/,lt=/\\(\\)?/g,ft=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,ht=/\w*$/,pt=/^[-+]0x[0-9a-f]+$/i,vt=/^0b[01]+$/i,gt=/^\[object .+?Constructor\]$/,dt=/^0o[0-7]+$/i,yt=/^(?:0|[1-9]\d*)$/,_t=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,mt=/($^)/,xt=/['\n\r\u2028\u2029\\]/g,wt="\\ud800-\\udfff",bt="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",St="\\u2700-\\u27bf",At="a-z\\xdf-\\xf6\\xf8-\\xff",Lt="A-Z\\xc0-\\xd6\\xd8-\\xde",Et="\\ufe0e\\ufe0f",Mt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Ft="["+wt+"]",kt="["+Mt+"]",Ct="["+bt+"]",Bt="\\d+",zt="["+St+"]",Rt="["+At+"]",Ot="[^"+wt+Mt+Bt+St+At+Lt+"]",jt="\\ud83c[\\udffb-\\udfff]",Pt="[^"+wt+"]",It="(?:\\ud83c[\\udde6-\\uddff]){2}",Tt="[\\ud800-\\udbff][\\udc00-\\udfff]",Yt="["+Lt+"]",Nt="\\u200d",Ut="(?:"+Rt+"|"+Ot+")",Dt="(?:"+Yt+"|"+Ot+")",Wt="(?:['’](?:d|ll|m|re|s|t|ve))?",Xt="(?:['’](?:D|LL|M|RE|S|T|VE))?",Zt="(?:"+Ct+"|"+jt+")?",Kt="["+Et+"]?",Vt=Kt+Zt+"(?:"+Nt+"(?:"+[Pt,It,Tt].join("|")+")"+Kt+Zt+")*",Ht="(?:"+[zt,It,Tt].join("|")+")"+Vt,qt="(?:"+[Pt+Ct+"?",Ct,It,Tt,Ft].join("|")+")",$t=RegExp("['’]","g"),Gt=RegExp(Ct,"g"),Jt=RegExp(jt+"(?="+jt+")|"+qt+Vt,"g"),Qt=RegExp([Yt+"?"+Rt+"+"+Wt+"(?="+[kt,Yt,"$"].join("|")+")",Dt+"+"+Xt+"(?="+[kt,Yt+Ut,"$"].join("|")+")",Yt+"?"+Ut+"+"+Wt,Yt+"+"+Xt,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Bt,Ht].join("|"),"g"),tn=RegExp("["+Nt+wt+bt+Et+"]"),nn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,rn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],en=-1,on={};on[R]=on[O]=on[j]=on[P]=on[I]=on[T]=on[Y]=on[N]=on[U]=!0,on[g]=on[d]=on[B]=on[y]=on[z]=on[_]=on[m]=on[x]=on[b]=on[S]=on[A]=on[E]=on[M]=on[F]=on[C]=!1;var un={};un[g]=un[d]=un[B]=un[z]=un[y]=un[_]=un[R]=un[O]=un[j]=un[P]=un[I]=un[b]=un[S]=un[A]=un[E]=un[M]=un[F]=un[k]=un[T]=un[Y]=un[N]=un[U]=!0,un[m]=un[x]=un[C]=!1;var an={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},sn=parseFloat,cn=parseInt,ln="object"==typeof r.g&&r.g&&r.g.Object===Object&&r.g,fn="object"==typeof self&&self&&self.Object===Object&&self,hn=ln||fn||Function("return this")(),pn=n&&!n.nodeType&&n,vn=pn&&t&&!t.nodeType&&t,gn=vn&&vn.exports===pn,dn=gn&&ln.process,yn=function(){try{return vn&&vn.require&&vn.require("util").types||dn&&dn.binding&&dn.binding("util")}catch(t){}}(),_n=yn&&yn.isArrayBuffer,mn=yn&&yn.isDate,xn=yn&&yn.isMap,wn=yn&&yn.isRegExp,bn=yn&&yn.isSet,Sn=yn&&yn.isTypedArray;function An(t,n,r){switch(r.length){case 0:return t.call(n);case 1:return t.call(n,r[0]);case 2:return t.call(n,r[0],r[1]);case 3:return t.call(n,r[0],r[1],r[2])}return t.apply(n,r)}function Ln(t,n,r,e){for(var i=-1,o=null==t?0:t.length;++i-1}function Bn(t,n,r){for(var e=-1,i=null==t?0:t.length;++e-1;);return r}function tr(t,n){for(var r=t.length;r--&&Nn(n,t[r],0)>-1;);return r}var nr=Zn({À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"}),rr=Zn({"&":"&","<":"<",">":">",'"':""","'":"'"});function er(t){return"\\"+an[t]}function ir(t){return tn.test(t)}function or(t){var n=-1,r=Array(t.size);return t.forEach((function(t,e){r[++n]=[e,t]})),r}function ur(t,n){return function(r){return t(n(r))}}function ar(t,n){for(var r=-1,e=t.length,i=0,o=[];++r",""":'"',"'":"'"}),vr=function t(n){var r,e=(n=null==n?hn:vr.defaults(hn.Object(),n,vr.pick(hn,rn))).Array,it=n.Date,wt=n.Error,bt=n.Function,St=n.Math,At=n.Object,Lt=n.RegExp,Et=n.String,Mt=n.TypeError,Ft=e.prototype,kt=bt.prototype,Ct=At.prototype,Bt=n["__core-js_shared__"],zt=kt.toString,Rt=Ct.hasOwnProperty,Ot=0,jt=(r=/[^.]+$/.exec(Bt&&Bt.keys&&Bt.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"",Pt=Ct.toString,It=zt.call(At),Tt=hn._,Yt=Lt("^"+zt.call(Rt).replace(nt,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Nt=gn?n.Buffer:i,Ut=n.Symbol,Dt=n.Uint8Array,Wt=Nt?Nt.allocUnsafe:i,Xt=ur(At.getPrototypeOf,At),Zt=At.create,Kt=Ct.propertyIsEnumerable,Vt=Ft.splice,Ht=Ut?Ut.isConcatSpreadable:i,qt=Ut?Ut.iterator:i,Jt=Ut?Ut.toStringTag:i,tn=function(){try{var t=so(At,"defineProperty");return t({},"",{}),t}catch(t){}}(),an=n.clearTimeout!==hn.clearTimeout&&n.clearTimeout,ln=it&&it.now!==hn.Date.now&&it.now,fn=n.setTimeout!==hn.setTimeout&&n.setTimeout,pn=St.ceil,vn=St.floor,dn=At.getOwnPropertySymbols,yn=Nt?Nt.isBuffer:i,In=n.isFinite,Zn=Ft.join,gr=ur(At.keys,At),dr=St.max,yr=St.min,_r=it.now,mr=n.parseInt,xr=St.random,wr=Ft.reverse,br=so(n,"DataView"),Sr=so(n,"Map"),Ar=so(n,"Promise"),Lr=so(n,"Set"),Er=so(n,"WeakMap"),Mr=so(At,"create"),Fr=Er&&new Er,kr={},Cr=Io(br),Br=Io(Sr),zr=Io(Ar),Rr=Io(Lr),Or=Io(Er),jr=Ut?Ut.prototype:i,Pr=jr?jr.valueOf:i,Ir=jr?jr.toString:i;function Tr(t){if(ta(t)&&!Wu(t)&&!(t instanceof Dr)){if(t instanceof Ur)return t;if(Rt.call(t,"__wrapped__"))return To(t)}return new Ur(t)}var Yr=function(){function t(){}return function(n){if(!Qu(n))return{};if(Zt)return Zt(n);t.prototype=n;var r=new t;return t.prototype=i,r}}();function Nr(){}function Ur(t,n){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!n,this.__index__=0,this.__values__=i}function Dr(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=p,this.__views__=[]}function Wr(t){var n=-1,r=null==t?0:t.length;for(this.clear();++n=n?t:n)),t}function ue(t,n,r,e,o,u){var a,s=1&n,c=2&n,l=4&n;if(r&&(a=o?r(t,e,o,u):r(t)),a!==i)return a;if(!Qu(t))return t;var f=Wu(t);if(f){if(a=function(t){var n=t.length,r=new t.constructor(n);return n&&"string"==typeof t[0]&&Rt.call(t,"index")&&(r.index=t.index,r.input=t.input),r}(t),!s)return Ei(t,a)}else{var h=fo(t),p=h==x||h==w;if(Vu(t))return xi(t,s);if(h==A||h==g||p&&!o){if(a=c||p?{}:po(t),!s)return c?function(t,n){return Mi(t,lo(t),n)}(t,function(t,n){return t&&Mi(n,Ba(n),t)}(a,t)):function(t,n){return Mi(t,co(t),n)}(t,re(a,t))}else{if(!un[h])return o?t:{};a=function(t,n,r){var e,i=t.constructor;switch(n){case B:return wi(t);case y:case _:return new i(+t);case z:return function(t,n){var r=n?wi(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)}(t,r);case R:case O:case j:case P:case I:case T:case Y:case N:case U:return bi(t,r);case b:return new i;case S:case F:return new i(t);case E:return function(t){var n=new t.constructor(t.source,ht.exec(t));return n.lastIndex=t.lastIndex,n}(t);case M:return new i;case k:return e=t,Pr?At(Pr.call(e)):{}}}(t,h,s)}}u||(u=new Vr);var v=u.get(t);if(v)return v;u.set(t,a),oa(t)?t.forEach((function(e){a.add(ue(e,n,r,e,t,u))})):na(t)&&t.forEach((function(e,i){a.set(i,ue(e,n,r,i,t,u))}));var d=f?i:(l?c?no:to:c?Ba:Ca)(t);return En(d||t,(function(e,i){d&&(e=t[i=e]),Qr(a,i,ue(e,n,r,i,t,u))})),a}function ae(t,n,r){var e=r.length;if(null==t)return!e;for(t=At(t);e--;){var o=r[e],u=n[o],a=t[o];if(a===i&&!(o in t)||!u(a))return!1}return!0}function se(t,n,r){if("function"!=typeof t)throw new Mt(o);return Fo((function(){t.apply(i,r)}),n)}function ce(t,n,r,e){var i=-1,o=Cn,u=!0,a=t.length,s=[],c=n.length;if(!a)return s;r&&(n=zn(n,$n(r))),e?(o=Bn,u=!1):n.length>=200&&(o=Jn,u=!1,n=new Kr(n));t:for(;++i-1},Xr.prototype.set=function(t,n){var r=this.__data__,e=te(r,t);return e<0?(++this.size,r.push([t,n])):r[e][1]=n,this},Zr.prototype.clear=function(){this.size=0,this.__data__={hash:new Wr,map:new(Sr||Xr),string:new Wr}},Zr.prototype.delete=function(t){var n=uo(this,t).delete(t);return this.size-=n?1:0,n},Zr.prototype.get=function(t){return uo(this,t).get(t)},Zr.prototype.has=function(t){return uo(this,t).has(t)},Zr.prototype.set=function(t,n){var r=uo(this,t),e=r.size;return r.set(t,n),this.size+=r.size==e?0:1,this},Kr.prototype.add=Kr.prototype.push=function(t){return this.__data__.set(t,u),this},Kr.prototype.has=function(t){return this.__data__.has(t)},Vr.prototype.clear=function(){this.__data__=new Xr,this.size=0},Vr.prototype.delete=function(t){var n=this.__data__,r=n.delete(t);return this.size=n.size,r},Vr.prototype.get=function(t){return this.__data__.get(t)},Vr.prototype.has=function(t){return this.__data__.has(t)},Vr.prototype.set=function(t,n){var r=this.__data__;if(r instanceof Xr){var e=r.__data__;if(!Sr||e.length<199)return e.push([t,n]),this.size=++r.size,this;r=this.__data__=new Zr(e)}return r.set(t,n),this.size=r.size,this};var le=Ci(_e),fe=Ci(me,!0);function he(t,n){var r=!0;return le(t,(function(t,e,i){return r=!!n(t,e,i)})),r}function pe(t,n,r){for(var e=-1,o=t.length;++e0&&r(a)?n>1?ge(a,n-1,r,e,i):Rn(i,a):e||(i[i.length]=a)}return i}var de=Bi(),ye=Bi(!0);function _e(t,n){return t&&de(t,n,Ca)}function me(t,n){return t&&ye(t,n,Ca)}function xe(t,n){return kn(n,(function(n){return $u(t[n])}))}function we(t,n){for(var r=0,e=(n=di(n,t)).length;null!=t&&rn}function Le(t,n){return null!=t&&Rt.call(t,n)}function Ee(t,n){return null!=t&&n in At(t)}function Me(t,n,r){for(var o=r?Bn:Cn,u=t[0].length,a=t.length,s=a,c=e(a),l=1/0,f=[];s--;){var h=t[s];s&&n&&(h=zn(h,$n(n))),l=yr(h.length,l),c[s]=!r&&(n||u>=120&&h.length>=120)?new Kr(s&&h):i}h=t[0];var p=-1,v=c[0];t:for(;++p=a?s:s*("desc"==r[e]?-1:1)}return t.index-n.index}(t,n,r)}));e--;)t[e]=t[e].value;return t}(i)}function De(t,n,r){for(var e=-1,i=n.length,o={};++e-1;)a!==t&&Vt.call(a,s,1),Vt.call(t,s,1);return t}function Xe(t,n){for(var r=t?n.length:0,e=r-1;r--;){var i=n[r];if(r==e||i!==o){var o=i;go(i)?Vt.call(t,i,1):si(t,i)}}return t}function Ze(t,n){return t+vn(xr()*(n-t+1))}function Ke(t,n){var r="";if(!t||n<1||n>f)return r;do{n%2&&(r+=t),(n=vn(n/2))&&(t+=t)}while(n);return r}function Ve(t,n){return ko(Ao(t,n,rs),t+"")}function He(t){return qr(Ya(t))}function qe(t,n){var r=Ya(t);return zo(r,oe(n,0,r.length))}function $e(t,n,r,e){if(!Qu(t))return t;for(var o=-1,u=(n=di(n,t)).length,a=u-1,s=t;null!=s&&++oo?0:o+n),(r=r>o?o:r)<0&&(r+=o),o=n>r?0:r-n>>>0,n>>>=0;for(var u=e(o);++i>>1,u=t[o];null!==u&&!aa(u)&&(r?u<=n:u=200){var c=n?null:Ki(t);if(c)return sr(c);u=!1,i=Jn,s=new Kr}else s=n?[]:a;t:for(;++e=e?t:ti(t,n,r)}var mi=an||function(t){return hn.clearTimeout(t)};function xi(t,n){if(n)return t.slice();var r=t.length,e=Wt?Wt(r):new t.constructor(r);return t.copy(e),e}function wi(t){var n=new t.constructor(t.byteLength);return new Dt(n).set(new Dt(t)),n}function bi(t,n){var r=n?wi(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}function Si(t,n){if(t!==n){var r=t!==i,e=null===t,o=t==t,u=aa(t),a=n!==i,s=null===n,c=n==n,l=aa(n);if(!s&&!l&&!u&&t>n||u&&a&&c&&!s&&!l||e&&a&&c||!r&&c||!o)return 1;if(!e&&!u&&!l&&t1?r[o-1]:i,a=o>2?r[2]:i;for(u=t.length>3&&"function"==typeof u?(o--,u):i,a&&yo(r[0],r[1],a)&&(u=o<3?i:u,o=1),n=At(n);++e-1?o[u?n[a]:a]:i}}function Pi(t){return Qi((function(n){var r=n.length,e=r,u=Ur.prototype.thru;for(t&&n.reverse();e--;){var a=n[e];if("function"!=typeof a)throw new Mt(o);if(u&&!s&&"wrapper"==eo(a))var s=new Ur([],!0)}for(e=s?e:r;++e1&&x.reverse(),p&&fs))return!1;var l=u.get(t),f=u.get(n);if(l&&f)return l==n&&f==t;var h=-1,p=!0,v=2&r?new Kr:i;for(u.set(t,n),u.set(n,t);++h-1&&t%1==0&&t1?"& ":"")+n[e],n=n.join(r>2?", ":" "),t.replace(ot,"{\n/* [wrapped with "+n+"] */\n")}(e,function(t,n){return En(v,(function(r){var e="_."+r[0];n&r[1]&&!Cn(t,e)&&t.push(e)})),t.sort()}(function(t){var n=t.match(ut);return n?n[1].split(at):[]}(e),r)))}function Bo(t){var n=0,r=0;return function(){var e=_r(),o=16-(e-r);if(r=e,o>0){if(++n>=800)return arguments[0]}else n=0;return t.apply(i,arguments)}}function zo(t,n){var r=-1,e=t.length,o=e-1;for(n=n===i?e:n;++r1?t[n-1]:i;return r="function"==typeof r?(t.pop(),r):i,iu(t,r)}));function fu(t){var n=Tr(t);return n.__chain__=!0,n}function hu(t,n){return n(t)}var pu=Qi((function(t){var n=t.length,r=n?t[0]:0,e=this.__wrapped__,o=function(n){return ie(n,t)};return!(n>1||this.__actions__.length)&&e instanceof Dr&&go(r)?((e=e.slice(r,+r+(n?1:0))).__actions__.push({func:hu,args:[o],thisArg:i}),new Ur(e,this.__chain__).thru((function(t){return n&&!t.length&&t.push(i),t}))):this.thru(o)})),vu=Fi((function(t,n,r){Rt.call(t,r)?++t[r]:ee(t,r,1)})),gu=ji(Do),du=ji(Wo);function yu(t,n){return(Wu(t)?En:le)(t,oo(n,3))}function _u(t,n){return(Wu(t)?Mn:fe)(t,oo(n,3))}var mu=Fi((function(t,n,r){Rt.call(t,r)?t[r].push(n):ee(t,r,[n])})),xu=Ve((function(t,n,r){var i=-1,o="function"==typeof n,u=Zu(t)?e(t.length):[];return le(t,(function(t){u[++i]=o?An(n,t,r):Fe(t,n,r)})),u})),wu=Fi((function(t,n,r){ee(t,r,n)}));function bu(t,n){return(Wu(t)?zn:Pe)(t,oo(n,3))}var Su=Fi((function(t,n,r){t[r?0:1].push(n)}),(function(){return[[],[]]})),Au=Ve((function(t,n){if(null==t)return[];var r=n.length;return r>1&&yo(t,n[0],n[1])?n=[]:r>2&&yo(n[0],n[1],n[2])&&(n=[n[0]]),Ue(t,ge(n,1),[])})),Lu=ln||function(){return hn.Date.now()};function Eu(t,n,r){return n=r?i:n,n=t&&null==n?t.length:n,Hi(t,c,i,i,i,i,n)}function Mu(t,n){var r;if("function"!=typeof n)throw new Mt(o);return t=pa(t),function(){return--t>0&&(r=n.apply(this,arguments)),t<=1&&(n=i),r}}var Fu=Ve((function(t,n,r){var e=1;if(r.length){var i=ar(r,io(Fu));e|=s}return Hi(t,e,n,r,i)})),ku=Ve((function(t,n,r){var e=3;if(r.length){var i=ar(r,io(ku));e|=s}return Hi(n,e,t,r,i)}));function Cu(t,n,r){var e,u,a,s,c,l,f=0,h=!1,p=!1,v=!0;if("function"!=typeof t)throw new Mt(o);function g(n){var r=e,o=u;return e=u=i,f=n,s=t.apply(o,r)}function d(t){var r=t-l;return l===i||r>=n||r<0||p&&t-f>=a}function y(){var t=Lu();if(d(t))return _(t);c=Fo(y,function(t){var r=n-(t-l);return p?yr(r,a-(t-f)):r}(t))}function _(t){return c=i,v&&e?g(t):(e=u=i,s)}function m(){var t=Lu(),r=d(t);if(e=arguments,u=this,l=t,r){if(c===i)return function(t){return f=t,c=Fo(y,n),h?g(t):s}(l);if(p)return mi(c),c=Fo(y,n),g(l)}return c===i&&(c=Fo(y,n)),s}return n=ga(n)||0,Qu(r)&&(h=!!r.leading,a=(p="maxWait"in r)?dr(ga(r.maxWait)||0,n):a,v="trailing"in r?!!r.trailing:v),m.cancel=function(){c!==i&&mi(c),f=0,e=l=u=c=i},m.flush=function(){return c===i?s:_(Lu())},m}var Bu=Ve((function(t,n){return se(t,1,n)})),zu=Ve((function(t,n,r){return se(t,ga(n)||0,r)}));function Ru(t,n){if("function"!=typeof t||null!=n&&"function"!=typeof n)throw new Mt(o);var r=function(){var e=arguments,i=n?n.apply(this,e):e[0],o=r.cache;if(o.has(i))return o.get(i);var u=t.apply(this,e);return r.cache=o.set(i,u)||o,u};return r.cache=new(Ru.Cache||Zr),r}function Ou(t){if("function"!=typeof t)throw new Mt(o);return function(){var n=arguments;switch(n.length){case 0:return!t.call(this);case 1:return!t.call(this,n[0]);case 2:return!t.call(this,n[0],n[1]);case 3:return!t.call(this,n[0],n[1],n[2])}return!t.apply(this,n)}}Ru.Cache=Zr;var ju=yi((function(t,n){var r=(n=1==n.length&&Wu(n[0])?zn(n[0],$n(oo())):zn(ge(n,1),$n(oo()))).length;return Ve((function(e){for(var i=-1,o=yr(e.length,r);++i=n})),Du=ke(function(){return arguments}())?ke:function(t){return ta(t)&&Rt.call(t,"callee")&&!Kt.call(t,"callee")},Wu=e.isArray,Xu=_n?$n(_n):function(t){return ta(t)&&Se(t)==B};function Zu(t){return null!=t&&Ju(t.length)&&!$u(t)}function Ku(t){return ta(t)&&Zu(t)}var Vu=yn||gs,Hu=mn?$n(mn):function(t){return ta(t)&&Se(t)==_};function qu(t){if(!ta(t))return!1;var n=Se(t);return n==m||"[object DOMException]"==n||"string"==typeof t.message&&"string"==typeof t.name&&!ea(t)}function $u(t){if(!Qu(t))return!1;var n=Se(t);return n==x||n==w||"[object AsyncFunction]"==n||"[object Proxy]"==n}function Gu(t){return"number"==typeof t&&t==pa(t)}function Ju(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=f}function Qu(t){var n=typeof t;return null!=t&&("object"==n||"function"==n)}function ta(t){return null!=t&&"object"==typeof t}var na=xn?$n(xn):function(t){return ta(t)&&fo(t)==b};function ra(t){return"number"==typeof t||ta(t)&&Se(t)==S}function ea(t){if(!ta(t)||Se(t)!=A)return!1;var n=Xt(t);if(null===n)return!0;var r=Rt.call(n,"constructor")&&n.constructor;return"function"==typeof r&&r instanceof r&&zt.call(r)==It}var ia=wn?$n(wn):function(t){return ta(t)&&Se(t)==E},oa=bn?$n(bn):function(t){return ta(t)&&fo(t)==M};function ua(t){return"string"==typeof t||!Wu(t)&&ta(t)&&Se(t)==F}function aa(t){return"symbol"==typeof t||ta(t)&&Se(t)==k}var sa=Sn?$n(Sn):function(t){return ta(t)&&Ju(t.length)&&!!on[Se(t)]},ca=Wi(je),la=Wi((function(t,n){return t<=n}));function fa(t){if(!t)return[];if(Zu(t))return ua(t)?fr(t):Ei(t);if(qt&&t[qt])return function(t){for(var n,r=[];!(n=t.next()).done;)r.push(n.value);return r}(t[qt]());var n=fo(t);return(n==b?or:n==M?sr:Ya)(t)}function ha(t){return t?(t=ga(t))===l||t===-1/0?17976931348623157e292*(t<0?-1:1):t==t?t:0:0===t?t:0}function pa(t){var n=ha(t),r=n%1;return n==n?r?n-r:n:0}function va(t){return t?oe(pa(t),0,p):0}function ga(t){if("number"==typeof t)return t;if(aa(t))return h;if(Qu(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=Qu(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=qn(t);var r=vt.test(t);return r||dt.test(t)?cn(t.slice(2),r?2:8):pt.test(t)?h:+t}function da(t){return Mi(t,Ba(t))}function ya(t){return null==t?"":ui(t)}var _a=ki((function(t,n){if(wo(n)||Zu(n))Mi(n,Ca(n),t);else for(var r in n)Rt.call(n,r)&&Qr(t,r,n[r])})),ma=ki((function(t,n){Mi(n,Ba(n),t)})),xa=ki((function(t,n,r,e){Mi(n,Ba(n),t,e)})),wa=ki((function(t,n,r,e){Mi(n,Ca(n),t,e)})),ba=Qi(ie),Sa=Ve((function(t,n){t=At(t);var r=-1,e=n.length,o=e>2?n[2]:i;for(o&&yo(n[0],n[1],o)&&(e=1);++r1),n})),Mi(t,no(t),r),e&&(r=ue(r,7,Gi));for(var i=n.length;i--;)si(r,n[i]);return r})),ja=Qi((function(t,n){return null==t?{}:function(t,n){return De(t,n,(function(n,r){return Ea(t,r)}))}(t,n)}));function Pa(t,n){if(null==t)return{};var r=zn(no(t),(function(t){return[t]}));return n=oo(n),De(t,r,(function(t,r){return n(t,r[0])}))}var Ia=Vi(Ca),Ta=Vi(Ba);function Ya(t){return null==t?[]:Gn(t,Ca(t))}var Na=Ri((function(t,n,r){return n=n.toLowerCase(),t+(r?Ua(n):n)}));function Ua(t){return qa(ya(t).toLowerCase())}function Da(t){return(t=ya(t))&&t.replace(_t,nr).replace(Gt,"")}var Wa=Ri((function(t,n,r){return t+(r?"-":"")+n.toLowerCase()})),Xa=Ri((function(t,n,r){return t+(r?" ":"")+n.toLowerCase()})),Za=zi("toLowerCase"),Ka=Ri((function(t,n,r){return t+(r?"_":"")+n.toLowerCase()})),Va=Ri((function(t,n,r){return t+(r?" ":"")+qa(n)})),Ha=Ri((function(t,n,r){return t+(r?" ":"")+n.toUpperCase()})),qa=zi("toUpperCase");function $a(t,n,r){return t=ya(t),(n=r?i:n)===i?function(t){return nn.test(t)}(t)?function(t){return t.match(Qt)||[]}(t):function(t){return t.match(st)||[]}(t):t.match(n)||[]}var Ga=Ve((function(t,n){try{return An(t,i,n)}catch(t){return qu(t)?t:new wt(t)}})),Ja=Qi((function(t,n){return En(n,(function(n){n=Po(n),ee(t,n,Fu(t[n],t))})),t}));function Qa(t){return function(){return t}}var ts=Pi(),ns=Pi(!0);function rs(t){return t}function es(t){return Re("function"==typeof t?t:ue(t,1))}var is=Ve((function(t,n){return function(r){return Fe(r,t,n)}})),os=Ve((function(t,n){return function(r){return Fe(t,r,n)}}));function us(t,n,r){var e=Ca(n),i=xe(n,e);null!=r||Qu(n)&&(i.length||!e.length)||(r=n,n=t,t=this,i=xe(n,Ca(n)));var o=!(Qu(r)&&"chain"in r&&!r.chain),u=$u(t);return En(i,(function(r){var e=n[r];t[r]=e,u&&(t.prototype[r]=function(){var n=this.__chain__;if(o||n){var r=t(this.__wrapped__);return(r.__actions__=Ei(this.__actions__)).push({func:e,args:arguments,thisArg:t}),r.__chain__=n,r}return e.apply(t,Rn([this.value()],arguments))})})),t}function as(){}var ss=Ni(zn),cs=Ni(Fn),ls=Ni(Pn);function fs(t){return _o(t)?Xn(Po(t)):function(t){return function(n){return we(n,t)}}(t)}var hs=Di(),ps=Di(!0);function vs(){return[]}function gs(){return!1}var ds,ys=Yi((function(t,n){return t+n}),0),_s=Zi("ceil"),ms=Yi((function(t,n){return t/n}),1),xs=Zi("floor"),ws=Yi((function(t,n){return t*n}),1),bs=Zi("round"),Ss=Yi((function(t,n){return t-n}),0);return Tr.after=function(t,n){if("function"!=typeof n)throw new Mt(o);return t=pa(t),function(){if(--t<1)return n.apply(this,arguments)}},Tr.ary=Eu,Tr.assign=_a,Tr.assignIn=ma,Tr.assignInWith=xa,Tr.assignWith=wa,Tr.at=ba,Tr.before=Mu,Tr.bind=Fu,Tr.bindAll=Ja,Tr.bindKey=ku,Tr.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return Wu(t)?t:[t]},Tr.chain=fu,Tr.chunk=function(t,n,r){n=(r?yo(t,n,r):n===i)?1:dr(pa(n),0);var o=null==t?0:t.length;if(!o||n<1)return[];for(var u=0,a=0,s=e(pn(o/n));uo?0:o+r),(e=e===i||e>o?o:pa(e))<0&&(e+=o),e=r>e?0:va(e);r>>0)?(t=ya(t))&&("string"==typeof n||null!=n&&!ia(n))&&!(n=ui(n))&&ir(t)?_i(fr(t),0,r):t.split(n,r):[]},Tr.spread=function(t,n){if("function"!=typeof t)throw new Mt(o);return n=null==n?0:dr(pa(n),0),Ve((function(r){var e=r[n],i=_i(r,0,n);return e&&Rn(i,e),An(t,this,i)}))},Tr.tail=function(t){var n=null==t?0:t.length;return n?ti(t,1,n):[]},Tr.take=function(t,n,r){return t&&t.length?ti(t,0,(n=r||n===i?1:pa(n))<0?0:n):[]},Tr.takeRight=function(t,n,r){var e=null==t?0:t.length;return e?ti(t,(n=e-(n=r||n===i?1:pa(n)))<0?0:n,e):[]},Tr.takeRightWhile=function(t,n){return t&&t.length?li(t,oo(n,3),!1,!0):[]},Tr.takeWhile=function(t,n){return t&&t.length?li(t,oo(n,3)):[]},Tr.tap=function(t,n){return n(t),t},Tr.throttle=function(t,n,r){var e=!0,i=!0;if("function"!=typeof t)throw new Mt(o);return Qu(r)&&(e="leading"in r?!!r.leading:e,i="trailing"in r?!!r.trailing:i),Cu(t,n,{leading:e,maxWait:n,trailing:i})},Tr.thru=hu,Tr.toArray=fa,Tr.toPairs=Ia,Tr.toPairsIn=Ta,Tr.toPath=function(t){return Wu(t)?zn(t,Po):aa(t)?[t]:Ei(jo(ya(t)))},Tr.toPlainObject=da,Tr.transform=function(t,n,r){var e=Wu(t),i=e||Vu(t)||sa(t);if(n=oo(n,4),null==r){var o=t&&t.constructor;r=i?e?new o:[]:Qu(t)&&$u(o)?Yr(Xt(t)):{}}return(i?En:_e)(t,(function(t,e,i){return n(r,t,e,i)})),r},Tr.unary=function(t){return Eu(t,1)},Tr.union=tu,Tr.unionBy=nu,Tr.unionWith=ru,Tr.uniq=function(t){return t&&t.length?ai(t):[]},Tr.uniqBy=function(t,n){return t&&t.length?ai(t,oo(n,2)):[]},Tr.uniqWith=function(t,n){return n="function"==typeof n?n:i,t&&t.length?ai(t,i,n):[]},Tr.unset=function(t,n){return null==t||si(t,n)},Tr.unzip=eu,Tr.unzipWith=iu,Tr.update=function(t,n,r){return null==t?t:ci(t,n,gi(r))},Tr.updateWith=function(t,n,r,e){return e="function"==typeof e?e:i,null==t?t:ci(t,n,gi(r),e)},Tr.values=Ya,Tr.valuesIn=function(t){return null==t?[]:Gn(t,Ba(t))},Tr.without=ou,Tr.words=$a,Tr.wrap=function(t,n){return Pu(gi(n),t)},Tr.xor=uu,Tr.xorBy=au,Tr.xorWith=su,Tr.zip=cu,Tr.zipObject=function(t,n){return pi(t||[],n||[],Qr)},Tr.zipObjectDeep=function(t,n){return pi(t||[],n||[],$e)},Tr.zipWith=lu,Tr.entries=Ia,Tr.entriesIn=Ta,Tr.extend=ma,Tr.extendWith=xa,us(Tr,Tr),Tr.add=ys,Tr.attempt=Ga,Tr.camelCase=Na,Tr.capitalize=Ua,Tr.ceil=_s,Tr.clamp=function(t,n,r){return r===i&&(r=n,n=i),r!==i&&(r=(r=ga(r))==r?r:0),n!==i&&(n=(n=ga(n))==n?n:0),oe(ga(t),n,r)},Tr.clone=function(t){return ue(t,4)},Tr.cloneDeep=function(t){return ue(t,5)},Tr.cloneDeepWith=function(t,n){return ue(t,5,n="function"==typeof n?n:i)},Tr.cloneWith=function(t,n){return ue(t,4,n="function"==typeof n?n:i)},Tr.conformsTo=function(t,n){return null==n||ae(t,n,Ca(n))},Tr.deburr=Da,Tr.defaultTo=function(t,n){return null==t||t!=t?n:t},Tr.divide=ms,Tr.endsWith=function(t,n,r){t=ya(t),n=ui(n);var e=t.length,o=r=r===i?e:oe(pa(r),0,e);return(r-=n.length)>=0&&t.slice(r,o)==n},Tr.eq=Yu,Tr.escape=function(t){return(t=ya(t))&&H.test(t)?t.replace(K,rr):t},Tr.escapeRegExp=function(t){return(t=ya(t))&&rt.test(t)?t.replace(nt,"\\$&"):t},Tr.every=function(t,n,r){var e=Wu(t)?Fn:he;return r&&yo(t,n,r)&&(n=i),e(t,oo(n,3))},Tr.find=gu,Tr.findIndex=Do,Tr.findKey=function(t,n){return Tn(t,oo(n,3),_e)},Tr.findLast=du,Tr.findLastIndex=Wo,Tr.findLastKey=function(t,n){return Tn(t,oo(n,3),me)},Tr.floor=xs,Tr.forEach=yu,Tr.forEachRight=_u,Tr.forIn=function(t,n){return null==t?t:de(t,oo(n,3),Ba)},Tr.forInRight=function(t,n){return null==t?t:ye(t,oo(n,3),Ba)},Tr.forOwn=function(t,n){return t&&_e(t,oo(n,3))},Tr.forOwnRight=function(t,n){return t&&me(t,oo(n,3))},Tr.get=La,Tr.gt=Nu,Tr.gte=Uu,Tr.has=function(t,n){return null!=t&&ho(t,n,Le)},Tr.hasIn=Ea,Tr.head=Zo,Tr.identity=rs,Tr.includes=function(t,n,r,e){t=Zu(t)?t:Ya(t),r=r&&!e?pa(r):0;var i=t.length;return r<0&&(r=dr(i+r,0)),ua(t)?r<=i&&t.indexOf(n,r)>-1:!!i&&Nn(t,n,r)>-1},Tr.indexOf=function(t,n,r){var e=null==t?0:t.length;if(!e)return-1;var i=null==r?0:pa(r);return i<0&&(i=dr(e+i,0)),Nn(t,n,i)},Tr.inRange=function(t,n,r){return n=ha(n),r===i?(r=n,n=0):r=ha(r),function(t,n,r){return t>=yr(n,r)&&t=-9007199254740991&&t<=f},Tr.isSet=oa,Tr.isString=ua,Tr.isSymbol=aa,Tr.isTypedArray=sa,Tr.isUndefined=function(t){return t===i},Tr.isWeakMap=function(t){return ta(t)&&fo(t)==C},Tr.isWeakSet=function(t){return ta(t)&&"[object WeakSet]"==Se(t)},Tr.join=function(t,n){return null==t?"":Zn.call(t,n)},Tr.kebabCase=Wa,Tr.last=qo,Tr.lastIndexOf=function(t,n,r){var e=null==t?0:t.length;if(!e)return-1;var o=e;return r!==i&&(o=(o=pa(r))<0?dr(e+o,0):yr(o,e-1)),n==n?function(t,n,r){for(var e=r+1;e--;)if(t[e]===n)return e;return e}(t,n,o):Yn(t,Dn,o,!0)},Tr.lowerCase=Xa,Tr.lowerFirst=Za,Tr.lt=ca,Tr.lte=la,Tr.max=function(t){return t&&t.length?pe(t,rs,Ae):i},Tr.maxBy=function(t,n){return t&&t.length?pe(t,oo(n,2),Ae):i},Tr.mean=function(t){return Wn(t,rs)},Tr.meanBy=function(t,n){return Wn(t,oo(n,2))},Tr.min=function(t){return t&&t.length?pe(t,rs,je):i},Tr.minBy=function(t,n){return t&&t.length?pe(t,oo(n,2),je):i},Tr.stubArray=vs,Tr.stubFalse=gs,Tr.stubObject=function(){return{}},Tr.stubString=function(){return""},Tr.stubTrue=function(){return!0},Tr.multiply=ws,Tr.nth=function(t,n){return t&&t.length?Ne(t,pa(n)):i},Tr.noConflict=function(){return hn._===this&&(hn._=Tt),this},Tr.noop=as,Tr.now=Lu,Tr.pad=function(t,n,r){t=ya(t);var e=(n=pa(n))?lr(t):0;if(!n||e>=n)return t;var i=(n-e)/2;return Ui(vn(i),r)+t+Ui(pn(i),r)},Tr.padEnd=function(t,n,r){t=ya(t);var e=(n=pa(n))?lr(t):0;return n&&en){var e=t;t=n,n=e}if(r||t%1||n%1){var o=xr();return yr(t+o*(n-t+sn("1e-"+((o+"").length-1))),n)}return Ze(t,n)},Tr.reduce=function(t,n,r){var e=Wu(t)?On:Kn,i=arguments.length<3;return e(t,oo(n,4),r,i,le)},Tr.reduceRight=function(t,n,r){var e=Wu(t)?jn:Kn,i=arguments.length<3;return e(t,oo(n,4),r,i,fe)},Tr.repeat=function(t,n,r){return n=(r?yo(t,n,r):n===i)?1:pa(n),Ke(ya(t),n)},Tr.replace=function(){var t=arguments,n=ya(t[0]);return t.length<3?n:n.replace(t[1],t[2])},Tr.result=function(t,n,r){var e=-1,o=(n=di(n,t)).length;for(o||(o=1,t=i);++ef)return[];var r=p,e=yr(t,p);n=oo(n),t-=p;for(var i=Hn(e,n);++r=u)return t;var s=r-lr(e);if(s<1)return e;var c=a?_i(a,0,s).join(""):t.slice(0,s);if(o===i)return c+e;if(a&&(s+=c.length-s),ia(o)){if(t.slice(s).search(o)){var l,f=c;for(o.global||(o=Lt(o.source,ya(ht.exec(o))+"g")),o.lastIndex=0;l=o.exec(f);)var h=l.index;c=c.slice(0,h===i?s:h)}}else if(t.indexOf(ui(o),s)!=s){var p=c.lastIndexOf(o);p>-1&&(c=c.slice(0,p))}return c+e},Tr.unescape=function(t){return(t=ya(t))&&V.test(t)?t.replace(Z,pr):t},Tr.uniqueId=function(t){var n=++Ot;return ya(t)+n},Tr.upperCase=Ha,Tr.upperFirst=qa,Tr.each=yu,Tr.eachRight=_u,Tr.first=Zo,us(Tr,(ds={},_e(Tr,(function(t,n){Rt.call(Tr.prototype,n)||(ds[n]=t)})),ds),{chain:!1}),Tr.VERSION="4.17.21",En(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){Tr[t].placeholder=Tr})),En(["drop","take"],(function(t,n){Dr.prototype[t]=function(r){r=r===i?1:dr(pa(r),0);var e=this.__filtered__&&!n?new Dr(this):this.clone();return e.__filtered__?e.__takeCount__=yr(r,e.__takeCount__):e.__views__.push({size:yr(r,p),type:t+(e.__dir__<0?"Right":"")}),e},Dr.prototype[t+"Right"]=function(n){return this.reverse()[t](n).reverse()}})),En(["filter","map","takeWhile"],(function(t,n){var r=n+1,e=1==r||3==r;Dr.prototype[t]=function(t){var n=this.clone();return n.__iteratees__.push({iteratee:oo(t,3),type:r}),n.__filtered__=n.__filtered__||e,n}})),En(["head","last"],(function(t,n){var r="take"+(n?"Right":"");Dr.prototype[t]=function(){return this[r](1).value()[0]}})),En(["initial","tail"],(function(t,n){var r="drop"+(n?"":"Right");Dr.prototype[t]=function(){return this.__filtered__?new Dr(this):this[r](1)}})),Dr.prototype.compact=function(){return this.filter(rs)},Dr.prototype.find=function(t){return this.filter(t).head()},Dr.prototype.findLast=function(t){return this.reverse().find(t)},Dr.prototype.invokeMap=Ve((function(t,n){return"function"==typeof t?new Dr(this):this.map((function(r){return Fe(r,t,n)}))})),Dr.prototype.reject=function(t){return this.filter(Ou(oo(t)))},Dr.prototype.slice=function(t,n){t=pa(t);var r=this;return r.__filtered__&&(t>0||n<0)?new Dr(r):(t<0?r=r.takeRight(-t):t&&(r=r.drop(t)),n!==i&&(r=(n=pa(n))<0?r.dropRight(-n):r.take(n-t)),r)},Dr.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},Dr.prototype.toArray=function(){return this.take(p)},_e(Dr.prototype,(function(t,n){var r=/^(?:filter|find|map|reject)|While$/.test(n),e=/^(?:head|last)$/.test(n),o=Tr[e?"take"+("last"==n?"Right":""):n],u=e||/^find/.test(n);o&&(Tr.prototype[n]=function(){var n=this.__wrapped__,a=e?[1]:arguments,s=n instanceof Dr,c=a[0],l=s||Wu(n),f=function(t){var n=o.apply(Tr,Rn([t],a));return e&&h?n[0]:n};l&&r&&"function"==typeof c&&1!=c.length&&(s=l=!1);var h=this.__chain__,p=!!this.__actions__.length,v=u&&!h,g=s&&!p;if(!u&&l){n=g?n:new Dr(this);var d=t.apply(n,a);return d.__actions__.push({func:hu,args:[f],thisArg:i}),new Ur(d,h)}return v&&g?t.apply(this,a):(d=this.thru(f),v?e?d.value()[0]:d.value():d)})})),En(["pop","push","shift","sort","splice","unshift"],(function(t){var n=Ft[t],r=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",e=/^(?:pop|shift)$/.test(t);Tr.prototype[t]=function(){var t=arguments;if(e&&!this.__chain__){var i=this.value();return n.apply(Wu(i)?i:[],t)}return this[r]((function(r){return n.apply(Wu(r)?r:[],t)}))}})),_e(Dr.prototype,(function(t,n){var r=Tr[n];if(r){var e=r.name+"";Rt.call(kr,e)||(kr[e]=[]),kr[e].push({name:n,func:r})}})),kr[Ii(i,2).name]=[{name:"wrapper",func:i}],Dr.prototype.clone=function(){var t=new Dr(this.__wrapped__);return t.__actions__=Ei(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=Ei(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=Ei(this.__views__),t},Dr.prototype.reverse=function(){if(this.__filtered__){var t=new Dr(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},Dr.prototype.value=function(){var t=this.__wrapped__.value(),n=this.__dir__,r=Wu(t),e=n<0,i=r?t.length:0,o=function(t,n,r){for(var e=-1,i=r.length;++e=this.__values__.length;return{done:t,value:t?i:this.__values__[this.__index__++]}},Tr.prototype.plant=function(t){for(var n,r=this;r instanceof Nr;){var e=To(r);e.__index__=0,e.__values__=i,n?o.__wrapped__=e:n=e;var o=e;r=r.__wrapped__}return o.__wrapped__=t,n},Tr.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof Dr){var n=t;return this.__actions__.length&&(n=new Dr(this)),(n=n.reverse()).__actions__.push({func:hu,args:[Qo],thisArg:i}),new Ur(n,this.__chain__)}return this.thru(Qo)},Tr.prototype.toJSON=Tr.prototype.valueOf=Tr.prototype.value=function(){return fi(this.__wrapped__,this.__actions__)},Tr.prototype.first=Tr.prototype.head,qt&&(Tr.prototype[qt]=function(){return this}),Tr}();hn._=vr,(e=function(){return vr}.call(n,r,n,t))===i||(t.exports=e)}.call(this)},670:(t,n,r)=>{"use strict";var e=r(289),i=r(579),o=r(586),u=r(543);function a(t){void 0!==t&&this.loadFeatureCollection(t)}function s(t,n){var r=n.geometry.coordinates[0];if(i(t,r)){for(var e=1;e=r||!s(e,t)||(u++,0))}))}},a.prototype.search=function(t,n,r){return void 0===r?this.searchForOnePolygon(t,n):this.searchForMultiplePolygons(t,n,r)},a.prototype.loadFeatureCollection=function(t){var n=[],r=[],i=0;function u(t){r.push(t);var e=o.getBoundingBox(t.geometry.coordinates[0]);e.polyId=i++,n.push(e)}t.features.forEach((function(t){if(t.geometry&&void 0!==t.geometry.coordinates[0]&&t.geometry.coordinates[0].length>0)switch(t.geometry.type){case"Polygon":u(t);break;case"MultiPolygon":for(var n=t.geometry.coordinates,r=0;r{"use strict";t.exports={getBoundingBox:function(t){for(var n=t[0],r={minX:n[0],minY:n[1],maxX:n[0],maxY:n[1]},e=1;er.maxX&&(r.maxX=o);var u=i[1];ur.maxY&&(r.maxY=u)}return r}}},579:t=>{t.exports=function(t,n){for(var r=t[0],e=t[1],i=!1,o=0,u=n.length-1;oe!=l>e&&r<(c-a)*(e-s)/(l-s)+a&&(i=!i)}return i}},314:function(t){t.exports=function(){"use strict";function t(r,e,i,o,u){for(;o>i;){if(o-i>600){var a=o-i+1,s=e-i+1,c=Math.log(a),l=.5*Math.exp(2*c/3),f=.5*Math.sqrt(c*l*(a-l)/a)*(s-a/2<0?-1:1);t(r,e,Math.max(i,Math.floor(e-s*l/a+f)),Math.min(o,Math.floor(e+(a-s)*l/a+f)),u)}var h=r[e],p=i,v=o;for(n(r,i,e),u(r[o],h)>0&&n(r,i,o);p0;)v--}0===u(r[i],h)?n(r,i,v):n(r,++v,o),v<=e&&(i=v+1),e<=v&&(o=v-1)}}function n(t,n,r){var e=t[n];t[n]=t[r],t[r]=e}function r(t,n){return tn?1:0}return function(n,e,i,o,u){t(n,e,i||0,o||n.length-1,u||r)}}()},289:(t,n,r)=>{"use strict";t.exports=i,t.exports.default=i;var e=r(314);function i(t,n){if(!(this instanceof i))return new i(t,n);this._maxEntries=Math.max(4,t||9),this._minEntries=Math.max(2,Math.ceil(.4*this._maxEntries)),n&&this._initFormat(n),this.clear()}function o(t,n,r){if(!r)return n.indexOf(t);for(var e=0;e=t.minX&&n.maxY>=t.minY}function g(t){return{children:t,height:1,leaf:!0,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0}}function d(t,n,r,i,o){for(var u,a=[n,r];a.length;)(r=a.pop())-(n=a.pop())<=i||(u=n+Math.ceil((r-n)/i/2)*i,e(t,u,n,r,o),a.push(n,u,u,r))}i.prototype={all:function(){return this._all(this.data,[])},search:function(t){var n=this.data,r=[],e=this.toBBox;if(!v(t,n))return r;for(var i,o,u,a,s=[];n;){for(i=0,o=n.children.length;i=0&&o[n].children.length>this._maxEntries;)this._split(o,n),n--;this._adjustParentBBoxes(i,o,n)},_split:function(t,n){var r=t[n],e=r.children.length,i=this._minEntries;this._chooseSplitAxis(r,i,e);var o=this._chooseSplitIndex(r,i,e),a=g(r.children.splice(o,r.children.length-o));a.height=r.height,a.leaf=r.leaf,u(r,this.toBBox),u(a,this.toBBox),n?t[n-1].children.push(a):this._splitRoot(r,a)},_splitRoot:function(t,n){this.data=g([t,n]),this.data.height=t.height+1,this.data.leaf=!1,u(this.data,this.toBBox)},_chooseSplitIndex:function(t,n,r){var e,i,o,u,s,c,l,h,p,v,g,d,y,_;for(c=l=1/0,e=n;e<=r-n;e++)p=i=a(t,0,e,this.toBBox),v=o=a(t,e,r,this.toBBox),void 0,void 0,void 0,void 0,g=Math.max(p.minX,v.minX),d=Math.max(p.minY,v.minY),y=Math.min(p.maxX,v.maxX),_=Math.min(p.maxY,v.maxY),u=Math.max(0,y-g)*Math.max(0,_-d),s=f(i)+f(o),u=n;i--)o=t.children[i],s(l,t.leaf?u(o):o),f+=h(l);return f},_adjustParentBBoxes:function(t,n,r){for(var e=r;e>=0;e--)s(n[e],t)},_condense:function(t){for(var n,r=t.length-1;r>=0;r--)0===t[r].children.length?r>0?(n=t[r-1].children).splice(n.indexOf(t[r]),1):this.clear():u(t[r],this.toBBox)},_initFormat:function(t){var n=["return a"," - b",";"];this.compareMinX=new Function("a","b",n.join(t[0])),this.compareMinY=new Function("a","b",n.join(t[1])),this.toBBox=new Function("a","return {minX: a"+t[0]+", minY: a"+t[1]+", maxX: a"+t[2]+", maxY: a"+t[3]+"};")}}},167:n=>{"use strict";n.exports=t}},r={};function e(t){var i=r[t];if(void 0!==i)return i.exports;var o=r[t]={id:t,loaded:!1,exports:{}};return n[t].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}e.n=t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},e.d=(t,n)=>{for(var r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},e.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),e.o=(t,n)=>Object.prototype.hasOwnProperty.call(t,n),e.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},e.nmd=t=>(t.paths=[],t.children||(t.children=[]),t);var i={};return(()=>{"use strict";e.r(i),e.d(i,{Glify:()=>M,default:()=>k,glify:()=>F});var t=e(167);class n extends t.Layer{constructor(t,n){super(),this._userDrawFunc=t,this._frame=null,this._redrawCallbacks=[],this._pane=n,this.options={}}drawing(t){return this._userDrawFunc=t,this}params(n){return t.Util.setOptions(this,n),this}redraw(n){return"function"==typeof n&&this._redrawCallbacks.push(n),null===this._frame&&(this._frame=t.Util.requestAnimFrame(this._redraw,this)),this}isAnimated(){return Boolean(this._map.options.zoomAnimation&&t.Browser.any3d)}onAdd(n){var r;this._map=n;const e=this.canvas=null!==(r=this.canvas)&&void 0!==r?r:document.createElement("canvas"),i=n.getSize(),o=this.isAnimated();e.width=i.x,e.height=i.y,e.className="leaflet-zoom-"+(o?"animated":"hide");const u=n.getPane(this._pane);if(!u)throw new Error("unable to find pane");return u.appendChild(this.canvas),n.on("moveend",this._reset,this),n.on("resize",this._resize,this),o&&n.on("zoomanim",t.Layer?this._animateZoom:this._animateZoomNoLayer,this),this._reset(),this}onRemove(n){if(this.canvas){const t=n.getPane(this._pane);if(!t)throw new Error("unable to find pane");t.removeChild(this.canvas)}return n.off("moveend",this._reset,this),n.off("resize",this._resize,this),this.isAnimated()&&n.off("zoomanim",t.Layer?this._animateZoom:this._animateZoomNoLayer,this),this}addTo(t){return t.addLayer(this),this}get map(){return this._map}set map(t){this._map=t}_resize(t){this.canvas&&(this.canvas.width=t.newSize.x,this.canvas.height=t.newSize.y)}_reset(){if(this.canvas){const n=this._map.containerPointToLayerPoint([0,0]);t.DomUtil.setPosition(this.canvas,n)}this._redraw()}_redraw(){const{_map:n,canvas:r}=this,e=n.getSize(),i=n.getBounds(),o=180*e.x/(20037508.34*(i.getEast()-i.getWest())),u=n.getZoom(),a=new t.LatLng(i.getNorth(),i.getWest()),s=this._unclampedProject(a,0);for(r&&this._userDrawFunc({bounds:i,canvas:r,offset:s,scale:Math.pow(2,u),size:e,zoomScale:o,zoom:u});this._redrawCallbacks.length>0;){const t=this._redrawCallbacks.shift();t&&t(this)}this._frame=null}_animateZoom(n){const{_map:r,canvas:e}=this,i=r.getZoomScale(n.zoom,r.getZoom()),o=this._unclampedLatLngBoundsToNewLayerBounds(r.getBounds(),n.zoom,n.center).min;e&&o&&t.DomUtil.setTransform(e,o,i)}_animateZoomNoLayer(n){const{_map:r,canvas:e}=this;if(e){const i=r.getZoomScale(n.zoom,r.getZoom()),o=r._getCenterOffset(n.center)._multiplyBy(-i).subtract(r._getMapPanePos());t.DomUtil.setTransform(e,o,i)}}_unclampedProject(n,r){var e;const{crs:i}=this._map.options,{R:o}=i.projection,u=Math.PI/180,a=n.lat,s=Math.sin(a*u),c=new t.Point(o*n.lng*u,o*Math.log((1+s)/(1-s))/2),l=null!==(e=null==i?void 0:i.scale(r))&&void 0!==e?e:0;return i.transformation._transform(c,l)}_unclampedLatLngBoundsToNewLayerBounds(n,r,e){const i=this._map._getNewPixelOrigin(e,r);return new t.Bounds([this._unclampedProject(n.getSouthWest(),r).subtract(i),this._unclampedProject(n.getNorthWest(),r).subtract(i),this._unclampedProject(n.getSouthEast(),r).subtract(i),this._unclampedProject(n.getNorthEast(),r).subtract(i)])}}function r(t){return`"${t}" not properly defined`}class o{constructor(){this.array=new Float32Array(16)}setSize(t,n){return this.array.set([2/t,0,0,0,0,-2/n,0,0,0,0,0,0,-1,1,0,1]),this}translateTo(t,n){const{array:r}=this;return r[12]=r[0]*t-1,r[13]=r[5]*n+1,this}scaleTo(t){const{array:n}=this;return n[0]*=t,n[5]*=t,this}}const u="overlayPane",a={pane:u};class s{get data(){if(!this.settings.data)throw new Error(r("settings.data"));return this.settings.data}get pane(){var t;return null!==(t=this.settings.pane)&&void 0!==t?t:u}get className(){var t;return null!==(t=this.settings.className)&&void 0!==t?t:""}get map(){if(!this.settings.map)throw new Error(r("settings.map"));return this.settings.map}get sensitivity(){if("number"!=typeof this.settings.sensitivity)throw new Error(r("settings.sensitivity"));return this.settings.sensitivity}get sensitivityHover(){if("number"!=typeof this.settings.sensitivityHover)throw new Error(r("settings.sensitivityHover"));return this.settings.sensitivityHover}get hoverWait(){var t;return null!==(t=this.settings.hoverWait)&&void 0!==t?t:250}get longitudeKey(){if("number"!=typeof this.settings.longitudeKey)throw new Error(r("settings.longitudeKey"));return this.settings.longitudeKey}get latitudeKey(){if("number"!=typeof this.settings.latitudeKey)throw new Error(r("settings.latitudeKey"));return this.settings.latitudeKey}get opacity(){if("number"!=typeof this.settings.opacity)throw new Error(r("settings.opacity"));return this.settings.opacity}get color(){var t;return null!==(t=this.settings.color)&&void 0!==t?t:null}constructor(t){var e,i;this.bytes=0,this.buffers={},this.attributeLocations={},this.uniformLocations={},this.settings={...a,...t},this.mapMatrix=new o,this.active=!0,this.vertexShader=null,this.fragmentShader=null,this.program=null,this.matrix=null,this.vertices=null,this.vertexLines=null;try{this.mapCenterPixels=this.map.project(this.map.getCenter(),0)}catch(t){this.mapCenterPixels={x:-0,y:-0}}const u=Boolean(t.preserveDrawingBuffer),s=this.layer=new n((t=>this.drawOnCanvas(t)),this.pane).addTo(this.map);if(!s.canvas)throw new Error(r("layer.canvas"));const c=this.canvas=s.canvas;c.width=c.clientWidth,c.height=c.clientHeight,c.style.position="absolute",this.className&&(c.className+=" "+this.className),this.gl=null!==(i=null!==(e=c.getContext("webgl2",{preserveDrawingBuffer:u}))&&void 0!==e?e:c.getContext("webgl",{preserveDrawingBuffer:u}))&&void 0!==i?i:c.getContext("experimental-webgl",{preserveDrawingBuffer:u})}attachShaderVariables(t){if(0===this.getShaderVariableCount())return this;const{gl:n,settings:r}=this,{shaderVariables:e}=r;let i=0;for(const r in e){if(!e.hasOwnProperty(r))continue;const o=e[r],u=this.getAttributeLocation(r);if(u<0)throw new Error("shader variable "+r+" not found");n.vertexAttribPointer(u,o.size,n[o.type],!!o.normalize,this.bytes*t,i*t),i+=o.size,n.enableVertexAttribArray(u)}return this}getShaderVariableCount(){var t;return Object.keys(null!==(t=this.settings.shaderVariables)&&void 0!==t?t:{}).length}setData(t){return this.settings={...this.settings,data:t},this.render()}setup(){const t=this.settings;return t.click&&t.setupClick&&t.setupClick(this.map),t.hover&&t.setupHover&&t.setupHover(this.map,this.hoverWait),this.setupVertexShader().setupFragmentShader().setupProgram()}setupVertexShader(){const{gl:t,settings:n}=this,e="function"==typeof n.vertexShaderSource?n.vertexShaderSource():n.vertexShaderSource,i=t.createShader(t.VERTEX_SHADER);if(!i)throw new Error("Not able to create vertex");if(!e)throw new Error(r("settings.vertexShaderSource"));return t.shaderSource(i,e),t.compileShader(i),this.vertexShader=i,this}setupFragmentShader(){const t=this.gl,n=this.settings,e="function"==typeof n.fragmentShaderSource?n.fragmentShaderSource():n.fragmentShaderSource,i=t.createShader(t.FRAGMENT_SHADER);if(!i)throw new Error("Not able to create fragment");if(!e)throw new Error(r("settings.fragmentShaderSource"));return t.shaderSource(i,e),t.compileShader(i),this.fragmentShader=i,this}setupProgram(){const{gl:t,vertexShader:n,fragmentShader:e}=this,i=t.createProgram();if(!i)throw new Error("Not able to create program");if(!n)throw new Error(r("this.vertexShader"));if(!e)throw new Error(r("this.fragmentShader"));return t.attachShader(i,n),t.attachShader(i,e),t.linkProgram(i),t.useProgram(i),t.blendFuncSeparate(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA,t.ONE,t.ONE_MINUS_SRC_ALPHA),t.enable(t.BLEND),this.program=i,this}addTo(t){return this.layer.addTo(null!=t?t:this.map),this.active=!0,this.render()}remove(t){if(void 0===t)this.removeInstance(),this.map.removeLayer(this.layer),this.active=!1;else{const n=this.settings.data.features||this.settings.data;"number"==typeof(t=t instanceof Array?t:[t])&&(t=[t]),t.sort(((t,n)=>t-n)).reverse().forEach((t=>{n.splice(t,1)})),this.render()}return this}insert(t,n){const r=Array.isArray(t)?t:[t],e=this.settings.data.features||this.settings.data;for(let t=0;t1?(c=i,l=o):(c=r+f*u,l=e+f*a);const h=t-c,p=n-l;return Math.sqrt(h*h+p*p)}function v(t,n,r){const e=r.latLngToLayerPoint(t),i=r.latLngToLayerPoint(n);return o=e.x-i.x,u=e.y-i.y,Math.sqrt(o*o+u*u);var o,u}const g={data:{type:"FeatureCollection",features:[]},color:c,className:"",opacity:.5,weight:2,sensitivity:.1,sensitivityHover:.03,shaderVariables:{vertex:{type:"FLOAT",start:0,size:2},color:{type:"FLOAT",start:2,size:4}}};class d extends s{get weight(){if(!this.settings.weight)throw new Error("settings.weight not correctly defined");return this.settings.weight}constructor(t){if(super(t),this.scale=1/0,this.bytes=6,this.allVertices=[],this.allVerticesTyped=new Float32Array(0),this.vertices=[],this.aPointSize=-1,this.hoveringFeatures=[],this.settings={...d.defaults,...t},!t.data)throw new Error('"data" is missing');this.active=!0,this.setup().render()}render(){this.resetVertices();const{canvas:t,gl:n,layer:r,mapMatrix:e}=this,i=this.getBuffer("vertex");n.bindBuffer(n.ARRAY_BUFFER,i);const o=this.allVerticesTyped.BYTES_PER_ELEMENT;n.bufferData(n.ARRAY_BUFFER,this.allVerticesTyped,n.STATIC_DRAW);const u=this.getAttributeLocation("vertex");return n.vertexAttribPointer(u,2,n.FLOAT,!1,o*this.bytes,0),n.enableVertexAttribArray(u),this.matrix=this.getUniformLocation("matrix"),this.aPointSize=this.getAttributeLocation("pointSize"),e.setSize(t.width,t.height),n.viewport(0,0,t.width,t.height),n.uniformMatrix4fv(this.matrix,!1,e.array),this.attachShaderVariables(o),r.redraw(),this}resetVertices(){const{map:t,opacity:n,color:r,weight:e,latitudeKey:i,longitudeKey:o,data:u,bytes:a,settings:s,mapCenterPixels:c}=this,{eachVertex:f}=s,{features:h}=u,p=h.length;let v,g,d=null,y=null,_=0;"function"==typeof r&&(d=r),"function"==typeof e&&(y=e);const m=t.project.bind(t),x=[];for(;_t.layer._leaflet_id===this.layer._leaflet_id));return-1!==t&&k.linesInstances.splice(t,1),this}drawOnCanvas(t){if(!this.gl)return this;const{gl:n,data:r,canvas:e,mapMatrix:i,matrix:o,allVertices:u,vertices:a,weight:s,aPointSize:c,bytes:l,mapCenterPixels:f}=this,{scale:h,offset:p,zoom:v}=t;this.scale=h;const g=Math.max(v-4,4);if(n.clear(n.COLOR_BUFFER_BIT),n.viewport(0,0,e.width,e.height),n.vertexAttrib1f(c,g),i.setSize(e.width,e.height).scaleTo(h),v>18)i.translateTo(-p.x+f.x,-p.y+f.y),n.uniformMatrix4fv(o,!1,i.array),n.drawArrays(n.LINES,0,u.length/l);else if("number"==typeof s)for(let t=-s;t<=s;t+=.5)for(let r=-s;r<=s;r+=.5)i.translateTo(-p.x+f.x+r/h,-p.y+f.y+t/h),n.uniformMatrix4fv(o,!1,i.array),n.drawArrays(n.LINES,0,u.length/l);else if("function"==typeof s){let t=0;const{features:e}=r;for(let r=0;r{const{latitudeKey:o,longitudeKey:u,sensitivity:a,weight:s,scale:c,active:l}=r;function f(n,s,l,f){p(t.latlng.lng,t.latlng.lat,s[u],s[o],n[u],n[o])<=a+f/c&&(e=l,i=r)}l&&r.map===n&&r.data.features.forEach(((t,n)=>{const r="function"==typeof s?s(n,t):s,{coordinates:e,type:i}=t.geometry;if("LineString"===i)for(let n=1;n0){const i=e[n-1];f(i[i.length-1],e[n][o],t,r)}else o>0&&f(e[n][o],e[n][o-1],t,r)}}))})),i&&e){const n=i.click(t,e);return void 0!==n?n:void 0}}static tryHover(n,r,e){const i=[];return e.forEach((e=>{const{sensitivityHover:o,latitudeKey:u,longitudeKey:a,data:s,hoveringFeatures:c,weight:l,scale:f}=e;function h(t,r,e,i){return p(n.latlng.lng,n.latlng.lat,r[a],r[u],t[a],t[u])<=o+i/f&&(g.includes(e)||g.push(e),!v.includes(e))}if(!e.active)return;if(r!==e.map)return;const v=c,g=[];e.hoveringFeatures=g;const d=(0,t.geoJSON)(s.features).getBounds();(function(t,n){const r=n.getNorthEast(),e=n.getSouthWest();return r.lat>t.lat&&t.lat>e.lat&&r.lng>t.lng&&t.lng>e.lng})(n.latlng,d)&&s.features.forEach(((t,r)=>{const o="function"==typeof l?l(r,t):l,{coordinates:u,type:a}=t.geometry;let s=!1;if("LineString"===a)for(let n=1;n0){const r=u[n-1];if(s=h(r[r.length-1],u[n][e],t,o),s)break}else if(e>0&&(s=h(u[n][e],u[n][e-1],t,o),s))break}if(s){const r=e.hover(n,t);void 0!==r&&i.push(r)}}));for(let t=0;tt.layer._leaflet_id===this.layer._leaflet_id));return-1!==t&&k.pointsInstances.splice(t,1),this}pointSize(t){const{map:n,size:r}=this,e="function"==typeof r?r(t,null):r,i=n.getZoom();return null===e?Math.max(i-4,1):e}drawOnCanvas(t){if(!this.gl)return this;const{gl:n,canvas:r,mapMatrix:e,matrix:i,map:o,allLatLngLookup:u,mapCenterPixels:a}=this,{offset:s}=t,c=o.getZoom(),l=Math.pow(2,c);return e.setSize(r.width,r.height).scaleTo(l).translateTo(-s.x+a.x,-s.y+a.y),n.clear(n.COLOR_BUFFER_BIT),n.viewport(0,0,r.width,r.height),n.uniformMatrix4fv(i,!1,e.array),n.drawArrays(n.POINTS,0,u.length),this}lookup(t){const n=t.lat+.03,r=t.lng+.03,e=[];let i,o,u,a,s,c=t.lat-.03;for(;c<=n;c+=.01)for(i=t.lng-.03;i<=r;i+=.01)if(s=c.toFixed(2)+"x"+i.toFixed(2),a=this.latLngLookup[s],a)for(o=0,u=a.length;o0?e:this.allLatLngLookup,l)}static closest(t,n,r){return n.length<1?null:n.reduce(((n,e)=>v(t,n.latLng,r){a=r.settings,r.active&&r.map===n&&(u=r.lookup(t.latlng),null!==u&&(i[u.key]=r,e.push(u)))})),e.length<1)return;if(!a)return;const s=this.closest(t.latlng,e,n);if(!s)return;const c=i[s.key];if(!c)return;const{sensitivity:l}=c,f=s.latLng;return h(n.latLngToLayerPoint(f),t.layerPoint,s.chosenSize*(null!=l?l:1))?(o=c.click(t,s.feature||s.latLng),void 0===o||o):void 0}static tryHover(t,n,r){const e=[];return r.forEach((r=>{const{sensitivityHover:i,hoveringFeatures:o}=r;if(!r.active)return;if(r.map!==n)return;const u=o,a=[];r.hoveringFeatures=a;const s=r.lookup(t.latlng);if(s){if(h(n.latLngToLayerPoint(s.latLng),t.layerPoint,s.chosenSize*i*30)){let n=s.feature||s.latLng;a.includes(n)||a.push(n);const i=r.hover(t,n);void 0!==i&&e.push(i)}for(let n=0;nt.layer._leaflet_id===this.layer._leaflet_id));return-1!==t&&k.shapesInstances.splice(t,1),this}drawOnCanvas(t){if(!this.gl)return this;const{scale:n,offset:r,canvas:e}=t,{mapMatrix:i,gl:o,vertices:u,settings:a,vertexLines:s,border:c,mapCenterPixels:l}=this;if(i.setSize(e.width,e.height).scaleTo(n).translateTo(-r.x+l.x,-r.y+l.y),o.clear(o.COLOR_BUFFER_BIT),o.viewport(0,0,e.width,e.height),o.uniformMatrix4fv(this.matrix,!1,i.array),c){const t=this.getBuffer("vertexLines"),n=new Float32Array(s),r=n.BYTES_PER_ELEMENT,i=this.getAttributeLocation("vertex");o.bindBuffer(o.ARRAY_BUFFER,null),o.bindBuffer(o.ARRAY_BUFFER,t),o.bufferData(o.ARRAY_BUFFER,n,o.STATIC_DRAW),null!==this.settings.shaderVariables&&this.attachShaderVariables(r),o.vertexAttribPointer(i,3,o.FLOAT,!1,r*this.bytes,0),o.enableVertexAttribArray(i),o.enable(o.DEPTH_TEST),o.viewport(0,0,e.width,e.height),o.drawArrays(o.LINES,0,s.length/this.bytes);const c=this.getBuffer("vertex"),l=new Float32Array(u);o.bindBuffer(o.ARRAY_BUFFER,null),o.bindBuffer(o.ARRAY_BUFFER,c),o.bufferData(o.ARRAY_BUFFER,l,o.STATIC_DRAW),null!==a.shaderVariables&&this.attachShaderVariables(r),o.vertexAttribPointer(i,2,o.FLOAT,!1,r*this.bytes,0),o.enableVertexAttribArray(i),o.enable(o.DEPTH_TEST),o.viewport(0,0,e.width,e.height)}return o.drawArrays(o.TRIANGLES,0,u.length/this.bytes),this}static tryClick(t,n,r){let e=null,i=null;if(r.forEach((function(r){if(!r.active)return;if(r.map!==n)return;if(!r.polygonLookup)return;const o=r.polygonLookup.search(t.latlng.lng,t.latlng.lat);o&&(i=r,e=o)})),i&&e){const n=i.click(t,e);return void 0!==n?n:void 0}}static tryHover(t,n,r){const e=[];return r.forEach((function(r){const{hoveringFeatures:i}=r;if(!r.active)return;if(r.map!==n)return;if(!r.polygonLookup)return;const o=i,u=[];r.hoveringFeatures=u;const a=r.polygonLookup.search(t.latlng.lng,t.latlng.lat);if(a){u.includes(a)||u.push(a);const n=r.hover(t,a);void 0!==n&&e.push(n)}for(let n=0;n border) {\r\n t = 1.0;\r\n } else if (dist > 0.0) {\r\n t = dist / border;\r\n }\r\n\r\n //works for overlapping circles if blending is enabled\r\n gl_FragColor = mix(color0, color1, t);\r\n}\r\n",point:"precision mediump float;\r\nvarying vec4 _color;\r\n\r\nvoid main() {\r\n float border = 0.1;\r\n float radius = 0.5;\r\n vec2 center = vec2(0.5, 0.5);\r\n\r\n vec4 pointColor = vec4(\r\n _color[0],\r\n _color[1],\r\n _color[2],\r\n _color[3]\r\n );\r\n\r\n vec2 m = gl_PointCoord.xy - center;\r\n float dist1 = radius - sqrt(m.x * m.x + m.y * m.y);\r\n\r\n float t1 = 0.0;\r\n if (dist1 > border) {\r\n t1 = 1.0;\r\n } else if (dist1 > 0.0) {\r\n t1 = dist1 / border;\r\n }\r\n\r\n //works for overlapping circles if blending is enabled\r\n //gl_FragColor = mix(color0, color1, t);\r\n\r\n //border\r\n float outerBorder = 0.05;\r\n float innerBorder = 0.8;\r\n vec4 borderColor = vec4(0, 0, 0, 0.4);\r\n vec2 uv = gl_PointCoord.xy;\r\n vec4 clearColor = vec4(0, 0, 0, 0);\r\n\r\n // Offset uv with the center of the circle.\r\n uv -= center;\r\n\r\n float dist2 = sqrt(dot(uv, uv));\r\n\r\n float t2 = 1.0 + smoothstep(radius, radius + outerBorder, dist2)\r\n - smoothstep(radius - innerBorder, radius, dist2);\r\n\r\n gl_FragColor = mix(mix(borderColor, clearColor, t2), pointColor, t1);\r\n}\r\n",puck:"precision mediump float;\r\nvarying vec4 _color;\r\n\r\nvoid main() {\r\n vec2 center = vec2(0.5);\r\n vec2 uv = gl_PointCoord.xy - center;\r\n float smoothing = 0.005;\r\n vec4 _color1 = vec4(_color[0], _color[1], _color[2], _color[3]);\r\n float radius1 = 0.3;\r\n vec4 _color2 = vec4(_color[0], _color[1], _color[2], _color[3]);\r\n float radius2 = 0.5;\r\n float dist = length(uv);\r\n\r\n //SMOOTH\r\n float gamma = 2.2;\r\n color1.rgb = pow(_color1.rgb, vec3(gamma));\r\n color2.rgb = pow(_color2.rgb, vec3(gamma));\r\n\r\n vec4 puck = mix(\r\n mix(\r\n _color1,\r\n _color2,\r\n smoothstep(\r\n radius1 - smoothing,\r\n radius1 + smoothing,\r\n dist\r\n )\r\n ),\r\n vec4(0,0,0,0),\r\n smoothstep(\r\n radius2 - smoothing,\r\n radius2 + smoothing,\r\n dist\r\n )\r\n );\r\n\r\n //Gamma correction (prevents color fringes)\r\n puck.rgb = pow(puck.rgb, vec3(1.0 / gamma));\r\n gl_FragColor = puck;\r\n}\r\n",simpleCircle:"precision mediump float;\r\nvarying vec4 _color;\r\n\r\nvoid main() {\r\n vec4 color1 = vec4(_color[0], _color[1], _color[2], _color[3]);\r\n\r\n //simple circles\r\n float d = distance (gl_PointCoord, vec2(0.5, 0.5));\r\n if (d < 0.5 ){\r\n gl_FragColor = color1;\r\n } else {\r\n discard;\r\n }\r\n}\r\n",square:"precision mediump float;\r\nvarying vec4 _color;\r\n\r\nvoid main() {\r\n //squares\r\n gl_FragColor = vec4(_color[0], _color[1], _color[2], _color[3]);\r\n}\r\n",polygon:"precision mediump float;\r\nvarying vec4 _color;\r\n\r\nvoid main() {\r\n gl_FragColor = vec4(\r\n _color[0],\r\n _color[1],\r\n _color[2],\r\n _color[3]\r\n );\r\n}\r\n"}};class M{constructor(){this.longitudeKey=1,this.latitudeKey=0,this.clickSetupMaps=[],this.hoverSetupMaps=[],this.shader=E,this.Points=_,this.Shapes=L,this.Lines=d,this.pointsInstances=[],this.shapesInstances=[],this.linesInstances=[]}longitudeFirst(){return this.longitudeKey=0,this.latitudeKey=1,this}latitudeFirst(){return this.latitudeKey=0,this.longitudeKey=1,this}get instances(){return[...this.pointsInstances,...this.linesInstances,...this.shapesInstances]}points(t){const n=new this.Points({setupClick:this.setupClick.bind(this),setupHover:this.setupHover.bind(this),latitudeKey:F.latitudeKey,longitudeKey:F.longitudeKey,vertexShaderSource:()=>this.shader.vertex,fragmentShaderSource:()=>this.shader.fragment.point,...t});return this.pointsInstances.push(n),n}lines(t){const n=new this.Lines({setupClick:this.setupClick.bind(this),setupHover:this.setupHover.bind(this),latitudeKey:this.latitudeKey,longitudeKey:this.longitudeKey,vertexShaderSource:()=>this.shader.vertex,fragmentShaderSource:()=>this.shader.fragment.polygon,...t});return this.linesInstances.push(n),n}shapes(t){const n=new this.Shapes({setupClick:this.setupClick.bind(this),setupHover:this.setupHover.bind(this),latitudeKey:this.latitudeKey,longitudeKey:this.longitudeKey,vertexShaderSource:()=>this.shader.vertex,fragmentShaderSource:()=>this.shader.fragment.polygon,...t});return this.shapesInstances.push(n),n}setupClick(t){this.clickSetupMaps.includes(t)||(this.clickSetupMaps.push(t),t.on("click",(n=>{let r;return r=this.Points.tryClick(n,t,this.pointsInstances),void 0!==r?r:(r=this.Lines.tryClick(n,t,this.linesInstances),void 0!==r?r:(r=this.Shapes.tryClick(n,t,this.shapesInstances),void 0!==r?r:void 0))})))}setupHover(t,n,r){this.hoverSetupMaps.includes(t)||(this.hoverSetupMaps.push(t),t.on("mousemove",function(t,n,r){let e=null;return function(i){const o=r&&!e;null!==e&&clearTimeout(e),e=setTimeout((function(){e=null,r||t(i)}),n),o&&t(i)}}((n=>{this.Points.tryHover(n,t,this.pointsInstances),this.Lines.tryHover(n,t,this.linesInstances),this.Shapes.tryHover(n,t,this.shapesInstances)}),null!=n?n:0,r)))}}const F=new M,k=F;"undefined"!=typeof window&&window.L&&(window.L.glify=F,window.L.Glify=M)})(),i})())); //# sourceMappingURL=glify-browser.js.map \ No newline at end of file diff --git a/man/addGlPoints.Rd b/man/addGlPoints.Rd index 28854a7..f24f536 100644 --- a/man/addGlPoints.Rd +++ b/man/addGlPoints.Rd @@ -60,7 +60,7 @@ addGlPolygons( ) } \arguments{ -\item{map}{a map widget object created from \code{\link[leaflet:leaflet]{leaflet()}}} +\item{map}{a map widget object created from \code{\link[leaflet]{leaflet}()}} \item{data}{sf/sp point/polygon/line data to add to the map.} @@ -72,7 +72,7 @@ See the examples or \link{makeColorMatrix} for more information.} Note: expect funny results if you set this to < 1.} \item{group}{the name of the group the newly created layers should belong to -(for \code{\link[leaflet:clearGroup]{clearGroup()}} and \code{\link[leaflet:addLayersControl]{addLayersControl()}} purposes). +(for \code{\link[leaflet]{clearGroup}} and \code{\link[leaflet]{addLayersControl}} purposes). Human-friendly group names are permitted--they need not be short, identifier-style names. Any number of layers and even different types of layers (e.g. markers and polygons) can share the same group name.} @@ -91,9 +91,9 @@ match the number of rows in the data, the popup vector is repeated to match the \item{pane}{A string which defines the pane of the layer. The default is \code{"overlayPane"}.} -\item{popupOptions}{A Vector of \code{\link[leaflet:popupOptions]{popupOptions()}} to provide popups} +\item{popupOptions}{A Vector of \code{\link[leaflet]{popupOptions}} to provide popups} -\item{labelOptions}{A Vector of \code{\link[leaflet:labelOptions]{labelOptions()}} to provide label +\item{labelOptions}{A Vector of \code{\link[leaflet]{labelOptions}} to provide label options for each label. Default \code{NULL}} \item{...}{Used to pass additional named arguments to \code{\link[yyjsonr]{write_json_str}} or diff --git a/man/remove.Rd b/man/remove.Rd index c1421e2..ea493fe 100644 --- a/man/remove.Rd +++ b/man/remove.Rd @@ -20,8 +20,8 @@ clearGlLayers(map) clearGlGroup(map, group) } \arguments{ -\item{map}{a map widget object, possibly created from \code{\link[leaflet:leaflet]{leaflet()}} -but more likely from \code{\link[leaflet:leafletProxy]{leafletProxy()}}} +\item{map}{a map widget object, possibly created from \code{\link[leaflet]{leaflet}}() +but more likely from \code{\link[leaflet]{leafletProxy}}()} \item{layerId}{character vector; the layer id(s) of the item to remove} From 3e9d39c98e2df66c9d11043c94571970f37a04c5 Mon Sep 17 00:00:00 2001 From: Sebastian Gatscha Date: Sun, 23 Jun 2024 02:28:34 +0200 Subject: [PATCH 14/14] hoveroff_event JS-func, use .nonce to trigger event --- NEWS | 2 +- R/glify-points.R | 2 + inst/htmlwidgets/Leaflet.glify/GlifyUtils.js | 42 +++++++++++++++++-- .../Leaflet.glify/addGlifyPoints.js | 7 +--- .../Leaflet.glify/addGlifyPolygons.js | 7 +--- .../Leaflet.glify/addGlifyPolylines.js | 7 +--- 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index 1cd51ca..2e17571 100644 --- a/NEWS +++ b/NEWS @@ -16,7 +16,7 @@ bug fixes * added `stroke` (default=TRUE) in `addGlPolygons` and `addGlPolygonsSrc` for drawing borders. #3 #68 * Labels work similar to `leaflet`. `leafgl` accepts a single string, a vector of strings or a formula. #78 * The `...` arguments are now passed to all methods in the underlying library. This allows us to set - additional arguments like `fragmentShaderSource`, `sensitivity` or `sensitivityHover`. + additional arguments like `fragmentShaderSource`, `sensitivity` or `sensitivityHover`. #81 documentation etc diff --git a/R/glify-points.R b/R/glify-points.R index c7ed8fa..c51c047 100644 --- a/R/glify-points.R +++ b/R/glify-points.R @@ -54,6 +54,8 @@ #' \code{input$MAPID_glify_click} #' \item \strong{Mouseover Events:} #' \code{input$MAPID_glify_mouseover} +#' \item \strong{Mouseout Events:} +#' \code{input$MAPID_glify_mouseout} #' } #' #' diff --git a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js index 15ce3a7..7f7309e 100644 --- a/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js +++ b/inst/htmlwidgets/Leaflet.glify/GlifyUtils.js @@ -152,7 +152,8 @@ function click_event_pts(e, point, addpopup, popup, popupOptions, layer, layerId group: layer.settings.className, lat: point[0], lng: point[1], - data: content + data: content, + ".nonce": Math.random() }); } if (addpopup) { @@ -174,7 +175,8 @@ function hover_event_pts(e, point, addlabel, label, layer, tooltip, layerId, dat group: layer.settings.className, lat: point[0], lng: point[1], - data: content + data: content, + ".nonce": Math.random() }); } if (addlabel) { @@ -185,6 +187,21 @@ function hover_event_pts(e, point, addlabel, label, layer, tooltip, layerId, dat } } } +function hoveroff_event_pts(e, point, layer, tooltip, layerId, data, map) { + if (map.hasLayer(layer.layer)) { + tooltip.remove(); + var idx = data.findIndex(k => k==point); + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_mouseout", { + id: layerId ? layerId[idx] : idx+1, + group: layer.settings.className, + lat: point[0], + lng: point[1], + ".nonce": Math.random() + }); + } + } +} function click_event(e, feature, addpopup, popup, popupOptions, layer, layerId, data, map) { if (map.hasLayer(layer.layer)) { const idx = data.features.findIndex(k => k==feature); @@ -194,7 +211,8 @@ function click_event(e, feature, addpopup, popup, popupOptions, layer, layerId, group: Object.values(layer.layer._eventParents)[0].groupname, lat: e.latlng.lat, lng: e.latlng.lng, - data: feature.properties + data: feature.properties, + ".nonce": Math.random() }); } if (addpopup) { @@ -215,7 +233,8 @@ function hover_event(e, feature, addlabel, label, layer, tooltip, layerId, data, group: Object.values(layer.layer._eventParents)[0].groupname, lat: e.latlng.lat, lng: e.latlng.lng, - data: feature.properties + data: feature.properties, + ".nonce": Math.random() }); } if (addlabel) { @@ -228,6 +247,21 @@ function hover_event(e, feature, addlabel, label, layer, tooltip, layerId, data, } } } +function hoveroff_event(e, feature, layer, tooltip, layerId, data, map) { + if (map.hasLayer(layer.layer)) { + tooltip.remove(); + const idx = data.features.findIndex(k => k==feature); + if (HTMLWidgets.shinyMode) { + Shiny.setInputValue(map.id + "_glify_mouseout", { + id: layerId ? layerId[idx] : idx+1, + group: Object.values(layer.layer._eventParents)[0].groupname, + lat: e.latlng.lat, + lng: e.latlng.lng, + ".nonce": Math.random() + }); + } + } +} function json2table(json, cls) { const cols = Object.keys(json); const vals = Object.values(json); diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js index ccff2a3..56b1b7a 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPoints.js @@ -37,11 +37,8 @@ LeafletWidget.methods.addGlifyPoints = function(data, cols, popup, label, opacit map: map, click: clickFun, hover: mouseoverFun, - hoverOff: function(e, feat) { - tooltip.remove(); - //if (HTMLWidgets.shinyMode) { - // Shiny.setInputValue(map.id + "_glify_mouseover", null); - //} + hoverOff: function(e, point) { + hoveroff_event_pts(e, point, pointslayer, tooltip, layerId, data, map); }, data: data, color: clrs, diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js index 2fa9045..2d9556d 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolygons.js @@ -29,11 +29,8 @@ LeafletWidget.methods.addGlifyPolygons = function(data, cols, popup, label, map: map, click: clickFun, hover: mouseoverFun, - hoverOff: function(e, feat) { - tooltip.remove(); - //if (HTMLWidgets.shinyMode) { - // Shiny.setInputValue(map.id + "_glify_mouseover", null); - //} + hoverOff: function(e, feature) { + hoveroff_event(e, feature, shapeslayer, tooltip, layerId, data, map); }, data: data, color: clrs, diff --git a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js index ee3a999..3f5fffe 100644 --- a/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js +++ b/inst/htmlwidgets/Leaflet.glify/addGlifyPolylines.js @@ -37,11 +37,8 @@ LeafletWidget.methods.addGlifyPolylines = function(data, cols, popup, label, map: map, click: clickFun, hover: mouseoverFun, - hoverOff: function(e, feat) { - tooltip.remove(); - //if (HTMLWidgets.shinyMode) { - // Shiny.setInputValue(map.id + "_glify_mouseover", null); - //} + hoverOff: function(e, feature) { + hoveroff_event(e, feature, lineslayer, tooltip, layerId, data, map); }, latitudeKey: 1, longitudeKey: 0,