Skip to content

Instantly share code, notes, and snippets.

@jcheng5
Last active December 15, 2022 16:01
Show Gist options
  • Star 39 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save jcheng5/c084a59717f18e947a17955007dc5f92 to your computer and use it in GitHub Desktop.
Save jcheng5/c084a59717f18e947a17955007dc5f92 to your computer and use it in GitHub Desktop.
Using arbitrary Leaflet plugins with Leaflet for R

Using arbitrary Leaflet JS plugins with Leaflet for R

The Leaflet JS mapping library has lots of plugins available. The Leaflet package for R provides direct support for some, but far from all, of these plugins, by providing R functions for invoking the plugins.

If you as an R user find yourself wanting to use a Leaflet plugin that isn't directly supported in the R package, you can use the technique shown here to load the plugin yourself and invoke it using JS code.

library(leaflet)
library(htmltools)
library(htmlwidgets)
# This tells htmlwidgets about our plugin name, version, and
# where to find the script. (There's also a stylesheet argument
# if the plugin comes with CSS files.)
esriPlugin <- htmlDependency("leaflet.esri", "1.0.3",
src = c(href = "https://cdn.jsdelivr.net/leaflet.esri/1.0.3/"),
script = "esri-leaflet.js"
)
# A function that takes a plugin htmlDependency object and adds
# it to the map. This ensures that however or whenever the map
# gets rendered, the plugin will be loaded into the browser.
registerPlugin <- function(map, plugin) {
map$dependencies <- c(map$dependencies, list(plugin))
map
}
leaflet() %>% setView(-122.23, 37.75, zoom = 10) %>%
# Register ESRI plugin on this map instance
registerPlugin(esriPlugin) %>%
# Add your custom JS logic here. The `this` keyword
# refers to the Leaflet (JS) map object.
onRender("function(el, x) {
L.esri.basemapLayer('Topographic').addTo(this);
}")
# This example shows the ability to pass extra R data to onRender.
# At the time of this writing it requires a custom build of htmlwidgets:
# devtools::install_github("ramnathv/htmlwidgets@joe/feature/onrender-data")
#
# Track the progress of this functionality at
# https://github.com/ramnathv/htmlwidgets/pull/202
library(leaflet)
library(htmltools)
library(htmlwidgets)
library(dplyr)
heatPlugin <- htmlDependency("Leaflet.heat", "99.99.99",
src = c(href = "http://leaflet.github.io/Leaflet.heat/dist/"),
script = "leaflet-heat.js"
)
registerPlugin <- function(map, plugin) {
map$dependencies <- c(map$dependencies, list(plugin))
map
}
leaflet() %>% addTiles() %>%
fitBounds(min(quakes$long), min(quakes$lat), max(quakes$long), max(quakes$lat)) %>%
registerPlugin(heatPlugin) %>%
onRender("function(el, x, data) {
data = HTMLWidgets.dataframeToD3(data);
data = data.map(function(val) { return [val.lat, val.long, val.mag*100]; });
L.heatLayer(data, {radius: 25}).addTo(this);
}", data = quakes %>% select(lat, long, mag))
@bhaskarvk
Copy link

@satishregonda & @klupido, we have found out that using a externally hosted javascript file may not always work. It is best if you try your respective examples by downloading the plugin javascript (and CSS and image files if any) locally.

Then instead of src = c(href = "https:/..."),, do src = normalizePath(<path to directory where the plugin files are downloaded>),

@LeonaLim
Copy link

LeonaLim commented Nov 1, 2016

I can't seem to get the leaflet.defaultextent plugin to work as well even though there is no error. Please assist.

leafletPlugin <- htmlDependency("leaflet.defaultextent", "0.0.3",
                                src = normalizePath("www/Leaflet.defaultextent-master"),
                                script = "leaflet.defaultextent.js"
)

registerPlugin <- function(map, plugin) {
  map$dependencies <- c(map$dependencies, list(plugin))
  map
}

