diff --git a/NAMESPACE b/NAMESPACE index 88194ff4..948b2281 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -31,6 +31,7 @@ export(addTangram) export(addTimeslider) export(addVelocity) export(addWMS) +export(addWMSHeader) export(antpathOptions) export(arrowheadOptions) export(clearAntpath) diff --git a/R/wmsheader.R b/R/wmsheader.R new file mode 100644 index 00000000..f21b881b --- /dev/null +++ b/R/wmsheader.R @@ -0,0 +1,44 @@ +wmsheaderDependency <- function() { + list( + htmltools::htmlDependency( + "lfx-wmsheader", + version = "1.0.0", + src = system.file("htmlwidgets/lfx-wmsheader", package = "leaflet.extras2"), + script = c( + "leaflet.wmsheader.js", + "leaflet.wmsheader-bindings.js" + ) + ) + ) +} + +#' Add WMS Layerwith custom Header +#' +#' @description +#' Custom headers on Leaflet TileLayer WMS. It's a simple plugin that allow to +#' set custom header for WMS interface. +#' +#' @inheritParams leaflet::addWMSTiles +#' @inherit leaflet::addWMSTiles return +#' @references \url{https://github.com/ticinum-aerospace/leaflet-wms-header} +#' @family WMS Functions +#' @export +addWMSHeader <- function(map, baseUrl, layerId = NULL, group = NULL, + options = WMSTileOptions(), + attribution = NULL, + layers = NULL, + header = NULL, + data = getMapData(map)) { + if (is.null(layers)) { + stop("layers is a required argument with comma-separated list of WMS layers to show") + } + options$attribution <- attribution + options$layers <- layers + + map$dependencies <- c(map$dependencies, wmsheaderDependency()) + + invokeMethod( + map, data, "addWMSHeader", baseUrl, layerId, + group, options, header + ) +} diff --git a/inst/examples/wmsheader_app.R b/inst/examples/wmsheader_app.R new file mode 100644 index 00000000..370a85ea --- /dev/null +++ b/inst/examples/wmsheader_app.R @@ -0,0 +1,34 @@ +library(shiny) +library(leaflet) +library(leaflet.extras2) + + +ui <- fluidPage( + leafletOutput("map", height = "500px") +) + +base64pwd <- paste0("user:strongpwd") + +server <- function(input, output, session) { + output$map <- renderLeaflet({ + leaflet() %>% + addTiles(group = "base") %>% + addWMSHeader(baseUrl = "http://localhost:8080/geoserver/wms", + layers = c("tiger:poi"), + group = "wmsgroup", + header = list( + list("header" = "Authorization", + "value" = paste0("Basic ", base64enc::base64encode(charToRaw(base64pwd))) ), + list("header" = "content-type", + "value" = "text/plain") + ), + options = leaflet::WMSTileOptions( + transparent = TRUE, format = "image/png")) %>% + addLayersControl(baseGroups = "base", + overlayGroups = c("tiger:poi")) + + }) +} +shinyApp(ui, server) + + diff --git a/inst/htmlwidgets/lfx-wmsheader/leaflet.wmsheader-bindings.js b/inst/htmlwidgets/lfx-wmsheader/leaflet.wmsheader-bindings.js new file mode 100644 index 00000000..614dc633 --- /dev/null +++ b/inst/htmlwidgets/lfx-wmsheader/leaflet.wmsheader-bindings.js @@ -0,0 +1,12 @@ +LeafletWidget.methods.addWMSHeader = function(baseUrl, layerId, group, options, header) { + + console.log("addWMSHeader header:"); console.log(header) + + if(options && options.crs) { + options.crs = LeafletWidget.utils.getCRS(options.crs); + } + + // Add WMS source + var source = L.TileLayer.wmsHeader(baseUrl, options, [header], null); + this.layerManager.addLayer(source, "tile", layerId, group); +}; diff --git a/inst/htmlwidgets/lfx-wmsheader/leaflet.wmsheader.js b/inst/htmlwidgets/lfx-wmsheader/leaflet.wmsheader.js new file mode 100644 index 00000000..65b3ec2d --- /dev/null +++ b/inst/htmlwidgets/lfx-wmsheader/leaflet.wmsheader.js @@ -0,0 +1,63 @@ +'use strict'; + +async function fetchImage(url, callback, headers, abort) { + let _headers = {}; + if (headers) { + headers.forEach(h => { + _headers[h.header] = h.value; + }); + } + const controller = new AbortController(); + const signal = controller.signal; + if (abort) { + abort.subscribe(() => { + controller.abort(); + }); + } + const f = await fetch(url, { + method: "GET", + headers: _headers, + mode: "cors", + signal: signal + }); + const blob = await f.blob(); + callback(blob); +} + +L.TileLayer.WMSHeader = L.TileLayer.WMS.extend({ + initialize: function (url, options, headers, abort, results) { + L.TileLayer.WMS.prototype.initialize.call(this, url, options); + this.headers = headers; + this.abort = abort; + this.results = results; + }, + createTile(coords, done) { + const url = this.getTileUrl(coords); + const img = document.createElement("img"); + img.setAttribute("role", "presentation"); + + self = this; + + fetchImage( + url, + resp => { + const reader = new FileReader(); + reader.onload = () => { + img.src = reader.result; + if (self.results) { + self.results.next(reader.result); + }; + }; + reader.readAsDataURL(resp); + done(null, img); + }, + this.headers, + this.abort + ); + return img; + } +}); + +L.TileLayer.wmsHeader = function (url, options, headers, abort, results) { + return new L.TileLayer.WMSHeader(url, options, headers, abort, results); +}; diff --git a/man/addWMSHeader.Rd b/man/addWMSHeader.Rd new file mode 100644 index 00000000..7de77868 --- /dev/null +++ b/man/addWMSHeader.Rd @@ -0,0 +1,57 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/wmsheader.R +\name{addWMSHeader} +\alias{addWMSHeader} +\title{Add WMS Layerwith custom Header} +\usage{ +addWMSHeader( + map, + baseUrl, + layerId = NULL, + group = NULL, + options = WMSTileOptions(), + attribution = NULL, + layers = NULL, + header = NULL, + data = getMapData(map) +) +} +\arguments{ +\item{map}{a map widget object created from \code{\link[leaflet]{leaflet}()}} + +\item{baseUrl}{a base URL of the WMS service} + +\item{layerId}{the layer id} + +\item{group}{the name of the group the newly created layers should belong to +(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.} + +\item{options}{a list of extra options for tile layers, popups, paths +(circles, rectangles, polygons, ...), or other map elements} + +\item{attribution}{the attribution text of the tile layer (HTML)} + +\item{layers}{comma-separated list of WMS layers to show} + +\item{data}{the data object from which the argument values are derived; by +default, it is the \code{data} object provided to \code{leaflet()} +initially, but can be overridden} +} +\value{ +the new \code{map} object +} +\description{ +Custom headers on Leaflet TileLayer WMS. It's a simple plugin that allow to +set custom header for WMS interface. +} +\references{ +\url{https://github.com/ticinum-aerospace/leaflet-wms-header} +} +\seealso{ +Other WMS Functions: +\code{\link{addWMS}()} +} +\concept{WMS Functions} diff --git a/package-lock.json b/package-lock.json index bbc4ce3d..75d287a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,12 @@ "d3-color": "^3.1.0", "d3-hexbin": "^0.2.2", "labelgun": "^6.1.0", - "leaflet": "^1.6.0", + "leaflet": "^1.9.4", "leaflet-ant-path": "^1.3.0", "leaflet-arrowheads": "^1.4.0", "leaflet-easyprint": "^2.1.9", "leaflet-geometryutil": "^0.10.1", + "leaflet-wms-header": "^1.0.13", "leaflet.heightgraph": "^1.4.0" } }, @@ -450,9 +451,9 @@ } }, "node_modules/leaflet": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.8.0.tgz", - "integrity": "sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA==" + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==" }, "node_modules/leaflet-ant-path": { "version": "1.3.0", @@ -485,6 +486,15 @@ "leaflet": "^1.6.0" } }, + "node_modules/leaflet-wms-header": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/leaflet-wms-header/-/leaflet-wms-header-1.0.13.tgz", + "integrity": "sha512-Nm9YGoAGIZPXDDZuJtWXlVcVg0a7cwOjk6zsXgKbRuTPnqykwMlQ9mgwANt9JALvcx2fh/+GYkuew0qsvX24vQ==", + "dependencies": { + "rxjs": "^6.6.3", + "typescript": "^2.9.2" + } + }, "node_modules/leaflet.heightgraph": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/leaflet.heightgraph/-/leaflet.heightgraph-1.4.0.tgz", @@ -516,10 +526,38 @@ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } } }, "dependencies": { @@ -836,9 +874,9 @@ } }, "leaflet": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.8.0.tgz", - "integrity": "sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA==" + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==" }, "leaflet-ant-path": { "version": "1.3.0", @@ -871,6 +909,15 @@ "leaflet": "^1.6.0" } }, + "leaflet-wms-header": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/leaflet-wms-header/-/leaflet-wms-header-1.0.13.tgz", + "integrity": "sha512-Nm9YGoAGIZPXDDZuJtWXlVcVg0a7cwOjk6zsXgKbRuTPnqykwMlQ9mgwANt9JALvcx2fh/+GYkuew0qsvX24vQ==", + "requires": { + "rxjs": "^6.6.3", + "typescript": "^2.9.2" + } + }, "leaflet.heightgraph": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/leaflet.heightgraph/-/leaflet.heightgraph-1.4.0.tgz", @@ -902,10 +949,28 @@ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==" } } } diff --git a/package.json b/package.json index fd03ebeb..717ae932 100644 --- a/package.json +++ b/package.json @@ -16,11 +16,12 @@ "d3-color": "^3.1.0", "d3-hexbin": "^0.2.2", "labelgun": "^6.1.0", - "leaflet": "^1.6.0", + "leaflet": "^1.9.4", "leaflet-ant-path": "^1.3.0", "leaflet-arrowheads": "^1.4.0", "leaflet-easyprint": "^2.1.9", "leaflet-geometryutil": "^0.10.1", + "leaflet-wms-header": "^1.0.13", "leaflet.heightgraph": "^1.4.0" } }