1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2 * licence. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3 * full text of the license. */
6 * @requires OpenLayers/Request/XMLHttpRequest.js
7 * @requires OpenLayers/Layer/Grid.js
11 * Class: OpenLayers.Layer.MapGuide
12 * Instances of OpenLayers.Layer.MapGuide are used to display
13 * data from a MapGuide OS instance.
16 * - <OpenLayers.Layer.Grid>
18 OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
21 * APIProperty: isBaseLayer
22 * {Boolean} Treat this layer as a base layer. Default is true.
27 * APIProperty: useHttpTile
28 * {Boolean} use a tile cache exposed directly via a webserver rather than the
29 * via mapguide server. This does require extra configuration on the Mapguide Server,
30 * and will only work when singleTile is false. The url for the layer must be set to the
31 * webserver path rather than the Mapguide mapagent.
32 * See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp
37 * APIProperty: singleTile
38 * {Boolean} use tile server or request single tile image.
43 * APIProperty: useOverlay
44 * {Boolean} flag to indicate if the layer should be retrieved using
45 * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests.
50 * APIProperty: useAsyncOverlay
51 * {Boolean} indicates if the MapGuide site supports the asynchronous
52 * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010
53 * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG
54 * is called asynchronously, allows selections to be drawn separately from
55 * the map and offers styling options.
57 * With older versions of MapGuide, set useAsyncOverlay=false. Note that in
58 * this case a synchronous AJAX call is issued and the mapname and session
59 * parameters must be used to initialize the layer, not the mapdefinition
60 * parameter. Also note that this will issue a synchronous AJAX request
61 * before the image request can be issued so the users browser may lock
62 * up if the MG Web tier does not respond in a timely fashion.
64 useAsyncOverlay: true,
67 * Constant: TILE_PARAMS
68 * {Object} Hashtable of default parameter key/value pairs for tiled layer
71 operation: 'GETTILEIMAGE',
76 * Constant: SINGLE_TILE_PARAMS
77 * {Object} Hashtable of default parameter key/value pairs for untiled layer
80 operation: 'GETMAPIMAGE',
88 * Constant: OVERLAY_PARAMS
89 * {Object} Hashtable of default parameter key/value pairs for untiled layer
92 operation: 'GETDYNAMICMAPOVERLAYIMAGE',
100 * Constant: FOLDER_PARAMS
101 * {Object} Hashtable of parameter key/value pairs which describe
102 * the folder structure for tiles as configured in the mapguide
103 * serverconfig.ini section [TileServiceProperties]
106 tileColumnsPerFolder: 30,
107 tileRowsPerFolder: 30,
113 * Property: defaultSize
114 * {<OpenLayers.Size>} Tile size as produced by MapGuide server
116 defaultSize: new OpenLayers.Size(300,300),
119 * Constructor: OpenLayers.Layer.MapGuide
120 * Create a new Mapguide layer, either tiled or untiled.
122 * For tiled layers, the 'groupName' and 'mapDefinition' values
123 * must be specified as parameters in the constructor.
125 * For untiled base layers, specify either combination of 'mapName' and
126 * 'session', or 'mapDefinition' and 'locale'.
128 * For older versions of MapGuide and overlay layers, set useAsyncOverlay
129 * to false and in this case mapName and session are required parameters
130 * for the constructor.
132 * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion
133 * factor that are different than the defaults used in OpenLayers,
134 * so these must be adjusted accordingly in your application.
135 * See the MapGuide example for how to set these values for MGOS.
138 * name - {String} Name of the layer displayed in the interface
139 * url - {String} Location of the MapGuide mapagent executable
140 * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi)
141 * params - {Object} hashtable of additional parameters to use. Some
142 * parameters may require additional code on the server. The ones that
143 * you may want to use are:
144 * - mapDefinition - {String} The MapGuide resource definition
145 * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition)
146 * - locale - Locale setting
147 * (for untiled overlays layers only)
148 * - mapName - {String} Name of the map as stored in the MapGuide session.
149 * (for untiled layers with a session parameter only)
150 * - session - { String} MapGuide session ID
151 * (for untiled overlays layers only)
152 * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only
153 * - format - Image format to be returned (for untiled overlay layers only)
154 * - showLayers - {String} A comma separated list of GUID's for the
155 * layers to display eg: 'cvc-xcv34,453-345-345sdf'.
156 * - hideLayers - {String} A comma separated list of GUID's for the
157 * layers to hide eg: 'cvc-xcv34,453-345-345sdf'.
158 * - showGroups - {String} A comma separated list of GUID's for the
159 * groups to display eg: 'cvc-xcv34,453-345-345sdf'.
160 * - hideGroups - {String} A comma separated list of GUID's for the
161 * groups to hide eg: 'cvc-xcv34,453-345-345sdf'
162 * - selectionXml - {String} A selection xml string Some server plumbing
163 * is required to read such a value.
164 * options - {Ojbect} Hashtable of extra options to tag onto the layer;
165 * will vary depending if tiled or untiled maps are being requested
167 initialize: function(name, url, params, options) {
169 OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments);
171 // unless explicitly set in options, if the layer is transparent,
172 // it will be an overlay
173 if (options == null || options.isBaseLayer == null) {
174 this.isBaseLayer = ((this.transparent != "true") &&
175 (this.transparent != true));
178 if (options && options.useOverlay!=null) {
179 this.useOverlay = options.useOverlay;
182 //initialize for untiled layers
183 if (this.singleTile) {
184 if (this.useOverlay) {
185 OpenLayers.Util.applyDefaults(
189 if (!this.useAsyncOverlay) {
190 this.params.version = "1.0.0";
193 OpenLayers.Util.applyDefaults(
195 this.SINGLE_TILE_PARAMS
199 //initialize for tiled layers
200 if (this.useHttpTile) {
201 OpenLayers.Util.applyDefaults(
206 OpenLayers.Util.applyDefaults(
211 this.setTileSize(this.defaultSize);
217 * Create a clone of this layer
220 * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer
222 clone: function (obj) {
224 obj = new OpenLayers.Layer.MapGuide(this.name,
229 //get all additions from superclasses
230 obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
237 * Creates a tile, initializes it, and adds it to the layer div.
240 * bounds - {<OpenLayers.Bounds>}
241 * position - {<OpenLayers.Pixel>}
244 * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
246 addTile:function(bounds,position) {
247 return new OpenLayers.Tile.Image(this, position, bounds,
248 null, this.tileSize);
253 * Return a query string for this layer
256 * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
260 * {String} A string with the layer's url and parameters and also
261 * the passed-in bounds and appropriate tile size specified
264 getURL: function (bounds) {
266 var center = bounds.getCenterLonLat();
267 var mapSize = this.map.getCurrentSize();
269 if (this.singleTile) {
270 //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with
271 //dynamic map parameters
273 setdisplaydpi: OpenLayers.DOTS_PER_INCH,
274 setdisplayheight: mapSize.h*this.ratio,
275 setdisplaywidth: mapSize.w*this.ratio,
276 setviewcenterx: center.lon,
277 setviewcentery: center.lat,
278 setviewscale: this.map.getScale()
281 if (this.useOverlay && !this.useAsyncOverlay) {
282 //first we need to call GETVISIBLEMAPEXTENT to set the extent
283 var getVisParams = {};
284 getVisParams = OpenLayers.Util.extend(getVisParams, params);
285 getVisParams.operation = "GETVISIBLEMAPEXTENT";
286 getVisParams.version = "1.0.0";
287 getVisParams.session = this.params.session;
288 getVisParams.mapName = this.params.mapName;
289 getVisParams.format = 'text/xml';
290 url = this.getFullRequestString( getVisParams );
292 OpenLayers.Request.GET({url: url, async: false});
294 //construct the full URL
295 url = this.getFullRequestString( params );
299 var currentRes = this.map.getResolution();
300 var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
301 colidx = Math.round(colidx/this.tileSize.w);
302 var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
303 rowidx = Math.round(rowidx/this.tileSize.h);
305 if (this.useHttpTile){
306 url = this.getImageFilePath(
310 scaleindex: this.resolutions.length - this.map.zoom - 1
314 url = this.getFullRequestString(
318 scaleindex: this.resolutions.length - this.map.zoom - 1
326 * Method: getFullRequestString
327 * getFullRequestString on MapGuide layers is special, because we
328 * do a regular expression replace on ',' in parameters to '+'.
329 * This is why it is subclassed here.
332 * altUrl - {String} Alternative base URL to use.
335 * {String} A string with the layer's url appropriately encoded for MapGuide
337 getFullRequestString:function(newParams, altUrl) {
338 // use layer's url unless altUrl passed in
339 var url = (altUrl == null) ? this.url : altUrl;
341 // if url is not a string, it should be an array of strings,
342 // in which case we will randomly select one of them in order
343 // to evenly distribute requests to different urls.
344 if (typeof url == "object") {
345 url = url[Math.floor(Math.random()*url.length)];
347 // requestString always starts with url
348 var requestString = url;
350 // create a new params hashtable with all the layer params and the
351 // new params together. then convert to string
352 var allParams = OpenLayers.Util.extend({}, this.params);
353 allParams = OpenLayers.Util.extend(allParams, newParams);
354 // ignore parameters that are already in the url search string
355 var urlParams = OpenLayers.Util.upperCaseObject(
356 OpenLayers.Util.getArgs(url));
357 for(var key in allParams) {
358 if(key.toUpperCase() in urlParams) {
359 delete allParams[key];
362 var paramsString = OpenLayers.Util.getParameterString(allParams);
364 /* MapGuide needs '+' seperating things like bounds/height/width.
365 Since typically this is URL encoded, we use a slight hack: we
366 depend on the list-like functionality of getParameterString to
367 leave ',' only in the case of list items (since otherwise it is
368 encoded) then do a regular expression replace on the , characters
370 paramsString = paramsString.replace(/,/g, "+");
372 if (paramsString != "") {
373 var lastServerChar = url.charAt(url.length - 1);
374 if ((lastServerChar == "&") || (lastServerChar == "?")) {
375 requestString += paramsString;
377 if (url.indexOf('?') == -1) {
378 //serverPath has no ? -- add one
379 requestString += '?' + paramsString;
381 //serverPath contains ?, so must already have paramsString at the end
382 requestString += '&' + paramsString;
386 return requestString;
390 * Method: getImageFilePath
391 * special handler to request mapguide tiles from an http exposed tilecache
394 * altUrl - {String} Alternative base URL to use.
397 * {String} A string with the url for the tile image
399 getImageFilePath:function(newParams, altUrl) {
400 // use layer's url unless altUrl passed in
401 var url = (altUrl == null) ? this.url : altUrl;
403 // if url is not a string, it should be an array of strings,
404 // in which case we will randomly select one of them in order
405 // to evenly distribute requests to different urls.
406 if (typeof url == "object") {
407 url = url[Math.floor(Math.random()*url.length)];
409 // requestString always starts with url
410 var requestString = url;
412 var tileRowGroup = "";
413 var tileColGroup = "";
415 if (newParams.tilerow < 0) {
419 if (newParams.tilerow == 0 ) {
422 tileRowGroup += Math.floor(Math.abs(newParams.tilerow/this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder;
425 if (newParams.tilecol < 0) {
429 if (newParams.tilecol == 0) {
432 tileColGroup += Math.floor(Math.abs(newParams.tilecol/this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder;
435 var tilePath = '/S' + Math.floor(newParams.scaleindex)
436 + '/' + this.params.basemaplayergroupname
437 + '/R' + tileRowGroup
438 + '/C' + tileColGroup
439 + '/' + (newParams.tilerow % this.params.tileRowsPerFolder)
440 + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder)
441 + '.' + this.params.format;
443 if (this.params.querystring) {
444 tilePath += "?" + this.params.querystring;
447 requestString += tilePath;
448 return requestString;
452 * Method: calculateGridLayout
453 * Generate parameters for the grid layout. This
456 * bounds - {<OpenLayers.Bound>}
457 * extent - {<OpenLayers.Bounds>}
458 * resolution - {Number}
461 * Object containing properties tilelon, tilelat, tileoffsetlat,
462 * tileoffsetlat, tileoffsetx, tileoffsety
464 calculateGridLayout: function(bounds, extent, resolution) {
465 var tilelon = resolution * this.tileSize.w;
466 var tilelat = resolution * this.tileSize.h;
468 var offsetlon = bounds.left - extent.left;
469 var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
470 var tilecolremain = offsetlon/tilelon - tilecol;
471 var tileoffsetx = -tilecolremain * this.tileSize.w;
472 var tileoffsetlon = extent.left + tilecol * tilelon;
474 var offsetlat = extent.top - bounds.top + tilelat;
475 var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
476 var tilerowremain = tilerow - offsetlat/tilelat;
477 var tileoffsety = tilerowremain * this.tileSize.h;
478 var tileoffsetlat = extent.top - tilelat*tilerow;
481 tilelon: tilelon, tilelat: tilelat,
482 tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
483 tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
487 CLASS_NAME: "OpenLayers.Layer.MapGuide"