First, create the Label class and place it in a label.js file.
// Define the overlay, derived from google.maps.OverlayView
function Label(opt_options) {
// Initialization
this.setValues(opt_options);
// Label specific
var span = this.span_ = document.createElement('span');
span.style.cssText = 'position: relative; left: -50%; top: -8px; ' +
'white-space: nowrap; border: 1px solid blue; ' +
'padding: 2px; background-color: white';
var div = this.div_ = document.createElement('div');
div.appendChild(span);
div.style.cssText = 'position: absolute; display: none';
};
Label.prototype = new google.maps.OverlayView;
// Implement onAdd
Label.prototype.onAdd = function() {
var pane = this.getPanes().overlayLayer;
pane.appendChild(this.div_);
// Ensures the label is redrawn if the text or position is changed.
var me = this;
this.listeners_ = [
google.maps.event.addListener(this, 'position_changed',
function() { me.draw(); }),
google.maps.event.addListener(this, 'text_changed',
function() { me.draw(); })
];
};
// Implement onRemove
Label.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
// Label is removed from the map, stop updating its position/text.
for (var i = 0, I = this.listeners_.length; i < I; ++i) {
google.maps.event.removeListener(this.listeners_[i]);
}
};
// Implement draw
Label.prototype.draw = function() {
var projection = this.getProjection();
var position = projection.fromLatLngToDivPixel(this.get('position'));
var div = this.div_;
div.style.left = position.x + 'px';
div.style.top = position.y + 'px';
div.style.display = 'block';
this.span_.innerHTML = this.get('text').toString();
};
Then use label.js in the map initialization:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Label Overlay Example</title>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="label.js"></script>
<script type="text/javascript">
function initialize() {
var latLng = new google.maps.LatLng(40, -100);
var map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 5,
center: latLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = new google.maps.Marker({
position: latLng,
draggable: true,
map: map
});
var label = new Label({
map: map
});
label.bindTo('position', marker, 'position');
label.bindTo('text', marker, 'position');
};
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="height: 100%; width: 100%"></div>
</body>
</html>
When run, it looks like this:

Drag the marker around and the text of the label with update with the LatLng of the marker.
18 comments:
I'm new to javascript and the google map api. How would I pass text to the label instead of the lat/lng?
No, always assign a LatLng object where a latlng is required such as:
var latLng = new google.maps.LatLng(40, -100);
or bind the value to the latlng of another object such as:
label.bindTo('position', marker, 'position');
I probably misunderstood your question. Regarding the 'text' value of the Label object, you can assign any string value, such as:
label.set('text', 'the text for my label');
Thanks for the fast reply!
After creating the map, marker and label, I should do:
label.bindTo('position', marker, 'position');
label.set('text','this is the text label');
I having a hard time grasping javascript conventions and don't understand what the bindTo or set really do.
I guess I have a bit more learning to do.
Can you explain what you are trying to do?
This blog describe a "Label" class. This class lets you place a label on the map at any LatLng position. So far example, to place a label above Paris, France, you could add the following code:
var parisLabel = new Label({map: map});
parisLabel.set('position', new google.maps.LatLng(48.866667, 2.333333));
parisLabel.set('text', 'Paris, France');
In the blog, I show how to get the label to move with the marker i.e. I have a draggable marker on the map and as the marker is dragged, a label is moved with it and the text of the label contains the current LatLng of the marker.
To do this I 'bind' the position and text of the label to the position of the marker. So when the position of the marker changes, the change is reflected in the position and text of the label.
'set' and 'bindTo' are methods of the MVCObject used in the google Maps API v3. Map, Marker and OverlayView all derive from this object and inherit these methods. You can read more about it in the Maps API v3 documentation http://code.google.com/apis/maps/documentation/v3/reference.html#MVCObject
For example, if we have:
var a = new google.maps.MVCObject;
var b = new google.maps.MVCObject;
b.bindTo('x', a, 'x');
if we do:
a.set('x', 5);
then
b.get('x') returns 5.
and similarly, if we do:
b.set('x', 2);
then
a.get('x') returns 2.
the values 'x' of a and b are 'bound' together.
By the way, this is not JavaScript convention, it's implemented in the google.maps.MVCObject.
What I'm doing is displaying a set of markers, but I want the marker labeled with text, not limited to the single character. Your "Label" class is perfect!
I thought the bindTo was a Javascript method, but now that you showed me they are part of the MVCObject makes a bit more sense. I guess I did not read the docs on the MVCObject enough.
With your help, I have now the prototype completed and can move on.
Thanks for taking the time to answer my questions an help me out.
Hello. Thanks for this post, it has really pointed me in the right direction.
I'm struggling with setting up multiple event listeners on multiple labels. I have multiple labels, but the click event that happens is always the last one set, rather than the event for the particular label that has been clicked on.
Some code:
Label.prototype.onAdd:
google.maps.event.addDomListener(this.div_, "click", function(event) {
google.maps.event.trigger(me, "click");
});
In my setlabel function:
google.maps.event.addListener(label, "click", function() {
map.setZoom(13);
map.panTo(latlng);
});
The latlng that is triggered is always the last one set. Can you help?
Thanks.
Hi Martin,
I'll need more information to help you. Are you able to post a link to a test page?
Also for general questions, I would suggest you post into the Maps Javascript API v3 forum so the answer to your question benefits the next developer having a similar problem.
http://groups.google.com/group/google-maps-js-api-v3/
Thanks
Hi Marc,
how can I hide/show a label the same time i hide/show a marker?
unfortunately I can't seem to get it right...
Thanks,
Cosmin
You need to bind the visible property of the marker to the label and use it to show/hide the label.
For example:
1. After the line "label.bindTo('text', marker, 'position');", add this line of code:
label.bindTo('visible', marker, 'visible');
2. Before the line "google.maps.event.addListener(this, 'text_changed',function() { me.draw(); })", add this line of code:
google.maps.event.addListener(this, 'visible_changed', function() { me.draw(); }),
3. Change the line "div.style.display = 'block';" to
var visible = this.get('visible');
div.style.display = visible ? 'block' : 'none';
Some explanations:
- The first change will ensure that the visible property of the marker is sync'ed to the label. Effectively adding a property to the label called 'visible' with the same value as the marker visible property.
- The second change ensures that we listen to the visible_changed event triggered when the visible property is changed and we ask to redraw the label.
- Finally the last change ensures that the display style is set according to the current value of the visible property.
I hope this helps.
great!
i was missing step 3 :)
thanks a lot ;)
There seems to be a tiny error in the code:
maps.google.event.removeListener(this.listeners_[i]);
I guess it should be:
google.maps.event.removeListener(this.listeners_[i]);
Thanks for the example
Btw I am having horrible problems removing the label. It should be removed when the marker is removed right ? I have made the binding:
label.bindTo('map', marker, 'map');
If I call marker.setMap(null) in the same method I created the marker and label in, it works like a charm. Both are removed.
Then I created a global variable to hold my marker and a button which would run the globalMarker.setMap(null).
But that does not work. I thought maybe the label object is garbagecollected at the end of the function so I created a globalLabel as well. but no luck.
I know this isnt due to your example but rather a javascript question in general. But does anyone know why this is and how to fix it?
Thanks Viktor. Error corrected.
Also if you have a test page on the label removal problem, i'll have a look.
Hello
I noticed that if I remove the label instead, the marker will also be removed. But since the position is updated when moving marker I assumed the map-param would be too.
Here is my example:
http://frankyboy.se/test/mymap_delete.html
To remove the label without removing the marker, you need to unbind to label and marker first such as:
myLabel.unbind('map');
myLabel.setMap(null);
myLabel = null;
If the marker's map and the label's map are bound together. calling setMap on either of them should be like calling setMap on both of them.
What I want to do is to remove them both by removing the marker. So if I remove the marker, I expect the label to be removed as well. And that is what I cannot get to work.
As you see in the example, pressing "remove marker" only removes the marker and not marker && label.
Post a Comment