Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a text overlay in Google Maps API v3 that does not pan?

I'm using Google Maps API v3. I would like to create a text overlay on a map that does not move when the map is panned. Is the best approach to manipulate the DOM elements accessible from the MapPanes object or is it best to create a custom control even though it would not do much other than display text?

like image 507
DaveBurns Avatar asked Feb 24 '11 02:02

DaveBurns


2 Answers

The simplest way that I found worked for me was a few lines of JavaScript added after I created a new map. So, after this:

map = new google.maps.Map('myMapDivId', mapOptions);

add this:

var myTitle = document.createElement('h1');
myTitle.style.color = 'white';
myTitle.innerHTML = 'Hello World';
var myTextDiv = document.createElement('div');
myTextDiv.appendChild(myTitle);

map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(myTextDiv);

You will probably want to style the text to look nicer.

An alternative is to put the div in your HTML:

<div id="myTextDiv" style="color: white; position: absolute;">
    <h1>Hello World</h1>
</div>

and then do this in your JavaScript:

var myControl = document.getElementById('myTextDiv');
map.controls[google.maps.ControlPosition.TOP_CENTER].push(myControl);

NOTE an important difference: If you use the HTML route to define your div, you must set the position style to absolute in the HTML to avoid rendering problems.

like image 126
DaveBurns Avatar answered Oct 06 '22 08:10

DaveBurns


From you're describing, the best approach would be a custom control. Docs for that are here. Custom controls can be as simple or a complicated as you want.

One reason why you would want to muck around with the map panes is if you wanted such a 'control' to lie underneath the markers / shadows / polylines etc. I'm doing this right now to show a crosshairs in the center of the map at all times. But because I keep it as an overlay, I choose the panes in such a way that the markers are above it, so they can continue to be clicked and interacted with - using the mapPane. Here's how I'm doing it:

var CrosshairOverlay = function(map){
    this._holder = null;
    this.setMap(map);
};
CrosshairOverlay.prototype = new google.maps.OverlayView();
CrosshairOverlay.prototype.onAdd = function(){
    var map = this.getMap();
    var holder = this._holder = $('<div>').attr('id', 'crosshair')[0];

    var crosshairPaper = this._paper = R(holder, 150, 150);
    // ... all your drawing and rendering code here.
    var projection = this.getProjection();
    var wrappedHolder = $(holder);

    var updateCrosshairPosition = function(){
        var center = projection.fromLatLngToDivPixel(map.getCenter());
        wrappedHolder.css({left:center.x-75, top:center.y-75});
    }
    _.each(['drag','dragend','bounds_changed','center_changed','zoom_changed','idle','resize'], function(event){            
        google.maps.event.addListener(map, event, updateCrosshairPosition);
    });
    google.maps.event.addListener(map, 'maptypeid_changed', function(){
        _.defer(updateCrosshairPosition);
    });

    this.getPanes().mapPane.appendChild(holder);
};
CrosshairOverlay.prototype.draw = function(){
};
CrosshairOverlay.prototype.onRemove = function(){
    this._holder.parentNode.removeChild(this._holder);
    this._holder = null;
};

The reason the maptypeid_changed has its own handler with a defer is because that event is fired before the map properly sets itself up when changing the type. Just run your function after the current event loop.

like image 41
Sudhir Jonathan Avatar answered Oct 06 '22 10:10

Sudhir Jonathan