leaflet() %>%   
  addTiles() %>%  
  fitBounds(110, -10, 120, 20)  %>%

  registerPlugin(leafletPlugin) %>%
  onRender('function(el, x) {
           var map = L.map("map", {center: mapCenter, zoom: 14, defaultExtentControl: true });
           L.control.defaultExtent()
           .addTo(map);')

@GaelCobrenord
Copy link

GaelCobrenord commented Jan 9, 2017

Hello, thank you for this tip it seems to be very useful. Unfortunately, I have not managed to make the L.control.mousePosition works with this method within a shiny app. Whenever the plugin works if we launch the leaflet by itself (outside the shiny app). The onRender function seems to be the cause of the dysfunction.

Here there is a reproducible example of my code (you just have to load the .js and .css files locally, doesn’t work with the link (https://github.com/ardhi/Leaflet.MousePosition/tree/master/src)):

rm(list=ls(all=TRUE))
library(shiny)
library(leaflet)
library(sp)
library(htmltools)
library(htmlwidgets)

path <- “YourPath”

shape <- Polygon(data.frame(lon = c(-5,-7,-6), lat = c(47, 47, 52)))
shape <-Polygons(list(shape), ID = 1)
shape <- SpatialPolygons(list(shape), proj4string = CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))
shape <- SpatialPolygonsDataFrame(shape, data.frame(ID= 1))

mouse_plug <- htmlDependency("Leaflet.MousePosition", "0",
  src = normalizePath(path),
  script = "L.Control.MousePosition.js",
  stylesheet = "L.Control.MousePosition.css"
)
registerPlugin <- function(map, plugin) {
  map$dependencies <- c(map$dependencies, list(plugin))
  map
}
ui <- fluidPage(
  leafletOutput("map")

)

server <- function(input, output, session) {
	output$map <- renderLeaflet({
		leaflet() %>%
			addPolygons(data = shape, group = "Fond de carte", color = "black", weight = 0.5, fillColor = rgb(238,197,135, maxColorValue = 255), opacity = 1) %>%  
			addLayersControl(
				overlayGroups = "triangle",
				options = layersControlOptions(autoZIndex = TRUE)
			)%>%
			registerPlugin(mouse_plug) %>%
			onRender("function(el, x) {
				 L.control.mousePosition().addTo(this);}"
			)
		  
	})
	
}

shinyApp(ui, server)

I am sorry but I do not know anything about JS code, I am just a R user and maybe it is obvious but I am totally stuck with that and I really need this plugin for my work.

I would be very greatful if you can help me !

Thank you

Gaël

@GaelCobrenord
Copy link

OK I'm sorry I didn't used the right keywords for my search, I felt on that: rstudio/shiny#1389
But I think I don't well understand the solution. I tried to install different versions of htlmlwidgets (included the development version) but it still doesn't work.

@GaelCobrenord
Copy link

GaelCobrenord commented Jan 10, 2017

Problem solved: I have just had to reboot R after uninstalling the old version of htmlwidgets and then reinstall the 0.8 version with the fixed 237 issue.

Sorry for the trouble

Gaël

@richardblades
Copy link

richardblades commented Jan 27, 2017

Hi, many thanks for the above insight... Its aloud me to load the Bing "Roads" basemap quite nicely... But I'm having real trouble applying the grayscale plugin to that layer... (I've tried many different methods). Can anyone help? Many thanks, Richard.

registerPlugin <- function(map, plugin) {
map$dependencies <- c(map$dependencies, list(plugin))
map
}

bingPlugin <- htmlDependency("leaflet.plugins", "2.0.0",
src=c(href="https://cdnjs.cloudflare.com/ajax/libs/leaflet-plugins/2.0.0/layer/tile/"),
script="Bing.min.js")

grayscalePlugin <- htmlDependency("leaflet-grayscale", "0.0.0" ,
src=c(href="https://github.com/Zverik/leaflet-grayscale"),
script="TileLayer.Grayscale.js")

leaflet() %>%
registerPlugin(grayscalePlugin) %>%
registerPlugin(bingPlugin) %>%
onRender("function(el, x) {
var imagerySet='Road';
var bing=new L.BingLayer.grayscale(
'IGQNg4zQGQnWnhrgeRtx~-_iDYzKzo9RJjvpr-6mMgg~AkD6k2dx3I-4tQgUUh1lITbm-ts2iumSNTmAd5qtIWCJPIoptszrzXs6-mk9_IcA',
{type: imagerySet});
this.addLayer(bing);
}") %>%
addPolygons(data=Building, color="black", fill=TRUE, fillColor="pink",
group="Building", opacity=0.3, weight=0.5)

