ym4r-mapstraction 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,179 @@
1
+ /*
2
+ Copyright (c) 2007, Andrew Turner
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
+ * Neither the name of the Mapstraction nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12
+ */
13
+
14
+
15
+ // Use http://jsdoc.sourceforge.net/ to generate documentation
16
+
17
+ // TODO: add reverse geocoding support
18
+
19
+ /**
20
+ * MapstractionGeocoder instantiates a geocoder with some API choice
21
+ * @param {Function} callback The function to call when a geocode request returns (function(waypoint))
22
+ * @param {String} api The API to use, currently only 'mapquest' is supported
23
+ * @param {Function} error_callback The optional function to call when a geocode request fails
24
+ * @constructor
25
+ */
26
+ function MapstractionGeocoder(callback, api, error_callback) {
27
+ this.api = api;
28
+ this.callback = callback;
29
+ this.geocoders = new Object();
30
+ if(error_callback == null) {
31
+ this.error_callback = this.geocode_error
32
+ } else {
33
+ this.error_callback = error_callback;
34
+ }
35
+
36
+ // This is so that it is easy to tell which revision of this file
37
+ // has been copied into other projects.
38
+ this.svn_revision_string = '$Revision: 107 $';
39
+
40
+ this.addAPI(api);
41
+
42
+ }
43
+
44
+
45
+ /**
46
+ * Internal function to actually set the router specific parameters
47
+ */
48
+ MapstractionGeocoder.prototype.addAPI = function(api) {
49
+
50
+ me = this;
51
+ switch (api) {
52
+ case 'google':
53
+ this.geocoders[api] = new GClientGeocoder();
54
+ break;
55
+ case 'mapquest':
56
+ //set up the connection to the geocode server
57
+ var proxyServerName = "";
58
+ var proxyServerPort = "";
59
+ var ProxyServerPath = "mapquest_proxy/JSReqHandler.php";
60
+
61
+ var serverName = "geocode.access.mapquest.com";
62
+ var serverPort = "80";
63
+ var serverPath = "mq";
64
+ this.geocoders[api] = new MQExec(serverName, serverPath, serverPort, proxyServerName,
65
+ ProxyServerPath, proxyServerPort );
66
+
67
+ break;
68
+ default:
69
+ alert(api + ' not supported by mapstraction-geocoder');
70
+ }
71
+ }
72
+ /**
73
+ * Change the Routing API to use
74
+ * @param {String} api The API to swap to
75
+ */
76
+ MapstractionGeocoder.prototype.swap = function(api) {
77
+ if (this.api == api) { return; }
78
+
79
+ this.api = api;
80
+ if (this.geocoders[this.api] == undefined) {
81
+ this.addAPI($(element),api);
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Default Geocode error function
87
+ */
88
+ MapstractionGeocoder.prototype.geocode_error = function(response) {
89
+ alert("Sorry, we were unable to geocode that address");
90
+ }
91
+
92
+ /**
93
+ * Default handler for geocode request completion
94
+ */
95
+ MapstractionGeocoder.prototype.geocode_callback = function(response, mapstraction_geocoder) {
96
+ var return_location = new Object();
97
+
98
+ // TODO: what if the api is switched during a geocode request?
99
+ // TODO: provide an option error callback
100
+ switch (mapstraction_geocoder.api) {
101
+ case 'google':
102
+ if (!response || response.Status.code != 200) {
103
+ mapstraction_geocoder.error_callback(response);
104
+ } else {
105
+ return_location.street = "";
106
+ return_location.locality = "";
107
+ return_location.region = "";
108
+ return_location.country = "";
109
+
110
+ place = response.Placemark[0];
111
+ if(place.AddressDetails.Country.AdministrativeArea != null) {
112
+ return_location.region = place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName;
113
+
114
+ if(place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea != null) {
115
+ if(place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality != null) {
116
+ return_location.locality = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
117
+
118
+ if(place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare != null)
119
+ return_location.street = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare.ThoroughfareName;
120
+ }
121
+
122
+ }
123
+
124
+ }
125
+ return_location.country = place.AddressDetails.Country.CountryNameCode;
126
+
127
+
128
+ return_location.point = new LatLonPoint(place.Point.coordinates[1],
129
+ place.Point.coordinates[0]);
130
+ mapstraction_geocoder.callback(return_location);
131
+ }
132
+ break;
133
+ case 'mapquest':
134
+ break;
135
+ }
136
+ }
137
+
138
+
139
+ /**
140
+ * Performs a geocoding and then calls the specified callback function with the location
141
+ * @param {Object} address The address object to geocode
142
+ */
143
+ MapstractionGeocoder.prototype.geocode = function(address) {
144
+ var return_location = new Object();
145
+
146
+ // temporary variable for later using in function closure
147
+ var mapstraction_geocoder = this;
148
+
149
+ switch (this.api) {
150
+ case 'google':
151
+ if (address.address == null || address.address == "")
152
+ address.address = address.street + ", " + address.locality + ", " + address.region + ", " + address.country
153
+ this.geocoders[this.api].getLocations(address.address, function(response) { mapstraction_geocoder.geocode_callback(response, mapstraction_geocoder); });
154
+ break;
155
+ case 'mapquest':
156
+ var mqaddress = new MQAddress();
157
+ var gaCollection = new MQLocationCollection("MQGeoAddress");
158
+ //populate the address object with the information from the form
159
+ mqaddress.setStreet(address.street);
160
+ mqaddress.setCity(address.locality);
161
+ mqaddress.setState(address.region);
162
+ mqaddress.setPostalCode(address.postalcode);
163
+ mqaddress.setCountry(address.country);
164
+
165
+ this.geocoders[this.api].geocode(mqaddress, gaCollection);
166
+ var geoAddr = gaCollection.get(0);
167
+ var mqpoint = geoAddr.getMQLatLng();
168
+ return_location.street = geoAddr.getStreet();
169
+ return_location.locality = geoAddr.getCity();
170
+ return_location.region = geoAddr.getState();
171
+ return_location.country = geoAddr.getCountry();
172
+ return_location.point = new LatLonPoint(mqpoint.getLatitude(), mqpoint.getLongitude());
173
+ this.callback(return_location, this);
174
+ break;
175
+ default:
176
+ alert(api + ' not supported by mapstraction-geocoder');
177
+ break;
178
+ }
179
+ }
@@ -0,0 +1,200 @@
1
+ /*
2
+ Copyright (c) 2007, Andrew Turner
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
+ * Neither the name of the Mapstraction nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12
+ */
13
+
14
+
15
+ // Use http://jsdoc.sourceforge.net/ to generate documentation
16
+
17
+ ////////////////////////////
18
+ //
19
+ // utility to functions, TODO namespace or remove before release
20
+ //
21
+ ///////////////////////////
22
+
23
+ /**
24
+ * MapstractionRouter instantiates a router with some API choice
25
+ * @param {Function} callback The function to call when a route request returns (function(waypoints, route))
26
+ * @param {String} api The API to use, currently only 'mapquest' is supported
27
+ * @param {Function} error_callback The optional function to call when a route request fails
28
+ * @constructor
29
+ */
30
+ function MapstractionRouter(callback, api, error_callback) {
31
+ this.api = api;
32
+ this.callback = callback;
33
+ this.routers = new Object();
34
+ this.geocoders = new Object();
35
+ if(error_callback == null) {
36
+ this.error_callback = this.route_error
37
+ } else {
38
+ this.error_callback = error_callback;
39
+ }
40
+
41
+ // This is so that it is easy to tell which revision of this file
42
+ // has been copied into other projects.
43
+ this.svn_revision_string = '$Revision: 107 $';
44
+
45
+ this.addAPI(api);
46
+
47
+ }
48
+
49
+ /**
50
+ * Internal function to actually set the router specific parameters
51
+ */
52
+ MapstractionRouter.prototype.addAPI = function(api) {
53
+ me = this;
54
+ switch (api) {
55
+ case 'mapquest':
56
+ //set up the connection to the route server
57
+ var proxyServerName = "";
58
+ var proxyServerPort = "";
59
+ var ProxyServerPath = "mapquest_proxy/JSReqHandler.php";
60
+
61
+ var geocoderServerName = "geocode.access.mapquest.com";
62
+ var routerServerName = "route.access.mapquest.com";
63
+ var serverPort = "80";
64
+ var serverPath = "mq";
65
+
66
+ this.geocoders[api] = new MQExec(geocoderServerName, serverPath, serverPort, proxyServerName,
67
+ ProxyServerPath, proxyServerPort );
68
+
69
+ this.routers[api] = new MQExec(routerServerName, serverPath, serverPort, proxyServerName,
70
+ ProxyServerPath, proxyServerPort );
71
+
72
+ break;
73
+ default:
74
+ alert(api + ' not supported by mapstraction-router');
75
+ }
76
+ }
77
+ /**
78
+ * Change the Routing API to use
79
+ * @param {String} api The API to swap to
80
+ */
81
+ MapstractionRouter.prototype.swap = function(api) {
82
+ if (this.api == api) { return; }
83
+
84
+ this.api = api;
85
+ if (this.routers[this.api] == undefined) {
86
+ this.addAPI($(element),api);
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Default Route error function
92
+ */
93
+ MapstractionRouter.prototype.route_error = function(response) {
94
+ alert("Sorry, we were unable to route that address");
95
+ }
96
+ /**
97
+ * Default handler for route request completion
98
+ */
99
+ MapstractionRouter.prototype.route_callback = function(response, mapstraction_router) {
100
+
101
+ // TODO: what if the api is switched during a route request?
102
+ // TODO: provide an option error callback
103
+ switch (mapstraction_router.api) {
104
+ case 'mapquest':
105
+ break;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Performs a routing and then calls the specified callback function with the waypoints and route
111
+ * @param {Array} addresses The array of address objects to use for the waypoints of the route
112
+ */
113
+ MapstractionRouter.prototype.route = function(addresses) {
114
+
115
+ var api = this.api;
116
+ switch (api) {
117
+ case 'mapquest':
118
+ var waypoints = new MQLocationCollection();
119
+ var mapstraction_points = Array();
120
+ var gaCollection = new MQLocationCollection("MQGeoAddress");
121
+ var routeOptions = new MQRouteOptions();
122
+ for (var i=0;i<addresses.length;i++) {
123
+ var mqaddress = new MQAddress();
124
+
125
+ //first geocode all the user entered locations
126
+ mqaddress.setStreet(addresses[i].street);
127
+ mqaddress.setCity(addresses[i].locality);
128
+ mqaddress.setState(addresses[i].region);
129
+ mqaddress.setPostalCode(addresses[i].postalcode);
130
+ mqaddress.setCountry(addresses[i].country);
131
+ this.geocoders[api].geocode(mqaddress, gaCollection);
132
+ var geoAddr = gaCollection.get(0);
133
+ waypoints.add(geoAddr);
134
+
135
+ // Create an array of Mapstraction points to use for markers
136
+ var mapstraction_point = new Object();
137
+ mapstraction_point.street = geoAddr.getStreet();
138
+ mapstraction_point.locality = geoAddr.getCity();
139
+ mapstraction_point.region = geoAddr.getState();
140
+ mapstraction_point.country = geoAddr.getCountry();
141
+ var mqpoint = geoAddr.getMQLatLng();
142
+ mapstraction_point.point = new LatLonPoint(mqpoint.getLatitude(), mqpoint.getLongitude());
143
+ mapstraction_points.push(mapstraction_point);
144
+ }
145
+
146
+ var session = new MQSession();
147
+ var routeResults = new MQRouteResults();
148
+ var routeBoundingBox = new MQRectLL(new MQLatLng(),new MQLatLng());
149
+ var sessId = this.routers[api].createSessionEx(session);
150
+ this.routers[api].doRoute(waypoints,routeOptions,routeResults,sessId,routeBoundingBox);
151
+
152
+ var routeParameters = new Array();
153
+ routeParameters['results'] = routeResults;
154
+ routeParameters['bounding_box'] = routeBoundingBox;
155
+ routeParameters['session_id'] = sessId;
156
+
157
+ this.callback(mapstraction_points, routeParameters);
158
+ break;
159
+ default:
160
+ alert(api + ' not supported by mapstraction-router');
161
+ break;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Performs a routing and then calls the specified callback function with the waypoints and route
167
+ * @param {Array} addresses The array of point/location objects to use for the route
168
+ */
169
+ MapstractionRouter.prototype.routePoints = function(points) {
170
+
171
+ var api = this.api;
172
+ switch (api) {
173
+ case 'mapquest':
174
+ var waypoints = new MQLocationCollection();
175
+ var routeOptions = new MQRouteOptions();
176
+
177
+ for (var i=0;i<points.length;i++) {
178
+ var geoAddr = new MQGeoAddress();
179
+ geoAddr.setMQLatLng(new MQLatLng(points[i].lat, points[i].lng));
180
+ waypoints.add(geoAddr);
181
+ }
182
+
183
+ var session = new MQSession();
184
+ var routeResults = new MQRouteResults();
185
+ var routeBoundingBox = new MQRectLL(new MQLatLng(),new MQLatLng());
186
+ var sessId = this.routers[api].createSessionEx(session);
187
+ this.routers[api].doRoute(waypoints,routeOptions,routeResults,sessId,routeBoundingBox);
188
+
189
+ var routeParameters = new Array();
190
+ routeParameters['results'] = routeResults;
191
+ routeParameters['bounding_box'] = routeBoundingBox;
192
+ routeParameters['session_id'] = sessId;
193
+
194
+ this.callback(points, routeParameters);
195
+ break;
196
+ default:
197
+ alert(api + ' not supported by mapstraction-router');
198
+ break;
199
+ }
200
+ }
@@ -0,0 +1,3570 @@
1
+ /*
2
+ Copyright (c) 2006-7, Tom Carden, Steve Coast, Mikel Maron, Andrew Turner, Henri Bergius
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
+ * Neither the name of the Mapstraction nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12
+ */
13
+
14
+
15
+ // Use http://jsdoc.sourceforge.net/ to generate documentation
16
+
17
+ ////////////////////////////
18
+ //
19
+ // utility to functions, TODO namespace or remove before release
20
+ //
21
+ ///////////////////////////
22
+
23
+ /**
24
+ * $, the dollar function, elegantising getElementById()
25
+ * @returns an element
26
+ */
27
+ function $m() {
28
+ var elements = new Array();
29
+ for (var i = 0; i < arguments.length; i++) {
30
+ var element = arguments[i];
31
+ if (typeof element == 'string')
32
+ element = document.getElementById(element);
33
+ if (arguments.length == 1)
34
+ return element;
35
+ elements.push(element);
36
+ }
37
+ return elements;
38
+ }
39
+
40
+ /**
41
+ * loadScript is a JSON data fetcher
42
+ */
43
+ function loadScript(src,callback) {
44
+ var script = document.createElement('script');
45
+ script.type = 'text/javascript';
46
+ script.src = src;
47
+ if (callback) {
48
+ var evl=new Object();
49
+ evl.handleEvent=function (e){callback();};
50
+ script.addEventListener('load',evl,true);
51
+ }
52
+ document.getElementsByTagName("head")[0].appendChild(script);
53
+ return;
54
+ }
55
+
56
+ function convertLatLonXY_Yahoo(point,level){ //Mercator
57
+ var size = 1 << (26 - level);
58
+ var pixel_per_degree = size / 360.0;
59
+ var pixel_per_radian = size / (2 * Math.PI);
60
+ var origin = new YCoordPoint(size / 2 , size / 2);
61
+ var answer = new YCoordPoint();
62
+ answer.x = Math.floor(origin.x + point.lon * pixel_per_degree);
63
+ var sin = Math.sin(point.lat * Math.PI / 180.0);
64
+ answer.y = Math.floor(origin.y + 0.5 * Math.log((1 + sin) / (1 - sin)) * -pixel_per_radian);
65
+ return answer;
66
+ }
67
+
68
+
69
+
70
+ /**
71
+ *
72
+ */
73
+ function loadStyle(href) {
74
+ var link = document.createElement('link');
75
+ link.type = 'text/css';
76
+ link.rel = 'stylesheet';
77
+ link.href = href;
78
+ document.getElementsByTagName("head")[0].appendChild(link);
79
+ return;
80
+ }
81
+
82
+
83
+ /**
84
+ * getStyle provides cross-browser access to css
85
+ */
86
+ function getStyle(el, prop) {
87
+ var y;
88
+ if (el.currentStyle)
89
+ y = el.currentStyle[prop];
90
+ else if (window.getComputedStyle)
91
+ y = window.getComputedStyle( el, '').getPropertyValue(prop);
92
+ return y;
93
+ }
94
+
95
+ // longitude to metres
96
+ // http://www.uwgb.edu/dutchs/UsefulData/UTMFormulas.HTM
97
+ // "A degree of longitude at the equator is 111.2km... For other latitudes,
98
+ // multiply by cos(lat)"
99
+ // assumes the earth is a sphere but good enough for our purposes
100
+
101
+ function lonToMetres (lon,lat) {
102
+ return lon * 111200 * Math.cos(lat * (Math.PI/180));
103
+ }
104
+
105
+ function metresToLon(m,lat) {
106
+ return m / (111200*Math.cos(lat * (Math.PI/180)));
107
+ }
108
+
109
+ // stuff to convert google zoom levels to/from degrees
110
+ // assumes zoom 0 = 256 pixels = 360 degrees
111
+ // zoom 1 = 256 pixels = 180 degrees
112
+ // etc.
113
+
114
+ function getDegreesFromGoogleZoomLevel (pixels,zoom)
115
+ {
116
+ return (360*pixels) / (Math.pow(2,zoom+8));
117
+ }
118
+
119
+ function getGoogleZoomLevelFromDegrees (pixels,degrees)
120
+ {
121
+ return logN ((360*pixels)/degrees, 2) - 8;
122
+ }
123
+
124
+ function logN (number,base)
125
+ {
126
+ return Math.log(number) / Math.log(base);
127
+ }
128
+
129
+
130
+ /////////////////////////////
131
+ //
132
+ // Mapstraction proper begins here
133
+ //
134
+ /////////////////////////////
135
+
136
+ /**
137
+ * Mapstraction instantiates a map with some API choice into the HTML element given
138
+ * @param {String} element The HTML element to replace with a map
139
+ * @param {String} api The API to use, one of 'google', 'yahoo', 'microsoft', 'openstreetmap', 'multimap', 'map24', 'openlayers', 'mapquest'
140
+ * @param {Bool} debug optional parameter to turn on debug support - this uses alert panels for unsupported actions
141
+ * @constructor
142
+ */
143
+ function Mapstraction(element,api,debug) {
144
+ this.api = api; // could detect this from imported scripts?
145
+ this.maps = new Object();
146
+ this.currentElement = $m(element);
147
+ this.eventListeners = new Array();
148
+ this.markers = new Array();
149
+ this.layers = new Array();
150
+ this.polylines = new Array();
151
+ this.images = new Array();
152
+ this.loaded = new Object();
153
+ this.onload = new Object();
154
+
155
+ // Mapstraction.writeInclude(api, "nothing");
156
+
157
+ // optional debug support
158
+ if(debug == true)
159
+ {
160
+ this.debug = true
161
+ }
162
+ else
163
+ {
164
+ this.debug = false
165
+ }
166
+
167
+ // This is so that it is easy to tell which revision of this file
168
+ // has been copied into other projects.
169
+ this.svn_revision_string = '$Revision$';
170
+ this.addControlsArgs = new Object();
171
+
172
+ if (this.currentElement)
173
+ {
174
+ this.addAPI($m(element),api);
175
+ }
176
+ }
177
+
178
+
179
+ /**
180
+ * swap will change the current api on the fly
181
+ * @param {String} api The API to swap to
182
+ */
183
+ Mapstraction.prototype.swap = function(element,api) {
184
+ if (this.api == api) { return; }
185
+
186
+ var center = this.getCenter();
187
+ var zoom = this.getZoom();
188
+
189
+ this.currentElement.style.visibility = 'hidden';
190
+ this.currentElement.style.display = 'none';
191
+
192
+
193
+ this.currentElement = $m(element);
194
+ this.currentElement.style.visibility = 'visible';
195
+ this.currentElement.style.display = 'block';
196
+
197
+ this.api = api;
198
+
199
+ if (this.maps[this.api] == undefined) {
200
+ this.addAPI($m(element),api);
201
+
202
+ this.setCenterAndZoom(center,zoom);
203
+
204
+ for (var i=0; i<this.markers.length; i++) {
205
+ this.addMarker( this.markers[i], true);
206
+ }
207
+
208
+ for (var i=0; i<this.polylines.length; i++) {
209
+ this.addPolyline( this.polylines[i], true);
210
+ }
211
+ }else{
212
+
213
+ //sync the view
214
+ this.setCenterAndZoom(center,zoom);
215
+
216
+ //TODO synchronize the markers and polylines too
217
+ // (any overlays created after api instantiation are not sync'd)
218
+ }
219
+
220
+ this.addControls(this.addControlsArgs);
221
+
222
+
223
+ }
224
+
225
+ Mapstraction.prototype.addAPI = function(element,api) {
226
+ me = this;
227
+ this.loaded[api] = false;
228
+ this.onload[api] = new Array();
229
+
230
+ switch (api) {
231
+ case 'yahoo':
232
+ if (YMap) {
233
+ this.maps[api] = new YMap(element);
234
+
235
+ YEvent.Capture(this.maps[api],EventsList.MouseClick,function(event,location) { me.clickHandler(location.Lat,location.Lon,location,me) });
236
+ YEvent.Capture(this.maps[api],EventsList.changeZoom,function() { me.moveendHandler(me) });
237
+ YEvent.Capture(this.maps[api],EventsList.endPan,function() { me.moveendHandler(me) });
238
+ this.loaded[api] = true;
239
+ }
240
+ else {
241
+ alert('Yahoo map script not imported');
242
+ }
243
+ break;
244
+ case 'google':
245
+ if (GMap2) {
246
+ if (GBrowserIsCompatible()) {
247
+ this.maps[api] = new GMap2(element);
248
+
249
+ GEvent.addListener(this.maps[api], 'click', function(marker,location) {
250
+ // If the user puts their own Google markers directly on the map
251
+ // then there is no location and this event should not fire.
252
+ if ( location ) {
253
+ me.clickHandler(location.y,location.x,location,me);
254
+ }
255
+ });
256
+
257
+ GEvent.addListener(this.maps[api], 'moveend', function() {me.moveendHandler(me)});
258
+ this.loaded[api] = true;
259
+ }
260
+ else {
261
+ alert('browser not compatible with Google Maps');
262
+ }
263
+ }
264
+ else {
265
+ alert('Google map script not imported');
266
+ }
267
+ break;
268
+ case 'microsoft':
269
+ if (VEMap) {
270
+
271
+ element.style.position='relative';
272
+
273
+ var msft_width = parseFloat(getStyle($m(element),'width'));
274
+ var msft_height = parseFloat(getStyle($m(element),'height'));
275
+ /* Hack so the VE works with FF2 */
276
+ var ffv = 0;
277
+ var ffn = "Firefox/";
278
+ var ffp = navigator.userAgent.indexOf(ffn);
279
+ if (ffp != -1) ffv = parseFloat(navigator.userAgent.substring(ffp+ffn.length));
280
+ if (ffv >= 1.5) {
281
+ Msn.Drawing.Graphic.CreateGraphic=function(f,b) { return new Msn.Drawing.SVGGraphic(f,b) }
282
+ }
283
+
284
+ this.maps[api] = new VEMap(element.id);
285
+ this.maps[api].LoadMap();
286
+
287
+ this.maps[api].AttachEvent("onclick", function(e) { me.clickHandler(e.view.LatLong.Latitude, e.view.LatLong.Longitude, me); });
288
+ this.maps[api].AttachEvent("onchangeview", function(e) {me.moveendHandler(me)});
289
+
290
+ //Source of our trouble with Mapufacture?
291
+ this.resizeTo(msft_width, msft_height);
292
+ this.loaded[api] = true;
293
+ }
294
+ else {
295
+ alert('Virtual Earth script not imported');
296
+ }
297
+ break;
298
+ case 'openlayers':
299
+
300
+ this.maps[api] = new OpenLayers.Map(
301
+ element.id,
302
+ {
303
+ maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
304
+ maxResolution:156543, numZoomLevels:18, units:'meters', projection: "EPSG:41001"
305
+ }
306
+ );
307
+
308
+ this.layers['osmmapnik'] = new OpenLayers.Layer.TMS(
309
+ 'OSM Mapnik',
310
+ [
311
+ "http://a.tile.openstreetmap.org/",
312
+ "http://b.tile.openstreetmap.org/",
313
+ "http://c.tile.openstreetmap.org/"
314
+ ],
315
+ {
316
+ type:'png',
317
+ getURL: function (bounds) {
318
+ var res = this.map.getResolution();
319
+ var x = Math.round ((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
320
+ var y = Math.round ((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
321
+ var z = this.map.getZoom();
322
+ var limit = Math.pow(2, z);
323
+ if (y < 0 || y >= limit) {
324
+ return null;
325
+ } else {
326
+ x = ((x % limit) + limit) % limit;
327
+ var path = z + "/" + x + "/" + y + "." + this.type;
328
+ var url = this.url;
329
+ if (url instanceof Array) {
330
+ url = this.selectUrl(path, url);
331
+ }
332
+ return url + path;
333
+ }
334
+ },
335
+ displayOutsideMaxExtent: true
336
+ }
337
+ );
338
+
339
+ this.layers['osm'] = new OpenLayers.Layer.TMS(
340
+ 'OSM',
341
+ [
342
+ "http://a.tah.openstreetmap.org/Tiles/tile.php/",
343
+ "http://b.tah.openstreetmap.org/Tiles/tile.php/",
344
+ "http://c.tah.openstreetmap.org/Tiles/tile.php/"
345
+ ],
346
+ {
347
+ type:'png',
348
+ getURL: function (bounds) {
349
+ var res = this.map.getResolution();
350
+ var x = Math.round ((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
351
+ var y = Math.round ((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
352
+ var z = this.map.getZoom();
353
+ var limit = Math.pow(2, z);
354
+ if (y < 0 || y >= limit) {
355
+ return null;
356
+ } else {
357
+ x = ((x % limit) + limit) % limit;
358
+ var path = z + "/" + x + "/" + y + "." + this.type;
359
+ var url = this.url;
360
+ if (url instanceof Array) {
361
+ url = this.selectUrl(path, url);
362
+ }
363
+ return url + path;
364
+ }
365
+ },
366
+ displayOutsideMaxExtent: true
367
+ }
368
+ );
369
+
370
+ this.maps[api].addLayer(this.layers['osmmapnik']);
371
+ this.maps[api].addLayer(this.layers['osm']);
372
+ this.loaded[api] = true;
373
+ break;
374
+ case 'openstreetmap':
375
+ // for now, osm is a hack on top of google
376
+ if (GMap2) {
377
+ if (GBrowserIsCompatible()) {
378
+ this.maps[api] = new GMap2(element);
379
+
380
+ GEvent.addListener(this.maps[api], 'click', function(marker,location) {
381
+ // If the user puts their own Google markers directly on the map
382
+ // then there is no location and this event should not fire.
383
+ if ( location ) {
384
+ me.clickHandler(location.y,location.x,location,me);
385
+ }
386
+ });
387
+
388
+ GEvent.addListener(this.maps[api], 'moveend', function() {me.moveendHandler(me)});
389
+
390
+ // Add OSM tiles
391
+
392
+ var copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180), new GLatLng(90,180)), 0, "copyleft");
393
+ var copyrightCollection = new GCopyrightCollection('OSM');
394
+ copyrightCollection.addCopyright(copyright);
395
+
396
+ var tilelayers = new Array();
397
+ tilelayers[0] = new GTileLayer(copyrightCollection, 1, 18);
398
+ tilelayers[0].getTileUrl = function (a, b) {
399
+ return "http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png";
400
+ };
401
+ tilelayers[0].isPng = function() { return true;};
402
+ tilelayers[0].getOpacity = function() { return 1.0; }
403
+
404
+ var custommap = new GMapType(tilelayers, new GMercatorProjection(19), "OSM", {errorMessage:"More OSM coming soon"});
405
+ this.maps[api].addMapType(custommap);
406
+
407
+ // Have to tell Mapstraction that we're good so the
408
+ // setCenterAndZoom call below initializes the map
409
+ this.loaded[api] = true;
410
+
411
+ var myPoint = new LatLonPoint(50.6805,-1.4062505);
412
+ this.setCenterAndZoom(myPoint, 11);
413
+
414
+ this.maps[api].setMapType(custommap);
415
+ }
416
+ else {
417
+ alert('browser not compatible with Google Maps');
418
+ }
419
+ }
420
+ else {
421
+ alert('Google map script not imported');
422
+ }
423
+
424
+ break;
425
+ case 'multimap':
426
+ this.maps[api] = new MultimapViewer( element );
427
+
428
+ this.maps[api].addEventHandler( 'click', function(eventType, eventTarget, arg1, arg2, arg3) {
429
+ if (arg1) {
430
+ me.clickHandler(arg1.lat, arg1.lon, me);
431
+ }
432
+ });
433
+ this.maps[api].addEventHandler( 'changeZoom', function(eventType, eventTarget, arg1, arg2, arg3) {
434
+ me.moveendHandler(me);
435
+ });
436
+ this.maps[api].addEventHandler( 'endPan', function(eventType, eventTarget, arg1, arg2, arg3) {
437
+ me.moveendHandler(me);
438
+ });
439
+ this.loaded[api] = true;
440
+ break;
441
+ case 'map24':
442
+ // Copied from Google and modified
443
+ if (Map24) {
444
+
445
+ Map24.loadApi(["core_api","wrapper_api"] , function() {
446
+
447
+ Map24.MapApplication.init
448
+ ( { NodeName: element.id, MapType: "Static" } );
449
+ me.maps[api] = Map24.MapApplication.Map;
450
+
451
+ Map24.MapApplication.Map.addListener('Map24.Event.MapClick',
452
+ function(e) {
453
+ me.clickHandler(e.Coordinate.Latitude/60,
454
+ e.Coordinate.Longitude/60,
455
+ me);
456
+
457
+ e.stop();
458
+ }
459
+ );
460
+
461
+ Map24.MapApplication.Map.addListener("MapPanStop",
462
+ function(e) {
463
+ me.moveendHandler(me);
464
+ }
465
+ );
466
+
467
+ /**/
468
+
469
+ var client=Map24.MapApplication.Map.MapClient['Static'];
470
+
471
+
472
+ /*
473
+
474
+ These *will* cause the specified listener to run when we stop
475
+ panning the map, but the default pan stop handler will be
476
+ cancelled. The result of this will be that when we have stopped
477
+ panning, we will permanently be in 'pan' mode and unable to do
478
+ anything else (e.g. click on the map to create a new marker).
479
+
480
+
481
+ var defaultOnPanStop = client.onPanStop;
482
+ var defaultOnZoomInStop = client.onZoomInStop;
483
+ var defaultOnZoomOutStop = client.onZoomOutStop;
484
+
485
+ client.onPanStop = function(e)
486
+ { me.moveendHandler(me); defaultOnPanStop(e);
487
+ status('DEFAULTONPANSTOP DONE');}
488
+
489
+ // Handle zoom events - these also fire moveendHandler for the
490
+ // other APIs in Mapstraction
491
+ client.onZoomInStop = function(e)
492
+ { me.moveendHandler(me); defaultOnZoomInStop(e); }
493
+ client.onZoomOutStop = function(e)
494
+ { me.moveendHandler(me); defaultOnZoomOutStop(e); }
495
+
496
+ */
497
+
498
+ me.loaded[api] = true;
499
+ for (var i = 0; i < me.onload[api].length; i++) {
500
+ me.onload[api][i]();
501
+ }
502
+ }, "2.0.1247" );
503
+
504
+ } else {
505
+ alert('map24 api not loaded');
506
+ }
507
+ break;
508
+ case 'mapquest':
509
+ myself = this;
510
+ MQInitOverlays( function() {
511
+ myself.loaded[api] = true;
512
+ myself.maps[api] = new MQTileMap(element);
513
+ for (var i = 0; i < myself.onload[api].length; i++) {
514
+ myself.onload[api][i]();
515
+ }
516
+ });
517
+
518
+ // MQEventManager.addListener(this.maps[api],"click",function(event,location) { me.clickHandler(location.Lat,location.Lon,location,me) });
519
+ // MQEventManager.addListener(this.maps[api],"zoomend",function() { me.moveendHandler(me) });
520
+ // MQEventManager.addListener(this.maps[api],"moveend",function() { me.moveendHandler(me) });
521
+ break;
522
+ case 'freeearth':
523
+ this.maps[api] = new FE.Map($m(element));
524
+ myself = this;
525
+ this.maps[api].onLoad = function() {
526
+ myself.freeEarthLoaded = true;
527
+ myself.loaded[api] = true;
528
+ for (var i = 0; i < myself.onload[api].length; i++) {
529
+ myself.onload[api][i]();
530
+ }
531
+ }
532
+ this.maps[api].load();
533
+ break;
534
+ default:
535
+ if(this.debug)
536
+ alert(api + ' not supported by mapstraction');
537
+ }
538
+
539
+
540
+ // this.resizeTo(getStyle($m(element),'width'), getStyle($m(element),'height'));
541
+ // the above line was called on all APIs but MSFT alters with the div size when it loads
542
+ // so you have to find the dimensions and set them again (see msft constructor).
543
+ // FIXME: test if google/yahoo etc need this resize called. Also - getStyle returns
544
+ // CSS size ('200px') not an integer, and resizeTo seems to expect ints
545
+
546
+ }
547
+
548
+ Mapstraction._getScriptLocation=function(){
549
+ var scriptLocation="";
550
+ var SCRIPT_NAME = "mapstraction.js";
551
+ var scripts=document.getElementsByTagName('script');
552
+ for(var i=0; i<scripts.length; i++) {
553
+ var src=scripts[i].getAttribute('src');
554
+ if(src) {
555
+ var index=src.lastIndexOf(SCRIPT_NAME);
556
+ if((index>-1)&&(index+SCRIPT_NAME.length==src.length)){scriptLocation=src.slice(0,-SCRIPT_NAME.length);
557
+ break;
558
+ }
559
+ }
560
+ }
561
+ return scriptLocation;
562
+ }
563
+ Mapstraction.writeInclude = function(api, key, version) {
564
+
565
+ var jsfiles=new Array();
566
+ var allScriptTags="";
567
+ var host=Mapstraction._getScriptLocation()+"lib/";
568
+ switch(api) {
569
+ case 'google':
570
+ if(version == null) { version = "2"; }
571
+ jsfiles.push('http://maps.google.com/maps?file=api&v=' + version + '&key=' + key);
572
+ break;
573
+ case "microsoft":
574
+ if(version == null) { version = "6.2"; }
575
+ jsfiles.push('http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=' + version);
576
+ break;
577
+ case "yahoo":
578
+ if(version == null) { version = "3.0"; }
579
+ jsfiles.push('http://api.maps.yahoo.com/ajaxymap?v='+ version + '&appid=' + key);
580
+ break;
581
+ case "openlayers":
582
+ jsfiles.push('http://openlayers.org/api/OpenLayers.js');
583
+ break;
584
+ case "multimap":
585
+ if(version == null) { version = "1.2"; }
586
+ jsfiles.push('http://developer.multimap.com/API/maps/' + version + '/' + key);
587
+ break;
588
+ case "map24":
589
+ jsfiles.push('http://api.maptp.map24.com/ajax?appkey=' + key);
590
+ break;
591
+ case "mapquest":
592
+ if(version == null) { version = "5.1"; }
593
+
594
+ jsfiles.push('http://btilelog.access.mapquest.com/tilelog/transaction?transaction=script&key=' + key + '&ipr=true&itk=true&v=' + version);
595
+ jsfiles.push('mapquest-js/mqcommon.js');
596
+ jsfiles.push('mapquest-js/mqutils.js');
597
+ jsfiles.push('mapquest-js/mqobjects.js');
598
+ jsfiles.push('mapquest-js/mqexec.js');
599
+ break;
600
+ case "freeearth":
601
+ jsfiles.push('http://freeearth.poly9.com/api.js');
602
+ }
603
+
604
+ for(var i=0; i<jsfiles.length; i++) {
605
+ if(/MSIE/.test(navigator.userAgent)||/Safari/.test(navigator.userAgent)) {
606
+ // var currentScriptTag="<script src='"+host+jsfiles[i]+"'></script>";
607
+ var currentScriptTag = jsfiles[i];
608
+ allScriptTags += currentScriptTag;
609
+ } else {
610
+ var s=document.createElement("script");
611
+ s.src=jsfiles[i];
612
+ s.type="text/javascript";
613
+ var h=document.getElementsByTagName("head").length ? document.getElementsByTagName("head")[0] : document.body;
614
+ h.appendChild(s);
615
+ }
616
+ }
617
+ if(allScriptTags) document.write(allScriptTags);
618
+
619
+ }
620
+
621
+ /* Returns the loaded state of a Map Provider
622
+ *
623
+ * @param {String} api Optional API to query for. If not specified, returns state of the originally created API
624
+ * @returns the state of the map loading
625
+ * @type Boolean
626
+ */
627
+ Mapstraction.prototype.isLoaded = function(api){
628
+ if(api == null)
629
+ api = this.api;
630
+
631
+ return this.loaded[api];
632
+ }
633
+
634
+ /* Set the debugging on or off - shows alert panels for functions that don't exist in Mapstraction
635
+ *
636
+ * @param {Bool} debug true to turn on debugging, false to turn it off
637
+ * @returns the state of debugging
638
+ * @type Boolean
639
+ */
640
+ Mapstraction.prototype.setDebug = function(debug){
641
+ if(debug != null)
642
+ return this.debug = debug;
643
+ else
644
+ return this.debug;
645
+ }
646
+
647
+ /* Resize the current map to the specified width and height
648
+ * (since it is actually on a child div of the mapElement passed
649
+ * as argument to the Mapstraction constructor, the resizing of this
650
+ * mapElement may have no effect on the size of the actual map)
651
+ *
652
+ * @param {int} width The width the map should be.
653
+ * @param {int} height The width the map should be.
654
+ */
655
+ Mapstraction.prototype.resizeTo = function(width,height){
656
+ if(this.loaded[this.api] == false) {
657
+ myself = this;
658
+ this.onload[this.api].push( function() { myself.resizeTo(width,height); } );
659
+ return;
660
+ }
661
+
662
+ switch (this.api) {
663
+ case 'yahoo':
664
+ this.maps[this.api].resizeTo(new YSize(width,height));
665
+ break;
666
+ case 'google':
667
+ case 'openstreetmap':
668
+ this.currentElement.style.width = width;
669
+ this.currentElement.style.height = height;
670
+ this.maps[this.api].checkResize();
671
+ break;
672
+ case 'openlayers':
673
+ this.currentElement.style.width = width;
674
+ this.currentElement.style.height = height;
675
+ this.maps[this.api].updateSize();
676
+ break;
677
+ case 'microsoft':
678
+ this.maps[this.api].Resize(width, height);
679
+ break;
680
+ case 'multimap':
681
+ this.currentElement.style.width = width;
682
+ this.currentElement.style.height = height;
683
+ this.maps[this.api].resize();
684
+ break;
685
+ case 'mapquest':
686
+ this.currentElement.style.width = width;
687
+ this.currentElement.style.height = height;
688
+ this.maps[this.api].setSize(new MQSize(width, height));
689
+ break;
690
+ case 'map24':
691
+ Map24.MapApplication.Map.Canvas['c'].resizeTo(width,height);
692
+ break;
693
+ }
694
+ }
695
+
696
+ /////////////////////////
697
+ //
698
+ // Event Handling
699
+ //
700
+ ///////////////////////////
701
+
702
+ Mapstraction.prototype.clickHandler = function(lat,lon, me) { //FIXME need to consolidate some of these handlers...
703
+ for(var i = 0; i < this.eventListeners.length; i++) {
704
+ if(this.eventListeners[i][1] == 'click') {
705
+ this.eventListeners[i][0](new LatLonPoint(lat,lon));
706
+ }
707
+ }
708
+ }
709
+
710
+ Mapstraction.prototype.moveendHandler = function(me) {
711
+ for(var i = 0; i < this.eventListeners.length; i++) {
712
+ if(this.eventListeners[i][1] == 'moveend') {
713
+ this.eventListeners[i][0]();
714
+ }
715
+ }
716
+ }
717
+
718
+ Mapstraction.prototype.addEventListener = function(type, func) {
719
+ var listener = new Array();
720
+ listener.push(func);
721
+ listener.push(type);
722
+ this.eventListeners.push(listener);
723
+
724
+ switch (this.api) {
725
+ case 'openlayers':
726
+ this.maps[this.api].events.register(type, this, func);
727
+ break;
728
+ }
729
+ }
730
+
731
+ ////////////////////
732
+ //
733
+ // map manipulation
734
+ //
735
+ /////////////////////
736
+
737
+
738
+ /**
739
+ * addControls adds controls to the map. You specify which controls to add in
740
+ * the associative array that is the only argument.
741
+ * addControls can be called multiple time, with different args, to dynamically change controls.
742
+ *
743
+ * args = {
744
+ * pan: true,
745
+ * zoom: 'large' || 'small',
746
+ * overview: true,
747
+ * scale: true,
748
+ * map_type: true,
749
+ * }
750
+ *
751
+ * @param {args} array Which controls to switch on
752
+ */
753
+ Mapstraction.prototype.addControls = function( args ) {
754
+ if(this.loaded[this.api] == false) {
755
+ myself = this;
756
+ this.onload[this.api].push( function() { myself.addControls(args); } );
757
+ return;
758
+ }
759
+
760
+ var map = this.maps[this.api];
761
+
762
+ this.addControlsArgs = args;
763
+
764
+ switch (this.api) {
765
+
766
+ case 'google':
767
+ case 'openstreetmap':
768
+ //remove old controls
769
+ if (this.controls) {
770
+ while (ctl = this.controls.pop()) {
771
+ map.removeControl(ctl);
772
+ }
773
+ } else {
774
+ this.controls = new Array();
775
+ }
776
+ c = this.controls;
777
+
778
+ // Google has a combined zoom and pan control.
779
+ if ( args.zoom || args.pan ) {
780
+ if ( args.zoom == 'large' ) {
781
+ c.unshift(new GLargeMapControl());
782
+ map.addControl(c[0]);
783
+ } else {
784
+ c.unshift(new GSmallMapControl());
785
+ map.addControl(c[0]);
786
+ }
787
+ }
788
+ if ( args.scale ) { c.unshift(new GScaleControl()); map.addControl(c[0]); }
789
+
790
+ if (this.api != "openstreetmap") {
791
+ if ( args.overview ) { c.unshift(new GOverviewMapControl()); map.addControl(c[0]); }
792
+ if ( args.map_type ) { c.unshift(new GMapTypeControl()); map.addControl(c[0]); }
793
+ }
794
+ break;
795
+
796
+ case 'yahoo':
797
+ if ( args.pan ) map.addPanControl();
798
+ else map.removePanControl();
799
+ if ( args.zoom == 'large' ) map.addZoomLong();
800
+ else if ( args.zoom == 'small' ) map.addZoomShort();
801
+ else map.removeZoomScale();
802
+ break;
803
+
804
+ case 'openlayers':
805
+ // FIXME: OpenLayers has a bug removing all the controls says crschmidt
806
+ for (var i = map.controls.length; i>1; i--) {
807
+ map.controls[i-1].deactivate();
808
+ map.removeControl(map.controls[i-1]);
809
+ }
810
+ // FIXME - can pan & zoom be separate?
811
+ if ( args.pan ) { map.addControl(new OpenLayers.Control.PanZoomBar()); }
812
+ else { }
813
+ if ( args.zoom == 'large' ) { map.addControl(new OpenLayers.Control.PanZoomBar());}
814
+ else if ( args.zoom == 'small' ) { map.addControl(new OpenLayers.Control.ZoomBox());}
815
+ else map.addControl(new OpenLayers.Control.ZoomBox());
816
+ if ( args.overview ) { map.addControl(new OpenLayers.Control.OverviewMap()); }
817
+ if ( args.map_type ) { map.addControl(new OpenLayers.Control.LayerSwitcher()); }
818
+ break;
819
+ case 'multimap':
820
+ //FIXME -- removeAllWidgets(); -- can't call addControls repeatedly
821
+
822
+ pan_zoom_widget = "MM";
823
+ if (args.zoom && args.zoom == "small") { pan_zoom_widget = pan_zoom_widget + "Small"; }
824
+ if (args.pan) { pan_zoom_widget = pan_zoom_widget + "Pan"; }
825
+ if (args.zoom) { pan_zoom_widget = pan_zoom_widget + "Zoom"; }
826
+ pan_zoom_widget = pan_zoom_widget + "Widget";
827
+
828
+ if (pan_zoom_widget != "MMWidget") {
829
+ eval(" map.addWidget( new " + pan_zoom_widget + "() );");
830
+ }
831
+
832
+ if ( args.map_type ) { map.addWidget( new MMMapTypeWidget() ); }
833
+ if ( args.overview ) { map.addWidget( new MMOverviewWidget() ); }
834
+ break;
835
+
836
+ case 'mapquest':
837
+ //remove old controls
838
+ if (this.controls) {
839
+ while (ctl = this.controls.pop()) {
840
+ map.removeControl(ctl);
841
+ }
842
+ } else {
843
+ this.controls = new Array();
844
+ }
845
+ c = this.controls;
846
+
847
+ if ( args.pan ) { c.unshift(new MQPanControl()); map.addControl(c[0], new MQMapCornerPlacement(MQMapCorner.TOP_LEFT, new MQSize(0,0))); }
848
+ if ( args.zoom == 'large' ) { c.unshift(new MQLargeZoomControl()); map.addControl(c[0], new MQMapCornerPlacement(MQMapCorner.TOP_LEFT, new MQSize(0,0))); }
849
+ else if ( args.zoom == 'small' ) { c.unshift(new MQZoomControl()); map.addControl(c[0], new MQMapCornerPlacement(MQMapCorner.BOTTOM_LEFT, new MQSize(0,0))); }
850
+
851
+ // TODO: Map View Control is wonky
852
+ if ( args.map_type ) { c.unshift(new MQViewControl()); map.addControl(c[0], new MQMapCornerPlacement(MQMapCorner.TOP_RIGHT, new MQSize(0,0))); }
853
+ break;
854
+ }
855
+ }
856
+
857
+
858
+ /**
859
+ * addSmallControls adds a small map panning control and zoom buttons to the map
860
+ * Supported by: yahoo, google, openstreetmap, openlayers, multimap, mapquest
861
+ */
862
+ Mapstraction.prototype.addSmallControls = function() {
863
+ if(this.loaded[this.api] == false) {
864
+ myself = this;
865
+ this.onload[this.api].push( function() { myself.addSmallControls(); } );
866
+ return;
867
+ }
868
+
869
+ var map = this.maps[this.api];
870
+
871
+ switch (this.api) {
872
+ case 'yahoo':
873
+ map.addPanControl();
874
+ map.addZoomShort();
875
+ this.addControlsArgs.pan = true;
876
+ this.addControlsArgs.zoom = 'small';
877
+ break;
878
+ case 'google':
879
+ case 'openstreetmap':
880
+ map.addControl(new GSmallMapControl());
881
+ this.addControlsArgs.zoom = 'small';
882
+ break;
883
+ case 'openlayers':
884
+ map.addControl(new OpenLayers.Control.ZoomBox());
885
+ map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
886
+ break;
887
+ case 'multimap':
888
+ smallPanzoomWidget = new MMSmallPanZoomWidget();
889
+ map.addWidget( smallPanzoomWidget );
890
+ this.addControlsArgs.pan = true;
891
+ this.addControlsArgs.zoom = 'small';
892
+ break;
893
+ case 'mapquest':
894
+ map.addControl(new MQZoomControl(map));
895
+ map.addControl(new PanControl(map));
896
+ this.addControlsArgs.pan = true;
897
+ this.addControlsArgs.zoom = 'small';
898
+
899
+ break;
900
+ }
901
+ }
902
+
903
+ /**
904
+ * addLargeControls adds a map panning control and zoom bar to the map
905
+ * Supported by: yahoo, google, openstreetmap, multimap, mapquest
906
+ */
907
+ Mapstraction.prototype.addLargeControls = function() {
908
+ if(this.loaded[this.api] == false) {
909
+ myself = this;
910
+ this.onload[this.api].push( function() { myself.addLargeControls(); } );
911
+ return;
912
+ }
913
+
914
+ var map = this.maps[this.api];
915
+
916
+ switch (this.api) {
917
+ case 'yahoo':
918
+ map.addPanControl();
919
+ map.addZoomLong();
920
+ this.addControlsArgs.pan = true; // keep the controls in case of swap
921
+ this.addControlsArgs.zoom = 'large';
922
+ break;
923
+ case 'openlayers':
924
+ map.addControl(new OpenLayers.Control.PanZoomBar());
925
+ break;
926
+ case 'google':
927
+ map.addControl(new GMapTypeControl());
928
+ map.addControl(new GOverviewMapControl()) ;
929
+ this.addControlsArgs.overview = true;
930
+ this.addControlsArgs.map_type = true;
931
+ case 'openstreetmap':
932
+ map.addControl(new GLargeMapControl());
933
+ map.addControl(new GScaleControl()) ;
934
+ this.addControlsArgs.pan = true;
935
+ this.addControlsArgs.zoom = 'large';
936
+ this.addControlsArgs.scale = true;
937
+ break;
938
+ case 'multimap':
939
+ panzoomWidget = new MMPanZoomWidget();
940
+ map.addWidget( panzoomWidget );
941
+ this.addControlsArgs.pan = true; // keep the controls in case of swap
942
+ this.addControlsArgs.zoom = 'large';
943
+ break;
944
+ case 'mapquest':
945
+ map.addControl(new MQLargeZoomControl(map));
946
+ map.addControl(new PanControl(map));
947
+ map.addControl(new MQViewControl(map));
948
+ this.addControlsArgs.pan = true;
949
+ this.addControlsArgs.zoom = 'large';
950
+ this.addControlsArgs.map_type = true;
951
+ break;
952
+ }
953
+ }
954
+
955
+ /**
956
+ * addMapTypeControls adds a map type control to the map (streets, aerial imagery etc)
957
+ * Supported by: yahoo, google, openstreetmap, multimap, mapquest
958
+ */
959
+ Mapstraction.prototype.addMapTypeControls = function() {
960
+ if(this.loaded[this.api] == false) {
961
+ myself = this;
962
+ this.onload[this.api].push( function() { myself.addMapTypeControls(); } );
963
+ return;
964
+ }
965
+
966
+ var map = this.maps[this.api];
967
+
968
+ switch (this.api) {
969
+ case 'yahoo':
970
+ map.addTypeControl();
971
+ break;
972
+ case 'google':
973
+ case 'openstreetmap':
974
+ map.addControl(new GMapTypeControl());
975
+ break;
976
+ case 'multimap':
977
+ map.addWidget( new MMMapTypeWidget() );
978
+ break;
979
+ case 'mapquest':
980
+ map.addControl(new MQViewControl(map));
981
+ break;
982
+ case 'openlayers':
983
+ map.addControl( new OpenLayers.Control.LayerSwitcher({'ascending':false}) );
984
+ break;
985
+ }
986
+ }
987
+
988
+ /**
989
+ * dragging
990
+ * enable/disable dragging of the map
991
+ * (only implemented for yahoo and google)
992
+ * Supported by: yahoo, google, openstreetmap, multimap
993
+ * @param {on} on Boolean
994
+ */
995
+ Mapstraction.prototype.dragging = function(on) {
996
+ if(this.loaded[this.api] == false) {
997
+ myself = this;
998
+ this.onload[this.api].push( function() { myself.dragging(on); } );
999
+ return;
1000
+ }
1001
+
1002
+ var map = this.maps[this.api];
1003
+
1004
+ switch (this.api) {
1005
+ case 'google':
1006
+ case 'openstreetmap':
1007
+ if (on) {
1008
+ map.enableDragging();
1009
+ } else {
1010
+ map.disableDragging();
1011
+ }
1012
+ break;
1013
+ case 'yahoo':
1014
+ if (on) {
1015
+ map.enableDragMap();
1016
+ } else {
1017
+ map.disableDragMap();
1018
+ }
1019
+ break;
1020
+ case 'multimap':
1021
+ if (on) {
1022
+ map.setOption("drag","dragmap");
1023
+ } else {
1024
+ map.setOption("drag","");
1025
+ }
1026
+ break;
1027
+ case 'mapquest':
1028
+ map.enableDragging(on);
1029
+ break;
1030
+ }
1031
+ }
1032
+
1033
+ /**
1034
+ * centers the map to some place and zoom level
1035
+ * @param {LatLonPoint} point Where the center of the map should be
1036
+ * @param {int} zoom The zoom level where 0 is all the way out.
1037
+ */
1038
+ Mapstraction.prototype.setCenterAndZoom = function(point, zoom) {
1039
+ if(this.loaded[this.api] == false) {
1040
+ myself = this;
1041
+ this.onload[this.api].push( function() { myself.setCenterAndZoom(point, zoom); } );
1042
+ return;
1043
+ }
1044
+ var map = this.maps[this.api];
1045
+
1046
+ switch (this.api) {
1047
+ case 'yahoo':
1048
+ var yzoom = 18 - zoom; // maybe?
1049
+ map.drawZoomAndCenter(point.toYahoo(),yzoom);
1050
+ break;
1051
+ case 'google':
1052
+ case 'openstreetmap':
1053
+ map.setCenter(point.toGoogle(), zoom);
1054
+ break;
1055
+ case 'microsoft':
1056
+ map.SetCenterAndZoom(point.toMicrosoft(),zoom);
1057
+ break;
1058
+ case 'openlayers':
1059
+ map.setCenter(point.toOpenLayers(), zoom);
1060
+ break;
1061
+ case 'multimap':
1062
+ map.goToPosition( new MMLatLon( point.lat, point.lng ) );
1063
+ map.setZoomFactor( zoom );
1064
+ break;
1065
+ case 'map24':
1066
+ var newSettings = new Object();
1067
+ newSettings.Latitude = point.lat*60;
1068
+ newSettings.Longitude = point.lon*60;
1069
+ var client = map.MapClient['Static'];
1070
+ var dLon = getDegreesFromGoogleZoomLevel
1071
+ (client.getCanvasSize().Width,zoom);
1072
+ newSettings.MinimumWidth = lonToMetres (dLon, point.lat);
1073
+ Map24.MapApplication.center ( newSettings );
1074
+ break;
1075
+ case 'mapquest':
1076
+ // MapQuest's zoom levels appear to be off by '3' from the other providers for the same bbox
1077
+ map.setCenter(new MQLatLng( point.lat, point.lng ), zoom - 3 );
1078
+ break;
1079
+ case 'freeearth':
1080
+ if (this.freeEarthLoaded) {
1081
+ map.setTargetLatLng( point.toFreeEarth() );
1082
+ } else {
1083
+ myself = this;
1084
+ this.freeEarthOnLoad.push( function() { myself.setCenterAndZoom(point); } );
1085
+ }
1086
+ break;
1087
+ default:
1088
+ if(this.debug)
1089
+ alert(this.api + ' not supported by Mapstraction.setCenterAndZoom');
1090
+ }
1091
+ }
1092
+
1093
+
1094
+ /**
1095
+ * addMarker adds a marker pin to the map
1096
+ * @param {Marker} marker The marker to add
1097
+ * @param {old} old If true, doesn't add this marker to the markers array. Used by the "swap" method
1098
+ */
1099
+ Mapstraction.prototype.addMarker = function(marker,old) {
1100
+ var map = this.maps[this.api];
1101
+ marker.mapstraction = this;
1102
+ marker.api = this.api;
1103
+ marker.map = this.maps[this.api];
1104
+
1105
+ if(this.loaded[this.api] == false) {
1106
+ myself = this;
1107
+ this.onload[this.api].push( function() { myself.addMarker(marker, old); } );
1108
+ return;
1109
+ }
1110
+
1111
+ switch (this.api) {
1112
+ case 'yahoo':
1113
+ var ypin = marker.toYahoo();
1114
+ marker.setChild(ypin);
1115
+ map.addOverlay(ypin);
1116
+ if (! old) { this.markers.push(marker); }
1117
+ break;
1118
+ case 'google':
1119
+ case 'openstreetmap':
1120
+ var gpin = marker.toGoogle();
1121
+ marker.setChild(gpin);
1122
+ map.addOverlay(gpin);
1123
+ if (! old) { this.markers.push(marker); }
1124
+ break;
1125
+ case 'microsoft':
1126
+ var mpin = marker.toMicrosoft();
1127
+ marker.setChild(mpin); // FIXME: MSFT maps remove the pin by pinID so this isn't needed?
1128
+ map.AddPushpin(mpin);
1129
+ if (! old) { this.markers.push(marker); }
1130
+ break;
1131
+ case 'openlayers':
1132
+ //this.map.addPopup(new OpenLayers.Popup("chicken", new OpenLayers.LonLat(5,40), new OpenLayers.Size(200,200), "example popup"));
1133
+ if (!this.layers['markers'])
1134
+ {
1135
+ this.layers['markers'] = new OpenLayers.Layer.Markers("markers");
1136
+ map.addLayer(this.layers['markers']);
1137
+ }
1138
+ var olmarker = marker.toOpenLayers();
1139
+ marker.setChild(olmarker);
1140
+ this.layers['markers'].addMarker(olmarker);
1141
+ if (! old) { this.markers.push(marker); }
1142
+ break;
1143
+ case 'multimap':
1144
+ var mmpin = marker.toMultiMap();
1145
+ marker.setChild(mmpin);
1146
+ map.addOverlay(mmpin);
1147
+ if (! old) { this.markers.push(marker); }
1148
+ break;
1149
+ case 'map24':
1150
+ var m24pin = marker.toMap24();
1151
+ marker.setChild(m24pin);
1152
+ m24pin.commit();
1153
+ if (! old) { this.markers.push(marker); }
1154
+ break;
1155
+ case 'mapquest':
1156
+ var mqpin = marker.toMapQuest();
1157
+ marker.setChild(mqpin);
1158
+ map.addPoi(mqpin);
1159
+ if (! old) { this.markers.push(marker); }
1160
+ break;
1161
+ case 'freeearth':
1162
+ var fepin = marker.toFreeEarth();
1163
+ marker.setChild(fepin);
1164
+ map.addOverlay(fepin);
1165
+ if (! old) { this.markers.push(marker); }
1166
+ break;
1167
+ default:
1168
+ if(this.debug)
1169
+ alert(this.api + ' not supported by Mapstraction.addMarker');
1170
+ }
1171
+ }
1172
+
1173
+ /**
1174
+ * addMarkerWithData will addData to the marker, then add it to the map
1175
+ * @param{marker} marker The marker to add
1176
+ * @param{data} data A data has to add
1177
+ */
1178
+ Mapstraction.prototype.addMarkerWithData = function(marker,data) {
1179
+ marker.addData(data);
1180
+ this.addMarker(marker);
1181
+ }
1182
+
1183
+ /**
1184
+ * addPolylineWithData will addData to the polyline, then add it to the map
1185
+ * @param{polyline} polyline The polyline to add
1186
+ * @param{data} data A data has to add
1187
+ */
1188
+ Mapstraction.prototype.addPolylineWithData = function(polyline,data) {
1189
+ polyline.addData(data);
1190
+ this.addPolyline(polyline);
1191
+ }
1192
+
1193
+ /**
1194
+ * removeMarker removes a Marker from the map
1195
+ * @param {Marker} marker The marker to remove
1196
+ */
1197
+ Mapstraction.prototype.removeMarker = function(marker) {
1198
+ if(this.loaded[this.api] == false) {
1199
+ myself = this;
1200
+ this.onload[this.api].push( function() { myself.removeMarker(marker); } );
1201
+ return;
1202
+ }
1203
+
1204
+ var map = this.maps[this.api];
1205
+
1206
+ var tmparray = new Array();
1207
+ while(this.markers.length > 0){
1208
+ current_marker = this.markers.pop();
1209
+ if(marker == current_marker) {
1210
+ switch (this.api) {
1211
+ case 'google':
1212
+ case 'openstreetmap':
1213
+ map.removeOverlay(marker.proprietary_marker);
1214
+ break;
1215
+ case 'yahoo':
1216
+ map.removeOverlay(marker.proprietary_marker);
1217
+ break;
1218
+ case 'microsoft':
1219
+ map.DeletePushpin(marker.pinID);
1220
+ break;
1221
+ case 'multimap':
1222
+ map.removeOverlay(marker.proprietary_marker);
1223
+ break;
1224
+ case 'mapquest':
1225
+ map.removePoi(marker.proprietary_marker);
1226
+ break;
1227
+ case 'map24':
1228
+ marker.proprietary_marker.remove();
1229
+ break;
1230
+ case 'openlayers':
1231
+ this.layers['markers'].removeMarker(marker.proprietary_marker);
1232
+ marker.proprietary_marker.destroy();
1233
+ break;
1234
+ }
1235
+ marker.onmap = false;
1236
+ break;
1237
+ } else {
1238
+ tmparray.push(current_marker);
1239
+ }
1240
+ }
1241
+ this.markers = this.markers.concat(tmparray);
1242
+ }
1243
+
1244
+ /**
1245
+ * removeAllMarkers removes all the Markers on a map
1246
+ */
1247
+ Mapstraction.prototype.removeAllMarkers = function() {
1248
+ if(this.loaded[this.api] == false) {
1249
+ myself = this;
1250
+ this.onload[this.api].push( function() { myself.removeAllMarkers(); } );
1251
+ return;
1252
+ }
1253
+
1254
+ var map = this.maps[this.api];
1255
+
1256
+ switch (this.api) {
1257
+ case 'yahoo':
1258
+ map.removeMarkersAll();
1259
+ break;
1260
+ case 'google':
1261
+ case 'openstreetmap':
1262
+ map.clearOverlays();
1263
+ break;
1264
+ case 'microsoft':
1265
+ map.DeleteAllPushpins();
1266
+ break;
1267
+ case 'multimap':
1268
+ map.removeAllOverlays();
1269
+ break;
1270
+ case 'mapquest':
1271
+ map.removeAllPois();
1272
+ break;
1273
+ case 'map24':
1274
+ // don't think map24 has a specific method for this
1275
+ var current_marker;
1276
+ while(this.markers.length > 0) {
1277
+ current_marker = this.markers.pop();
1278
+ current_marker.proprietary_marker.remove();
1279
+ }
1280
+ break;
1281
+ case 'openlayers':
1282
+ this.layers['markers'].clearMarkers();
1283
+ break;
1284
+ default:
1285
+ if(this.debug)
1286
+ alert(this.api + ' not supported by Mapstraction.removeAllMarkers');
1287
+ }
1288
+
1289
+ this.markers = new Array(); // clear the mapstraction list of markers too
1290
+
1291
+ }
1292
+
1293
+
1294
+ /**
1295
+ * Add a polyline to the map
1296
+ */
1297
+ Mapstraction.prototype.addPolyline = function(polyline,old) {
1298
+
1299
+ if(this.loaded[this.api] == false) {
1300
+ myself = this;
1301
+ this.onload[this.api].push( function() { myself.addPolyline(polyline,old); } );
1302
+ return;
1303
+ }
1304
+
1305
+ var map = this.maps[this.api];
1306
+
1307
+ switch (this.api) {
1308
+ case 'yahoo':
1309
+ ypolyline = polyline.toYahoo();
1310
+ polyline.setChild(ypolyline);
1311
+ map.addOverlay(ypolyline);
1312
+ if(!old) {this.polylines.push(polyline);}
1313
+ break;
1314
+ case 'google':
1315
+ case 'openstreetmap':
1316
+ gpolyline = polyline.toGoogle();
1317
+ polyline.setChild(gpolyline);
1318
+ map.addOverlay(gpolyline);
1319
+ if(!old) {this.polylines.push(polyline);}
1320
+ break;
1321
+ case 'microsoft':
1322
+ mpolyline = polyline.toMicrosoft();
1323
+ polyline.setChild(mpolyline);
1324
+ map.AddPolyline(mpolyline);
1325
+ if(!old) {this.polylines.push(polyline);}
1326
+ break;
1327
+ case 'openlayers':
1328
+ if(this.debug)
1329
+ alert(this.api + ' not supported by Mapstraction.addPolyline');
1330
+ break;
1331
+ case 'multimap':
1332
+ mmpolyline = polyline.toMultiMap();
1333
+ polyline.setChild(mmpolyline);
1334
+ map.addOverlay( mmpolyline );
1335
+ if(!old) {this.polylines.push(polyline);}
1336
+ break;
1337
+ case 'mapquest':
1338
+ mqpolyline = polyline.toMapQuest();
1339
+ polyline.setChild(mqpolyline);
1340
+ map.addOverlay( mqpolyline );
1341
+ if(!old) {this.polylines.push(polyline);}
1342
+ break;
1343
+ case 'map24':
1344
+ var m24polyline = polyline.toMap24();
1345
+ polyline.setChild(m24polyline);
1346
+ m24polyline.commit();
1347
+ if(!old) {this.polylines.push(polyline);}
1348
+ break;
1349
+ default:
1350
+ if(this.debug)
1351
+ alert(this.api + ' not supported by Mapstraction.addPolyline');
1352
+ }
1353
+ }
1354
+
1355
+ /**
1356
+ * Remove the polyline from the map
1357
+ */
1358
+ Mapstraction.prototype.removePolyline = function(polyline) {
1359
+ if(this.loaded[this.api] == false) {
1360
+ myself = this;
1361
+ this.onload[this.api].push( function() { myself.removePolyline(polyline); } );
1362
+ return;
1363
+ }
1364
+
1365
+ var map = this.maps[this.api];
1366
+
1367
+ var tmparray = new Array();
1368
+ while(this.polylines.length > 0){
1369
+ current_polyline = this.polylines.pop();
1370
+ if(polyline == current_polyline) {
1371
+ switch (this.api) {
1372
+ case 'google':
1373
+ case 'openstreetmap':
1374
+ map.removeOverlay(polyline.proprietary_polyline);
1375
+ break;
1376
+ case 'yahoo':
1377
+ map.removeOverlay(polyline.proprietary_polyline);
1378
+ break;
1379
+ case 'microsoft':
1380
+ map.DeletePolyline(polyline.pllID);
1381
+ break;
1382
+ case 'multimap':
1383
+ polyline.proprietary_polyline.remove();
1384
+ break;
1385
+ case 'mapquest':
1386
+ map.removeOverlay(polyline.proprietary_polyline);
1387
+ break;
1388
+ case 'map24':
1389
+ polyline.proprietary_polyline.remove();
1390
+ break;
1391
+ }
1392
+ polyline.onmap = false;
1393
+ break;
1394
+ } else {
1395
+ tmparray.push(current_polyline);
1396
+ }
1397
+ }
1398
+ this.polylines = this.polylines.concat(tmparray);
1399
+ }
1400
+
1401
+ /**
1402
+ * Removes all polylines from the map
1403
+ */
1404
+ Mapstraction.prototype.removeAllPolylines = function() {
1405
+ if(this.loaded[this.api] == false) {
1406
+ myself = this;
1407
+ this.onload[this.api].push( function() { myself.removeAllPolylines(); } );
1408
+ return;
1409
+ }
1410
+
1411
+ var map = this.maps[this.api];
1412
+
1413
+ switch (this.api) {
1414
+ case 'yahoo':
1415
+ for(var i = 0, length = this.polylines.length;i < length;i++){
1416
+ map.removeOverlay(this.polylines[i].proprietary_polyline);
1417
+ }
1418
+ break;
1419
+ case 'google':
1420
+ case 'openstreetmap':
1421
+ for(var i = 0, length = this.polylines.length;i < length;i++){
1422
+ map.removeOverlay(this.polylines[i].proprietary_polyline);
1423
+ }
1424
+ break;
1425
+ case 'microsoft':
1426
+ map.DeleteAllPolylines();
1427
+ break;
1428
+ case 'multimap':
1429
+ for(var i = 0, length = this.polylines.length;i < length;i++){
1430
+ this.polylines[i].proprietary_polyline.remove();
1431
+ }
1432
+ break;
1433
+ case 'mapquest':
1434
+ map.removeAllOverlays();
1435
+ break;
1436
+ case 'map24':
1437
+ // don't think map24 has a specific method for this
1438
+ var current_polyline;
1439
+ while(this.polylines.length > 0) {
1440
+ current_polyline = this.polylines.pop();
1441
+ current_polyline.proprietary_polyline.remove();
1442
+ }
1443
+ break;
1444
+ default:
1445
+ if(this.debug)
1446
+ alert(this.api + ' not supported by Mapstraction.removeAllPolylines');
1447
+
1448
+ }
1449
+ this.polylines = new Array();
1450
+ }
1451
+
1452
+ /**
1453
+ * getCenter gets the central point of the map
1454
+ * @returns the center point of the map
1455
+ * @type LatLonPoint
1456
+ */
1457
+ Mapstraction.prototype.getCenter = function() {
1458
+ if(this.loaded[this.api] == false) {
1459
+ return null;
1460
+ }
1461
+
1462
+ var map = this.maps[this.api];
1463
+
1464
+ var point = undefined;
1465
+ switch (this.api) {
1466
+ case 'yahoo':
1467
+ var pt = map.getCenterLatLon();
1468
+ point = new LatLonPoint(pt.Lat,pt.Lon);
1469
+ break;
1470
+ case 'google':
1471
+ case 'openstreetmap':
1472
+ var pt = map.getCenter();
1473
+ point = new LatLonPoint(pt.lat(),pt.lng());
1474
+ break;
1475
+ case 'openlayers':
1476
+ var pt = map.getCenter();
1477
+ point = new LatLonPoint(pt.lat, pt.lon);
1478
+ break;
1479
+ case 'microsoft':
1480
+ var pt = map.GetCenter();
1481
+ point = new LatLonPoint(pt.Latitude,pt.Longitude);
1482
+ break;
1483
+ case 'multimap':
1484
+ var pt = map.getCurrentPosition();
1485
+ point = new LatLonPoint(pt.y, pt.x);
1486
+ break;
1487
+ case 'mapquest':
1488
+ var pt = map.getCenter();
1489
+ point = new LatLonPoint(pt.getLatitude(), pt.getLongitude());
1490
+ break;
1491
+ case 'map24':
1492
+ var pt = map.MapClient['Static'].getCurrentMapView().getCenter();
1493
+ point = new LatLonPoint(pt.Y/60,pt.X/60);
1494
+ break;
1495
+
1496
+
1497
+ default:
1498
+ if(this.debug)
1499
+ alert(this.api + ' not supported by Mapstraction.getCenter');
1500
+ }
1501
+ return point;
1502
+ }
1503
+
1504
+ /**
1505
+ * setCenter sets the central point of the map
1506
+ * @param {LatLonPoint} point The point at which to center the map
1507
+ */
1508
+ Mapstraction.prototype.setCenter = function(point) {
1509
+ if(this.loaded[this.api] == false) {
1510
+ myself = this;
1511
+ this.onload[this.api].push( function() { myself.setCenter(point); } );
1512
+ return;
1513
+ }
1514
+
1515
+ var map = this.maps[this.api];
1516
+
1517
+ switch (this.api) {
1518
+ case 'yahoo':
1519
+ map.panToLatLon(point.toYahoo());
1520
+ break;
1521
+ case 'google':
1522
+ case 'openstreetmap':
1523
+ map.setCenter(point.toGoogle());
1524
+ break;
1525
+ case 'openlayers':
1526
+ map.setCenter(point.toOpenLayers());
1527
+ break;
1528
+ case 'microsoft':
1529
+ map.SetCenter(point.toMicrosoft());
1530
+ break;
1531
+ case 'multimap':
1532
+ map.goToPosition(point.toMultiMap());
1533
+ break;
1534
+ case 'mapquest':
1535
+ map.setCenter(point.toMapQuest());
1536
+ break;
1537
+ case 'freeearth':
1538
+ if (this.freeEarthLoaded) {
1539
+ map.setTargetLatLng( point.toFreeEarth() );
1540
+ } else {
1541
+ myself = this;
1542
+ this.freeEarthOnLoad.push( function() { myself.setCenterAndZoom(point); }
1543
+ );
1544
+ }
1545
+ break;
1546
+ case 'map24':
1547
+ // Since center changes the zoom level to default
1548
+ // we have to get the original metre width and pass it back in when
1549
+ // centering.
1550
+ var mv = map.MapClient['Static'].getCurrentMapView();
1551
+ var newSettings = new Object();
1552
+ newSettings.MinimumWidth = lonToMetres
1553
+ (mv.LowerRight.Longitude - mv.TopLeft.Longitude,
1554
+ (mv.LowerRight.Latitude+mv.TopLeft.Latitude)/2);
1555
+ newSettings.Latitude = point.lat*60;
1556
+ newSettings.Longitude = point.lon*60;
1557
+ Map24.MapApplication.center(newSettings);
1558
+ break;
1559
+ default:
1560
+ if(this.debug)
1561
+ alert(this.api + ' not supported by Mapstraction.setCenter');
1562
+ }
1563
+ }
1564
+ /**
1565
+ * setZoom sets the zoom level for the map
1566
+ * MS doesn't seem to do zoom=0, and Gg's sat goes closer than it's maps, and MS's sat goes closer than Y!'s
1567
+ * TODO: Mapstraction.prototype.getZoomLevels or something.
1568
+ * @param {int} zoom The (native to the map) level zoom the map to.
1569
+ */
1570
+ Mapstraction.prototype.setZoom = function(zoom) {
1571
+ if(this.loaded[this.api] == false) {
1572
+ myself = this;
1573
+ this.onload[this.api].push( function() { myself.setZoom(zoom); } );
1574
+ return;
1575
+ }
1576
+
1577
+ var map = this.maps[this.api];
1578
+
1579
+ switch (this.api) {
1580
+ case 'yahoo':
1581
+ var yzoom = 18 - zoom; // maybe?
1582
+ map.setZoomLevel(yzoom);
1583
+ break;
1584
+ case 'google':
1585
+ case 'openstreetmap':
1586
+ map.setZoom(zoom);
1587
+ break;
1588
+ case 'openlayers':
1589
+ map.zoomTo(zoom);
1590
+ break;
1591
+ case 'microsoft':
1592
+ map.SetZoomLevel(zoom);
1593
+ break;
1594
+ case 'multimap':
1595
+ map.setZoomFactor(zoom);
1596
+ break;
1597
+ case 'mapquest':
1598
+ map.setZoomLevel(zoom - 3); // MapQuest seems off by 3
1599
+ break;
1600
+ case 'map24':
1601
+ // get the current centre than calculate the settings based on this
1602
+ var point = this.getCenter();
1603
+ var newSettings = new Object();
1604
+ newSettings.Latitude = point.lat*60;
1605
+ newSettings.Longitude = point.lon*60;
1606
+ var client = map.MapClient['Static'];
1607
+ var dLon = getDegreesFromGoogleZoomLevel
1608
+ (client.getCanvasSize().Width,zoom);
1609
+ newSettings.MinimumWidth = lonToMetres (dLon, point.lat);
1610
+ Map24.MapApplication.center ( newSettings );
1611
+ break;
1612
+ default:
1613
+ if(this.debug)
1614
+ alert(this.api + ' not supported by Mapstraction.setZoom');
1615
+ }
1616
+ }
1617
+ /**
1618
+ * autoCenterAndZoom sets the center and zoom of the map to the smallest bounding box
1619
+ * containing all markers
1620
+ *
1621
+ */
1622
+ Mapstraction.prototype.autoCenterAndZoom = function() {
1623
+ if(this.loaded[this.api] == false) {
1624
+ myself = this;
1625
+ this.onload[this.api].push( function() { myself.autoCenterAndZoom(); } );
1626
+ return;
1627
+ }
1628
+
1629
+ var lat_max = -90;
1630
+ var lat_min = 90;
1631
+ var lon_max = -180;
1632
+ var lon_min = 180;
1633
+
1634
+ for (var i=0; i<this.markers.length; i++) {;
1635
+ lat = this.markers[i].location.lat;
1636
+ lon = this.markers[i].location.lon;
1637
+ if (lat > lat_max) lat_max = lat;
1638
+ if (lat < lat_min) lat_min = lat;
1639
+ if (lon > lon_max) lon_max = lon;
1640
+ if (lon < lon_min) lon_min = lon;
1641
+ }
1642
+ for (i=0; i<this.polylines.length; i++) {
1643
+ for (j=0; j<this.polylines[i].points.length; j++) {
1644
+ lat = this.polylines[i].points[j].lat;
1645
+ lon = this.polylines[i].points[j].lon;
1646
+
1647
+ if (lat > lat_max) lat_max = lat;
1648
+ if (lat < lat_min) lat_min = lat;
1649
+ if (lon > lon_max) lon_max = lon;
1650
+ if (lon < lon_min) lon_min = lon;
1651
+ }
1652
+ }
1653
+ this.setBounds( new BoundingBox(lat_min, lon_min, lat_max, lon_max) );
1654
+ }
1655
+
1656
+ /**
1657
+ * centerAndZoomOnPoints sets the center and zoom of the map from an array of points
1658
+ *
1659
+ * This is useful if you don't want to have to add markers to the map
1660
+ */
1661
+ Mapstraction.prototype.centerAndZoomOnPoints = function(points) {
1662
+ var bounds = new BoundingBox(points[0].lat,points[0].lon,points[0].lat,points[0].lon);
1663
+
1664
+ for (var i=1, len = points.length ; i<len; i++) {
1665
+ bounds.extend(points[i]);
1666
+ }
1667
+
1668
+ this.setBounds(bounds);
1669
+ }
1670
+
1671
+ /**
1672
+ * getZoom returns the zoom level of the map
1673
+ * @returns the zoom level of the map
1674
+ * @type int
1675
+ */
1676
+ Mapstraction.prototype.getZoom = function() {
1677
+ if(this.loaded[this.api] == false) {
1678
+ myself = this;
1679
+ return -1;
1680
+ }
1681
+
1682
+ var map = this.maps[this.api];
1683
+
1684
+ switch (this.api) {
1685
+ case 'yahoo':
1686
+ return 18 - map.getZoomLevel(); // maybe?
1687
+ case 'google':
1688
+ case 'openstreetmap':
1689
+ return map.getZoom();
1690
+ case 'openlayers':
1691
+ return map.zoom;
1692
+ case 'microsoft':
1693
+ return map.GetZoomLevel();
1694
+ case 'multimap':
1695
+ return map.getZoomFactor();
1696
+ case 'mapquest':
1697
+ return map.getZoomLevel() + 3; // Mapquest seems off by 3?
1698
+ case 'map24':
1699
+ // since map24 doesn't use a Google-style set of zoom levels, we have
1700
+ // to round to the nearest zoom
1701
+ var mv = map.MapClient['Static'].getCurrentMapView();
1702
+ var dLon = (mv.LowerRight.Longitude - mv.TopLeft.Longitude) / 60;
1703
+ var width = map.MapClient['Static'].getCanvasSize().Width;
1704
+ var zoom = getGoogleZoomLevelFromDegrees (width,dLon);
1705
+ return Math.round(zoom);
1706
+ default:
1707
+ if(this.debug)
1708
+ alert(this.api + ' not supported by Mapstraction.getZoom');
1709
+ }
1710
+ }
1711
+
1712
+ /**
1713
+ * getZoomLevelForBoundingBox returns the best zoom level for bounds given
1714
+ * @param boundingBox the bounds to fit
1715
+ * @returns the closest zoom level that contains the bounding box
1716
+ * @type int
1717
+ */
1718
+ Mapstraction.prototype.getZoomLevelForBoundingBox = function( bbox ) {
1719
+ if(this.loaded[this.api] == false) {
1720
+ myself = this;
1721
+ return -1;
1722
+ }
1723
+
1724
+ var map = this.maps[this.api];
1725
+
1726
+ // NE and SW points from the bounding box.
1727
+ var ne = bbox.getNorthEast();
1728
+ var sw = bbox.getSouthWest();
1729
+
1730
+ switch (this.api) {
1731
+ case 'google':
1732
+ case 'openstreetmap':
1733
+ var gbox = new GLatLngBounds( sw.toGoogle(), ne.toGoogle() );
1734
+ var zoom = map.getBoundsZoomLevel( gbox );
1735
+ return zoom;
1736
+ break;
1737
+ case 'openlayers':
1738
+ var olbox = bbox.toOpenLayers();
1739
+ var zoom = map.getZoomForExtent(olbox);
1740
+ break;
1741
+ case 'multimap':
1742
+ var mmlocation = map.getBoundsZoomFactor( sw.toMultiMap(), ne.toMultiMap() );
1743
+ var zoom = mmlocation.zoom_factor();
1744
+ return zoom;
1745
+ break;
1746
+ case 'map24':
1747
+ // since map24 doesn't use a Google-style set of zoom levels, we work
1748
+ // out what zoom level will show the given longitude difference within
1749
+ // the current map pixel width
1750
+ var dLon = ne.lon - sw.lon;
1751
+ var width = map.MapClient['Static'].getCanvasSize().Width;
1752
+ var zoom = getGoogleZoomLevelFromDegrees (width,dLon);
1753
+ return Math.round(zoom);
1754
+ break;
1755
+ default:
1756
+ if(this.debug)
1757
+ alert( this.api + ' not supported by Mapstraction.getZoomLevelForBoundingBox' );
1758
+ }
1759
+ }
1760
+
1761
+
1762
+ // any use this being a bitmask? Should HYBRID = ROAD | SATELLITE?
1763
+ Mapstraction.ROAD = 1;
1764
+ Mapstraction.SATELLITE = 2;
1765
+ Mapstraction.HYBRID = 3;
1766
+
1767
+ /**
1768
+ * setMapType sets the imagery type for the map.
1769
+ * The type can be one of:
1770
+ * Mapstraction.ROAD
1771
+ * Mapstraction.SATELLITE
1772
+ * Mapstraction.HYBRID
1773
+ * @param {int} type The (native to the map) level zoom the map to.
1774
+ */
1775
+ Mapstraction.prototype.setMapType = function(type) {
1776
+ if(this.loaded[this.api] == false) {
1777
+ myself = this;
1778
+ this.onload[this.api].push( function() { myself.setMapType(type); } );
1779
+ return;
1780
+ }
1781
+
1782
+ var map = this.maps[this.api];
1783
+
1784
+ switch (this.api) {
1785
+ case 'yahoo':
1786
+ switch(type) {
1787
+ case Mapstraction.ROAD:
1788
+ map.setMapType(YAHOO_MAP_REG);
1789
+ break;
1790
+ case Mapstraction.SATELLITE:
1791
+ map.setMapType(YAHOO_MAP_SAT);
1792
+ break;
1793
+ case Mapstraction.HYBRID:
1794
+ map.setMapType(YAHOO_MAP_HYB);
1795
+ break;
1796
+ default:
1797
+ map.setMapType(YAHOO_MAP_REG);
1798
+ }
1799
+ break;
1800
+ case 'google':
1801
+ case 'openstreetmap':
1802
+ switch(type) {
1803
+ case Mapstraction.ROAD:
1804
+ map.setMapType(G_NORMAL_MAP);
1805
+ break;
1806
+ case Mapstraction.SATELLITE:
1807
+ map.setMapType(G_SATELLITE_MAP);
1808
+ break;
1809
+ case Mapstraction.HYBRID:
1810
+ map.setMapType(G_HYBRID_MAP);
1811
+ break;
1812
+ default:
1813
+ map.setMapType(G_NORMAL_MAP);
1814
+ }
1815
+ break;
1816
+ case 'microsoft':
1817
+ // TODO: oblique?
1818
+ switch(type) {
1819
+ case Mapstraction.ROAD:
1820
+ map.SetMapStyle(Msn.VE.MapStyle.Road);
1821
+ break;
1822
+ case Mapstraction.SATELLITE:
1823
+ map.SetMapStyle(Msn.VE.MapStyle.Aerial);
1824
+ break;
1825
+ case Mapstraction.HYBRID:
1826
+ map.SetMapStyle(Msn.VE.MapStyle.Hybrid);
1827
+ break;
1828
+ default:
1829
+ map.SetMapStyle(Msn.VE.MapStyle.Road);
1830
+ }
1831
+ break;
1832
+ case 'multimap':
1833
+ maptypes = map.getAvailableMapTypes();
1834
+ maptype = -1;
1835
+ for (var i = 0; i < maptypes.length; i++) {
1836
+ switch (maptypes[i]) {
1837
+ case MM_WORLD_MAP:
1838
+ if (type == Mapstraction.ROAD) {
1839
+ maptype = maptypes[i];
1840
+ }
1841
+ default_type = maptypes[i];
1842
+ break;
1843
+ case MM_WORLD_AERIAL:
1844
+ if (type == Mapstraction.SATELLITE) {
1845
+ maptype = maptypes[i];
1846
+ }
1847
+ break;
1848
+ case MM_WORLD_HYBRID:
1849
+ if (type == Mapstraction.HYBRID) {
1850
+ maptype = maptypes[i];
1851
+ }
1852
+ break;
1853
+ }
1854
+ }
1855
+ if (maptype == -1) { maptype = default_type; }
1856
+ map.setMapType(maptype);
1857
+ break;
1858
+ case 'mapquest':
1859
+ switch (type) {
1860
+ case Mapstraction.ROAD:
1861
+ map.setMapType("map");
1862
+ break;
1863
+ case Mapstraction.SATELLITE:
1864
+ map.setMapType("sat");
1865
+ break;
1866
+ case Mapstraction.HYBRID:
1867
+ map.setMapType("hyb");
1868
+ break;
1869
+ }
1870
+ break;
1871
+ default:
1872
+ if(this.debug)
1873
+ alert(this.api + ' not supported by Mapstraction.setMapType');
1874
+ }
1875
+ }
1876
+
1877
+ /**
1878
+ * getMapType gets the imagery type for the map.
1879
+ * The type can be one of:
1880
+ * Mapstraction.ROAD
1881
+ * Mapstraction.SATELLITE
1882
+ * Mapstraction.HYBRID
1883
+ */
1884
+ Mapstraction.prototype.getMapType = function() {
1885
+ if(this.loaded[this.api] == false) {
1886
+ myself = this;
1887
+ return -1;
1888
+ }
1889
+
1890
+ var map = this.maps[this.api];
1891
+
1892
+ var type;
1893
+ switch (this.api) {
1894
+ case 'yahoo':
1895
+ type = map.getCurrentMapType();
1896
+ switch(type) {
1897
+ case YAHOO_MAP_REG:
1898
+ return Mapstraction.ROAD;
1899
+ break;
1900
+ case YAHOO_MAP_SAT:
1901
+ return Mapstraction.SATELLITE;
1902
+ break;
1903
+ case YAHOO_MAP_HYB:
1904
+ return Mapstraction.HYBRID;
1905
+ break;
1906
+ default:
1907
+ return null;
1908
+ }
1909
+ break;
1910
+ case 'google':
1911
+ case 'openstreetmap':
1912
+ type = map.getCurrentMapType();
1913
+ switch(type) {
1914
+ case G_NORMAL_MAP:
1915
+ return Mapstraction.ROAD;
1916
+ break;
1917
+ case G_SATELLITE_MAP:
1918
+ return Mapstraction.SATELLITE;
1919
+ break;
1920
+ case G_HYBRID_MAP:
1921
+ return Mapstraction.HYBRID;
1922
+ break;
1923
+ default:
1924
+ return null;
1925
+ }
1926
+ break;
1927
+ case 'microsoft':
1928
+ // TODO: oblique?
1929
+ type = map.GetMapStyle();
1930
+ switch(type) {
1931
+ case Msn.VE.MapStyle.Road:
1932
+ return Mapstraction.ROAD;
1933
+ break;
1934
+ case Msn.VE.MapStyle.Aerial:
1935
+ return Mapstraction.SATELLITE;
1936
+ break;
1937
+ case Msn.VE.MapStyle.Hybrid:
1938
+ return Mapstraction.HYBRID;
1939
+ break;
1940
+ default:
1941
+ return null;
1942
+ }
1943
+ break;
1944
+ case 'multimap':
1945
+ maptypes = map.getAvailableMapTypes();
1946
+ type = map.getMapType();
1947
+ switch(type) {
1948
+ case MM_WORLD_MAP:
1949
+ return Mapstraction.ROAD;
1950
+ break;
1951
+ case MM_WORLD_AERIAL:
1952
+ return Mapstraction.SATELLITE;
1953
+ break;
1954
+ case MM_WORLD_HYBRID:
1955
+ return Mapstraction.HYBRID;
1956
+ break;
1957
+ default:
1958
+ return null;
1959
+ }
1960
+ break;
1961
+ case 'mapquest':
1962
+ type = map.getMapType();
1963
+ switch(type) {
1964
+ case "map":
1965
+ return Mapstraction.ROAD;
1966
+ break;
1967
+ case "sat":
1968
+ return Mapstraction.SATELLITE;
1969
+ break;
1970
+ case "hyb":
1971
+ return Mapstraction.HYBRID;
1972
+ break;
1973
+ default:
1974
+ return null;
1975
+ }
1976
+ break;
1977
+ default:
1978
+ if(this.debug)
1979
+ alert(this.api + ' not supported by Mapstraction.getMapType');
1980
+ }
1981
+ }
1982
+
1983
+ /**
1984
+ * getBounds gets the BoundingBox of the map
1985
+ * @returns the bounding box for the current map state
1986
+ * @type BoundingBox
1987
+ */
1988
+ Mapstraction.prototype.getBounds = function () {
1989
+ if(this.loaded[this.api] == false) {
1990
+ return null;
1991
+ }
1992
+
1993
+ var map = this.maps[this.api];
1994
+
1995
+ switch (this.api) {
1996
+ case 'google':
1997
+ case 'openstreetmap':
1998
+ var gbox = map.getBounds();
1999
+ var sw = gbox.getSouthWest();
2000
+ var ne = gbox.getNorthEast();
2001
+ return new BoundingBox(sw.lat(), sw.lng(), ne.lat(), ne.lng());
2002
+ break;
2003
+ case 'openlayers':
2004
+ var olbox = map.calculateBounds();
2005
+ break;
2006
+ case 'yahoo':
2007
+ var ybox = map.getBoundsLatLon();
2008
+ return new BoundingBox(ybox.LatMin, ybox.LonMin, ybox.LatMax, ybox.LonMax);
2009
+ break;
2010
+ case 'microsoft':
2011
+ var mbox = map.GetMapView();
2012
+ var nw = mbox.TopLeftLatLong;
2013
+ var se = mbox.BottomRightLatLong;
2014
+ return new BoundingBox(se.Latitude,nw.Longitude,nw.Latitude,se.Longitude);
2015
+ break;
2016
+ case 'multimap':
2017
+ var mmbox = map.getMapBounds();
2018
+ var sw = mmbox.getSouthWest();
2019
+ var ne = mmbox.getNorthEast();
2020
+ return new BoundingBox(sw.lat, sw.lon, ne.lat, ne.lon);
2021
+ break;
2022
+ case 'mapquest':
2023
+ var mqbox = map.getMapBounds(); // MQRectLL
2024
+ var se = mqbox.getLowerRightLatLng();
2025
+ var nw = mqbox.getUpperLeftLatLng();
2026
+
2027
+ // NW is this correct ???
2028
+ // return new BoundingBox(se.lat, se.lon, nw.lat, nw.lon);
2029
+
2030
+ // should be this instead
2031
+ return new BoundingBox(se.lat, nw.lon, nw.lat, se.lon);
2032
+
2033
+ break;
2034
+ case 'map24':
2035
+ var mv = map.MapClient['Static'].getCurrentMapView();
2036
+ var se = mv.LowerRight;
2037
+ var nw = mv.TopLeft;
2038
+ return new BoundingBox (se.Latitude/60, nw.Longitude/60,
2039
+ nw.Latitude/60, se.Longitude/60 );
2040
+ break;
2041
+ default:
2042
+ if(this.debug)
2043
+ alert(this.api + ' not supported by Mapstraction.getBounds');
2044
+
2045
+ }
2046
+ }
2047
+
2048
+ /**
2049
+ * setBounds sets the map to the appropriate location and zoom for a given BoundingBox
2050
+ * @param {BoundingBox} the bounding box you want the map to show
2051
+ */
2052
+ Mapstraction.prototype.setBounds = function(bounds){
2053
+ if(this.loaded[this.api] == false) {
2054
+ myself = this;
2055
+ this.onload[this.api].push( function() { myself.setBounds(bounds); } );
2056
+ return;
2057
+ }
2058
+
2059
+ var map = this.maps[this.api];
2060
+
2061
+ var sw = bounds.getSouthWest();
2062
+ var ne = bounds.getNorthEast();
2063
+ switch (this.api) {
2064
+ case 'google':
2065
+ case 'openstreetmap':
2066
+ var gbounds = new GLatLngBounds(new GLatLng(sw.lat,sw.lon),new GLatLng(ne.lat,ne.lon));
2067
+ map.setCenter(gbounds.getCenter(), map.getBoundsZoomLevel(gbounds));
2068
+ break;
2069
+
2070
+ case 'openlayers':
2071
+ var bounds = new OpenLayers.Bounds();
2072
+ bounds.extend(new LatLonPoint(sw.lat,sw.lon).toOpenLayers());
2073
+ bounds.extend(new LatLonPoint(ne.lat,ne.lon).toOpenLayers());
2074
+ map.zoomToExtent(bounds);
2075
+ break;
2076
+ case 'yahoo':
2077
+ if(sw.lon > ne.lon)
2078
+ sw.lon -= 360;
2079
+ var center = new YGeoPoint((sw.lat + ne.lat)/2,
2080
+ (ne.lon + sw.lon)/2);
2081
+
2082
+ var container = map.getContainerSize();
2083
+ for(var zoom = 1 ; zoom <= 17 ; zoom++){
2084
+ var sw_pix = convertLatLonXY_Yahoo(sw,zoom);
2085
+ var ne_pix = convertLatLonXY_Yahoo(ne,zoom);
2086
+ if(sw_pix.x > ne_pix.x)
2087
+ sw_pix.x -= (1 << (26 - zoom)); //earth circumference in pixel
2088
+ if(Math.abs(ne_pix.x - sw_pix.x)<=container.width
2089
+ && Math.abs(ne_pix.y - sw_pix.y) <= container.height){
2090
+ map.drawZoomAndCenter(center,zoom); //Call drawZoomAndCenter here: OK if called multiple times anyway
2091
+ break;
2092
+ }
2093
+ }
2094
+ break;
2095
+ case 'microsoft':
2096
+ map.SetMapView([new VELatLong(sw.lat,sw.lon),new VELatLong(ne.lat,ne.lon)]);
2097
+ break;
2098
+ case 'multimap':
2099
+ var mmlocation = map.getBoundsZoomFactor( sw.toMultiMap(), ne.toMultiMap() );
2100
+ var center = new LatLonPoint(mmlocation.coords.lat, mmlocation.coords.lon);
2101
+ this.setCenterAndZoom(center, mmlocation.zoom_factor);
2102
+ break;
2103
+ case 'mapquest':
2104
+ // TODO: MapQuest.setBounds
2105
+ if(this.debug)
2106
+ alert(this.api + ' not supported by Mapstraction.setBounds');
2107
+
2108
+ break;
2109
+ case 'freeearth':
2110
+ var center = new LatLonPoint((sw.lat + ne.lat)/2, (ne.lon + sw.lon)/2);
2111
+ this.setCenter(center);
2112
+ break;
2113
+
2114
+ case 'map24':
2115
+ var settings = new Object();
2116
+ settings.Latitude = ((sw.lat+ne.lat) / 2) * 60;
2117
+ settings.Longitude = ((sw.lon+ne.lon) / 2) * 60;
2118
+
2119
+ // need to convert lat/lon to metres
2120
+ settings.MinimumWidth = lonToMetres
2121
+ (ne.lon-sw.lon, (ne.lat+sw.lat)/2);
2122
+
2123
+ Map24.MapApplication.center ( settings );
2124
+
2125
+ break;
2126
+ default:
2127
+ if(this.debug)
2128
+ alert(this.api + ' not supported by Mapstraction.setBounds');
2129
+ }
2130
+ }
2131
+
2132
+ /**
2133
+ * addImageOverlay layers an georeferenced image over the map
2134
+ * @param {id} unique DOM identifier
2135
+ * @param {src} url of image
2136
+ * @param {opacity} opacity 0-100
2137
+ * @param {west} west boundary
2138
+ * @param {south} south boundary
2139
+ * @param {east} east boundary
2140
+ * @param {north} north boundary
2141
+ */
2142
+ Mapstraction.prototype.addImageOverlay = function(id, src, opacity, west, south, east, north) {
2143
+ if(this.loaded[this.api] == false) {
2144
+ myself = this;
2145
+ this.onload[this.api].push( function() { myself.addImageOverlay(id, src, opacity, west, south, east, north); } );
2146
+ return;
2147
+ }
2148
+
2149
+ var map = this.maps[this.api];
2150
+
2151
+ var b = document.createElement("img");
2152
+ b.style.display = 'block';
2153
+ b.setAttribute('id',id);
2154
+ b.setAttribute('src',src);
2155
+ b.style.position = 'absolute';
2156
+ b.style.zIndex = 1;
2157
+ b.setAttribute('west',west);
2158
+ b.setAttribute('south',south);
2159
+ b.setAttribute('east',east);
2160
+ b.setAttribute('north',north);
2161
+
2162
+ switch (this.api) {
2163
+ case 'google':
2164
+ case 'openstreetmap':
2165
+ map.getPane(G_MAP_MAP_PANE).appendChild(b);
2166
+ this.setImageOpacity(id, opacity);
2167
+ this.setImagePosition(id);
2168
+ GEvent.bind(map, "zoomend", this, function(){this.setImagePosition(id)});
2169
+ GEvent.bind(map, "moveend", this, function(){this.setImagePosition(id)});
2170
+ break;
2171
+
2172
+ case 'multimap':
2173
+ map.getContainer().appendChild(b);
2174
+ this.setImageOpacity(id, opacity);
2175
+ this.setImagePosition(id);
2176
+ me = this;
2177
+ map.addEventHandler( 'changeZoom', function(eventType, eventTarget, arg1, arg2, arg3) {
2178
+ me.setImagePosition(id);
2179
+ });
2180
+ map.addEventHandler( 'drag', function(eventType, eventTarget, arg1, arg2, arg3) {
2181
+ me.setImagePosition(id);
2182
+ });
2183
+ map.addEventHandler( 'endPan', function(eventType, eventTarget, arg1, arg2, arg3) {
2184
+ me.setImagePosition(id);
2185
+ });
2186
+ break;
2187
+
2188
+ default:
2189
+ b.style.display = 'none';
2190
+ if(this.debug)
2191
+ alert(this.api + "not supported by Mapstraction.addImageOverlay not supported");
2192
+ break;
2193
+ }
2194
+ }
2195
+
2196
+ Mapstraction.prototype.setImageOpacity = function(id, opacity) {
2197
+ if(opacity<0){opacity=0;} if(opacity>=100){opacity=100;}
2198
+ var c=opacity/100;
2199
+ var d=document.getElementById(id);
2200
+ if(typeof(d.style.filter)=='string'){d.style.filter='alpha(opacity:'+opacity+')';}
2201
+ if(typeof(d.style.KHTMLOpacity)=='string'){d.style.KHTMLOpacity=c;}
2202
+ if(typeof(d.style.MozOpacity)=='string'){d.style.MozOpacity=c;}
2203
+ if(typeof(d.style.opacity)=='string'){d.style.opacity=c;}
2204
+ }
2205
+
2206
+ Mapstraction.prototype.setImagePosition = function(id) {
2207
+ if(this.loaded[this.api] == false) {
2208
+ myself = this;
2209
+ this.onload[this.api].push( function() { myself.setImagePosition(id); } );
2210
+ return;
2211
+ }
2212
+
2213
+ var map = this.maps[this.api];
2214
+ var x = document.getElementById(id);
2215
+ var d; var e;
2216
+
2217
+ switch (this.api) {
2218
+ case 'google':
2219
+ case 'openstreetmap':
2220
+ d = map.fromLatLngToDivPixel(new GLatLng(x.getAttribute('north'), x.getAttribute('west')));
2221
+ e = map.fromLatLngToDivPixel(new GLatLng(x.getAttribute('south'), x.getAttribute('east')));
2222
+ break;
2223
+ case 'multimap':
2224
+ d = map.geoPosToContainerPixels(new MMLatLon(x.getAttribute('north'), x.getAttribute('west')));
2225
+ e = map.geoPosToContainerPixels(new MMLatLon(x.getAttribute('south'), x.getAttribute('east')));
2226
+ break;
2227
+ }
2228
+
2229
+ x.style.top=d.y+'px';
2230
+ x.style.left=d.x+'px';
2231
+ x.style.width=e.x-d.x+'px';
2232
+ x.style.height=e.y-d.y+'px';
2233
+ }
2234
+
2235
+ /**
2236
+ * addOverlay adds a GeoRSS or KML overlay to the map
2237
+ * some flavors of GeoRSS and KML are not supported by some of the Map providers
2238
+ * @param{url} GeoRSS feed URL
2239
+ * @param{autoCenterAndZoom} set true to auto center and zoom after the feed is loaded
2240
+ */
2241
+ Mapstraction.prototype.addOverlay = function(url, autoCenterAndZoom) {
2242
+ if(this.loaded[this.api] == false) {
2243
+ myself = this;
2244
+ this.onload[this.api].push( function() { myself.addOverlay(url); } );
2245
+ return;
2246
+ }
2247
+
2248
+ var map = this.maps[this.api];
2249
+
2250
+ switch (this.api) {
2251
+ case 'yahoo':
2252
+ map.addOverlay(new YGeoRSS(url));
2253
+ break;
2254
+ case 'openstreetmap': // OSM uses the google interface, so allow cascade
2255
+ case 'google':
2256
+ var geoXML = new GGeoXml(url);
2257
+ map.addOverlay(geoXML, function() {
2258
+ if(autoCenterAndZoom) { geoXML.gotoDefaultViewport(map); }
2259
+ });
2260
+ break;
2261
+ case 'microsoft':
2262
+ var veLayerSpec = new VELayerSpecification();
2263
+ veLayerSpec.Type = VELayerType.GeoRSS;
2264
+ veLayerSpec.ID = 1;
2265
+ veLayerSpec.LayerSource = url;
2266
+ veLayerSpec.Method = 'get';
2267
+ // veLayerSpec.FnCallback = onFeedLoad;
2268
+ map.AddLayer(veLayerSpec);
2269
+ break;
2270
+ // case 'openlayers':
2271
+ // map.addLayer(new OpenLayers.Layer.GeoRSS("GeoRSS Layer", url));
2272
+ // break;
2273
+ case 'multimap':
2274
+ break;
2275
+ case 'freeearth':
2276
+ if (this.freeEarthLoaded) {
2277
+ var ferss = new FE.GeoRSS(url);
2278
+ map.addOverlay(ferss);
2279
+ } else {
2280
+ myself = this;
2281
+ this.freeEarthOnLoad.push( function() { myself.addOverlay(url); } );
2282
+ }
2283
+ break;
2284
+ default:
2285
+ if(this.debug)
2286
+ alert(this.api + ' not supported by Mapstraction.addGeoRSSOverlay');
2287
+ }
2288
+
2289
+ }
2290
+
2291
+ /* Adds a Tile Layer to the map
2292
+ *
2293
+ * Requires providing a parameterized tile url. Use {Z}, {X}, and {Y} to specify where the parameters
2294
+ * should go in the URL.
2295
+ *
2296
+ * For example, the OpenStreetMap tiles are:
2297
+ * http://tile.openstreetmap.org/{Z}/{X}/{Y}.png
2298
+ *
2299
+ * @param {tile_url} template url of the tiles.
2300
+ * @param {opacity} opacity of the tile layer - 0 is transparent, 1 is opaque. (default=0.6)
2301
+ * @param {copyright_text} copyright text to use for the tile layer. (default=Mapstraction)
2302
+ * @param {min_zoom} Minimum (furtherest out) zoom level that tiles are available (default=1)
2303
+ * @param {max_zoom} Maximum (closest) zoom level that the tiles are available (default=18)
2304
+ */
2305
+ Mapstraction.prototype.addTileLayer = function(tile_url, opacity, copyright_text, min_zoom, max_zoom) {
2306
+ if(!tile_url)
2307
+ return;
2308
+ if (! this.tileLayers) {
2309
+ this.tileLayers = [];
2310
+ }
2311
+ if(!opacity)
2312
+ opacity = 0.6;
2313
+ if(!copyright_text)
2314
+ copyright_text = "Mapstraction";
2315
+ if(!min_zoom)
2316
+ min_zoom = 1;
2317
+ if(!max_zoom)
2318
+ max_zoom = 18;
2319
+
2320
+ console.log(this.api);
2321
+ switch (this.api) {
2322
+ case 'google':
2323
+ case 'openstreetmap':
2324
+ var copyright = new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180), new GLatLng(90,180)), 0, "copyleft");
2325
+ var copyrightCollection = new GCopyrightCollection(copyright_text);
2326
+ copyrightCollection.addCopyright(copyright);
2327
+
2328
+ var tilelayers = new Array();
2329
+ tilelayers[0] = new GTileLayer(copyrightCollection, min_zoom, max_zoom);
2330
+ tilelayers[0].isPng = function() { return true;};
2331
+ tilelayers[0].getOpacity = function() { return opacity; }
2332
+ tilelayers[0].getTileUrl = function (a, b) {
2333
+ url = tile_url;
2334
+ url = url.replace(/\{Z\}/,b);
2335
+ url = url.replace(/\{X\}/,a.x);
2336
+ url = url.replace(/\{Y\}/,a.y);
2337
+ return url
2338
+ };
2339
+ tileLayerOverlay = new GTileLayerOverlay(tilelayers[0]);
2340
+
2341
+ this.tileLayers.push( [tile_url, tileLayerOverlay, true] );
2342
+ this.maps[this.api].addOverlay(tileLayerOverlay);
2343
+ break;
2344
+
2345
+ }
2346
+ return tileLayerOverlay;
2347
+ }
2348
+
2349
+ /* Turns a Tile Layer on or off
2350
+ *
2351
+ * @param {tile_url} url of the tile layer that was created.
2352
+ */
2353
+ Mapstraction.prototype.toggleTileLayer = function(tile_url) {
2354
+ switch (this.api) {
2355
+ case 'google':
2356
+ case 'openstreetmap':
2357
+ for (var f=0; f<this.tileLayers.length; f++) {
2358
+ if(this.tileLayers[f][0] == tile_url) {
2359
+ if(this.tileLayers[f][2]) {
2360
+ this.maps[this.api].removeOverlay(this.tileLayers[f][1]);
2361
+ this.tileLayers[f][2] = false;
2362
+ } else {
2363
+ this.maps[this.api].addOverlay(this.tileLayers[f][1]);
2364
+ this.tileLayers[f][2] = true;
2365
+ }
2366
+ }
2367
+ }
2368
+ break;
2369
+ }
2370
+ }
2371
+
2372
+ /**
2373
+ * addFilter adds a marker filter
2374
+ * @param {field} name of attribute to filter on
2375
+ * @param {operator} presently only "ge" or "le"
2376
+ * @param {value} the value to compare against
2377
+ */
2378
+ Mapstraction.prototype.addFilter = function(field, operator, value) {
2379
+ if (! this.filters) {
2380
+ this.filters = [];
2381
+ }
2382
+ this.filters.push( [field, operator, value] );
2383
+ }
2384
+
2385
+ /**
2386
+ * removeFilter
2387
+ */
2388
+ Mapstraction.prototype.removeFilter = function(field, operator, value) {
2389
+ if (! this.filters) { return; }
2390
+
2391
+ var del;
2392
+ for (var f=0; f<this.filters.length; f++) {
2393
+ if (this.filters[f][0] == field &&
2394
+ (! operator || (this.filters[f][1] == operator && this.filters[f][2] == value))) {
2395
+ this.filters.splice(f,1);
2396
+ f--; //array size decreased
2397
+ }
2398
+ }
2399
+ }
2400
+
2401
+ /*
2402
+ * toggleFilter: delete the current filter if present; otherwise add it
2403
+ */
2404
+ Mapstraction.prototype.toggleFilter = function(field, operator, value) {
2405
+ if (! this.filters) {
2406
+ this.filters = [];
2407
+ }
2408
+
2409
+ var found = false;
2410
+ for (var f=0; f<this.filters.length; f++) {
2411
+ if (this.filters[f][0] == field && this.filters[f][1] == operator && this.filters[f][2] == value) {
2412
+ this.filters.splice(f,1);
2413
+ f--; //array size decreased
2414
+ found = true;
2415
+ }
2416
+ }
2417
+
2418
+ if (! found) {
2419
+ this.addFilter(field, operator, value);
2420
+ }
2421
+ }
2422
+
2423
+ /*
2424
+ * removeAllFilters
2425
+ */
2426
+ Mapstraction.prototype.removeAllFilters = function() {
2427
+ this.filters = [];
2428
+ }
2429
+
2430
+ /**
2431
+ * doFilter executes all filters added since last call
2432
+ */
2433
+ Mapstraction.prototype.doFilter = function() {
2434
+ if(this.loaded[this.api] == false) {
2435
+ myself = this;
2436
+ this.onload[this.api].push( function() { myself.doFilter(); } );
2437
+ return;
2438
+ }
2439
+
2440
+ var map = this.maps[this.api];
2441
+
2442
+ if (this.filters) {
2443
+
2444
+ switch (this.api) {
2445
+ case 'multimap':
2446
+ /* TODO polylines aren't filtered in multimap */
2447
+ var mmfilters = [];
2448
+ for (var f=0; f<this.filters.length; f++) {
2449
+ mmfilters.push( new MMSearchFilter( this.filters[f][0], this.filters[f][1], this.filters[f][2] ));
2450
+ }
2451
+ map.setMarkerFilters( mmfilters );
2452
+ map.redrawMap();
2453
+ break;
2454
+ default:
2455
+ var vis;
2456
+ for (var m=0; m<this.markers.length; m++) {
2457
+ vis = true;
2458
+ for (var f=0; f<this.filters.length; f++) {
2459
+ if (! this.applyFilter(this.markers[m], this.filters[f])) {
2460
+ vis = false;
2461
+ }
2462
+ }
2463
+ if (vis) {
2464
+ this.markers[m].show();
2465
+ } else {
2466
+ this.markers[m].hide();
2467
+ }
2468
+ }
2469
+
2470
+
2471
+ /*
2472
+ for (var p=0; m<this.polylines.length; p++) {
2473
+ vis = true;
2474
+ for (var f=0; f<this.filters.length; f++) {
2475
+ if (! this.applyFilter(this.polylines[p], this.filters[f])) {
2476
+ vis = false;
2477
+ }
2478
+ }
2479
+ if (vis) {
2480
+ this.polylines[p].show();
2481
+ } else {
2482
+ this.polylines[p].hide();
2483
+ }
2484
+ }
2485
+ */
2486
+ break;
2487
+ }
2488
+
2489
+ }
2490
+
2491
+ }
2492
+
2493
+ Mapstraction.prototype.applyFilter = function(o, f) {
2494
+ var vis = true;
2495
+ switch (f[1]) {
2496
+ case 'ge':
2497
+ if (o.getAttribute( f[0] ) < f[2]) {
2498
+ vis = false;
2499
+ }
2500
+ break;
2501
+ case 'le':
2502
+ if (o.getAttribute( f[0] ) > f[2]) {
2503
+ vis = false;
2504
+ }
2505
+ break;
2506
+ case 'eq':
2507
+ if (o.getAttribute( f[0] ) != f[2]) {
2508
+ vis = false;
2509
+ }
2510
+ break;
2511
+ }
2512
+
2513
+ return vis;
2514
+ }
2515
+
2516
+ /**
2517
+ * getAttributeExtremes returns the minimum/maximum of "field" from all markers
2518
+ * @param {field} name of "field" to query
2519
+ * @returns {array} of minimum/maximum
2520
+ */
2521
+ Mapstraction.prototype.getAttributeExtremes = function(field) {
2522
+ var min;
2523
+ var max;
2524
+ for (var m=0; m<this.markers.length; m++) {
2525
+ if (! min || min > this.markers[m].getAttribute(field)) {
2526
+ min = this.markers[m].getAttribute(field);
2527
+ }
2528
+ if (! max || max < this.markers[m].getAttribute(field)) {
2529
+ max = this.markers[m].getAttribute(field);
2530
+ }
2531
+ }
2532
+ for (var p=0; m<this.polylines.length; m++) {
2533
+ if (! min || min > this.polylines[p].getAttribute(field)) {
2534
+ min = this.polylines[p].getAttribute(field);
2535
+ }
2536
+ if (! max || max < this.polylines[p].getAttribute(field)) {
2537
+ max = this.polylines[p].getAttribute(field);
2538
+ }
2539
+ }
2540
+
2541
+ return [min, max];
2542
+ }
2543
+
2544
+ /**
2545
+ * getMap returns the native map object that mapstraction is talking to
2546
+ * @returns the native map object mapstraction is using
2547
+ */
2548
+ Mapstraction.prototype.getMap = function() {
2549
+ // FIXME in an ideal world this shouldn't exist right?
2550
+ return this.maps[this.api];
2551
+ }
2552
+
2553
+
2554
+ //////////////////////////////
2555
+ //
2556
+ // LatLonPoint
2557
+ //
2558
+ /////////////////////////////
2559
+
2560
+ /**
2561
+ * LatLonPoint is a point containing a latitude and longitude with helper methods
2562
+ * @param {double} lat is the latitude
2563
+ * @param {double} lon is the longitude
2564
+ * @returns a new LatLonPoint
2565
+ * @type LatLonPoint
2566
+ */
2567
+ function LatLonPoint(lat,lon) {
2568
+ // TODO error if undefined?
2569
+ // if (lat == undefined) alert('undefined lat');
2570
+ // if (lon == undefined) alert('undefined lon');
2571
+ this.lat = lat;
2572
+ this.lon = lon;
2573
+ this.lng = lon; // lets be lon/lng agnostic
2574
+ }
2575
+
2576
+ /**
2577
+ * toYahoo returns a Y! maps point
2578
+ * @returns a YGeoPoint
2579
+ */
2580
+ LatLonPoint.prototype.toYahoo = function() {
2581
+ return new YGeoPoint(this.lat,this.lon);
2582
+ }
2583
+ /**
2584
+ * toGoogle returns a Google maps point
2585
+ * @returns a GLatLng
2586
+ */
2587
+ LatLonPoint.prototype.toGoogle = function() {
2588
+ return new GLatLng(this.lat,this.lon);
2589
+ }
2590
+ /**
2591
+ * toOpenLayers returns an OpenLayers point
2592
+ * Does a conversion from Latitude/Longitude to projected coordinates
2593
+ * @returns a OpenLayers. LonLat
2594
+ */
2595
+ LatLonPoint.prototype.toOpenLayers = function() {
2596
+ var ollon = this.lon * 20037508.34 / 180;
2597
+ var ollat = Math.log(Math.tan((90 + this.lat) * Math.PI / 360)) / (Math.PI / 180);
2598
+ ollat = ollat * 20037508.34 / 180;
2599
+ //console.log("COORD: " + this.lat + ', ' + this.lon + " OL: " + ollat + ', ' +ollon);
2600
+ return new OpenLayers.LonLat(ollon, ollat);
2601
+ }
2602
+
2603
+ /**
2604
+ * fromOpenLayers converts an OpenLayers point to Mapstraction LatLonPoint
2605
+ * Does a conversion from projectect coordinates to Latitude/Longitude
2606
+ * @returns a LatLonPoint
2607
+ */
2608
+ LatLonPoint.prototype.fromOpenLayers = function() {
2609
+ var lon = (this.lon / 20037508.34) * 180;
2610
+ var lat = (this.lat / 20037508.34) * 180;
2611
+
2612
+ lat = 180/Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
2613
+
2614
+ this.lon = lon;
2615
+ this.lat = lat;
2616
+ }
2617
+ /**
2618
+ * toMicrosoft returns a VE maps point
2619
+ * @returns a VELatLong
2620
+ */
2621
+ LatLonPoint.prototype.toMicrosoft = function() {
2622
+ return new VELatLong(this.lat,this.lon);
2623
+ }
2624
+ /**
2625
+ * toMultiMap returns a MultiMap point
2626
+ * @returns a MMLatLon
2627
+ */
2628
+ LatLonPoint.prototype.toMultiMap = function() {
2629
+ return new MMLatLon(this.lat, this.lon);
2630
+ }
2631
+
2632
+ /**
2633
+ * toMapQuest returns a MapQuest point
2634
+ * @returns a MQLatLng
2635
+ */
2636
+ LatLonPoint.prototype.toMapQuest = function() {
2637
+ return new MQLatLng(this.lat, this.lon);
2638
+ }
2639
+
2640
+ /**
2641
+ * toFreeEarth returns a FreeEarth point
2642
+ * @returns a FE.LatLng
2643
+ */
2644
+ LatLonPoint.prototype.toFreeEarth = function() {
2645
+ return new FE.LatLng(this.lat,this.lon);
2646
+ }
2647
+
2648
+ /**
2649
+ * toMap24 returns a Map24 point
2650
+ * @returns a Map24.Point
2651
+ */
2652
+ LatLonPoint.prototype.toMap24 = function() {
2653
+ return new Map24.Point (this.lon,this.lat);
2654
+ }
2655
+
2656
+
2657
+ /**
2658
+ * toString returns a string represntation of a point
2659
+ * @returns a string like '51.23, -0.123'
2660
+ * @type String
2661
+ */
2662
+ LatLonPoint.prototype.toString = function() {
2663
+ return this.lat + ', ' + this.lon;
2664
+ }
2665
+ /**
2666
+ * distance returns the distance in kilometers between two points
2667
+ * @param {LatLonPoint} otherPoint The other point to measure the distance from to this one
2668
+ * @returns the distance between the points in kilometers
2669
+ * @type double
2670
+ */
2671
+ LatLonPoint.prototype.distance = function(otherPoint) {
2672
+ var d,dr;
2673
+ with (Math) {
2674
+ dr = 0.017453292519943295; // 2.0 * PI / 360.0; or, radians per degree
2675
+ d = cos(otherPoint.lon*dr - this.lon*dr) * cos(otherPoint.lat*dr - this.lat*dr);
2676
+ return acos(d)*6378.137; // equatorial radius
2677
+ }
2678
+ return -1;
2679
+ }
2680
+ /**
2681
+ * equals tests if this point is the same as some other one
2682
+ * @param {LatLonPoint} otherPoint The other point to test with
2683
+ * @returns true or false
2684
+ * @type boolean
2685
+ */
2686
+ LatLonPoint.prototype.equals = function(otherPoint) {
2687
+ return this.lat == otherPoint.lat && this.lon == otherPoint.lon;
2688
+ }
2689
+
2690
+ //////////////////////////
2691
+ //
2692
+ // BoundingBox
2693
+ //
2694
+ //////////////////////////
2695
+
2696
+ /**
2697
+ * BoundingBox creates a new bounding box object
2698
+ * @param {double} swlat the latitude of the south-west point
2699
+ * @param {double} swlon the longitude of the south-west point
2700
+ * @param {double} nelat the latitude of the north-east point
2701
+ * @param {double} nelon the longitude of the north-east point
2702
+ * @returns a new BoundingBox
2703
+ * @type BoundingBox
2704
+ * @constructor
2705
+ */
2706
+ function BoundingBox(swlat, swlon, nelat, nelon) {
2707
+ //FIXME throw error if box bigger than world
2708
+ //alert('new bbox ' + swlat + ',' + swlon + ',' + nelat + ',' + nelon);
2709
+ this.sw = new LatLonPoint(swlat, swlon);
2710
+ this.ne = new LatLonPoint(nelat, nelon);
2711
+ }
2712
+
2713
+ /**
2714
+ * getSouthWest returns a LatLonPoint of the south-west point of the bounding box
2715
+ * @returns the south-west point of the bounding box
2716
+ * @type LatLonPoint
2717
+ */
2718
+ BoundingBox.prototype.getSouthWest = function() {
2719
+ return this.sw;
2720
+ }
2721
+
2722
+ /**
2723
+ * getNorthEast returns a LatLonPoint of the north-east point of the bounding box
2724
+ * @returns the north-east point of the bounding box
2725
+ * @type LatLonPoint
2726
+ */
2727
+ BoundingBox.prototype.getNorthEast = function() {
2728
+ return this.ne;
2729
+ }
2730
+
2731
+ /**
2732
+ * isEmpty finds if this bounding box has zero area
2733
+ * @returns whether the north-east and south-west points of the bounding box are the same point
2734
+ * @type boolean
2735
+ */
2736
+ BoundingBox.prototype.isEmpty = function() {
2737
+ return this.ne == this.sw; // is this right? FIXME
2738
+ }
2739
+
2740
+ /**
2741
+ * contains finds whether a given point is within a bounding box
2742
+ * @param {LatLonPoint} point the point to test with
2743
+ * @returns whether point is within this bounding box
2744
+ * @type boolean
2745
+ */
2746
+ BoundingBox.prototype.contains = function(point){
2747
+ return point.lat >= this.sw.lat && point.lat <= this.ne.lat && point.lon>= this.sw.lon && point.lon <= this.ne.lon;
2748
+ }
2749
+
2750
+ /**
2751
+ * toSpan returns a LatLonPoint with the lat and lon as the height and width of the bounding box
2752
+ * @returns a LatLonPoint containing the height and width of this bounding box
2753
+ * @type LatLonPoint
2754
+ */
2755
+ BoundingBox.prototype.toSpan = function() {
2756
+ return new LatLonPoint( Math.abs(this.sw.lat - this.ne.lat), Math.abs(this.sw.lon - this.ne.lon) );
2757
+ }
2758
+ /**
2759
+ * extend extends the bounding box to include the new point
2760
+ */
2761
+ BoundingBox.prototype.extend = function(point) {
2762
+ if(this.sw.lat > point.lat)
2763
+ this.sw.lat = point.lat;
2764
+ if(this.sw.lon > point.lon)
2765
+ this.sw.lon = point.lon;
2766
+ if(this.ne.lat < point.lat)
2767
+ this.ne.lat = point.lat;
2768
+ if(this.ne.lon < point.lon)
2769
+ this.ne.lon = point.lon;
2770
+
2771
+ return;
2772
+ }
2773
+
2774
+ //////////////////////////////
2775
+ //
2776
+ // Marker
2777
+ //
2778
+ ///////////////////////////////
2779
+
2780
+ /**
2781
+ * Marker create's a new marker pin
2782
+ * @param {LatLonPoint} point the point on the map where the marker should go
2783
+ * @constructor
2784
+ */
2785
+ function Marker(point) {
2786
+ this.location = point;
2787
+ this.onmap = false;
2788
+ this.proprietary_marker = false;
2789
+ this.attributes = new Array();
2790
+ this.pinID = "mspin-"+new Date().getTime()+'-'+(Math.floor(Math.random()*Math.pow(2,16)));
2791
+ }
2792
+
2793
+ Marker.prototype.setChild = function(some_proprietary_marker) {
2794
+ this.proprietary_marker = some_proprietary_marker;
2795
+ this.onmap = true
2796
+ }
2797
+
2798
+ Marker.prototype.setLabel = function(labelText) {
2799
+ this.labelText = labelText;
2800
+ }
2801
+
2802
+ /**
2803
+ * addData conviniently set a hash of options on a marker
2804
+ */
2805
+ Marker.prototype.addData = function(options){
2806
+ if(options.label)
2807
+ this.setLabel(options.label);
2808
+ if(options.infoBubble)
2809
+ this.setInfoBubble(options.infoBubble);
2810
+ if(options.icon) {
2811
+ if(options.iconSize)
2812
+ this.setIcon(options.icon, new Array(options.iconSize[0], options.iconSize[1]));
2813
+ else
2814
+ this.setIcon(options.icon);
2815
+
2816
+ if(options.iconAnchor)
2817
+ this.setIconAnchor(new Array(options.iconAnchor[0], options.iconAnchor[1]));
2818
+
2819
+ }
2820
+ if(options.iconShadow) {
2821
+ if(options.iconShadowSize)
2822
+ this.setShadowIcon(options.iconShadow, new Array(options.iconShadowSize[0], options.iconShadowSize[1]));
2823
+ else
2824
+ this.setIcon(options.iconShadow);
2825
+ }
2826
+ if(options.infoDiv)
2827
+ this.setInfoDiv(options.infoDiv[0],options.infoDiv[1]);
2828
+ if(options.draggable)
2829
+ this.setDraggable(options.draggable);
2830
+ if(options.hover)
2831
+ this.setHover(options.hover);
2832
+ if(options.hoverIcon)
2833
+ this.setHoverIcon(options.hoverIcon);
2834
+ if(options.openBubble)
2835
+ this.openBubble();
2836
+ if(options.date)
2837
+ this.setAttribute( 'date', eval(options.date) );
2838
+ if(options.category)
2839
+ this.setAttribute( 'category', options.category );
2840
+ }
2841
+
2842
+ /**
2843
+ * setInfoBubble sets the html/text content for a bubble popup for a marker
2844
+ * @param {String} infoBubble the html/text you want displayed
2845
+ */
2846
+ Marker.prototype.setInfoBubble = function(infoBubble) {
2847
+ this.infoBubble = infoBubble;
2848
+ }
2849
+
2850
+ /**
2851
+ * setInfoDiv sets the text and the id of the div element where to the information
2852
+ * useful for putting information in a div outside of the map
2853
+ * @param {String} infoDiv the html/text you want displayed
2854
+ * @param {String} div the element id to use for displaying the text/html
2855
+ */
2856
+ Marker.prototype.setInfoDiv = function(infoDiv,div){
2857
+ this.infoDiv = infoDiv;
2858
+ this.div = div;
2859
+ }
2860
+
2861
+ /**
2862
+ * setIcon sets the icon for a marker
2863
+ * @param {String} iconUrl The URL of the image you want to be the icon
2864
+ */
2865
+ Marker.prototype.setIcon = function(iconUrl, iconSize, iconAnchor){
2866
+ this.iconUrl = iconUrl;
2867
+ if(iconSize)
2868
+ this.iconSize = iconSize;
2869
+ if(iconAnchor)
2870
+ this.iconAnchor = iconAnchor;
2871
+
2872
+ }
2873
+ /**
2874
+ * setIconSize sets the size of the icon for a marker
2875
+ * @param {String} iconSize The array size in pixels of the marker image
2876
+ */
2877
+ Marker.prototype.setIconSize = function(iconSize){
2878
+ if(iconSize)
2879
+ this.iconSize = iconSize;
2880
+ }
2881
+ /**
2882
+ * setIconAnchor sets the anchor point for a marker
2883
+ * @param {String} iconAnchor The array offset of the anchor point
2884
+ */
2885
+ Marker.prototype.setIconAnchor = function(iconAnchor){
2886
+ if(iconAnchor)
2887
+ this.iconAnchor = iconAnchor;
2888
+ }
2889
+ /**
2890
+ * setShadowIcon sets the icon for a marker
2891
+ * @param {String} iconUrl The URL of the image you want to be the icon
2892
+ */
2893
+ Marker.prototype.setShadowIcon = function(iconShadowUrl, iconShadowSize){
2894
+ this.iconShadowUrl = iconShadowUrl;
2895
+ if(iconShadowSize)
2896
+ this.iconShadowSize = iconShadowSize;
2897
+ }
2898
+
2899
+ Marker.prototype.setHoverIcon = function(hoverIconUrl){
2900
+ this.hoverIconUrl = hoverIconUrl;
2901
+ }
2902
+
2903
+ /**
2904
+ * setDraggable sets the draggable state of the marker
2905
+ * @param {Bool} draggable set to true if marker should be draggable by the user
2906
+ */
2907
+ Marker.prototype.setDraggable = function(draggable) {
2908
+ this.draggable = draggable;
2909
+ }
2910
+
2911
+ /**
2912
+ * setHover sets that the marker info is displayed on hover
2913
+ * @param {Bool} hover set to true if marker should display info on hover
2914
+ */
2915
+ Marker.prototype.setHover = function(hover) {
2916
+ this.hover = hover;
2917
+ }
2918
+
2919
+ /**
2920
+ * Dynamically changes the marker to the new icon URL
2921
+ *
2922
+ */
2923
+ Marker.prototype.changeIcon = function(iconUrl) {
2924
+ if (this.proprietary_marker) {
2925
+ this.proprietary_marker.setImage(iconUrl);
2926
+ }
2927
+ }
2928
+ /**
2929
+ * Reverts an icon back to its original icon
2930
+ *
2931
+ * This is useful for when you change the marker and want to have it higlight on hover
2932
+ */
2933
+ Marker.prototype.revertIcon = function() {
2934
+ this.changeIcon(this.iconUrl);
2935
+ }
2936
+
2937
+ /**
2938
+ * toYahoo returns a Yahoo Maps compatible marker pin
2939
+ * @returns a Yahoo Maps compatible marker
2940
+ */
2941
+ Marker.prototype.toYahoo = function() {
2942
+ var ymarker;
2943
+ if(this.iconUrl) {
2944
+ ymarker = new YMarker(this.location.toYahoo (),new YImage(this.iconUrl));
2945
+ } else {
2946
+ ymarker = new YMarker(this.location.toYahoo());
2947
+ }
2948
+ if(this.iconSize) {
2949
+ ymarker.size = new YSize(this.iconSize[0], this.iconSize[1]);
2950
+ }
2951
+ if(this.labelText) {
2952
+ ymarker.addLabel(this.labelText);
2953
+ }
2954
+
2955
+ if(this.infoBubble) {
2956
+ var theInfo = this.infoBubble;
2957
+ var event_action;
2958
+ if(this.hover) {
2959
+ event_action = EventsList.MouseOver;
2960
+ }
2961
+ else {
2962
+ event_action = EventsList.MouseClick;
2963
+ }
2964
+ YEvent.Capture(ymarker, event_action, function() {
2965
+ ymarker.openSmartWindow(theInfo); });
2966
+
2967
+ }
2968
+
2969
+ if(this.infoDiv) {
2970
+ var theInfo = this.infoDiv;
2971
+ var div = this.div;
2972
+ var event_div;
2973
+ if(this.hover) {
2974
+ event_action = EventsList.MouseOver;
2975
+ }
2976
+ else {
2977
+ event_action = EventsList.MouseClick;
2978
+ }
2979
+ YEvent.Capture(ymarker, event_action, function() {
2980
+ document.getElementById(div).innerHTML = theInfo;});
2981
+ }
2982
+
2983
+ return ymarker;
2984
+ }
2985
+
2986
+ /**
2987
+ * toGoogle returns a Google Maps compatible marker pin
2988
+ * @returns Google Maps compatible marker
2989
+ */
2990
+ Marker.prototype.toGoogle = function() {
2991
+ var options = new Object();
2992
+ if(this.labelText) {
2993
+ options.title = this.labelText;
2994
+ }
2995
+ if(this.iconUrl){
2996
+ var icon = new GIcon(G_DEFAULT_ICON,this.iconUrl);
2997
+ if(this.iconSize) {
2998
+ icon.iconSize = new GSize(this.iconSize[0], this.iconSize[1]);
2999
+ var anchor;
3000
+ if(this.iconAnchor) {
3001
+ anchor = new GPoint(this.iconAnchor[0], this.iconAnchor[1]);
3002
+ }
3003
+ else {
3004
+ // FIXME: hard-coding the anchor point
3005
+ anchor = new GPoint(this.iconSize[0]/2, this.iconSize[1]/2);
3006
+ }
3007
+ icon.iconAnchor = anchor;
3008
+ }
3009
+ if(this.iconShadowUrl) {
3010
+ icon.shadow = this.iconShadowUrl;
3011
+ if(this.iconShadowSize) {
3012
+ icon.shadowSize = new GSize(this.iconShadowSize[0], this.iconShadowSize[1]);
3013
+ }
3014
+ }
3015
+ options.icon = icon;
3016
+ }
3017
+ if(this.draggable){
3018
+ options.draggable = this.draggable;
3019
+ }
3020
+ var gmarker = new GMarker( this.location.toGoogle(),options);
3021
+
3022
+
3023
+ if(this.infoBubble) {
3024
+ var theInfo = this.infoBubble;
3025
+ var event_action;
3026
+ if(this.hover) {
3027
+ event_action = "mouseover";
3028
+ }
3029
+ else {
3030
+ event_action = "click";
3031
+ }
3032
+ GEvent.addListener(gmarker, event_action, function() {
3033
+ gmarker.openInfoWindowHtml(theInfo, {maxWidth: 100});
3034
+ });
3035
+ }
3036
+
3037
+ if(this.hoverIconUrl) {
3038
+ GEvent.addListener(gmarker, "mouseover", function() {
3039
+ gmarker.setImage(this.hoverIconUrl);
3040
+ });
3041
+ GEvent.addListener(gmarker, "mouseout", function() {
3042
+ gmarker.setImage(this.iconUrl);
3043
+ });
3044
+ }
3045
+
3046
+ if(this.infoDiv){
3047
+ var theInfo = this.infoDiv;
3048
+ var div = this.div;
3049
+ var event_action;
3050
+ if(this.hover) {
3051
+ event_action = "mouseover";
3052
+ }
3053
+ else {
3054
+ event_action = "click";
3055
+ }
3056
+ GEvent.addListener(gmarker, event_action, function() {
3057
+ document.getElementById(div).innerHTML = theInfo;
3058
+ });
3059
+ }
3060
+
3061
+ return gmarker;
3062
+ }
3063
+
3064
+ /**
3065
+ * toOpenLayers returns an OpenLayers compatible marker pin
3066
+ * @returns OpenLayers compatible marker
3067
+ */
3068
+ Marker.prototype.toOpenLayers = function() {
3069
+
3070
+ if(this.iconSize) {
3071
+ var size = new OpenLayers.Size(this.iconSize[0], this.iconSize[1]);
3072
+ }
3073
+ else
3074
+ {
3075
+ var size = new OpenLayers.Size(15,20);
3076
+ }
3077
+
3078
+ if(this.iconAnchor)
3079
+ {
3080
+ var anchor = new OpenLayers.Pixel(this.iconAnchor[0], this.iconAnchor[1]);
3081
+ }
3082
+ else
3083
+ {
3084
+ // FIXME: hard-coding the anchor point
3085
+ anchor = new OpenLayers.Pixel(-(size.w/2), -size.h);
3086
+ }
3087
+ if(this.iconUrl) {
3088
+ var icon = new OpenLayers.Icon(this.iconUrl, size, anchor);
3089
+ }
3090
+ else
3091
+ {
3092
+ var icon = new OpenLayers.Icon('http://boston.openguides.org/markers/AQUA.png', size, anchor);
3093
+ }
3094
+
3095
+ var marker = new OpenLayers.Marker(this.location.toOpenLayers(), icon);
3096
+ return marker;
3097
+ }
3098
+
3099
+ /**
3100
+ * toMicrosoft returns a MSFT VE compatible marker pin
3101
+ * @returns MSFT VE compatible marker
3102
+ */
3103
+ Marker.prototype.toMicrosoft = function() {
3104
+ var pin = new VEPushpin(this.pinID,this.location.toMicrosoft(),
3105
+ this.iconUrl,this.labelText,this.infoBubble);
3106
+ return pin;
3107
+ }
3108
+
3109
+ /**
3110
+ * toMap24 returns a Map24 Location
3111
+ * @returns Map24 Location
3112
+ */
3113
+ Marker.prototype.toMap24 = function() {
3114
+
3115
+ var ops = new Object();
3116
+ ops.Longitude = this.location.lon*60;
3117
+ ops.Latitude = this.location.lat*60;
3118
+ if(this.infoBubble) {
3119
+ // not sure how map24 differentiates between tooltips and
3120
+ // info bubble content
3121
+ ops.TooltipContent = this.infoBubble;
3122
+ }
3123
+
3124
+ if(this.labelText) {
3125
+ // ????
3126
+ }
3127
+
3128
+ ops.LogoURL = this.iconUrl ? this.iconUrl :
3129
+ "http://www.free-map.org.uk/images/marker.png";
3130
+
3131
+ ops.TooltipLayout = Map24.MapObject.LAYOUT_BUBBLE;
3132
+
3133
+ if(this.hover) {
3134
+ ops.TooltipOpen = "OnMouseOver";
3135
+ // ops.TooltipClose = "OnMouseOut";
3136
+ } else {
3137
+ ops.TooltipOpen = "OnClick";
3138
+ // ops.TooltipClose = "OnMouseOut";
3139
+ }
3140
+
3141
+
3142
+ var m24Location = new Map24.Location ( ops );
3143
+ return m24Location;
3144
+ }
3145
+
3146
+ /**
3147
+ * toMultiMap returns a MultiMap compatible marker pin
3148
+ * @returns MultiMap compatible marker
3149
+ */
3150
+ Marker.prototype.toMultiMap = function() {
3151
+ if (this.iconUrl) {
3152
+ var icon = new MMIcon(this.iconUrl);
3153
+ icon.iconSize = new MMDimensions(32, 32); //how to get this?
3154
+
3155
+ var mmmarker = new MMMarkerOverlay( this.location.toMultiMap(), {'icon' : icon} );
3156
+ } else {
3157
+ var mmmarker = new MMMarkerOverlay( this.location.toMultiMap());
3158
+ }
3159
+ if(this.labelText){
3160
+ }
3161
+ if(this.infoBubble) {
3162
+ mmmarker.setInfoBoxContent(this.infoBubble);
3163
+ }
3164
+ if(this.infoDiv) {
3165
+ }
3166
+
3167
+ for (var key in this.attributes) {
3168
+ mmmarker.setAttribute(key, this.attributes[ key ]);
3169
+ }
3170
+
3171
+ return mmmarker;
3172
+ }
3173
+
3174
+ /**
3175
+ * toMapQuest returns a MapQuest compatible marker pin
3176
+ * @returns MapQuest compatible marker
3177
+ */
3178
+ Marker.prototype.toMapQuest = function() {
3179
+
3180
+ var mqmarker = new MQPoi( this.location.toMapQuest() );
3181
+
3182
+ if(this.iconUrl){
3183
+ var mqicon = new MQMapIcon();
3184
+ mqicon.setImage(this.iconUrl,32,32,true,false);
3185
+ // TODO: Finish MapQuest icon params - icon file location, width, height, recalc infowindow offset, is it a PNG image?
3186
+ mqmarker.setIcon(mqicon);
3187
+ // mqmarker.setLabel('Hola!');
3188
+ }
3189
+
3190
+ if(this.labelText) { mqmarker.setInfoTitleHTML( this.labelText ); }
3191
+
3192
+ if(this.infoBubble) { mqmarker.setInfoContentHTML( this.infoBubble ); }
3193
+
3194
+ if(this.infoDiv){
3195
+ var theInfo = this.infoDiv;
3196
+ var div = this.div;
3197
+ MQEventManager.addListener(mqmarker, "click", function() {
3198
+ document.getElementById(div).innerHTML = theInfo;
3199
+ });
3200
+ }
3201
+
3202
+ return mqmarker;
3203
+ }
3204
+
3205
+ /**
3206
+ * toFreeEarth returns a FreeEarth compatible marker pin
3207
+ * @returns FreeEarth compatible marker
3208
+ */
3209
+ Marker.prototype.toFreeEarth = function() {
3210
+ var feicon;
3211
+
3212
+ if (this.iconUrl) {
3213
+ feicon = new FE.Icon(this.iconUrl);
3214
+ } else {
3215
+ feicon = new FE.Icon("http://freeearth.poly9.com/images/bullmarker.png");
3216
+ }
3217
+ var femarker = new FE.Pushpin( this.location.toFreeEarth(), feicon);
3218
+
3219
+ if(this.infoBubble) {
3220
+ var theBubble = this.infoBubble;
3221
+ FE.Event.addListener(femarker, 'click', function() {
3222
+ femarker.openInfoWindowHtml( theBubble, 200, 100 );
3223
+ } );
3224
+ }
3225
+
3226
+ if(this.infoDiv) {
3227
+ var theInfo = this.infoDiv;
3228
+ var div = this.div;
3229
+ FE.Event.addListener(femarker, 'click', function() {
3230
+ document.getElementById(div).innerHTML = theInfo;
3231
+ });
3232
+ }
3233
+
3234
+ return femarker;
3235
+ }
3236
+
3237
+ /**
3238
+ * setAttribute: set an arbitrary key/value pair on a marker
3239
+ * @arg(String) key
3240
+ * @arg value
3241
+ */
3242
+ Marker.prototype.setAttribute = function(key,value) {
3243
+ this.attributes[key] = value;
3244
+ }
3245
+
3246
+ /**
3247
+ * getAttribute: gets the value of "key"
3248
+ * @arg(String) key
3249
+ * @returns value
3250
+ */
3251
+ Marker.prototype.getAttribute = function(key) {
3252
+ return this.attributes[key];
3253
+ }
3254
+
3255
+
3256
+
3257
+ /**
3258
+ * openBubble opens the infoBubble
3259
+ */
3260
+ Marker.prototype.openBubble = function() {
3261
+ if(this.mapstraction.loaded[this.api] == false) {
3262
+ var my_marker = this;
3263
+ this.mapstraction.onload[this.api].push( function() { my_marker.openBubble(); } );
3264
+ return;
3265
+ }
3266
+
3267
+ if( this.api) {
3268
+ switch (this.api) {
3269
+ case 'yahoo':
3270
+ var ypin = this.proprietary_marker;
3271
+ ypin.openSmartWindow(this.infoBubble);
3272
+ break;
3273
+ case 'google':
3274
+ case 'openstreetmap':
3275
+ var gpin = this.proprietary_marker;
3276
+ gpin.openInfoWindowHtml(this.infoBubble);
3277
+ break;
3278
+ case 'microsoft':
3279
+ var pin = this.proprietary_marker;
3280
+ // bloody microsoft -- this is broken
3281
+ var el = $m(this.pinID + "_" + this.maps[this.api].GUID).onmouseover;
3282
+ setTimeout(el, 1000); // wait a second in case the map is booting as it cancels the event
3283
+ break;
3284
+ case 'multimap':
3285
+ this.proprietary_marker.openInfoBox();
3286
+ break;
3287
+ case 'mapquest':
3288
+ // MapQuest hack to work around bug when opening marker
3289
+ this.proprietary_marker.setRolloverEnabled(false);
3290
+ this.proprietary_marker.showInfoWindow();
3291
+ this.proprietary_marker.setRolloverEnabled(true);
3292
+ break;
3293
+ }
3294
+ } else {
3295
+ alert('You need to add the marker before opening it');
3296
+ }
3297
+ }
3298
+
3299
+ /**
3300
+ * hide the marker
3301
+ */
3302
+ Marker.prototype.hide = function() {
3303
+ if (this.api) {
3304
+ switch (this.api) {
3305
+ case 'google':
3306
+ case 'openstreetmap':
3307
+ this.proprietary_marker.hide();
3308
+ break;
3309
+ case 'openlayers':
3310
+ this.proprietary_marker.display(false);
3311
+ break;
3312
+ case 'yahoo':
3313
+ this.proprietary_marker.hide();
3314
+ break;
3315
+ case 'map24':
3316
+ this.proprietary_marker.hide();
3317
+ break;
3318
+ case 'multimap':
3319
+ this.proprietary_marker.setVisibility(false);
3320
+ break;
3321
+ case 'mapquest':
3322
+ this.proprietary_marker.setVisible(false);
3323
+ break;
3324
+ default:
3325
+ if(this.debug)
3326
+ alert(this.api + "not supported by Marker.hide");
3327
+ }
3328
+ }
3329
+ }
3330
+
3331
+ /**
3332
+ * show the marker
3333
+ */
3334
+ Marker.prototype.show = function() {
3335
+ if (this.api) {
3336
+ switch (this.api) {
3337
+ case 'google':
3338
+ case 'openstreetmap':
3339
+ this.proprietary_marker.show();
3340
+ break;
3341
+ case 'openlayers':
3342
+ this.proprietary_marker.display(true);
3343
+ break;
3344
+ case 'map24':
3345
+ this.proprietary_marker.show();
3346
+ break;
3347
+ case 'yahoo':
3348
+ this.proprietary_marker.unhide();
3349
+ break;
3350
+ case 'multimap':
3351
+ this.proprietary_marker.setVisibility(true);
3352
+ break;
3353
+ case 'mapquest':
3354
+ this.proprietary_marker.setVisible(true);
3355
+ break;
3356
+ default:
3357
+ if(this.debug)
3358
+ alert(this.api + "not supported by Marker.show");
3359
+ }
3360
+ }
3361
+ }
3362
+
3363
+ ///////////////
3364
+ // Polyline ///
3365
+ ///////////////
3366
+
3367
+
3368
+ function Polyline(points) {
3369
+ this.points = points;
3370
+ this.attributes = new Array();
3371
+ this.onmap = false;
3372
+ this.proprietary_polyline = false;
3373
+ this.pllID = "mspll-"+new Date().getTime()+'-'+(Math.floor(Math.random()*Math.pow(2,16)));
3374
+ }
3375
+
3376
+ /**
3377
+ * addData conviniently set a hash of options on a polyline
3378
+ */
3379
+ Polyline.prototype.addData = function(options){
3380
+ if(options.color)
3381
+ this.setColor(options.color);
3382
+ if(options.width)
3383
+ this.setWidth(options.width); // NW corrected from setInfoBubble()
3384
+ if(options.opacity)
3385
+ this.setIcon(options.opacity);
3386
+ if(options.date)
3387
+ this.setAttribute( 'date', eval(options.date) );
3388
+ if(options.category)
3389
+ this.setAttribute( 'category', options.category );
3390
+ }
3391
+
3392
+ Polyline.prototype.setChild = function(some_proprietary_polyline) {
3393
+ this.proprietary_polyline = some_proprietary_polyline;
3394
+ this.onmap = true;
3395
+ }
3396
+
3397
+ //in the form: #RRGGBB
3398
+ //Note map24 insists on upper case, so we convert it.
3399
+ Polyline.prototype.setColor = function(color){
3400
+ this.color = (color.length==7 && color[0]=="#") ? color.toUpperCase() : color;
3401
+ }
3402
+
3403
+ //An integer
3404
+ Polyline.prototype.setWidth = function(width){
3405
+ this.width = width;
3406
+ }
3407
+
3408
+ //A float between 0.0 and 1.0
3409
+ Polyline.prototype.setOpacity = function(opacity){
3410
+ this.opacity = opacity;
3411
+ }
3412
+
3413
+ Polyline.prototype.toYahoo = function() {
3414
+ var ypolyline;
3415
+ var ypoints = [];
3416
+ for (var i = 0, length = this.points.length ; i< length; i++){
3417
+ ypoints.push(this.points[i].toYahoo());
3418
+ }
3419
+ ypolyline = new YPolyline(ypoints,this.color,this.width,this.opacity);
3420
+ return ypolyline;
3421
+ }
3422
+
3423
+ Polyline.prototype.toGoogle = function() {
3424
+ var gpolyline;
3425
+ var gpoints = [];
3426
+ for (var i = 0, length = this.points.length ; i< length; i++){
3427
+ gpoints.push(this.points[i].toGoogle());
3428
+ }
3429
+ gpolyline = new GPolyline(gpoints,this.color,this.width,this.opacity);
3430
+ return gpolyline;
3431
+ }
3432
+
3433
+ Polyline.prototype.toMap24 = function() {
3434
+ var m24polyline;
3435
+ var m24longs = "";
3436
+ var m24lats = "";
3437
+ for (var i=0; i<this.points.length; i++) {
3438
+ if(i) {
3439
+ m24longs += "|";
3440
+ m24lats += "|";
3441
+ }
3442
+ m24longs += (this.points[i].lon*60);
3443
+ m24lats += (this.points[i].lat*60);
3444
+ }
3445
+
3446
+ m24polyline = new Map24.Polyline({
3447
+ Longitudes: m24longs,
3448
+ Latitudes: m24lats,
3449
+ Color: this.color || "black",
3450
+ Width: this.width || 3
3451
+ });
3452
+ return m24polyline;
3453
+ }
3454
+
3455
+ Polyline.prototype.toMicrosoft = function() {
3456
+ var mpolyline;
3457
+ var mpoints = [];
3458
+ for (var i = 0, length = this.points.length ; i< length; i++){
3459
+ mpoints.push(this.points[i].toMicrosoft());
3460
+ }
3461
+
3462
+ var color;
3463
+ var opacity = this.opacity ||1.0;
3464
+ if(this.color){
3465
+ color = new VEColor(parseInt(this.color.substr(1,2),16),parseInt(this.color.substr(3,2),16),parseInt(this.color.substr(5,2),16), opacity);
3466
+ }else{
3467
+ color = new VEColor(0,255,0, opacity);
3468
+ }
3469
+
3470
+ mpolyline = new VEPolyline(this.pllID,mpoints,color,this.width);
3471
+ return mpolyline;
3472
+ }
3473
+
3474
+ Polyline.prototype.toMultiMap = function() {
3475
+ var mmpolyline;
3476
+ var mmpoints = [];
3477
+ for (var i = 0, length = this.points.length ; i< length; i++){
3478
+ mmpoints.push(this.points[i].toMultiMap());
3479
+ }
3480
+ mmpolyline = new MMPolyLineOverlay(mmpoints, this.color, this.opacity, this.width, false, undefined);
3481
+ return mmpolyline;
3482
+ }
3483
+
3484
+ Polyline.prototype.toMapQuest = function() {
3485
+ var mqpolyline = new MQLineOverlay();
3486
+ mqpolyline.setColor(this.color||"red");
3487
+ mqpolyline.setBorderWidth(this.width || 3);
3488
+ mqpolyline.setKey("Line");
3489
+ mqpolyline.setColorAlpha(this.opacity);
3490
+
3491
+ var mqpoints = new MQLatLngCollection();
3492
+ for (var i = 0, length = this.points.length ; i< length; i++){
3493
+ mqpoints.add(this.points[i].toMapQuest());
3494
+ }
3495
+ mqpolyline.setShapePoints(mqpoints);
3496
+ return mqpolyline;
3497
+ }
3498
+ Polyline.prototype.toFreeEarth = function() {
3499
+ var fepoints = new Array();
3500
+
3501
+ for (var i = 0, length = this.points.length ; i< length; i++){
3502
+ fepoints.push(this.points[i].toFreeEarth());
3503
+ }
3504
+
3505
+ var fepolyline = new FE.Polyline(fepoints, this.color || '0xff0000', this.width || 1, this.opacity || 1);
3506
+
3507
+ return fepolyline;
3508
+ }
3509
+
3510
+ /**
3511
+ * setAttribute: set an arbitrary key/value pair on a polyline
3512
+ * @arg(String) key
3513
+ * @arg value
3514
+ */
3515
+ Polyline.prototype.setAttribute = function(key,value) {
3516
+ this.attributes[key] = value;
3517
+ }
3518
+
3519
+ /**
3520
+ * getAttribute: gets the value of "key"
3521
+ * @arg(String) key
3522
+ * @returns value
3523
+ */
3524
+ Polyline.prototype.getAttribute = function(key) {
3525
+ return this.attributes[key];
3526
+ }
3527
+
3528
+ /**
3529
+ * show: not yet implemented
3530
+ */
3531
+ Polyline.prototype.show = function() {
3532
+ if (this.api) {
3533
+ }
3534
+ }
3535
+
3536
+ /**
3537
+ * hide: not yet implemented
3538
+ */
3539
+ Polyline.prototype.hide = function() {
3540
+ if (this.api) {
3541
+ }
3542
+ }
3543
+
3544
+ /////////////
3545
+ /// Route ///
3546
+ /////////////
3547
+
3548
+ /**
3549
+ * Show a route from MapstractionRouter on a mapstraction map
3550
+ * Currently only supported by MapQuest
3551
+ * @params {Object} route The route object returned in the callback from MapstractionRouter
3552
+ */
3553
+ Mapstraction.prototype.showRoute = function(route) {
3554
+ if(this.loaded[this.api] == false) {
3555
+ myself = this;
3556
+ this.onload[this.api].push( function() { myself.showRoute(route); } );
3557
+ return;
3558
+ }
3559
+ var map = this.maps[this.api];
3560
+ switch (this.api) {
3561
+ case 'mapquest':
3562
+ map.addRouteHighlight(route['bounding_box'],"http://map.access.mapquest.com",route['session_id'],true);
3563
+ break;
3564
+ default:
3565
+ if(this.debug)
3566
+ alert(api + ' not supported by Mapstration.showRoute');
3567
+ break;
3568
+ }
3569
+ }
3570
+