I'm using Google Maps API to load multiple polygons into the map using the geoJSON data layer. Some of these polygons overlap in certain regions. When a user clicks on a point that is inside of multiple polygons, I want to display the properties (name, tags, etc) in an InfoBox with the click event.
I'm wanting to display the properties of all the polygons for a given point. Currently when I click on a point I can only see one polygon, despite the point being inside of multiple polygons.
How can I access all the properties of all the polygons with Google Maps API v3?
const map = useGoogleMap(); // google map instance
const polygons; // an array of polygons, example snippet below.
map.data.addGeoJson(polygons);
map.data.addListener('click', function(event) {
// how can i access other features underneath this clicked point
console.log(event.feature); // only returns "Geofence 1"
})
example GeoJson:
polygons = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "Geofence 1"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-8.96484375,
-9.96885060854611
],
[
3.955078125,
-9.96885060854611
],
[
3.955078125,
-0.17578097424708533
],
[
-8.96484375,
-0.17578097424708533
],
[
-8.96484375,
-9.96885060854611
]
]
]
}
},
{
"type": "Feature",
"properties": {
"name": "Geofence 2"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-6.591796875,
-8.320212289522944
],
[
2.197265625,
-8.320212289522944
],
[
2.197265625,
-1.9332268264771106
],
[
-6.591796875,
-1.9332268264771106
],
[
-6.591796875,
-8.320212289522944
]
]
]
}
},
{
"type": "Feature",
"properties": {
"name": "Geofence 3"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-4.39453125,
-6.926426847059551
],
[
0.263671875,
-6.926426847059551
],
[
0.263671875,
-3.337953961416472
],
[
-4.39453125,
-3.337953961416472
],
[
-4.39453125,
-6.926426847059551
]
]
]
}
}
]
}
One option would be to use the containsLocation method in the geometry library.
containsLocation(point, polygon) Parameters:
point: LatLng
polygon: Polygon
Return Value: boolean
Computes whether the given point lies inside the specified polygon.
Unfortunately that only works with native google.maps.Polygon
objects not Data.Polygon
objects. Translate the data in the feature into native google.maps.Polygon
objects, push them on an array, then process through the array to see which polygon(s) the click is in.
google.maps.Polygon
for each polygon in the input (assumes only polygons) var polygonArray = [];
map.data.addListener('addfeature', function(e) {
e.feature.getGeometry().getArray().forEach(function(latLngArry){
const polygon = new google.maps.Polygon({
map: map,
paths: latLngArry.getArray(),
clickable: false,
name: e.feature.getProperty("name") // save the data we want to output as an attribute
})
polygonArray.push(polygon);
})
map.addListener('click', function(event) {
var content = "";
for (var i=0;i<polygonArray.length;i++) {
if (google.maps.geometry.poly.containsLocation(event.latLng, polygonArray[i])) {
if (content.length!=0)
content+=" : "
content += polygonArray[i].name;
}
}
console.log(content);
})
// This example uses the Google Maps JavaScript API's Data layer
// to create a rectangular polygon with 2 holes in it.
function initMap() {
const map = new google.maps.Map(document.getElementById("map"));
const infowindow = new google.maps.InfoWindow();
var bounds = new google.maps.LatLngBounds();
var polygonArray = [];
map.data.addListener('addfeature', function(e) {
console.log(e.feature.getGeometry().getArray().length);
e.feature.getGeometry().getArray().forEach(function(latLngArry) {
console.log(latLngArry.getArray())
const polygon = new google.maps.Polygon({
map: map,
paths: latLngArry.getArray(),
clickable: false,
name: e.feature.getProperty("name")
})
polygonArray.push(polygon);
})
processPoints(e.feature.getGeometry(), bounds.extend, bounds);
map.fitBounds(bounds);
});
const features = map.data.addGeoJson(polygons);
map.data.setMap(null);
map.addListener('click', function(event) {
var content = "";
for (var i = 0; i < polygonArray.length; i++) {
if (google.maps.geometry.poly.containsLocation(event.latLng, polygonArray[i])) {
if (content.length != 0)
content += " : "
content += polygonArray[i].name;
}
}
console.log(content);
document.getElementById('info').innerHTML = content;
infowindow.setPosition(event.latLng);
if (content.length == 0) content = "no GeoFence";
infowindow.setContent(content);
infowindow.open(map);
})
function processPoints(geometry, callback, thisArg) {
if (geometry instanceof google.maps.LatLng) {
callback.call(thisArg, geometry);
} else if (geometry instanceof google.maps.Data.Point) {
callback.call(thisArg, geometry.get());
} else {
geometry.getArray().forEach(function(g) {
processPoints(g, callback, thisArg);
});
}
}
}
const polygons = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"name": "Geofence 1"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-8.96484375, -9.96885060854611],
[
3.955078125, -9.96885060854611
],
[
3.955078125, -0.17578097424708533
],
[-8.96484375, -0.17578097424708533],
[-8.96484375, -9.96885060854611]
]
]
}
},
{
"type": "Feature",
"properties": {
"name": "Geofence 2"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-6.591796875, -8.320212289522944],
[
2.197265625, -8.320212289522944
],
[
2.197265625, -1.9332268264771106
],
[-6.591796875, -1.9332268264771106],
[-6.591796875, -8.320212289522944]
]
]
}
},
{
"type": "Feature",
"properties": {
"name": "Geofence 3"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-4.39453125, -6.926426847059551],
[
0.263671875, -6.926426847059551
],
[
0.263671875, -3.337953961416472
],
[-4.39453125, -3.337953961416472],
[-4.39453125, -6.926426847059551]
]
]
}
}
]
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 90%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<title>Data Layer: Polygon</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=&v=weekly" defer></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="info"></div>
<div id="map"></div>
</body>
</html>