Fine-tuning Leaflet in R with JavaScript

I created a series of maps for a recent project exploring school transfers in Indiana using R packages that provide a way for people who aren’t fluent in JavaScript to leverage its power within their projects.

The eponymous R package Leaflet uses its namesake JavaScript library to create interactive maps. Crosstalk similarly uses JavaScript behind the scenes to allow users to interactively filter their data visualizations. In the end, I still needed a little raw JavaScript from outside those packages to make things work properly.

One issue involved the drop-down filter that selects a school or school corporation for the maps. It doesn’t load an initial value so all the markers are loaded at once creating a visual mess. It’s a known issue. One solution is adding a JavaScript function that loads the page with a specific value selected in the filter.

The first step for this is accomplished when using Crosstalk’s filter_select function to create the filter. The function’s id argument assigns a value - filter_stlmt in this case - to id that a JavaScript function will later use to find the right element of the page.

```{r, filter}
# dropdown filter for school corporation of legal settlement
filter <-   
  filter_select(
    id = "filter_stlmt",
    label = "Select school corporation", 
    sharedData = schl_data,
    multiple = F,
    group = ~stlmt_corp_name, 
  )

```

The next step is to create a JavaScript function - filter_stlmt_corp() in this case - that loads a default value in the filter. The function is added as its own JavaScript chunk at the tail end of the RMarkdown document. It finds the id created above - filter_stlmt - and sets a value for it, in this case the first Indiana school corporation by alphabetical order.

```{js filter}

function filter_stlmt_corp() {
    document.getElementById("filter_stlmt").getElementsByClassName("selectized")
[0].selectize.setValue("Adams Central Community Schools",  false);
 }

window.onload=function(){
filter_stlmt_corp()
}
```

Although a user can easily use the filter themselves to resolve the overloaded map, loading a value by default makes the relationship between the drop-down filter and the map more intuitive, encouraging further exploration.

The map exported without using JavaScript to load a default value into the drop-down filter, left, is overwhelmed with data points and looks terrible until a user selects a school from the filter. The map loaded with a default filter value, right, is more legible.

The second issue related to map movement. Each marker representing a transfer relationship has an associated popup chart. When a marker is selected, the map scrolls up to accommodate the vertical popup. This is expected behavior. When the popup closes, however, the map remains in its new adjusted position, leaving much of the state and the other markers out of view.

GIF showing popup chart resetting boundaries of overall map.

One solution to return the map to its original state when the popup closes is the following JavaScript function (ht to Vedo) that can be piped onto the end of existing R map code using the onRender function from the htmlwidgets package.

onRender("function(el, x) {
                          var map = this;
                          map.eachLayer(function(layer) {
  
                            if(layer instanceof L.CircleMarker){
                              layer.on('click', function(e){
  
                                layer.getPopup().on('remove', function () {
  
                                  map.setView(map._initialCenter, map._initialZoom);
                                });
                              })
                              .addTo(map)
                            }
                          });
                        }
    ")

With a little JavaScript help, the map is restored to its original position after the popup chart is closed, improving the user experience.

GIF animation showing map resetting to proper boundaries after popup chart is closed.

That the solution to both the issues was to use JavaScript outside the R packages involved is a strong argument for spending time getting to know it better.

The project’s code and data can be found at github.

Previous
Previous

Visualizing rates with icons using the ggimage package.

Next
Next

Exploring school transfers in Indiana