1 if (Garmin == undefined) var Garmin = {};
  2 /** Copyright © 2007-2010 Garmin Ltd. or its subsidiaries.
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the 'License')
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *    http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an 'AS IS' BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  * 
 16  * @fileoverview Garmin.MapController Overlays tracks and waypoint data on Google maps.
 17  * @version 1.9
 18  */
 19 /**
 20  * Accepts Garmin.Series objects and draws them on a Google Map.
 21  * 
 22  * @class Garmin.MapController
 23  * @constructor 
 24  * @param (String) mapString id of element to place map in
 25  */
 26 Garmin.MapController = function(mapString){}; //just here for jsdoc
 27 Garmin.MapController = Class.create();
 28 Garmin.MapController.prototype = {
 29 
 30     initialize: function(mapString) {
 31         this.mapElement = $(mapString);
 32         this.usePositionMarker = true;
 33         
 34         this.polylines = new Array();
 35         this.markers = new Array();
 36         this.tracks = new Array();
 37         this.markerIndex = 0;
 38 
 39         this.timeToCheck = false;
 40         try {
 41 	        this.map = new GMap2( $(mapString) );
 42 	        this.map.addControl(new GSmallMapControl());
 43 			this.map.addControl(new GMapTypeControl());
 44         	new GKeyboardHandler(this.map);
 45         } catch (e) {
 46         	alert("WARNING: application will not function properly with missing Google script element or invalid Google map key.  Error: "+e);
 47         }
 48         window.onUnload = "GUnload()";
 49     },
 50 
 51     /** Set the center point and zoom level of the map.
 52      * @param (Number) Latitude of the center point
 53      * @param (Number) Longitude of the center point
 54      * @param (Number) Zoom level
 55      */
 56     centerAndScale: function(lat, lon, scale) {
 57     	scale = (scale == null ? 13 : scale);
 58         this.map.setCenter(new GLatLng(lat, lon), scale);
 59     },
 60     
 61     /** Draw track on map.
 62      * @param (Garmin.Track) The track to draw
 63      * @param (String) Color in RGB Hex format, default: "#ff0000"
 64      */    
 65     drawTrack: function(series, color) {
 66         color = (color == null ? "#ff0000" : color);
 67         
 68         // create a smaller version of the whole track
 69         // create 300 points or so ...
 70 	    // Problem is that Google Maps dies when you hit near 500 points, so we have to
 71 	    // ensure that we create fewer than that for the track.
 72         var drawAt = Math.ceil(series.getSamplesLength()/300);
 73         var drawnPoints = new Array();
 74 
 75         try {
 76         	// create up to 300 points
 77 			for(var h = 0; h < series.getSamplesLength(); h += drawAt) {
 78 				drawnPoints.push(this.createNearestValidLocationPoint(series, h, -1));
 79 		    }
 80 		    // create the end point
 81            	drawnPoints.push(this.createNearestValidLocationPoint(series, series.getSamplesLength()-1, -1));
 82         } catch( e ) {
 83             alert("GoogleMapControl.drawTrack: " + e.message);
 84         }	    
 85         
 86         if (drawnPoints.length > 0) {
 87 	        //draw the new smaller version
 88 	        var polyline = new GPolyline(drawnPoints, color, 2, .8)
 89 			try {
 90 				this.centerAndScale(drawnPoints[0].lat(), drawnPoints[0].lng());			
 91 	        	this.map.addOverlay( polyline );
 92 		        this.addStartFinishMarkers(series);
 93 		        this.bounds = this.findAZoomLevel(drawnPoints);
 94 		        this.setOnBounds( this.bounds );
 95 			} catch(e){ alert("GoogleMapControl.drawTrack, IE error on map.addOverlay("+polyline+") err: "+e); }
 96         }
 97     },
 98 
 99 	/**Creates a GLatLng for the sample in the series closest to the index with a valid location (lat and lon).
100 	 * @param series - The series to search through.
101 	 * @param index - The index to start searching from.
102 	 * @param incDirection - The direction to travel for the search.
103 	 * @return A GLatLng of the nearest valid location sample found.
104 	 */
105 	createNearestValidLocationPoint: function(series, index, incDirection) {
106     	var sample = series.findNearestValidLocationSample(index, -1);
107     	if (sample != null) {
108     		var sampleLat = sample.getMeasurement(Garmin.Sample.MEASUREMENT_KEYS.latitude).getValue();
109     		var sampleLon = sample.getMeasurement(Garmin.Sample.MEASUREMENT_KEYS.longitude).getValue();
110     		return new GLatLng(sampleLat, sampleLon);    		
111     	} else {
112 			throw new Error("No valid location point in series.");
113     	}
114 	},
115 
116     /** Draw waypoint on map.
117      * @param (Garmin.Series) series containing a waypoint to add to the map
118      */
119     drawWaypoint: function(series) {
120     	var sample = series.getSample(0);
121         this.centerAndScale(sample.getLatitude(), sample.getLongitude(), 15);    	
122         this.addMarker(sample.getLatitude(), sample.getLongitude());
123     },
124 
125     /** Calculates minimum bounding box for an set of points.
126      * @param (Array) The array of points to find a zoom level for
127      */
128     findAZoomLevel: function(points) {
129         var bounds = new GLatLngBounds(points[0], points[0]);
130         
131         for(var i=1; i<points.length-1; i+=3) {
132             bounds.extend(points[i]);
133         }
134         
135         return bounds;
136     },
137     
138 	/** Check the new dimensions of the map, and determine the bounds of the tracks
139 	 * Then set the map to zoom to that bound level
140    	 * @private
141 	 */
142     sizeAndSetOnBounds: function() {
143         this.map.checkResize();
144         this.setOnBounds( this.bounds );
145     },
146 
147     /** Set the bounding box on the map.
148      * @param (GLatLngBounds) bounding box for the
149      */
150     setOnBounds: function(bounds) {
151         this.map.setCenter( this.bounds.getCenter(), this.map.getBoundsZoomLevel(this.bounds) );
152     },
153     
154     /** Add an icon to a point.
155      * @param {Number} latitude of marker
156      * @param {Number} longitude of marker
157      */
158     addMarker: function(latitude, longitude) {
159     	this.addMarkerWithIcon(latitude, longitude, Garmin.MapIcons.getRedIcon());
160     },
161 
162     /** Adds a marker to the point with the icon specified
163      * @param {Number} latitude of marker
164      * @param {Number} longitude of marker
165      * @param (GIcon) icon to add at the point
166      */
167     addMarkerWithIcon: function(latitude, longitude, icon) {
168         var gMarker = new GMarker(new GLatLng(latitude, longitude), icon);
169         this.markers.push(gMarker);
170         this.map.addOverlay(gMarker);
171     },
172 
173     /** Add start and finish markers to a track
174      * @param (Garmin.Series) The series to add markers to
175      */
176     addStartFinishMarkers: function(series) {
177     	var firstSample = series.getFirstValidLocationSample();
178     	var lastSample = series.getLastValidLocationSample();
179         this.addMarkerWithIcon(firstSample.getLatitude(), firstSample.getLongitude(), Garmin.MapIcons.getGreenIcon());
180         this.addMarkerWithIcon(lastSample.getLatitude(), lastSample.getLongitude(), Garmin.MapIcons.getRedIcon());
181     },
182 
183     /** String representation of map.
184      * @return (String)
185      */
186     toString: function() {
187         return "Google Based Map Controller, managing " + this.tracks.length + " track(s)";
188     }
189 };
190 
191 /** Icons used to mark waypoints and POIs on Google maps.  
192  * 
193  * @class Garmin.MapIcons
194  * @constructor 
195  */
196 Garmin.MapIcons = function(){}; //just here for jsdoc
197 Garmin.MapIcons = {
198     getRedIcon: function() {
199         var icon = new GIcon();
200         icon.image = "http://developer.garmin.com/img/marker_red.png";
201         return Garmin.MapIcons._applyShadowAndStuff(icon);
202     },
203     
204     getGreenIcon: function() {
205         var icon = new GIcon();
206         icon.image = "http://developer.garmin.com/img/marker_green.png";
207         return Garmin.MapIcons._applyShadowAndStuff(icon);
208     },
209     
210     _applyShadowAndStuff: function(icon) {
211         icon.iconSize = new GSize(12, 20);
212         icon.shadow = "http://developer.garmin.com/img/marker_shadow.png";
213         icon.shadowSize = new GSize(22, 20);
214         icon.iconAnchor = new GPoint(6, 20);
215         icon.infoWindowAnchor = new GPoint(5, 1);
216         return icon;
217     }
218 }