MapGuide.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
  2. * full list of contributors). Published under the Clear BSD license.
  3. * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  4. * full text of the license. */
  5. /**
  6. * @requires OpenLayers/Request/XMLHttpRequest.js
  7. * @requires OpenLayers/Layer/Grid.js
  8. */
  9. /**
  10. * Class: OpenLayers.Layer.MapGuide
  11. * Instances of OpenLayers.Layer.MapGuide are used to display
  12. * data from a MapGuide OS instance.
  13. *
  14. * Inherits from:
  15. * - <OpenLayers.Layer.Grid>
  16. */
  17. OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
  18. /**
  19. * APIProperty: isBaseLayer
  20. * {Boolean} Treat this layer as a base layer. Default is true.
  21. **/
  22. isBaseLayer: true,
  23. /**
  24. * APIProperty: useHttpTile
  25. * {Boolean} use a tile cache exposed directly via a webserver rather than the
  26. * via mapguide server. This does require extra configuration on the Mapguide Server,
  27. * and will only work when singleTile is false. The url for the layer must be set to the
  28. * webserver path rather than the Mapguide mapagent.
  29. * See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp
  30. **/
  31. useHttpTile: false,
  32. /**
  33. * APIProperty: singleTile
  34. * {Boolean} use tile server or request single tile image.
  35. **/
  36. singleTile: false,
  37. /**
  38. * APIProperty: useOverlay
  39. * {Boolean} flag to indicate if the layer should be retrieved using
  40. * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests.
  41. **/
  42. useOverlay: false,
  43. /**
  44. * APIProperty: useAsyncOverlay
  45. * {Boolean} indicates if the MapGuide site supports the asynchronous
  46. * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010
  47. * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG
  48. * is called asynchronously, allows selections to be drawn separately from
  49. * the map and offers styling options.
  50. *
  51. * With older versions of MapGuide, set useAsyncOverlay=false. Note that in
  52. * this case a synchronous AJAX call is issued and the mapname and session
  53. * parameters must be used to initialize the layer, not the mapdefinition
  54. * parameter. Also note that this will issue a synchronous AJAX request
  55. * before the image request can be issued so the users browser may lock
  56. * up if the MG Web tier does not respond in a timely fashion.
  57. **/
  58. useAsyncOverlay: true,
  59. /**
  60. * Constant: TILE_PARAMS
  61. * {Object} Hashtable of default parameter key/value pairs for tiled layer
  62. */
  63. TILE_PARAMS: {
  64. operation: 'GETTILEIMAGE',
  65. version: '1.2.0'
  66. },
  67. /**
  68. * Constant: SINGLE_TILE_PARAMS
  69. * {Object} Hashtable of default parameter key/value pairs for untiled layer
  70. */
  71. SINGLE_TILE_PARAMS: {
  72. operation: 'GETMAPIMAGE',
  73. format: 'PNG',
  74. locale: 'en',
  75. clip: '1',
  76. version: '1.0.0'
  77. },
  78. /**
  79. * Constant: OVERLAY_PARAMS
  80. * {Object} Hashtable of default parameter key/value pairs for untiled layer
  81. */
  82. OVERLAY_PARAMS: {
  83. operation: 'GETDYNAMICMAPOVERLAYIMAGE',
  84. format: 'PNG',
  85. locale: 'en',
  86. clip: '1',
  87. version: '2.0.0'
  88. },
  89. /**
  90. * Constant: FOLDER_PARAMS
  91. * {Object} Hashtable of parameter key/value pairs which describe
  92. * the folder structure for tiles as configured in the mapguide
  93. * serverconfig.ini section [TileServiceProperties]
  94. */
  95. FOLDER_PARAMS: {
  96. tileColumnsPerFolder: 30,
  97. tileRowsPerFolder: 30,
  98. format: 'png',
  99. querystring: null
  100. },
  101. /**
  102. * Property: defaultSize
  103. * {<OpenLayers.Size>} Tile size as produced by MapGuide server
  104. **/
  105. defaultSize: new OpenLayers.Size(300,300),
  106. /**
  107. * Property: tileOriginCorner
  108. * {String} MapGuide tile server uses top-left as tile origin
  109. **/
  110. tileOriginCorner: "tl",
  111. /**
  112. * Constructor: OpenLayers.Layer.MapGuide
  113. * Create a new Mapguide layer, either tiled or untiled.
  114. *
  115. * For tiled layers, the 'groupName' and 'mapDefinition' values
  116. * must be specified as parameters in the constructor.
  117. *
  118. * For untiled base layers, specify either combination of 'mapName' and
  119. * 'session', or 'mapDefinition' and 'locale'.
  120. *
  121. * For older versions of MapGuide and overlay layers, set useAsyncOverlay
  122. * to false and in this case mapName and session are required parameters
  123. * for the constructor.
  124. *
  125. * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion
  126. * factor that are different than the defaults used in OpenLayers,
  127. * so these must be adjusted accordingly in your application.
  128. * See the MapGuide example for how to set these values for MGOS.
  129. *
  130. * Parameters:
  131. * name - {String} Name of the layer displayed in the interface
  132. * url - {String} Location of the MapGuide mapagent executable
  133. * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi)
  134. * params - {Object} hashtable of additional parameters to use. Some
  135. * parameters may require additional code on the server. The ones that
  136. * you may want to use are:
  137. * - mapDefinition - {String} The MapGuide resource definition
  138. * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition)
  139. * - locale - Locale setting
  140. * (for untiled overlays layers only)
  141. * - mapName - {String} Name of the map as stored in the MapGuide session.
  142. * (for untiled layers with a session parameter only)
  143. * - session - { String} MapGuide session ID
  144. * (for untiled overlays layers only)
  145. * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only
  146. * - format - Image format to be returned (for untiled overlay layers only)
  147. * - showLayers - {String} A comma separated list of GUID's for the
  148. * layers to display eg: 'cvc-xcv34,453-345-345sdf'.
  149. * - hideLayers - {String} A comma separated list of GUID's for the
  150. * layers to hide eg: 'cvc-xcv34,453-345-345sdf'.
  151. * - showGroups - {String} A comma separated list of GUID's for the
  152. * groups to display eg: 'cvc-xcv34,453-345-345sdf'.
  153. * - hideGroups - {String} A comma separated list of GUID's for the
  154. * groups to hide eg: 'cvc-xcv34,453-345-345sdf'
  155. * - selectionXml - {String} A selection xml string Some server plumbing
  156. * is required to read such a value.
  157. * options - {Object} Hashtable of extra options to tag onto the layer;
  158. * will vary depending if tiled or untiled maps are being requested
  159. */
  160. initialize: function(name, url, params, options) {
  161. OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments);
  162. // unless explicitly set in options, if the layer is transparent,
  163. // it will be an overlay
  164. if (options == null || options.isBaseLayer == null) {
  165. this.isBaseLayer = ((this.transparent != "true") &&
  166. (this.transparent != true));
  167. }
  168. if (options && options.useOverlay!=null) {
  169. this.useOverlay = options.useOverlay;
  170. }
  171. //initialize for untiled layers
  172. if (this.singleTile) {
  173. if (this.useOverlay) {
  174. OpenLayers.Util.applyDefaults(
  175. this.params,
  176. this.OVERLAY_PARAMS
  177. );
  178. if (!this.useAsyncOverlay) {
  179. this.params.version = "1.0.0";
  180. }
  181. } else {
  182. OpenLayers.Util.applyDefaults(
  183. this.params,
  184. this.SINGLE_TILE_PARAMS
  185. );
  186. }
  187. } else {
  188. //initialize for tiled layers
  189. if (this.useHttpTile) {
  190. OpenLayers.Util.applyDefaults(
  191. this.params,
  192. this.FOLDER_PARAMS
  193. );
  194. } else {
  195. OpenLayers.Util.applyDefaults(
  196. this.params,
  197. this.TILE_PARAMS
  198. );
  199. }
  200. this.setTileSize(this.defaultSize);
  201. }
  202. },
  203. /**
  204. * Method: clone
  205. * Create a clone of this layer
  206. *
  207. * Returns:
  208. * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer
  209. */
  210. clone: function (obj) {
  211. if (obj == null) {
  212. obj = new OpenLayers.Layer.MapGuide(this.name,
  213. this.url,
  214. this.params,
  215. this.getOptions());
  216. }
  217. //get all additions from superclasses
  218. obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
  219. return obj;
  220. },
  221. /**
  222. * Method: getURL
  223. * Return a query string for this layer
  224. *
  225. * Parameters:
  226. * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
  227. * for the request
  228. *
  229. * Returns:
  230. * {String} A string with the layer's url and parameters and also
  231. * the passed-in bounds and appropriate tile size specified
  232. * as parameters.
  233. */
  234. getURL: function (bounds) {
  235. var url;
  236. var center = bounds.getCenterLonLat();
  237. var mapSize = this.map.getSize();
  238. if (this.singleTile) {
  239. //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with
  240. //dynamic map parameters
  241. var params = {
  242. setdisplaydpi: OpenLayers.DOTS_PER_INCH,
  243. setdisplayheight: mapSize.h*this.ratio,
  244. setdisplaywidth: mapSize.w*this.ratio,
  245. setviewcenterx: center.lon,
  246. setviewcentery: center.lat,
  247. setviewscale: this.map.getScale()
  248. };
  249. if (this.useOverlay && !this.useAsyncOverlay) {
  250. //first we need to call GETVISIBLEMAPEXTENT to set the extent
  251. var getVisParams = {};
  252. getVisParams = OpenLayers.Util.extend(getVisParams, params);
  253. getVisParams.operation = "GETVISIBLEMAPEXTENT";
  254. getVisParams.version = "1.0.0";
  255. getVisParams.session = this.params.session;
  256. getVisParams.mapName = this.params.mapName;
  257. getVisParams.format = 'text/xml';
  258. url = this.getFullRequestString( getVisParams );
  259. OpenLayers.Request.GET({url: url, async: false});
  260. }
  261. //construct the full URL
  262. url = this.getFullRequestString( params );
  263. } else {
  264. //tiled version
  265. var currentRes = this.map.getResolution();
  266. var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
  267. colidx = Math.round(colidx/this.tileSize.w);
  268. var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
  269. rowidx = Math.round(rowidx/this.tileSize.h);
  270. if (this.useHttpTile){
  271. url = this.getImageFilePath(
  272. {
  273. tilecol: colidx,
  274. tilerow: rowidx,
  275. scaleindex: this.resolutions.length - this.map.zoom - 1
  276. });
  277. } else {
  278. url = this.getFullRequestString(
  279. {
  280. tilecol: colidx,
  281. tilerow: rowidx,
  282. scaleindex: this.resolutions.length - this.map.zoom - 1
  283. });
  284. }
  285. }
  286. return url;
  287. },
  288. /**
  289. * Method: getFullRequestString
  290. * getFullRequestString on MapGuide layers is special, because we
  291. * do a regular expression replace on ',' in parameters to '+'.
  292. * This is why it is subclassed here.
  293. *
  294. * Parameters:
  295. * altUrl - {String} Alternative base URL to use.
  296. *
  297. * Returns:
  298. * {String} A string with the layer's url appropriately encoded for MapGuide
  299. */
  300. getFullRequestString:function(newParams, altUrl) {
  301. // use layer's url unless altUrl passed in
  302. var url = (altUrl == null) ? this.url : altUrl;
  303. // if url is not a string, it should be an array of strings,
  304. // in which case we will randomly select one of them in order
  305. // to evenly distribute requests to different urls.
  306. if (typeof url == "object") {
  307. url = url[Math.floor(Math.random()*url.length)];
  308. }
  309. // requestString always starts with url
  310. var requestString = url;
  311. // create a new params hashtable with all the layer params and the
  312. // new params together. then convert to string
  313. var allParams = OpenLayers.Util.extend({}, this.params);
  314. allParams = OpenLayers.Util.extend(allParams, newParams);
  315. // ignore parameters that are already in the url search string
  316. var urlParams = OpenLayers.Util.upperCaseObject(
  317. OpenLayers.Util.getParameters(url));
  318. for(var key in allParams) {
  319. if(key.toUpperCase() in urlParams) {
  320. delete allParams[key];
  321. }
  322. }
  323. var paramsString = OpenLayers.Util.getParameterString(allParams);
  324. /* MapGuide needs '+' seperating things like bounds/height/width.
  325. Since typically this is URL encoded, we use a slight hack: we
  326. depend on the list-like functionality of getParameterString to
  327. leave ',' only in the case of list items (since otherwise it is
  328. encoded) then do a regular expression replace on the , characters
  329. to '+' */
  330. paramsString = paramsString.replace(/,/g, "+");
  331. if (paramsString != "") {
  332. var lastServerChar = url.charAt(url.length - 1);
  333. if ((lastServerChar == "&") || (lastServerChar == "?")) {
  334. requestString += paramsString;
  335. } else {
  336. if (url.indexOf('?') == -1) {
  337. //serverPath has no ? -- add one
  338. requestString += '?' + paramsString;
  339. } else {
  340. //serverPath contains ?, so must already have paramsString at the end
  341. requestString += '&' + paramsString;
  342. }
  343. }
  344. }
  345. return requestString;
  346. },
  347. /**
  348. * Method: getImageFilePath
  349. * special handler to request mapguide tiles from an http exposed tilecache
  350. *
  351. * Parameters:
  352. * altUrl - {String} Alternative base URL to use.
  353. *
  354. * Returns:
  355. * {String} A string with the url for the tile image
  356. */
  357. getImageFilePath:function(newParams, altUrl) {
  358. // use layer's url unless altUrl passed in
  359. var url = (altUrl == null) ? this.url : altUrl;
  360. // if url is not a string, it should be an array of strings,
  361. // in which case we will randomly select one of them in order
  362. // to evenly distribute requests to different urls.
  363. if (typeof url == "object") {
  364. url = url[Math.floor(Math.random()*url.length)];
  365. }
  366. // requestString always starts with url
  367. var requestString = url;
  368. var tileRowGroup = "";
  369. var tileColGroup = "";
  370. if (newParams.tilerow < 0) {
  371. tileRowGroup = '-';
  372. }
  373. if (newParams.tilerow == 0 ) {
  374. tileRowGroup += '0';
  375. } else {
  376. tileRowGroup += Math.floor(Math.abs(newParams.tilerow/this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder;
  377. }
  378. if (newParams.tilecol < 0) {
  379. tileColGroup = '-';
  380. }
  381. if (newParams.tilecol == 0) {
  382. tileColGroup += '0';
  383. } else {
  384. tileColGroup += Math.floor(Math.abs(newParams.tilecol/this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder;
  385. }
  386. var tilePath = '/S' + Math.floor(newParams.scaleindex)
  387. + '/' + this.params.basemaplayergroupname
  388. + '/R' + tileRowGroup
  389. + '/C' + tileColGroup
  390. + '/' + (newParams.tilerow % this.params.tileRowsPerFolder)
  391. + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder)
  392. + '.' + this.params.format;
  393. if (this.params.querystring) {
  394. tilePath += "?" + this.params.querystring;
  395. }
  396. requestString += tilePath;
  397. return requestString;
  398. },
  399. /**
  400. * Method: calculateGridLayout
  401. * Generate parameters for the grid layout. This
  402. *
  403. * Parameters:
  404. * bounds - {<OpenLayers.Bound>}
  405. * origin - {<OpenLayers.LonLat>}
  406. * resolution - {Number}
  407. *
  408. * Returns:
  409. * Object containing properties tilelon, tilelat, tileoffsetlat,
  410. * tileoffsetlat, tileoffsetx, tileoffsety
  411. */
  412. calculateGridLayout: function(bounds, origin, resolution) {
  413. var tilelon = resolution * this.tileSize.w;
  414. var tilelat = resolution * this.tileSize.h;
  415. var offsetlon = bounds.left - origin.lon;
  416. var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
  417. var tilecolremain = offsetlon/tilelon - tilecol;
  418. var tileoffsetx = -tilecolremain * this.tileSize.w;
  419. var tileoffsetlon = origin.lon + tilecol * tilelon;
  420. var offsetlat = origin.lat - bounds.top + tilelat;
  421. var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
  422. var tilerowremain = tilerow - offsetlat/tilelat;
  423. var tileoffsety = tilerowremain * this.tileSize.h;
  424. var tileoffsetlat = origin.lat - tilelat*tilerow;
  425. return {
  426. tilelon: tilelon, tilelat: tilelat,
  427. tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
  428. tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
  429. };
  430. },
  431. CLASS_NAME: "OpenLayers.Layer.MapGuide"
  432. });