@rickyars
Copy link

Like everyone else, I'm also having problems adapting the example. My question is this: what's the best way to debug problems? All I know is that it's not working for me, but no error messages are reported. I tried opening the map in the browser and inspecting but nothing appears on the console. Suggestions?

@rickyars
Copy link

Any idea why I can't get this to work when using leafletProxy?

@rickyars
Copy link

Another question: I'm trying to pass an icon to a marker. Using a URL it works file. But when I try to grab the icon locally from disk I get a blue box with a question mark. I'm presuming that it can't find the icon. So what is the "working" directory for the javascript that's run in OnRender?

@rickyars
Copy link

One more thing for others looking for help with this. You can't use forEach in your inside OnRender. I think this has to do with the fact that this has special meaning in forEach - I'm not a javascript programmer so that's about the extent of my knowledge - and since this is the map they don't play nice together. Convert your forEach to a for-loop.

@Surya1987
Copy link

Hi All,

I want to add Leaflet.AreaSelect Plugin to map using R. I want to select an area on the map and need to know the information of the points/circles inside that. Kindly share the code if you have worked on.

@roberrrt-s
Copy link

This solution, while tested, keeps giving me the following error:
$ operator is invalid for atomic vectors

Anyone has a clue what's the problem here?

@Bignoozer
Copy link

Hello everybody,

First, I'm not sure it's the good place to post so sorry if it's not.

I'm trying to add a rotatedMarker in my leaflet map using a leafletProxy.
Unfortunatly it's not working.

Puting it directly in the leaflet map works fine.

here is the code.

`
library(shiny)
library(dplyr)
library(leaflet)
library(htmltools)
library(htmlwidgets)

      angle <- 20
      
      travel <- data.frame("time" = c("6/20/17 13:32", "6/20/17 13:33", "6/20/17 13:34", "6/20/17 13:35", "6/20/17 13:36", "6/20/17 13:37"),
                           "lat" = c(59.313833, 59.312333, 59.309897, 59.307728, 59.300728, 59.298184),
                           "lon" = c(18.070431, 18.07431, 18.085347, 18.076543, 18.080761, 18.076176),
                           stringsAsFactors = F) %>%
      mutate(
        time = as.POSIXct(time, format = "%m/%d/%y %H:%M")
      )
      
      rotatedMarker <- htmlDependency(
        "Leaflet.rotatedMarker",
        "0.1.2",
        src = normalizePath("./www/js"),
        script = "leaflet.rotatedMarker.js"
      )
      
      registerPlugin <- function(map, plugin) {
        map$dependencies <- c(map$dependencies, list(plugin))
        map
      }
      
      ui <- fluidPage(
        sliderInput(inputId = "time", label = "Time", min = min(travel$time), 
                    max = max(travel$time),
                    value = min(travel$time),
                    step=60, # set to increment by 60 seconds, adjust appropriately
                    animate= animationOptions(interval = 2000, loop = F)),
        leafletOutput("mymap")
      )
      
      server <- function(input, output, session) {
        
        points <- reactive({
          travel %>% 
            filter(time == input$time)
        })
        
        history <- reactive({
          travel %>%
            filter(time <= input$time)
        })
        
        output$mymap <- renderLeaflet({
          
          req(input$time)
          
          m <- leaflet(travel) %>% 
            addTiles(urlTemplate = "map/tiles/{z}/{x}/{y}.png", 
                     option=tileOptions(tms = T, continuousWorld = T, minZoom="4",maxZoom="4")) %>%
            addPolylines(lng = ~lon,
                         lat = ~lat,
                         data = travel) %>%
            fitBounds(~min(lon),
                      ~min(lat),
                      ~max(lon),
                      ~max(lat))
        })
        
        observe({
          proxy <- leafletProxy("mymap")
      
          proxy %>% clearControls()
          if (input$time) {
            
            data <- points()
            ind <- which(travel$time == data$time)
            angle <- angle * ind
            
            proxy %>% clearMarkers() %>%
              registerPlugin(rotatedMarker) %>%
              onRender(paste0("function(el, x) {
                              var planeIcon = L.icon({iconUrl: 'images/icon_plane.png', iconAnchor: [16, 16]});
                              var pathPattern = L.marker([", data$lat[1], ",", data$lon[1], "], {icon: planeIcon, rotationAngle:", angle, "}).addTo(mymap);
                              }"))
          }
        })
      
        session$onSessionEnded(stopApp)
      }
      
      shinyApp(ui, server)

`

