I found myself in need of using custom google maps markers. Taking into consideration that the
Google Chart tools API is now deprecated and will cease to work on
April 20, 2015 and using 3rd party api was off the table I had to glue together several samples and fumble through many tutorials. I mostly based this on following great code sample
http://blog.mridey.com/2009/09/label-overlay-example-for-google-maps.html by Marc Ridey. Default google maps Marker consist of a red pin with a dot in the middle. To achieve a similar effect with a custom content marker I created a Label object. First problem to overcome was creating a proper marker with editable text inside.
1 function Label(opt_options) {
2 // Initialization
3 this.setValues(opt_options);
4
5 // Image initialization
6 var labImg = document.createElement('img');
7 labImg.setAttribute('src','Images/marker.png');
8 labImg.style.cssText = 'position: relative;left: -50%; top: -100%';
9 labImg.setAttribute('alt','');
10 labImg.style.width = '21px'
11 labImg.style.height = '34px'
12
13 // Marker text initialization
14 var span = this.span_ = document.createElement('span');
15 span.style.cssText = 'position: absolute; top: -100%;
16 left: -12px; width: 21px; align: left; text-align: center';
17
18 // Creating a div with image background and text inside
19 var div = this.div_ = document.createElement('div');
20 div.appendChild(labImg);
21 div.appendChild(span);
22 div.style.cssText = 'position: absolute; display: none;';
23 };
In the code above I'm creating a simple marker that consists of a div with image as background and a span which will include the markers's text. For this marker to become a map overlay object it has to inherit google.maps.OverlayView. The former we'll force us to implement onAdd(), onRemove() and draw() methods, which are described properly in the link I provided earlier. I created two collections to help me in my implementation. First one: positions collection holds latitudes and longitudes, the second one data such as zIndex nad label's text. I populated them in addMarker method. As I mentioned earlier we need to setup the inheritance somewhere in code:
Label.prototype = new google.maps.OverlayView;
And finally function for adding new markers:
1 // Adding new marker
2 function addMarker(long, lat, desc) {
3 var latlng = new google.maps.LatLng(lat,long);
4 var label = new Label({
5 map: map
6 });
7
8 label.set('zIndex',10000000 - (long * 10000));
9 label.set('text', desc);
10
11 labels[id] = label;
12 positions[id] = latlng;
13 }
These two functions and the code from the link I pasted earlier is enough to create a map with your own markers with your own labels inside. The method that changes most from Marc Ridey's tutorial is the draw event method. It actually differs slightly but I'll add it, to make the post more complete.
1 // Label drawing event
2 Label.prototype.draw = function() {
3 var projection = this.getProjection();
4 var oldid = this.get('text')
5 var position = projection.fromLatLngToDivPixel(positions[oldid]);
6 var div = this.div_;
7
8 div.style.left = position.x + 'px';
9 div.style.top = position.y + 'px';
10 div.style.display = 'block';
11 div.style.zIndex = this.get('zIndex');
12 this.span_.innerHTML = this.get('text').toString();
13 };
I also added several functions that controlled the map later from my WPF application:
1 // Remove marker by id
2 function deleteMarker(id) {
3 var label = labels[id];
4 label.onRemove();
5 }
6
7 // Center on location
8 function setCenter(lat, long) {
9 var latlng = new google.maps.LatLng(lat, long);
10 map.panTo(latlng);
11 }
12
13 // Zoom to fit markers
14 function zoomToMarkers() {
15 var bounds = new google.maps.LatLngBounds();
16 for(var x in markers) {
17 bounds.extend(markers[x]);
18 }
19
20 map.fitBounds(bounds);
21 }
22
23 // Remove all markers
24 function clearMarkers() {
25 for(var x in markers) {
26 var label = labels[x];
27 label.onRemove();
28 }
29 }