WMTSGetFeatureInfo.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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/Control.js
  7. * @requires OpenLayers/Handler/Click.js
  8. * @requires OpenLayers/Handler/Hover.js
  9. * @requires OpenLayers/Request.js
  10. * @requires OpenLayers/Format/WMSGetFeatureInfo.js
  11. */
  12. /**
  13. * Class: OpenLayers.Control.WMTSGetFeatureInfo
  14. * The WMTSGetFeatureInfo control uses a WMTS query to get information about a
  15. * point on the map. The information may be in a display-friendly format
  16. * such as HTML, or a machine-friendly format such as GML, depending on the
  17. * server's capabilities and the client's configuration. This control
  18. * handles click or hover events, attempts to parse the results using an
  19. * OpenLayers.Format, and fires a 'getfeatureinfo' event for each layer
  20. * queried.
  21. *
  22. * Inherits from:
  23. * - <OpenLayers.Control>
  24. */
  25. OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
  26. /**
  27. * APIProperty: hover
  28. * {Boolean} Send GetFeatureInfo requests when mouse stops moving.
  29. * Default is false.
  30. */
  31. hover: false,
  32. /**
  33. * Property: requestEncoding
  34. * {String} One of "KVP" or "REST". Only KVP encoding is supported at this
  35. * time.
  36. */
  37. requestEncoding: "KVP",
  38. /**
  39. * APIProperty: drillDown
  40. * {Boolean} Drill down over all WMTS layers in the map. When
  41. * using drillDown mode, hover is not possible. A getfeatureinfo event
  42. * will be fired for each layer queried.
  43. */
  44. drillDown: false,
  45. /**
  46. * APIProperty: maxFeatures
  47. * {Integer} Maximum number of features to return from a WMTS query. This
  48. * sets the feature_count parameter on WMTS GetFeatureInfo
  49. * requests.
  50. */
  51. maxFeatures: 10,
  52. /** APIProperty: clickCallback
  53. * {String} The click callback to register in the
  54. * {<OpenLayers.Handler.Click>} object created when the hover
  55. * option is set to false. Default is "click".
  56. */
  57. clickCallback: "click",
  58. /**
  59. * Property: layers
  60. * {Array(<OpenLayers.Layer.WMTS>)} The layers to query for feature info.
  61. * If omitted, all map WMTS layers will be considered.
  62. */
  63. layers: null,
  64. /**
  65. * APIProperty: queryVisible
  66. * {Boolean} Filter out hidden layers when searching the map for layers to
  67. * query. Default is true.
  68. */
  69. queryVisible: true,
  70. /**
  71. * Property: infoFormat
  72. * {String} The mimetype to request from the server
  73. */
  74. infoFormat: 'text/html',
  75. /**
  76. * Property: vendorParams
  77. * {Object} Additional parameters that will be added to the request, for
  78. * WMTS implementations that support them. This could e.g. look like
  79. * (start code)
  80. * {
  81. * radius: 5
  82. * }
  83. * (end)
  84. */
  85. vendorParams: {},
  86. /**
  87. * Property: format
  88. * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses.
  89. * Default is <OpenLayers.Format.WMSGetFeatureInfo>.
  90. */
  91. format: null,
  92. /**
  93. * Property: formatOptions
  94. * {Object} Optional properties to set on the format (if one is not provided
  95. * in the <format> property.
  96. */
  97. formatOptions: null,
  98. /**
  99. * APIProperty: handlerOptions
  100. * {Object} Additional options for the handlers used by this control, e.g.
  101. * (start code)
  102. * {
  103. * "click": {delay: 100},
  104. * "hover": {delay: 300}
  105. * }
  106. * (end)
  107. */
  108. handlerOptions: null,
  109. /**
  110. * Property: handler
  111. * {Object} Reference to the <OpenLayers.Handler> for this control
  112. */
  113. handler: null,
  114. /**
  115. * Property: hoverRequest
  116. * {<OpenLayers.Request>} contains the currently running hover request
  117. * (if any).
  118. */
  119. hoverRequest: null,
  120. /**
  121. * Constant: EVENT_TYPES
  122. *
  123. * Supported event types (in addition to those from <OpenLayers.Control>):
  124. * beforegetfeatureinfo - Triggered before each request is sent.
  125. * The event object has an *xy* property with the position of the
  126. * mouse click or hover event that triggers the request and a *layer*
  127. * property referencing the layer about to be queried. If a listener
  128. * returns false, the request will not be issued.
  129. * getfeatureinfo - Triggered when a GetFeatureInfo response is received.
  130. * The event object has a *text* property with the body of the
  131. * response (String), a *features* property with an array of the
  132. * parsed features, an *xy* property with the position of the mouse
  133. * click or hover event that triggered the request, a *layer* property
  134. * referencing the layer queried and a *request* property with the
  135. * request itself. If drillDown is set to true, one event will be fired
  136. * for each layer queried.
  137. * exception - Triggered when a GetFeatureInfo request fails (with a
  138. * status other than 200) or whenparsing fails. Listeners will receive
  139. * an event with *request*, *xy*, and *layer* properties. In the case
  140. * of a parsing error, the event will also contain an *error* property.
  141. */
  142. EVENT_TYPES: ["beforegetfeatureinfo", "getfeatureinfo", "exception"],
  143. /**
  144. * Property: pending
  145. * {Number} The number of pending requests.
  146. */
  147. pending: 0,
  148. /**
  149. * Constructor: <OpenLayers.Control.WMTSGetFeatureInfo>
  150. *
  151. * Parameters:
  152. * options - {Object}
  153. */
  154. initialize: function(options) {
  155. // concatenate events specific to vector with those from the base
  156. this.EVENT_TYPES =
  157. OpenLayers.Control.WMTSGetFeatureInfo.prototype.EVENT_TYPES.concat(
  158. OpenLayers.Control.prototype.EVENT_TYPES
  159. );
  160. options = options || {};
  161. options.handlerOptions = options.handlerOptions || {};
  162. OpenLayers.Control.prototype.initialize.apply(this, [options]);
  163. if (!this.format) {
  164. this.format = new OpenLayers.Format.WMSGetFeatureInfo(
  165. options.formatOptions
  166. );
  167. }
  168. if (this.drillDown === true) {
  169. this.hover = false;
  170. }
  171. if (this.hover) {
  172. this.handler = new OpenLayers.Handler.Hover(
  173. this, {
  174. move: this.cancelHover,
  175. pause: this.getInfoForHover
  176. },
  177. OpenLayers.Util.extend(
  178. this.handlerOptions.hover || {}, {delay: 250}
  179. )
  180. );
  181. } else {
  182. var callbacks = {};
  183. callbacks[this.clickCallback] = this.getInfoForClick;
  184. this.handler = new OpenLayers.Handler.Click(
  185. this, callbacks, this.handlerOptions.click || {}
  186. );
  187. }
  188. },
  189. /**
  190. * Method: getInfoForClick
  191. * Called on click
  192. *
  193. * Parameters:
  194. * evt - {<OpenLayers.Event>}
  195. */
  196. getInfoForClick: function(evt) {
  197. this.request(evt.xy, {});
  198. },
  199. /**
  200. * Method: getInfoForHover
  201. * Pause callback for the hover handler
  202. *
  203. * Parameters:
  204. * evt - {Object}
  205. */
  206. getInfoForHover: function(evt) {
  207. this.request(evt.xy, {hover: true});
  208. },
  209. /**
  210. * Method: cancelHover
  211. * Cancel callback for the hover handler
  212. */
  213. cancelHover: function() {
  214. if (this.hoverRequest) {
  215. --this.pending;
  216. if (this.pending <= 0) {
  217. OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait");
  218. this.pending = 0;
  219. }
  220. this.hoverRequest.abort();
  221. this.hoverRequest = null;
  222. }
  223. },
  224. /**
  225. * Method: findLayers
  226. * Internal method to get the layers, independent of whether we are
  227. * inspecting the map or using a client-provided array
  228. */
  229. findLayers: function() {
  230. var candidates = this.layers || this.map.layers;
  231. var layers = [];
  232. var layer;
  233. for (var i=candidates.length-1; i>=0; --i) {
  234. layer = candidates[i];
  235. if (layer instanceof OpenLayers.Layer.WMTS &&
  236. layer.requestEncoding === this.requestEncoding &&
  237. (!this.queryVisible || layer.getVisibility())) {
  238. layers.push(layer);
  239. if (!this.drillDown || this.hover) {
  240. break;
  241. }
  242. }
  243. }
  244. return layers;
  245. },
  246. /**
  247. * Method: buildRequestOptions
  248. * Build an object with the relevant options for the GetFeatureInfo request.
  249. *
  250. * Parameters:
  251. * layer - {<OpenLayers.Layer.WMTS>} A WMTS layer.
  252. * xy - {<OpenLayers.Pixel>} The position on the map where the
  253. * mouse event occurred.
  254. */
  255. buildRequestOptions: function(layer, xy) {
  256. var loc = this.map.getLonLatFromPixel(xy);
  257. var getTileUrl = layer.getURL(
  258. new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat)
  259. );
  260. var params = OpenLayers.Util.getParameters(getTileUrl);
  261. var tileInfo = layer.getTileInfo(loc);
  262. OpenLayers.Util.extend(params, {
  263. service: "WMTS",
  264. version: layer.version,
  265. request: "GetFeatureInfo",
  266. infoFormat: this.infoFormat,
  267. i: tileInfo.i,
  268. j: tileInfo.j
  269. });
  270. OpenLayers.Util.applyDefaults(params, this.vendorParams);
  271. return {
  272. url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url,
  273. params: OpenLayers.Util.upperCaseObject(params),
  274. callback: function(request) {
  275. this.handleResponse(xy, request, layer);
  276. },
  277. scope: this
  278. };
  279. },
  280. /**
  281. * Method: request
  282. * Sends a GetFeatureInfo request to the WMTS
  283. *
  284. * Parameters:
  285. * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event
  286. * occurred.
  287. * options - {Object} additional options for this method.
  288. *
  289. * Valid options:
  290. * - *hover* {Boolean} true if we do the request for the hover handler
  291. */
  292. request: function(xy, options) {
  293. options = options || {};
  294. var layers = this.findLayers();
  295. if (layers.length > 0) {
  296. var issue, layer;
  297. for (var i=0, len=layers.length; i<len; i++) {
  298. layer = layers[i];
  299. issue = this.events.triggerEvent("beforegetfeatureinfo", {
  300. xy: xy,
  301. layer: layer
  302. });
  303. if (issue !== false) {
  304. ++this.pending;
  305. var requestOptions = this.buildRequestOptions(layer, xy);
  306. var request = OpenLayers.Request.GET(requestOptions);
  307. if (options.hover === true) {
  308. this.hoverRequest = request;
  309. }
  310. }
  311. }
  312. if (this.pending > 0) {
  313. OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait");
  314. }
  315. }
  316. },
  317. /**
  318. * Method: handleResponse
  319. * Handler for the GetFeatureInfo response.
  320. *
  321. * Parameters:
  322. * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event
  323. * occurred.
  324. * request - {XMLHttpRequest} The request object.
  325. * layer - {<OpenLayers.Layer.WMTS>} The queried layer.
  326. */
  327. handleResponse: function(xy, request, layer) {
  328. --this.pending;
  329. if (this.pending <= 0) {
  330. OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait");
  331. this.pending = 0;
  332. }
  333. if (request.status && (request.status < 200 || request.status >= 300)) {
  334. this.events.triggerEvent("exception", {
  335. xy: xy,
  336. request: request,
  337. layer: layer
  338. });
  339. } else {
  340. var doc = request.responseXML;
  341. if (!doc || !doc.documentElement) {
  342. doc = request.responseText;
  343. }
  344. var features, except;
  345. try {
  346. features = this.format.read(doc);
  347. } catch (error) {
  348. except = true;
  349. this.events.triggerEvent("exception", {
  350. xy: xy,
  351. request: request,
  352. error: error,
  353. layer: layer
  354. });
  355. }
  356. if (!except) {
  357. this.events.triggerEvent("getfeatureinfo", {
  358. text: request.responseText,
  359. features: features,
  360. request: request,
  361. xy: xy,
  362. layer: layer
  363. });
  364. }
  365. }
  366. },
  367. CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo"
  368. });