Thanks for the help.

@JCGTech
Copy link

JCGTech commented Feb 12, 2018

YES! Thank you

@mimaque
Copy link

mimaque commented Mar 21, 2018

@bhaskarvk 's comment of substituting the src call inside htmlDependency for normalizePath and downloading the zipfile to the specified path allowed me to run locally his pulsating marker example, which I could not run before

@laurapoggio-sptools
Copy link

laurapoggio-sptools commented Apr 18, 2018

I am trying to use the SideBySide plugin, however without any luck at the moment. I tried the suggestion of downloading the file and this answer here. Below what I am trying to run (using chrome under fedora 27). I can see the first layer but not the handle to compare the two.

Any help would be greatly appreciated. Thanks

LeafletSideBySidePlugin <- htmlDependency("leaflet-side-by-side","2.0.0",
                                          src = normalizePath("/full/path/to/folder/with/js"),
                                          script="leaflet-side-by-side.js")

registerPlugin <- function(map, plugin) {
  map$dependencies <- c(map$dependencies, list(plugin))
  map
}

leaflet() %>%
 registerPlugin(LeafletSideBySidePlugin) %>%
  onRender("
           function(el, x) {
           var mylayer1 = L.tileLayer(
           'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
           maxZoom: 18
           }).addTo(this);
           var mylayer2 = L.tileLayer(
           '//stamen-tiles-{s}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png',{
           maxZoom: 14
           }).addTo(this);
           L.control.sideBySide(mylayer1, mylayer2).addTo(this);
          } ")

@chintanp
Copy link

This gist is really helpful and on point and exactly what I was looking for. I tried using the method to use the "Leaflet playback" plugin.

My code looks like this:

# Draw a line from startPoint to Endpoint on the map
                    leafletProxy(mapId = "map") %>%
                        onRender(
                            "function(el, x, data) {
                                // Initialize playback
                                var playback = new L.Playback(this, data, onPlaybackTimeChange);
                                console.log('Inside leaflet playback');
                            };
                            
                            // A callback so timeline is set after changing playback time
                            function onPlaybackTimeChange (ms) {
                                //timeline.setCustomTime(new Date(ms));
                            };", data = geojson_ends
                        )

I register the plugin with the first call to leaflet where I create the map. Two functions are created inside the onRender as L.PLayback needs a callback function onPalybackTimeChange. The leafletproxy is just used for updating the plot. As such I don't think this is working. No error, just no change in behavior.

  • Is there a way to debug this? I tried putting a console.log to see it gets printed, no luck.
  • Is there a way I can use "Developer tools" to inspect the code in the the browser? If yes, which file should I look for? Apparently, shiny creates a bunch of files.
  • Any other hints/comments?

@Jigar-S
Copy link

Jigar-S commented Dec 31, 2018

This is really helpful information. We are trying implement the 'leaflet-measure' plugin but it simply does not render properly (renders without any icons being displayed). This post seems like a promising solution, but on trial and error, it fails to load any plugins that are of type leaflet-control. Dunno if this is the correct place to post, but I would really appreciate some help to rectify the issue.
Here's my code to use the leaflet-control type plugins using this method.

`library(leaflet)
library(htmltools)
library(htmlwidgets)

LeafletMeasure <- htmlDependency("leaflet-measure","3.1.0",
src = c(href="https://github.com/ljigis/leaflet-measure/src"),
script="leaflet-measure.js",
stylesheet = "https://github.com/ljigis/leaflet-measure/scss/leaflet-measure.scss")

registerPlugin <- function(map, plugin) {
map$dependencies <- c(map$dependencies, list(plugin))
map
}

leaflet() %>% addTiles() %>%
setView(lng = 12, lat = 50, zoom = 4) %>%
registerPlugin(LeafletMeasure) %>%
onRender("
function(el, x) {
measureControl.addTo(this);}")`

