如何在 Google 地图 API 中创建图例?
How do I create a legend in Google Maps API?
我正在使用具有 172 个特征点的非常长的 GEOJSON 文件。我使用 7 个类别对它们进行了分类,并尝试使用结果数据创建图例。我遇到了一些目前无法弄清楚的错误。
- CSS 中的图例格式无效。
- 圆圈不起作用(显示为正方形且未填充填充颜色)。
代码如下:
<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;
});
我正在使用具有 172 个特征点的非常长的 GEOJSON 文件。我使用 7 个类别对它们进行了分类,并尝试使用结果数据创建图例。我遇到了一些目前无法弄清楚的错误。
- CSS 中的图例格式无效。
- 圆圈不起作用(显示为正方形且未填充填充颜色)。
代码如下:
<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 在
更新: 解决由于多个图标具有相同比例而导致的问题。你在代码中有这个:
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;
});