Creating Custom Overlay on The Map

Creating Custom Overlay on the map

Okay, I tried to do things on my Own, and put this code to get the above effect:

public class MarkerOverlay extends Overlay {

Geocoder geoCoder = null;

public MarkerOverlay() {
super();
}

@Override
public boolean onTap(GeoPoint geoPoint, MapView mapView){
selectedLatitude = geoPoint.getLatitudeE6();
selectedLongitude = geoPoint.getLongitudeE6();
return super.onTap(geoPoint,mapView);
}

@Override
public void draw(Canvas canvas, MapView mapV, boolean shadow){

if(shadow){
Projection projection = mapV.getProjection();
Point pt = new Point();
projection.toPixels(globalGeoPoint,pt);

GeoPoint newGeos = new GeoPoint(selectedLat+(100),selectedLong); // adjust your radius accordingly
Point pt2 = new Point();
projection.toPixels(newGeos,pt2);
float circleRadius = Math.abs(pt2.y-pt.y);

Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

circlePaint.setColor(0x30000000);
circlePaint.setStyle(Style.FILL_AND_STROKE);
canvas.drawCircle((float)pt.x, (float)pt.y, circleRadius, circlePaint);

circlePaint.setColor(0x99000000);
circlePaint.setStyle(Style.STROKE);
canvas.drawCircle((float)pt.x, (float)pt.y, circleRadius, circlePaint);

Bitmap markerBitmap = BitmapFactory.decodeResource(getApplicationContext().getResources(),R.drawable.pin);
canvas.drawBitmap(markerBitmap,pt.x,pt.y-markerBitmap.getHeight(),null);

super.draw(canvas,mapV,shadow);
}
}
}

This let me have following effect:

Effect on Map

The calculation used may not be what you want.

Its just for demonstration purposes.
Real range/distance calculation requires the use of bearing too and has some specific formula.

Let me know if you have any questions regarding this.

Make custom overlay clickable (Google Maps API v3)

Update for v3: overlayLayer doesn't accept mouse events anymore. Add your overlay to overlayMouseTarget instead, add the listener, and it should receive mouse events normally.

//add element to clickable layer 
this.getPanes().overlayMouseTarget.appendChild(div);

// set this as locally scoped var so event does not get confused
var me = this;

// Add a listener - we'll accept clicks anywhere on this div, but you may want
// to validate the click i.e. verify it occurred in some portion of your overlay.
google.maps.event.addDomListener(div, 'click', function() {
google.maps.event.trigger(me, 'click');
});

See: http://code.google.com/apis/maps/documentation/javascript/reference.html#MapPanes

How to make Google Maps' custom overlay above marker's click zone?

Okay, I found the answer, I have to disable some mouse events on my custom overlay.

google.maps.event.addDomListener(this._div, 'click', function (e) {
e.cancelBubble = true;
e.stopPropagation && e.stopPropagation();
})

Here's the code: https://jsfiddle.net/liangyongning/cd5wbzL8/7/

Reference: Prevent google overlay/infowindow from allowing clicks through to markers underneath

Custom overlay map types and mapTypeControl

Well, looks like there is no native way, to bind an overlay map type to a base map type or to use Googles map type control for overlay map type.

So here is what I have finally done, to work around this issue: http://jsfiddle.net/lejared/720L7wu0/3/

var ReliefCtrl = {/* see fiddle */};

I've build a custom control (with the look an feel of the native Google maps controls). This Control toggles my overlay map type (Hillshading). You can define a array of base map types suitable for this overlay map type. The control will than show/hide itself automatically if a suitable base map type is selected.

2017-02-01: Updates fiddle to match new native look of googles map controls.

Moving a custom overlay in Google Maps javascript API v3

After struggling with this some time (it really took me several hours) I have manage to do it getting inspired by this fiddle:

https://jsfiddle.net/doktormolle/QRuW8/

The functionality is not the same, but I could get some ideas.

Since there is not a lot of documentation I have created my own fiddle with a working (and simplified) example, just in case is useful for anyone:

https://jsfiddle.net/javigbas/3zx5xa2u/

:)

Google map api v3, how to add polygons to custom overlay

If you set clickable:false on the google.maps.Polygons, they will be prevented from intercepting the mouse events.

clickable | boolean | Indicates whether this Polygon handles mouse events. Defaults to true

How to make overlaid POIs in google maps accessible

Basics about Google Maps

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 fundamentals

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.

Bind Overlay to pane

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).

Bind Overlay directly to map

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.

Fundamentals of POIs and Markers

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 (Points of interest)

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:

Sample Image

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

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:

Sample Image

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.

Conclusion so far

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 challenge

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.

What information / experience exists?

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 challenge in 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.

Comment concerning examples on jsfiddle.net

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.

Step 1

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.



Related Topics



Leave a reply



Submit