The plugin has a scss that is in a different folder from the standard src folder. I have tried referencing the file through the Github repository as well as local copy.

@jcheng5
Copy link
Author

jcheng5 commented Feb 28, 2019

Wow, sorry, I didn't know there were so many messages posted here over the years. @Jigar-S, leaflet-measure is already bundled with the leaflet R package, just do leaflet() %>% addMeasure() for example.

For the rest of you, I'd focus on the following for debugging:

  1. Are my JS/CSS resources being properly attached? (BTW, you can't use .scss or .less files from htmlDependency directly, they have to be compiled to .css first for the browser to understand them.) You can use Chrome Developer Tools to see if there are any errors in the Console tab about JS and CSS URLs not being downloaded, and look in the Elements tab to see if the proper JS/CSS links are in the <head> of the document.
  2. Am I getting any JS errors? Again, use the Chrome Developer Tools' Console tab to see if there are errors. If there are, you need to fix those first.
  3. If the previous steps pass, or you have trouble figuring out the cause of the errors, then try the JS Debugger. One easy way is to add the statement debugger; to the start of your onRender function's JS function. Then, if you load the page with Chrome Developer Tools enabled, the JS debugger should pause just inside your JS function. With the debugger paused, you can examine the values of this, el, x, etc. to see if everything matches your expectations.

If you have continued problems, feel free to file an issue on the rstudio/leaflet repository, or drop by https://community.rstudio.com/c/shiny.

@helgasoft
Copy link

helgasoft commented May 20, 2019

@jcheng5, thank you for this thread and all the directions.
Sharing our successful integration of one JS plugin for tile-layer opacity.
Shiny app code is here. The js/css files have to be downloaded before execution.
The bulk of the work was to find the Leaflet JS 'hook-up' objects, which are not documented.

@micahwilhelm
Copy link

@helgasoft, thank you for sharing your code! Do you know the 'hook-up' object syntaxes for polygons, polylines or markers?
My attempt to integrate the leaflet-groupedlayercontrol plugin have so far been unsuccessful. Thanks in advance for any tips you might offer.

@helgasoft
Copy link

@micahwilhelm, here is the code on how to integrate this plugin.
I wish someone could find a way to add group markers from R, not only from Javascript...

@michaelgaunt404
Copy link

michaelgaunt404 commented Sep 27, 2020

@helgasoft
@jcheng5

Great work! do you know how you would do something like this with a map that is already constructed with mapview?

I would like to make the resulting map's legend say:

Places
|-> names
|-> village
Other
|-> Changed Name

install.packages("mapview")
install.packages("dplyr")
install.packages("magrittr")
library(mapview)
library(dplyr)
library(magrittr)

names = breweries %>%
select(brewery)

village = breweries %>%
select(village)

Complicated Name_layer = breweries %>%
select(number.of.types)

mapview(names, legend = F) +
mapview(village, legend = F) +
mapview(Complicated Name_layer, legend = F)

Thank you so much!!

image

@nash1119
Copy link

@jcheng5 and community

Does anyone know how to successfully pass R objects into the JS logic?

My attempt:

library(leaflet)
library(htmltools)
library(htmlwidgets)
library(fontawesome)
library(jsonlite)

beautifyPlugin <- htmlDependency("Leaflet.BeautifyMarker", "1.0.9",
                                 src = c(href="https://cdn.jsdelivr.net/npm/beautifymarker@1.0.9/"),
                                 script = "leaflet-beautify-marker-icon.min.js",
                                 stylesheet = "leaflet-beautify-marker-icon.min.css"
)

fontawesomePlugin <- htmlDependency("Leaflet.BeautifyMarkerFA", "1.0.9",
                                    src = c(href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/"),
                                    stylesheet = "font-awesome.min.css"
)

registerPlugin <- function(map, plugin) {
  map$dependencies <- c(map$dependencies, list(plugin))
  map
}

iconName <- list(icon = 'leaf')
toJSON(iconName)
#> {"icon":["leaf"]}
  
leaflet() %>% setView(-122.23, 37.75, zoom = 10)%>%
  addTiles()%>%
  registerPlugin(fontawesomePlugin)%>%
  registerPlugin(beautifyPlugin) %>%
  onRender("function(el, x, iconName) {
          options = {
              icon: data.icon,
              iconShape: 'marker'
           };
           L.marker([37.77, -122.40] ,
           {icon: L.BeautifyIcon.icon(options)
           }).addTo(this).bindPopup('test');
           }")

Created on 2020-10-20 by the reprex package (v0.3.0)

@helgasoft
Copy link

@nash1119 - why not just paste the value inside the JS code string:

library(leaflet)
library(htmltools)
library(htmlwidgets)
beautifyPlugin <- htmlDependency( "Beautify", "1.0.9",
                                 src = c(href="https://cdn.jsdelivr.net/npm/beautifymarker@1.0.9/"),
                                 script = "leaflet-beautify-marker-icon.min.js",
                                 stylesheet = "leaflet-beautify-marker-icon.min.css"
)
fontawesomePlugin <- htmlDependency( "fontawesome", "4.5.0",
                                    src = c(href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/"),
                                    stylesheet = "font-awesome.min.css"
)
registerPlugin <- function(map, plugin) {
  map$dependencies <- c(map$dependencies, list(plugin))
  map
}
myIcon <- 'leaf'
leaflet() %>% setView(-122.23, 37.75, zoom = 10) %>% addTiles()%>%
 registerPlugin(fontawesomePlugin) %>% 
 registerPlugin(beautifyPlugin) %>%
 onRender(paste0("function(el, x) {
	L.marker([37.77, -122.40] , 
		{icon: L.BeautifyIcon.icon({ icon:'" ,myIcon, "', iconShape: 'marker' }) }).addTo(this).bindPopup('test');
 }"))

@nash1119
Copy link

@helgasoft thank you!

@nash1119
Copy link

nash1119 commented Nov 9, 2020

@rickyars @Bignoozer @chintanp or anyone, did you ever find a solution to why this does not seem to work with leafletProxy()? I am currently having this issue. Thanks!

@viniciuszendron
Copy link

@nash1119 @rickyars @Bignoozer @chintanp please take a look at the question below:

https://stackoverflow.com/questions/52846472/leaflet-plugin-and-leafletproxy-with-polylinedecorator-as-example

It worked for my case as a workaround. You need to anticipate what is coming by creating a function associated to an event listener inside onRender, and call this directly on leaflet, not leafletProxy.

Maybe @jcheng5 could have some idea on why the main approach described in this gist doesn't work well with leafletProxy.

@oggioniale
Copy link

Hello,
some of you have experience about integration of Leaflet.LayerTreePlugin with R Shiny

library(htmltools)
library(htmlwidgets)
library(dplyr)

layerTreePlugin <- htmltools::htmlDependency(
  "Leaflet.LayerTreePlugin", "1.0.0",
  src = "./www/js/",
  script = "leaflet-layer-tree-control.js"
)

registerPlugin <- function(map, plugin) {
  map$dependencies <- c(map$dependencies, list(plugin))
  map
}

leaflet() %>% addTiles() %>%
  registerPlugin(layerTreePlugin) %>%
  onRender("function(el, x) {
  function buildContentFromLayer(layer) {
		var content = '<table>';
		var properties = layer.feature.properties;
		for (var i in properties) {
			content += '<tr><td>' + i + '</td><td>' + properties[i] + '</td></tr>';
		}
		content += '</table>';
		return content;
	}
  
	// Icons
	var greenIcon = L.icon({
		iconUrl: 'https://leafletjs.com/examples/custom-icons/leaf-green.png',
		shadowUrl: 'https://leafletjs.com/examples/custom-icons/leaf-shadow.png',

		iconSize: [38, 95],
		shadowSize: [50, 64],
		iconAnchor: [22, 94],
		shadowAnchor: [4, 62],
		popupAnchor: [-3, -76]
	});
	
	var tree = [{code: 'root', name: 'All the Layers', active: true,
			selectedByDefault: false,
			openByDefault: true,
			childLayers: [
				{
					code: 'base',
					name: 'Base layers',
					active: true,
					selectedByDefault: false,
					openByDefault: true,
					childLayers: [
						{
							code: 'osm',
							name: 'OpenStreetMap',
							active: true,
							selectedByDefault: false,
							openByDefault: true,
							childLayers: [],
							selectType: 'MULTIPLE',
							serviceType: 'OSM',
							params: {
								url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
							}
						},
						{
							code: 'google',
							name: 'Google',
							active: true,
							selectedByDefault: true,
							openByDefault: true,
							childLayers: [],
							selectType: 'NONE',
							serviceType: 'GOOGLE',
							params: {}
						},
						{
							code: 'google_terrain',
							name: 'Google Terrain',
							active: true,
							selectedByDefault: false,
							openByDefault: true,
							childLayers: [],
							selectType: 'NONE',
							serviceType: 'GOOGLE_TERRAIN',
							params: {}
						}
					],
					selectType: 'SINGLE',
					serviceType: null,
					params: {}
				},
				{
					code: 'overlays',
					name: 'Overlays',
					active: true,
					selectedByDefault: false,
					openByDefault: true,
					childLayers: [
						{
							code: '50m_coastline',
							name: 'rsg:50m_coastline',
							active: true,
							selectedByDefault: true,
							openByDefault: true,
							selectType: 'MULTIPLE',
							serviceType: 'WFS',
							coordinateSystem: 'EPSG:4326',
							onPopup: function (layer) {
								return buildContentFromLayer(layer);
							},
							params: {
								request: 'getFeature',
								service: 'WFS',
								typeName: 'rsg:50m_coastline',
								style: '{\"stroke\":true,\"fillColor\":\"violet\",\"border\":\"orange\",\"weight\":3,\"opacity\":0.5,\"color\":\"red\",\"dashArray\":\"5\",\"fillOpacity\":0.1}',
								  version: '1.1.0',
								  outputFormat: 'application/json',
								  url: 'https://rsg.pml.ac.uk/geoserver/wfs',
								  maxFeatures: '25'
								},
								childLayers: [
								  {
								    code: 'MPA_SCOTLAND',
								    name: 'rsg:MPA_SCOTLAND',
								    active: true,
								    selectedByDefault: true,
								    openByDefault: true,
								    selectType: 'MULTIPLE',
								    serviceType: 'WFS',
								    coordinateSystem: 'EPSG:4326',
								    onPopup: function (layer) {
								      return buildContentFromLayer(layer);
								    },
								    params: {
								      request: 'getFeature',
								      service: 'WFS',
								      typeName: 'rsg:MPA_SCOTLAND',
								      style: '{\"stroke\":true,\"fillColor\":\"yellow\",\"border\":\"gray\",\"weight\":3,\"opacity\":0.5,\"color\":\"gray\",\"dashArray\":\"5\",\"fillOpacity\":0.1}',
								      version: '1.1.1',
								      outputFormat: 'application/json',
								      url: 'https://rsg.pml.ac.uk/geoserver/wfs',
								      maxFeatures: '25'
								    }
								  },
								  {
								    code: 'MMO_Fish_Shellfish_Cages_A',
								    name: 'rsg:MMO_Fish_Shellfish_Cages_A',
								    active: true,
								    selectedByDefault: false,
								    openByDefault: true,
								    selectType: 'MULTIPLE',
								    serviceType: 'WFS',
								    coordinateSystem: 'EPSG:4326',
								    onPopup: function (layer) {
								      return buildContentFromLayer(layer);
								    },
								    params: {
								      request: 'getFeature',
								      service: 'WFS',
								      typeName: 'rsg:MMO_Fish_Shellfish_Cages_A',
								      version: '1.1.1',
								      outputFormat: 'application/json',
								      url: 'https://rsg.pml.ac.uk/geoserver/wfs',
								      maxFeatures: '25'
								    }
								  }
								  ]
								},
{
  code: 'tiger_roads',
  name: 'tiger:tiger_roads',
  active: true,
  selectedByDefault: false,
  openByDefault: true,
  selectType: 'MULTIPLE',
  serviceType: 'WFS',
  coordinateSystem: 'EPSG:4326',
  onPopup: function (layer) {
    return buildContentFromLayer(layer);
  },
  params: {
    request: 'getFeature',
    service: 'WFS',
    typeName: 'tiger:tiger_roads',
    style: '{\"stroke\":true,\"fillColor\":\"green\",\"border\":\"cyan\",\"weight\":3,\"opacity\":0.5,\"color\":\"red\",\"dashArray\":\"3\",\"fillOpacity\":0.1}',
    version: '1.1.1',
    outputFormat: 'application/json',
    url: 'https://rsg.pml.ac.uk/geoserver/wfs',
    maxFeatures: '25'
  },
  childLayers: [
    {
      code: 'poi',
      name: 'tiger:poi',
      active: true,
      selectedByDefault: true,
      openByDefault: true,
      childLayers: [],
      selectType: 'MULTIPLE',
      serviceType: 'WFS',
      coordinateSystem: 'EPSG:4326',
      onPopup: function (layer) {
        return buildContentFromLayer(layer);
      },
      params: {
        request: 'getFeature',
        service: 'WFS',
        typeName: 'tiger:poi',
        version: '1.1.1',
        outputFormat: 'application/json',
        url: 'https://rsg.pml.ac.uk/geoserver/wfs',
        maxFeatures: '25',
        icon: greenIcon
      },
    }
    ]
}
],
selectType: 'MULTIPLE',
serviceType: null,
params: {}
}
],
selectType: 'NONE',
serviceType: null,
params: {}
}
];

// Base Layers
var layerBuilders = {
  GOOGLE: function (layerSettings) {
    return L.tileLayer('http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', {
      maxZoom: 20,
      subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
    });
  },
  GOOGLE_TERRAIN: function (layerSettings) {
    return L.tileLayer('http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', {
      maxZoom: 20,
      subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
    });
  }
  
};

// The Tree Control
new L.Control.LayerTreeControl({
  layerTree: tree,
  openByDefault: true,
  layerBuilders: layerBuilders,
  featureBuilders: {
    WFS: {
      zoom: L.Control.LayerTreeControl.WFSZoomFeature
    }
  }
}).addTo(this);

  }")

The map is empty without any Layer Tree

@nicksinus
Copy link

nicksinus commented Jul 16, 2021

I'm trying to use Leaflet.LabelTextCollision, but it doesn't work. What did i miss?

library(tidyverse)
library(leaflet)
library(htmltools)
library(htmlwigets)




label <- data.frame(
lat = c(61.09049, 56.89039, 57.52678, 60.74516, 56.92379, 64.54302, 56.25897, 56.49648, 56.27996, 56.74812, 59.93873, 56.77972, 56.85867, 60.08370, 56.25897),
lon = c(43.17148, 32.65250,  38.31669, 42.04732, 32.74461, 40.53712, 32.08586, 31.64108, 31.66774, 33.51162, 30.31623, 31.25263, 35.92083, 30.27957, 32.08586),
name_label = c("label_1", "label_2", "label_1000", "label_10000", "label_70000", "label_8", "label_999999", "label_777", "label_888888", "label_888", "label_999", "label_7", "label_9", "label_777777777", "label_999999999")
)




col_Plugin <- htmlDependency(
  "Leaflet.LabelTextCollision", "1.4.0",
  src = "./Leaflet.LabelTextCollision-master/dist",
  script = "L.LabelTextCollision.js"
)


registerPlugin <- function(map, plugin) {
  map$dependencies <- c(map$dependencies, list(plugin))
  map
}  


leaflet() %>%
  
  setView(35, 55, zoom = 4) %>%
  
  addProviderTiles(provider =  "OpenStreetMap") %>%
  
  registerPlugin(col_Plugin) %>%

  addLabelOnlyMarkers(lng = label$lon,
                      lat = label$lat,
                      label = lapply(label$name_label, HTML),
                      labelOptions = labelOptions(noHide = T,
                                                  textOnly = F,
                                                  direction = "top")
  ) %>% 
  
  onRender("function(el, x) {

  L.LabelTextCollision().addTo(this);}"

  )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment