OpenStreetMapImageryProvider.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*global define*/
  2. define([
  3. '../Core/Credit',
  4. '../Core/defaultValue',
  5. '../Core/defined',
  6. '../Core/defineProperties',
  7. '../Core/DeveloperError',
  8. '../Core/Event',
  9. '../Core/Rectangle',
  10. '../Core/WebMercatorTilingScheme',
  11. './ImageryProvider'
  12. ], function(
  13. Credit,
  14. defaultValue,
  15. defined,
  16. defineProperties,
  17. DeveloperError,
  18. Event,
  19. Rectangle,
  20. WebMercatorTilingScheme,
  21. ImageryProvider) {
  22. "use strict";
  23. var trailingSlashRegex = /\/$/;
  24. var defaultCredit = new Credit('MapQuest, Open Street Map and contributors, CC-BY-SA');
  25. /**
  26. * Provides tiled imagery hosted by OpenStreetMap or another provider of Slippy tiles. Please be aware
  27. * that a default-constructed instance of this class will connect to OpenStreetMap's volunteer-run
  28. * servers, so you must conform to their
  29. * {@link http://wiki.openstreetmap.org/wiki/Tile_usage_policy|Tile Usage Policy}.
  30. *
  31. * @alias OpenStreetMapImageryProvider
  32. * @constructor
  33. *
  34. * @param {Object} [options] Object with the following properties:
  35. * @param {String} [options.url='//a.tile.openstreetmap.org'] The OpenStreetMap server url.
  36. * @param {String} [options.fileExtension='png'] The file extension for images on the server.
  37. * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL.
  38. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle of the layer.
  39. * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider.
  40. * @param {Number} [options.maximumLevel=18] The maximum level-of-detail supported by the imagery provider.
  41. * @param {Credit|String} [options.credit='MapQuest, Open Street Map and contributors, CC-BY-SA'] A credit for the data source, which is displayed on the canvas.
  42. *
  43. * @see ArcGisMapServerImageryProvider
  44. * @see BingMapsImageryProvider
  45. * @see SingleTileImageryProvider
  46. * @see TileMapServiceImageryProvider
  47. * @see WebMapServiceImageryProvider
  48. *
  49. * @see {@link http://wiki.openstreetmap.org/wiki/Main_Page|OpenStreetMap Wiki}
  50. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  51. *
  52. * @example
  53. * // OpenStreetMap tile provider
  54. * var osm = new Cesium.OpenStreetMapImageryProvider({
  55. * url : '//a.tile.openstreetmap.org/'
  56. * });
  57. */
  58. var OpenStreetMapImageryProvider = function OpenStreetMapImageryProvider(options) {
  59. options = defaultValue(options, {});
  60. var url = defaultValue(options.url, '//a.tile.openstreetmap.org/');
  61. if (!trailingSlashRegex.test(url)) {
  62. url = url + '/';
  63. }
  64. this._url = url;
  65. this._fileExtension = defaultValue(options.fileExtension, 'png');
  66. this._proxy = options.proxy;
  67. this._tileDiscardPolicy = options.tileDiscardPolicy;
  68. this._tilingScheme = new WebMercatorTilingScheme();
  69. this._tileWidth = 256;
  70. this._tileHeight = 256;
  71. this._minimumLevel = defaultValue(options.minimumLevel, 0);
  72. this._maximumLevel = defaultValue(options.maximumLevel, 18);
  73. this._rectangle = defaultValue(options.rectangle, this._tilingScheme.rectangle);
  74. // Check the number of tiles at the minimum level. If it's more than four,
  75. // throw an exception, because starting at the higher minimum
  76. // level will cause too many tiles to be downloaded and rendered.
  77. var swTile = this._tilingScheme.positionToTileXY(Rectangle.southwest(this._rectangle), this._minimumLevel);
  78. var neTile = this._tilingScheme.positionToTileXY(Rectangle.northeast(this._rectangle), this._minimumLevel);
  79. var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1);
  80. if (tileCount > 4) {
  81. throw new DeveloperError('The imagery provider\'s rectangle and minimumLevel indicate that there are ' + tileCount + ' tiles at the minimum level. Imagery providers with more than four tiles at the minimum level are not supported.');
  82. }
  83. this._errorEvent = new Event();
  84. this._ready = true;
  85. var credit = defaultValue(options.credit, defaultCredit);
  86. if (typeof credit === 'string') {
  87. credit = new Credit(credit);
  88. }
  89. this._credit = credit;
  90. };
  91. function buildImageUrl(imageryProvider, x, y, level) {
  92. var url = imageryProvider._url + level + '/' + x + '/' + y + '.' + imageryProvider._fileExtension;
  93. var proxy = imageryProvider._proxy;
  94. if (defined(proxy)) {
  95. url = proxy.getURL(url);
  96. }
  97. return url;
  98. }
  99. defineProperties(OpenStreetMapImageryProvider.prototype, {
  100. /**
  101. * Gets the URL of the service hosting the imagery.
  102. * @memberof OpenStreetMapImageryProvider.prototype
  103. * @type {String}
  104. * @readonly
  105. */
  106. url : {
  107. get : function() {
  108. return this._url;
  109. }
  110. },
  111. /**
  112. * Gets the proxy used by this provider.
  113. * @memberof OpenStreetMapImageryProvider.prototype
  114. * @type {Proxy}
  115. * @readonly
  116. */
  117. proxy : {
  118. get : function() {
  119. return this._proxy;
  120. }
  121. },
  122. /**
  123. * Gets the width of each tile, in pixels. This function should
  124. * not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  125. * @memberof OpenStreetMapImageryProvider.prototype
  126. * @type {Number}
  127. * @readonly
  128. */
  129. tileWidth : {
  130. get : function() {
  131. //>>includeStart('debug', pragmas.debug);
  132. if (!this._ready) {
  133. throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.');
  134. }
  135. //>>includeEnd('debug');
  136. return this._tileWidth;
  137. }
  138. },
  139. /**
  140. * Gets the height of each tile, in pixels. This function should
  141. * not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  142. * @memberof OpenStreetMapImageryProvider.prototype
  143. * @type {Number}
  144. * @readonly
  145. */
  146. tileHeight: {
  147. get : function() {
  148. //>>includeStart('debug', pragmas.debug);
  149. if (!this._ready) {
  150. throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.');
  151. }
  152. //>>includeEnd('debug');
  153. return this._tileHeight;
  154. }
  155. },
  156. /**
  157. * Gets the maximum level-of-detail that can be requested. This function should
  158. * not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  159. * @memberof OpenStreetMapImageryProvider.prototype
  160. * @type {Number}
  161. * @readonly
  162. */
  163. maximumLevel : {
  164. get : function() {
  165. //>>includeStart('debug', pragmas.debug);
  166. if (!this._ready) {
  167. throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.');
  168. }
  169. //>>includeEnd('debug');
  170. return this._maximumLevel;
  171. }
  172. },
  173. /**
  174. * Gets the minimum level-of-detail that can be requested. This function should
  175. * not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  176. * @memberof OpenStreetMapImageryProvider.prototype
  177. * @type {Number}
  178. * @readonly
  179. */
  180. minimumLevel : {
  181. get : function() {
  182. //>>includeStart('debug', pragmas.debug);
  183. if (!this._ready) {
  184. throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.');
  185. }
  186. //>>includeEnd('debug');
  187. return this._minimumLevel;
  188. }
  189. },
  190. /**
  191. * Gets the tiling scheme used by this provider. This function should
  192. * not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  193. * @memberof OpenStreetMapImageryProvider.prototype
  194. * @type {TilingScheme}
  195. * @readonly
  196. */
  197. tilingScheme : {
  198. get : function() {
  199. //>>includeStart('debug', pragmas.debug);
  200. if (!this._ready) {
  201. throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.');
  202. }
  203. //>>includeEnd('debug');
  204. return this._tilingScheme;
  205. }
  206. },
  207. /**
  208. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  209. * not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  210. * @memberof OpenStreetMapImageryProvider.prototype
  211. * @type {Rectangle}
  212. * @readonly
  213. */
  214. rectangle : {
  215. get : function() {
  216. //>>includeStart('debug', pragmas.debug);
  217. if (!this._ready) {
  218. throw new DeveloperError('rectangle must not be called before the imagery provider is ready.');
  219. }
  220. //>>includeEnd('debug');
  221. return this._rectangle;
  222. }
  223. },
  224. /**
  225. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  226. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  227. * returns undefined, no tiles are filtered. This function should
  228. * not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  229. * @memberof OpenStreetMapImageryProvider.prototype
  230. * @type {TileDiscardPolicy}
  231. * @readonly
  232. */
  233. tileDiscardPolicy : {
  234. get : function() {
  235. //>>includeStart('debug', pragmas.debug);
  236. if (!this._ready) {
  237. throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.');
  238. }
  239. //>>includeEnd('debug');
  240. return this._tileDiscardPolicy;
  241. }
  242. },
  243. /**
  244. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  245. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  246. * are passed an instance of {@link TileProviderError}.
  247. * @memberof OpenStreetMapImageryProvider.prototype
  248. * @type {Event}
  249. * @readonly
  250. */
  251. errorEvent : {
  252. get : function() {
  253. return this._errorEvent;
  254. }
  255. },
  256. /**
  257. * Gets a value indicating whether or not the provider is ready for use.
  258. * @memberof OpenStreetMapImageryProvider.prototype
  259. * @type {Boolean}
  260. * @readonly
  261. */
  262. ready : {
  263. get : function() {
  264. return this._ready;
  265. }
  266. },
  267. /**
  268. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  269. * the source of the imagery. This function should not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  270. * @memberof OpenStreetMapImageryProvider.prototype
  271. * @type {Credit}
  272. * @readonly
  273. */
  274. credit : {
  275. get : function() {
  276. return this._credit;
  277. }
  278. },
  279. /**
  280. * Gets a value indicating whether or not the images provided by this imagery provider
  281. * include an alpha channel. If this property is false, an alpha channel, if present, will
  282. * be ignored. If this property is true, any images without an alpha channel will be treated
  283. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  284. * and texture upload time are reduced.
  285. * @memberof OpenStreetMapImageryProvider.prototype
  286. * @type {Boolean}
  287. * @readonly
  288. */
  289. hasAlphaChannel : {
  290. get : function() {
  291. return true;
  292. }
  293. }
  294. });
  295. /**
  296. * Gets the credits to be displayed when a given tile is displayed.
  297. *
  298. * @param {Number} x The tile X coordinate.
  299. * @param {Number} y The tile Y coordinate.
  300. * @param {Number} level The tile level;
  301. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  302. *
  303. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  304. */
  305. OpenStreetMapImageryProvider.prototype.getTileCredits = function(x, y, level) {
  306. return undefined;
  307. };
  308. /**
  309. * Requests the image for a given tile. This function should
  310. * not be called before {@link OpenStreetMapImageryProvider#ready} returns true.
  311. *
  312. * @param {Number} x The tile X coordinate.
  313. * @param {Number} y The tile Y coordinate.
  314. * @param {Number} level The tile level.
  315. * @returns {Promise} A promise for the image that will resolve when the image is available, or
  316. * undefined if there are too many active requests to the server, and the request
  317. * should be retried later. The resolved image may be either an
  318. * Image or a Canvas DOM object.
  319. *
  320. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  321. */
  322. OpenStreetMapImageryProvider.prototype.requestImage = function(x, y, level) {
  323. //>>includeStart('debug', pragmas.debug);
  324. if (!this._ready) {
  325. throw new DeveloperError('requestImage must not be called before the imagery provider is ready.');
  326. }
  327. //>>includeEnd('debug');
  328. var url = buildImageUrl(this, x, y, level);
  329. return ImageryProvider.loadImage(this, url);
  330. };
  331. /**
  332. * Picking features is not currently supported by this imagery provider, so this function simply returns
  333. * undefined.
  334. *
  335. * @param {Number} x The tile X coordinate.
  336. * @param {Number} y The tile Y coordinate.
  337. * @param {Number} level The tile level.
  338. * @param {Number} longitude The longitude at which to pick features.
  339. * @param {Number} latitude The latitude at which to pick features.
  340. * @return {Promise} A promise for the picked features that will resolve when the asynchronous
  341. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  342. * instances. The array may be empty if no features are found at the given location.
  343. * It may also be undefined if picking is not supported.
  344. */
  345. OpenStreetMapImageryProvider.prototype.pickFeatures = function() {
  346. return undefined;
  347. };
  348. return OpenStreetMapImageryProvider;
  349. });