如何在 Google 地图 API 中创建图例?

How do I create a legend in Google Maps API?

我正在使用具有 172 个特征点的非常长的 GEOJSON 文件。我使用 7 个类别对它们进行了分类,并尝试使用结果数据创建图例。我遇到了一些目前无法弄清楚的错误。

  1. CSS 中的图例格式无效。
  2. 圆圈不起作用(显示为正方形且未填充填充颜色)。

代码如下:

<style>
    #map {height: 100%; width:100%;}
    html,body { padding:0; margin:0; height:100%; }
    .gm-style .gm-style-iw {
        font-size: 14px;
        font-family: sans-serif;
        padding-top: 20px;
        padding-right: 20px;
        padding-bottom: 20px;
        padding-left: 20px;
    }
</style>
<script>

    var map;

    function getIcons(HospStrk) {
        var HospType = ""; // marker fill colour
        var HospSize = 0; // marker size
 
        switch (true) {
            case ( HospStrk == 'Regional Stroke Centre'): HospType = '#88419D'; HospSize = 14; break;   
            case ( HospStrk == 'Designated District Stroke Centre'): HospType = '#8C96C6'; HospSize = 12; break;
            case ( HospStrk == 'TeleStroke'): HospType = '#B3CDE3'; HospSize = 10; break;
            case ( HospStrk == 'Non Designated Stroke Hospital with Stroke Services'): HospType = '#EDF8FB'; HospSize = 8; break;
            case ( HospStrk == 'Only Emergency Department Services'): HospType = '#2CA25F'; HospSize = 6; break;
            case ( HospStrk == 'Nursing Stations / Non-ED Sites'): HospType = '#99D8C9'; HospSize = 5; break;
            case ( HospStrk == 'Unknown'): HospType = '#525252'; HospSize = 4; break;
        } 
        
        return {
            path: google.maps.SymbolPath.CIRCLE,
            scale: HospSize,
            fillColor: HospType,
            fillOpacity: 1,
            strokeWeight: .1,
            name: HospStrk,

        };
    };

    function makeLegend(map) {
        var legendmap = {
            cat1: {ServiceType: "Regional Stroke Centre"},
            cat2: {ServiceType: "Designated District Stroke Centre"},
            cat3: {ServiceType: "TeleStroke"},
            cat4: {ServiceType: "Non Designated Stroke Hospital with Stroke Services"},
            cat5: {ServiceType: "Only Emergency Department Services"},
            cat6: {ServiceType: "Nursing Stations / Non-ED Sites"},
            cat7: {ServiceType: "Unknown"}
        };
        var icons = [];
        var cnt=0;
        // Construct the circle for each value in legendmap.
        for (var entry in legendmap) {
            // Add the circle for this entry to the map.
            var icon = getIcons(legendmap[entry].ServiceType);
            icons[cnt] = icon;
            cnt++;
        };
            
        var legend = document.getElementById('legend');
        legend.style.backgroundColor = '#fff';
        legend.style.border = '3px solid #000';
        legend.style.padding = '10px';
        legend.style.margin = '10px';

        var sheet = document.createElement('style')
        sheet.innerHTML="div{font-family: sans-serif; font-size: 12;}"
        legend.appendChild(sheet);
        var tbl = document.createElement('table');
        var tblBody =document.createElement('tbody');

        for (let i = 0; i < icons.length; i++) { 
            var type = icons[i];
            var name = type.name;
            var icon = type.icon;
            var scale = type.scale;
            var opacity = type.fillOpacity;
            var fColor = type.fillColor;
            
            var row = document.createElement('tr');
            var cell = document.createElement('td');    
            var img  = document.createElement('div');
            img.innerHTML="<svg viewBox=\"0 0 100 100\" height=\"" + scale*2 + "\" width=\"" + scale*2 + "\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"50\" cy=\"50\" r=\"50\" style=\"fill: "+ fColor +"; stroke-width: 1;\" opacity=\"" + opacity + "\"/></svg>";
            cell.appendChild(img);
            row.appendChild(cell);
            var cell = document.createElement('td');
            var span = document.createElement('span');
            span.style.fontSize = "12px";
            span.appendChild(document.createTextNode(name));
            cell.appendChild(span);
            row.appendChild(cell);

            tblBody.appendChild(row);
        };

        tbl.appendChild(tblBody);
        
        legend.appendChild(tbl);
        
        // add the created legend to the map
        map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(legend);
    };

    function initMap() {
        const mapDiv = document.getElementById("map");
        const originalMapCenter = new google.maps.LatLng(45.870774886089386, -79.33149271169445);
        const map = new google.maps.Map(mapDiv, {
            zoom: 6,
            center: originalMapCenter, 
            });
        
        var hosp = new google.maps.Data({map: map});
        hosp.loadGeoJson('./Hospitals.json');

        hosp.setStyle(function(feature) {
            var HospStrk = feature.getProperty('ServiceType'); 
            return {
                icon: getIcons(HospStrk)
            };                  
        }); 

        makeLegend(map);

    }

</script>

这是 geojson 文件的片段:

