UTFGrid.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
  2. * full list of contributors). Published under the 2-clause BSD license.
  3. * See license.txt in the OpenLayers distribution or repository for the
  4. * full text of the license. */
  5. /**
  6. * @requires OpenLayers/Tile.js
  7. * @requires OpenLayers/Format/JSON.js
  8. * @requires OpenLayers/Request.js
  9. */
  10. /**
  11. * Class: OpenLayers.Tile.UTFGrid
  12. * Instances of OpenLayers.Tile.UTFGrid are used to manage
  13. * UTFGrids. This is an unusual tile type in that it doesn't have a
  14. * rendered image; only a 'hit grid' that can be used to
  15. * look up feature attributes.
  16. *
  17. * See the <OpenLayers.Tile.UTFGrid> constructor for details on constructing a
  18. * new instance.
  19. *
  20. * Inherits from:
  21. * - <OpenLayers.Tile>
  22. */
  23. OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, {
  24. /**
  25. * Property: url
  26. * {String}
  27. * The URL of the UTFGrid file being requested. Provided by the <getURL>
  28. * method.
  29. */
  30. url: null,
  31. /**
  32. * Property: utfgridResolution
  33. * {Number}
  34. * Ratio of the pixel width to the width of a UTFGrid data point. If an
  35. * entry in the grid represents a 4x4 block of pixels, the
  36. * utfgridResolution would be 4. Default is 2.
  37. */
  38. utfgridResolution: 2,
  39. /**
  40. * Property: json
  41. * {Object}
  42. * Stores the parsed JSON tile data structure.
  43. */
  44. json: null,
  45. /**
  46. * Property: format
  47. * {OpenLayers.Format.JSON}
  48. * Parser instance used to parse JSON for cross browser support. The native
  49. * JSON.parse method will be used where available (all except IE<8).
  50. */
  51. format: null,
  52. /**
  53. * Constructor: OpenLayers.Tile.UTFGrid
  54. * Constructor for a new <OpenLayers.Tile.UTFGrid> instance.
  55. *
  56. * Parameters:
  57. * layer - {<OpenLayers.Layer>} layer that the tile will go in.
  58. * position - {<OpenLayers.Pixel>}
  59. * bounds - {<OpenLayers.Bounds>}
  60. * url - {<String>} Deprecated. Remove me in 3.0.
  61. * size - {<OpenLayers.Size>}
  62. * options - {Object}
  63. */
  64. /**
  65. * APIMethod: destroy
  66. * Clean up.
  67. */
  68. destroy: function() {
  69. this.clear();
  70. OpenLayers.Tile.prototype.destroy.apply(this, arguments);
  71. },
  72. /**
  73. * Method: draw
  74. * Check that a tile should be drawn, and draw it.
  75. * In the case of UTFGrids, "drawing" it means fetching and
  76. * parsing the json.
  77. *
  78. * Returns:
  79. * {Boolean} Was a tile drawn?
  80. */
  81. draw: function() {
  82. var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments);
  83. if (drawn) {
  84. if (this.isLoading) {
  85. this.abortLoading();
  86. //if we're already loading, send 'reload' instead of 'loadstart'.
  87. this.events.triggerEvent("reload");
  88. } else {
  89. this.isLoading = true;
  90. this.events.triggerEvent("loadstart");
  91. }
  92. this.url = this.layer.getURL(this.bounds);
  93. if (this.layer.useJSONP) {
  94. // Use JSONP method to avoid xbrowser policy
  95. var ols = new OpenLayers.Protocol.Script({
  96. url: this.url,
  97. callback: function(response) {
  98. this.isLoading = false;
  99. this.events.triggerEvent("loadend");
  100. this.json = response.data;
  101. },
  102. scope: this
  103. });
  104. ols.read();
  105. this.request = ols;
  106. } else {
  107. // Use standard XHR
  108. this.request = OpenLayers.Request.GET({
  109. url: this.url,
  110. callback: function(response) {
  111. this.isLoading = false;
  112. this.events.triggerEvent("loadend");
  113. if (response.status === 200) {
  114. this.parseData(response.responseText);
  115. }
  116. },
  117. scope: this
  118. });
  119. }
  120. } else {
  121. this.unload();
  122. }
  123. return drawn;
  124. },
  125. /**
  126. * Method: abortLoading
  127. * Cancel a pending request.
  128. */
  129. abortLoading: function() {
  130. if (this.request) {
  131. this.request.abort();
  132. delete this.request;
  133. }
  134. this.isLoading = false;
  135. },
  136. /**
  137. * Method: getFeatureInfo
  138. * Get feature information associated with a pixel offset. If the pixel
  139. * offset corresponds to a feature, the returned object will have id
  140. * and data properties. Otherwise, null will be returned.
  141. *
  142. *
  143. * Parameters:
  144. * i - {Number} X-axis pixel offset (from top left of tile)
  145. * j - {Number} Y-axis pixel offset (from top left of tile)
  146. *
  147. * Returns:
  148. * {Object} Object with feature id and data properties corresponding to the
  149. * given pixel offset.
  150. */
  151. getFeatureInfo: function(i, j) {
  152. var info = null;
  153. if (this.json) {
  154. var id = this.getFeatureId(i, j);
  155. if (id !== null) {
  156. info = {id: id, data: this.json.data[id]};
  157. }
  158. }
  159. return info;
  160. },
  161. /**
  162. * Method: getFeatureId
  163. * Get the identifier for the feature associated with a pixel offset.
  164. *
  165. * Parameters:
  166. * i - {Number} X-axis pixel offset (from top left of tile)
  167. * j - {Number} Y-axis pixel offset (from top left of tile)
  168. *
  169. * Returns:
  170. * {Object} The feature identifier corresponding to the given pixel offset.
  171. * Returns null if pixel doesn't correspond to a feature.
  172. */
  173. getFeatureId: function(i, j) {
  174. var id = null;
  175. if (this.json) {
  176. var resolution = this.utfgridResolution;
  177. var row = Math.floor(j / resolution);
  178. var col = Math.floor(i / resolution);
  179. var charCode = this.json.grid[row].charCodeAt(col);
  180. var index = this.indexFromCharCode(charCode);
  181. var keys = this.json.keys;
  182. if (!isNaN(index) && (index in keys)) {
  183. id = keys[index];
  184. }
  185. }
  186. return id;
  187. },
  188. /**
  189. * Method: indexFromCharCode
  190. * Given a character code for one of the UTFGrid "grid" characters,
  191. * resolve the integer index for the feature id in the UTFGrid "keys"
  192. * array.
  193. *
  194. * Parameters:
  195. * charCode - {Integer}
  196. *
  197. * Returns:
  198. * {Integer} Index for the feature id from the keys array.
  199. */
  200. indexFromCharCode: function(charCode) {
  201. if (charCode >= 93) {
  202. charCode--;
  203. }
  204. if (charCode >= 35) {
  205. charCode --;
  206. }
  207. return charCode - 32;
  208. },
  209. /**
  210. * Method: parseData
  211. * Parse the JSON from a request
  212. *
  213. * Parameters:
  214. * str - {String} UTFGrid as a JSON string.
  215. *
  216. * Returns:
  217. * {Object} parsed javascript data
  218. */
  219. parseData: function(str) {
  220. if (!this.format) {
  221. this.format = new OpenLayers.Format.JSON();
  222. }
  223. this.json = this.format.read(str);
  224. },
  225. /**
  226. * Method: clear
  227. * Delete data stored with this tile.
  228. */
  229. clear: function() {
  230. this.json = null;
  231. },
  232. CLASS_NAME: "OpenLayers.Tile.UTFGrid"
  233. });