The common POIs in g-maps are shown fixed on the tiles but seemingly clickable by overlaid links. When I make a transparent map-overlay the POI-links are still visible but not clickable anymore.
The problem might get more clear with a screenshot, the right POI I can only click in the top right area beside the darker overlay:
I tried already to bind the overlay to the layer with the lowest z-index, without success though:
mapPane z-index:100
overlayLayer z-index:101
floatPane z-index:102
markerLayer z-index:103
overlayImage z-index:104
floatShadow z-index:105
overlayMouseTarget z-index:106
floatPane z-index:107
const panes = this.getPanes();
panes.mapPane.appendChild(this.div_);
I know that contrary to markers the API-support for POIs is limited and at least partially bound to the places API. Nevertheless, I'd prefer the approach concerning z-index or some other method to handle POIs more general, so that I never have to use additional APIs and that the solution works for all shown POIs.
For markers the method setZIndex
exists, but that seems not to help here: Marker API
I'm aware of the situation that on higher resolutions more POIs are shown, this has no impact to the problem though.
So how to make POI-links below an overlay in g-maps clickable?
EDIT:
Based on the answers
I think the problem is nearly solved. Due to the answer and comment of @Brett Donald I found some fault in my own SVG-code and realized that the markup is not completely created by g-map but that the SVGs are indeed created / provided by myself.
In the individual class class USGSOverlay extends google.maps.OverlayView
I've the option to add the required code to achieve my target. I also realized that this class is essential to solve the problem.
In the example which is mentioned in the one linked answer not all click-events behind the overlay are possible, so it's possible to open windows by click on POIs but not to close them again behind the layer.
I will give the bounty to the one who can enrich the linked example with the option to close the info windows behind the overlay.
Google Maps (may) consist of many layers which are hard to verify in the browser console. I marked the outer map layer in the console and copied the whole html which is produced by JavaScript in an editor, so it's easier to verify and to search for expected elements like markers or overlays.
Nevertheless, debugging objects like map, markers or overlays can be done very well by console.log()
.
Concerning layers with z-index there is, like mentioned in the question, a clear structure. But z-index as well as the content of each layer can be adjusted (or not used) and I doubt that it's useful to show the general structure in detail without concrete use-case. So any according details are directly related to the question.
Overlays can be done on many levels, there exists also a special class google.maps.GroundOverlay
which is sorted directly above the map. To get an overview about objects and methods related to overlay a good start is just to search for the word overlay
in the listing with classes and properties.
A common way to realize overlays is to create the definition based on google.maps.OverlayView
and to bind the overlay to a pane:
class USGSOverlay extends google.maps.OverlayView {
bounds_;
image_;
div_;
constructor(bounds, image) { ... }
onAdd() {
this._div = document.createElement('div');
...
const panes = this.getPanes();
// inding overlay to a pane,
// `mapPane` can be exchanged by a different existing pane:
panes.mapPane.appendChild(this.div_);
...
}
draw() { ... }
onRemove() { ... }
}
overlay = new USGSOverlay(map);
overlay.setMap(map);
This procedure will bind the map to a predefined pane which usually has the z-index like listed in the question (range of default z-index from 100 to 107).
It's also possible to bind an overlay independent of the panes to a map, then it will be directly above the map if no distinct z-index is defined. This method is used in the linked example. The example is using the prototype so it's a bit more complicated but essentially is done like this:
class MyOverlay extends google.maps.OverlayView {
...
onAdd() {
// NO binding like `panes.mapPane.appendChild(this.div_);`
}
...
}
overlay = new MyOverlay(map);
overlay.setMap(map);
The choice which method is used might have impact on the produced html in the map but in any case has impact to the z-index. So whatever the target of any manipulation is beyond this choice, it has impact on further proceedings.
POIs (Points of interest) in google maps are handled completely differently and have in most cases different z-indexes too. The functionality for the user might be the same though.
POIs can be en- or disabled with the settings:
const styles = {
default: [],
hide: [
{featureType: "poi.attraction", stylers: [{ visibility: "off" }]},
{featureType: "poi.business", stylers: [{ visibility: "off" }]},
{featureType: "poi.government", stylers: [{ visibility: "off" }]},
{featureType: "poi.medical",stylers: [{ visibility: "off" }]},
{featureType: "poi.park",stylers: [{ visibility: "off" }]},
{featureType: "poi.place_of_worship", stylers: [{ visibility: "off" }]},
{featureType: "poi.school", stylers: [{ visibility: "off" }]},
{featureType: "poi.sports_complex", stylers: [{ visibility: "off" }]},
],
};
map.setOptions({ styles: styles["hide"] });
Images of POIs are directly "printed" on the map tiles which are just png-images. POIs can't be moved and beyond a click function to open an info-window they usually have no direct functionality on the map (they might be connected though with advanced map options).
This is an image directly copied from g-map including a POI:
Concerning functionality POIs are a combination of Image and HTML-Markup, which are both not directly combined in the HTML source but logically combined by position on the map.
Markers can have individual functions, individual design and some can be also dragged to other locations if the map supports it. They have a different standard design and can have a different z-index than POIs, furthermore they have an own API which also allows to change the z-index.
This is a standard marker:
While Images of POIs are always underneath any overlay, Markers can be shown above overlays, which also has some impact to juggling with z-indexes in comparison.
There are many layers with different z-indexes and more could probably easily created. Many challenges concerning google maps relate to the z-index and the sorting in the html source, so binding elements to the right layer is likely the solution for many cases.
The primary part of the challenge is to create overlays and enabling the clicks on POIs and their info-windows below these overlays. It might be considerable to display the info-windows above the overlays.
The second part of the challenge is to display markers and their info-windows above the overlays. This seems to be much easier than the first part.
This question was how to disable mouse events below an overlay and currently I've the impression it's answer is way to complicated as it would be possible just to raise the z-index of the overlay to avoid mouse events by binding it to a pane. Nevertheless I'm quite glad about question beside answers as the site shines a light on several details.
Also the short example is quite useful to see things in action and to verify some details.
The example shows that the overlays never prevent click events on POIs below overlays that are bound directly to the map in contrast to any pane.
Nevertheless the info windows can't be closed and so the info windows are a challenge by themselves.
Placing marker on top of the overlay should be easy by binding them to a pane.
So the overlay shall be bound directly to the map, markers to a pane.
Options concerning info windows for POIs are not clear yet, they shall be shown above the overlay or else at least be closable.
It might be still to verify if the behavior of and related to the overlay is always the same if it's built by svg, by html markup or by path i.e with the polygon option.
Local code and code on jsfiddle.net behave a bit different and are not 100% consistent in behavior. So jsfiddle.net is good to show running examples but the code has to be changed perhaps or just used in another variant. If something is not working on jsfiddle.net, try it on your own server first before commenting.
As the linked question was about preventing what I want to achieve, first the individual event handlers in the example / answer have to be deactivated.
Furthermore the definition this._div.style.zIndex = 1000;
can be deactivated to get the option to close open info-windows.
Strange seems to be that info-windows are not always overlaid, but sometimes on top of the overlay, sometimes below. This should be consistent, at best above the overlay. Another issue is that the info windows are not always closable but in most cases when I tried (On jsfiddle.net this does not work).
The small changes can be seen here in action.
Here is the full code for testing on the own server, add your own API key in the bottom of the file in the variable "googleApiKey":
<!doctype html>
<html>
<head>
<title>Example for clickevents</title>
<style>
html, body {height: 100%;margin: 0;padding: 0;}
#googleMap {height: 70%; width:100%}
</style>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<script
type="application/javascript"
src="//code.jquery.com/jquery-2.1.3.js"
></script>
</head>
<body>
<div id="googleMap"></div>
<div id="message"></div>
<script>
let map;
function log(msg) {
//console.log(msg);
document.getElementById('message').innerHTML += msg + '<br>';
}
function initMap() {
var mapProp = {
center: new google.maps.LatLng(51.508742, -0.120850),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
let myMarkers = [];
myMarkers['marker1'] = new google.maps.Marker({
position: new google.maps.LatLng(51.506742, -0.120850),
map: map,
title: "MARKER 1",
});
myMarkers['marker2'] = new google.maps.Marker({
position: new google.maps.LatLng(51.510742, -0.120850),
map: map,
title: "MARKER 2",
});
for (currentMarker in myMarkers) {
var marker = new google.maps.Marker({
position: myMarkers[currentMarker].position,
map: map,
title: myMarkers[currentMarker].title,
// icon: icon,
});
}
var infowindow = new google.maps.InfoWindow({
content: 'Welcome to Google! Thanks for using our products and services (“Services”). The Services are provided by Google Inc. (“Google”), located at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.By using our Services, you are agreeing to these terms. Please read them carefully.Our Services are very diverse, so sometimes additional terms or product requirements (including age requirements) may apply. Additional terms will be available with the relevant Services, and those additional terms become part of your agreement with us if you use those Services.'
});
myMarkers['marker1'].addListener('click', function () { infowindow.open(map, myMarkers['marker1']); });
myMarkers['marker2'].addListener('click', function () { log('marker2 clicked'); });
MyOverlay.prototype = new google.maps.OverlayView; //extends google.maps.OverlayView {
function MyOverlay(map) {
this._div = document.createElement('div');
this._div.style.background = 'rgba(0, 0, 60, 0.2)';
this._div.style.position = 'absolute';
// this._div.style.zIndex = 1000;
this._div.style.width = '100%';
this._div.style.height = '200px';
this.listeners = [];
this.setMap(map);
}
const overlay = new MyOverlay(map);
// const overlay = new MyOverlay;
MyOverlay.events = [
'mousedown', 'mousemove', 'mouseover',
'mouseout', 'mouseup', 'mousewheel',
'DOMMouseScroll', 'touchstart', 'touchend',
'touchmove', 'dblclick', 'contextmenu'
];
MyOverlay.prototype.onAdd = function () {
var self = this;
this.getPanes().floatPane.appendChild(this._div);
this.listeners = MyOverlay.events.map(function (event) {
console.log({map:map,event:event});
myMarkers['marker1'].addListener('mousedown', function () { log('marker1 clicked'); });
});
};
MyOverlay.prototype.onRemove = function () {
this.getPanes().floatPane.removeChild(this._div);
};
MyOverlay.prototype.draw = function () {
myMarkers['marker1'].addListener('mousedown', function () { log('marker1 clicked'); });
};
overlay.setMap(map);
console.log(overlay);
}
window.initMap = initMap;
googleApiKey = '';
</script>
<script
src="https://maps.googleapis.com/maps/api/js?key=" + googleApiKey + "&callback=initMap&v=weekly&channel=2®ion=DE&language=de"
async defer
></script>
</body>
</html>
So actually my own initial question how to make POIs accessible is answered, I will answer on more details I mentioned above in "The challenge" later by extending this answer.