{
  "type" : "FeatureCollection",
  "features" : [
    {
      "type" : "Feature",
      "id" : 1,
      "geometry" : {
        "type" : "Point",
        "coordinates" : [
          -82.390372739999975,
          42.977287040000078
        ]
      },
      "properties" : {
        "OBJECTID" : 1,
        "LHIN_Institution__Site_" : "Bluewater Health - Sarnia General Site",
        "Name" : "Bluewater Health - Sarnia General Site",
        "LHIN" : "Erie St. Clair LHIN",
        "Location" : "Sarnia",
        "StrokeNetwork" : "Southwestern Ontario",
        "Address" : "89 Norman St, Sarnia, Ontario N7T 6S3",
        "Email" : null,
        "Phone" : null,
        "Website" : "https://www.bluewaterhealth.ca/programs-services/cardiac-care/sarnia-lambton-district-stroke-centre-stroke-prevention-clinic",
        "StrokeServices" : "Stroke Services Available",
        "ServiceType" : "Designated District Stroke Centre",
        "TeleStroke" : "No",
        "Refer_HyperAcute" : null,
        "Refer_SecStrokePrev" : null,
        "Refer_IPAcuteStrokeCare" : null,
        "Refer_EndovascularTreatment" : "London Health Sciences Centre - University",
        "Refer_StrokeAdmission" : null,
        "Refer_TelestrokeEVT" : null,
        "NonDesignatedStrokeServices" : "No",
        "Refer_NonDesignatedEVT" : "No",
        "NonDesignatedStrokeHospital" : null,
        "EVT" : "No",
        "TeleStrokeUser" : "Yes",
        "HyperAcute" : "Yes",
        "SSPC" : "Yes",
        "AcuteStrokeIP" : "No",
        "AcuteStrokeUnit" : "Yes",
        "StrokeRehabInPatient" : "Yes",
        "Ref_IPStrReh_Name" : null,
        "OutpatientStrokeRehab" : "Yes",
        "CommunityStrokeRehab" : "No"
      }
    },
    {
      "type" : "Feature",
      "id" : 2,
      "geometry" : {
        "type" : "Point",
        "coordinates" : [
          -82.147076289999973,
          42.878295480000077
        ]
      },
      "properties" : {
        "OBJECTID" : 2,
        "LHIN_Institution__Site_" : "Bluewater Health - Health-Petrolia Site",
        "Name" : "Bluewater Health - Health-Petrolia Site",
        "LHIN" : "Erie St. Clair LHIN",
        "Location" : "Petrolia",
        "StrokeNetwork" : "Southwestern Ontario",
        "Address" : "450 Blanche St, Petrolia, Ontario N0N 1R0",
        "Email" : null,
        "Phone" : null,
        "Website" : null,
        "StrokeServices" : "No Stroke Services Available",
        "ServiceType" : "Only Emergency Department Services",
        "TeleStroke" : "No",
        "Refer_HyperAcute" : "Bluewater Health - Sarnia General Site",
        "Refer_SecStrokePrev" : "Bluewater Health - Sarnia General Site",
        "Refer_IPAcuteStrokeCare" : "Bluewater Health - Sarnia General Site",
        "Refer_EndovascularTreatment" : null,
        "Refer_StrokeAdmission" : null,
        "Refer_TelestrokeEVT" : null,
        "NonDesignatedStrokeServices" : "No",
        "Refer_NonDesignatedEVT" : "No",
        "NonDesignatedStrokeHospital" : null,
        "EVT" : "No",
        "TeleStrokeUser" : "No",
        "HyperAcute" : "No",
        "SSPC" : "No",
        "AcuteStrokeIP" : "No",
        "AcuteStrokeUnit" : "No",
        "StrokeRehabInPatient" : "No",
        "Ref_IPStrReh_Name" : null,
        "OutpatientStrokeRehab" : "No",
        "CommunityStrokeRehab" : "No"
      }
    }
]

<circle><img data 属性一起嵌入到 <svg> 中对我不起作用,即使只是尝试在 HTML 中简单地输出:

<img src='data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" height="50" width="50" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50" style="fill: #EDF8FB; stroke-width: 1;" opacity="1"/></svg>'>

但是删除周围的 <img 是有效的,这对我适用于你的地图:

div.innerHTML = "<svg viewBox=\"0 0 100 100\" height=\"" + scale + "\" width=\"" + scale + "\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"50\" cy=\"50\" r=\"50\" style=\"fill: "+ fColor +"; stroke-width: 1;\" opacity=\"" + opacity + "\"/></svg> " + name;

它仍然没有采用您在 <style> 块中定义的样式。 https://developers.google.com/maps/documentation/javascript/controls#CustomControls给出的例子都是用JS定义了CSS规则。

然后这样做就成功了:

legend.style.backgroundColor = '#fff';
legend.style.border = '3px solid #000';
legend.style.padding = '10px';
legend.style.margin = '10px';

也就是说,geocodezip 在 的示例不需要以这种方式设置 CSS 的样式,所以上面还有其他内容。

更新: 解决由于多个图标具有相同比例而导致的问题。你在代码中有这个:

icons[icon.scale] = icon;

因此它会覆盖 icons 中具有相同比例的所有内容的相同值,只会以最后一个图标的值结束。所以你多次设置 icons[6]

icons 是一个数组,但您将其视为一个对象,其中每个元素可能都有一个唯一的键。

相反,您只需要追加到数组中:

icons.push(icon);

然后你在数组上循环的方式应该改变。目前它正在使用 var key in icons 方法,该方法适用于对象中的键。

改为:

for (let i = 0; i < icons.length; i++) { 
   var type = icons[i];

我在那里看到一个问题,它不再按您期望的升序排列。为此,快速排序解决了这个问题:

icons.sort(function(icon1, icon2) {
    return icon1.scale > icon2.scale;
});