简体   繁体   English

使用 R Leaflet 创建交互式地图,在多边形单击时显示标记

[英]Create interactive map with R Leaflet that shows markers upon polygon click

Creating a leaflet map in R can be tricky if one wants to add reactive, or otherwise customized, features.如果想要添加响应式或其他自定义功能,在R创建传单地图可能会很棘手。 My goal was to use my workflow in R to make a choropleth map that is then augmented by the ability to click a polygon and 'reveal' a set of points.我的目标是使用我在R工作流程制作一个等值线图,然后通过单击多边形和“显示”一组点的能力来增强该地图。

A similar question was asked and answered in another post , but it is completely done in leaflet.js .另一篇文章中提出并回答了类似的问题,但它完全是在leaflet.js完成的。 Converting this solution to something that can be done from within R but without shiny is not as straight forward.将此解决方案转换为可以在R完成但没有shiny事情并不是那么简单。 I know it will involve using htmlwidgets::onRender() and some JavaScript knowledge.我知道这将涉及使用htmlwidgets::onRender()和一些JavaScript知识。

Here is a reprex of a basic plot to add 'reactive' points to:这是添加“反应”点的基本图的再现:

# Load libraries
library(sf)
library(leaflet)

# Grab data sample from the sf package for mapping
nc <- st_read(system.file("shape/nc.shp", package="sf"))

# Set a basic palette 
pal <- colorNumeric("viridis", NULL)

# Create the leaflet widget with R code
nc_map <- leaflet() %>%
  addProviderTiles(providers$CartoDB.Positron) %>% # To get city names
  addPolygons(data = nc,
              fillColor = ~pal(AREA),
              color = 'grey',
              opacity = 1,
              layerId = ~CNTY_ID,
              group = 'Municipality',
              fillOpacity = 0.65,
              weight = 1.5,
              dashArray = '3',
              smoothFactor = 1,
              highlight = highlightOptions( # Make highlight pop out
                weight = 3.5,
                color = '#666',
                dashArray = "",
                fillOpacity = 0.5,
                bringToFront = T),
              popup = ~NAME,
              popupOptions = popupOptions(
                style = list('font-weight' = 'normal', padding = '3px 8px'),
                textsize = '15px',
                maxWidght = 200,
                maxHeight = 250,
                direction = 'auto')) %>%
  addLegend(data = nc, pal = pal, values = ~AREA,
            opacity = 0.7,
            title = 'Area of county',
            position = "bottomleft") 

We can start from @nikoshr's solution using leaflet.js , making a few adjustments to work from R .我们可以从@nikoshr 的解决方案开始,使用leaflet.js ,对R进行一些调整。 Here is the basic idea:这是基本思想:

  • Pass the data-set containing the point information during the onRender() step, and convert to geoJSON .onRender()步骤传递包含点信息的数据集,并转换为geoJSON
  • Use the layerID from addPolygons in your R leaflet widget to track unique polygons, in this case the CNTY_ID .在 R 传单小部件中使用layerIDaddPolygons来跟踪唯一的多边形,在本例中为CNTY_ID
  • Loop through just the polygon layer using a conditional statement ( if(layer instanceof L.Polygon) ).使用条件语句( if(layer instanceof L.Polygon) )仅循环遍历多边形图层。 I had issues if it looped through all layers.如果它循环遍历所有层,我会遇到问题。
  • Create a featureGroup() to add points to dynamically;创建一个featureGroup()来动态添加点; previous solutions used a layerGroup() but this doesn't work with the method .bringToFront()以前的解决方案使用的layerGroup()但是,这并不与法工作.bringToFront()
  • Add an .on('click') command that will add the markers to the specific to the CNTY_ID .添加一个.on('click')命令,将标记添加到特定的CNTY_ID
  • Add an .on('mouseover') command to ensure the marker points are always on top, no matter what the highlight option is chosen in the R widget.添加.on('mouseover')命令以确保标记点始终位于顶部,无论在 R 小部件中选择什么突出显示选项。

Working from the leaflet widget provided in the question above, the following can be added to create the desired map:使用上述问题中提供的传单小部件,可以添加以下内容以创建所需的地图:

library(geojsonsf)

# Custom points to appear in the data (centroids)
nc_centroid <- st_centroid(nc)


nc_map %>%  htmlwidgets::onRender("

function(el, x, data){

var mymap= this;

// Create new group
var featureGroup = L.featureGroup();
mymap.addLayer(featureGroup);

// For each polygon layer...
mymap.eachLayer(function(layer){
  
  if(layer instanceof L.Polygon) {
  
    // Zoom to the clicked area
    layer.on('click', function(e){
      var bbox = e.target.getBounds();
      var sw = bbox.getSouthWest();
      var ne = bbox.getNorthEast();
      mymap.fitBounds([sw, ne]);
      
      // Grab ID from the polygon clicked 
      var clickedPoly = e.sourceTarget.options.layerId;
      
      // Clear prior layer and fill with markers with matching polygon ID
      featureGroup.clearLayers();
      featureGroup.addLayer(L.geoJson(data, {
        
        pointToLayer: function(feature, latlng){
          var markerlayer = L.circleMarker(latlng, { 
            color: '#2e2eb8',
            radius: 7,
            fill: true,
            fillOpacity: .5,
            opacity: .5
          });
          return markerlayer;
        },
        
        // Add labels to the markers
        onEachFeature: function(feature, layer) {
          if (feature.properties && feature.properties.NAME) {
            return layer.bindTooltip(feature.properties.NAME);
          }
        },
        // Keep only counties within the clicked polygon
        filter: function (feature) {
          return feature.properties.CNTY_ID === clickedPoly;
        }
      }));
    });
    
    // Ensure that the markers are always on top
    layer.on('mouseover', function(e){
      featureGroup.bringToFront();
    });
  };  
});
}", data = geojsonsf::sf_geojson(nc_centroid))

This will create a map that shows the popup for the county as well as the point (with tooltip on hover) when the associated polygon is clicked.这将创建一个地图,显示该县的弹出窗口以及单击关联多边形时的点(悬停工具提示)。 The polygon will be highlighted upon mouseover, but will not mask the points.鼠标悬停时多边形将突出显示,但不会掩盖点。

在此处输入图片说明 在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM