Wednesday, September 30, 2009

Listening to map events in Google Maps API v3 OverlayView

In my previous post, I showed how to create a simple Label overlay. In that example, the draw method was only called when the position of the overlay relative to the map needed to be recalculated or when the text for the label had changed.

But what if the look/content of the overlay you want to create depends on the map center or the map bounds. Currently, OverlayView.draw is not called if the map is dragged for example.

I've created below a 'Center' overlay to demonstrate how to listen to map events in the overlay.

first, in center.js I have:

// Define the overlay, derived from google.maps.OverlayView
function Center(opt_options) {
// Initialization
this.setValues(opt_options);

// Center specific
var div1 = document.createElement('div');
div1.style.cssText = 'position: absolute; left: -20px; top: -20px; ' +
'border-right: 1px solid blue; border-bottom: 1px solid blue; width: 19px; height: 19px';
var div2 = document.createElement('div');
div2.style.cssText = 'position: absolute; left: 1px; top: -20px; ' +
'border-left: 1px solid blue; border-bottom: 1px solid blue; width: 19px; height: 19px';
var div3 = document.createElement('div');
div3.style.cssText = 'position: absolute; left: -20px; top: 1px; ' +
'border-right: 1px solid blue; border-top: 1px solid blue; width: 19px; height: 19px';
var div4 = document.createElement('div');
div4.style.cssText = 'position: absolute; left: 1px; top: 1px; ' +
'border-left: 1px solid blue; border-top: 1px solid blue; width: 19px; height: 19px';

var div = this.div_ = document.createElement('div');
div.appendChild(div1);
div.appendChild(div2);
div.appendChild(div3);
div.appendChild(div4);
div.style.cssText = 'position: absolute; display: none';
};
Center.prototype = new google.maps.OverlayView;

// Implement onAdd
Center.prototype.onAdd = function() {
var pane = this.getPanes().overlayLayer;
pane.appendChild(this.div_);

// Ensures the center is redrawn if the map center changes
var me = this;
this.listeners_ = [
google.maps.event.addListener(this.getMap(), 'center_changed',
function() { me.draw(); }),
];
};

// Implement onRemove
Center.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) {
maps.google.event.removeListener(this.listeners_[i]);
}
};

// Implement draw
Center.prototype.draw = function() {
var projection = this.getProjection();
var position = projection.fromLatLngToDivPixel(this.getMap().getCenter());

var div = this.div_;
div.style.left = position.x + 'px';
div.style.top = position.y + 'px';
div.style.display = 'block';
};

and in the map initialization I just added:

<script type="text/javascript" src="center.js"></script>

and

var center = new Center({
map: map
});

Adding the Center object to the map creates a cross at the center of the map. When the map is dragged or zoomed, the overlay is redrawn, allowing it to stay centered.

The result looks like this:

Tuesday, September 29, 2009

Label overlay example for Google Maps API v3

Here's a simple example of creating a custom overlay class for Google Maps API v3. This Label overlay can either be used on its own, or bound to a marker.

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.

Friday, September 11, 2009

Hosting Google Maps in a Microsoft WPF application using XAML

Ever wondered how to implement Google Maps in a WPF application using XAML?

Find out how: http://code.google.com/apis/maps/articles/flashmapinwpf.html