BingMapsImageryProvider.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /*global define*/
  2. define([
  3. '../Core/BingMapsApi',
  4. '../Core/Cartesian2',
  5. '../Core/Credit',
  6. '../Core/defaultValue',
  7. '../Core/defined',
  8. '../Core/defineProperties',
  9. '../Core/DeveloperError',
  10. '../Core/Event',
  11. '../Core/jsonp',
  12. '../Core/Math',
  13. '../Core/Rectangle',
  14. '../Core/TileProviderError',
  15. '../Core/WebMercatorTilingScheme',
  16. '../ThirdParty/when',
  17. './BingMapsStyle',
  18. './DiscardMissingTileImagePolicy',
  19. './ImageryProvider'
  20. ], function(
  21. BingMapsApi,
  22. Cartesian2,
  23. Credit,
  24. defaultValue,
  25. defined,
  26. defineProperties,
  27. DeveloperError,
  28. Event,
  29. jsonp,
  30. CesiumMath,
  31. Rectangle,
  32. TileProviderError,
  33. WebMercatorTilingScheme,
  34. when,
  35. BingMapsStyle,
  36. DiscardMissingTileImagePolicy,
  37. ImageryProvider) {
  38. "use strict";
  39. /**
  40. * Provides tiled imagery using the Bing Maps Imagery REST API.
  41. *
  42. * @alias BingMapsImageryProvider
  43. * @constructor
  44. *
  45. * @param {Object} options Object with the following properties:
  46. * @param {String} options.url The url of the Bing Maps server hosting the imagery.
  47. * @param {String} [options.key] The Bing Maps key for your application, which can be
  48. * created at {@link https://www.bingmapsportal.com/}.
  49. * If this parameter is not provided, {@link BingMapsApi.defaultKey} is used.
  50. * If {@link BingMapsApi.defaultKey} is undefined as well, a message is
  51. * written to the console reminding you that you must create and supply a Bing Maps
  52. * key as soon as possible. Please do not deploy an application that uses
  53. * Bing Maps imagery without creating a separate key for your application.
  54. * @param {String} [options.tileProtocol] The protocol to use when loading tiles, e.g. 'http:' or 'https:'.
  55. * By default, tiles are loaded using the same protocol as the page.
  56. * @param {String} [options.mapStyle=BingMapsStyle.AERIAL] The type of Bing Maps
  57. * imagery to load.
  58. * @param {String} [options.culture=''] The culture to use when requesting Bing Maps imagery. Not
  59. * all cultures are supported. See {@link http://msdn.microsoft.com/en-us/library/hh441729.aspx}
  60. * for information on the supported cultures.
  61. * @param {TileDiscardPolicy} [options.tileDiscardPolicy] The policy that determines if a tile
  62. * is invalid and should be discarded. If this value is not specified, a default
  63. * {@link DiscardMissingTileImagePolicy} is used which requests
  64. * tile 0,0 at the maximum tile level and checks pixels (0,0), (120,140), (130,160),
  65. * (200,50), and (200,200). If all of these pixels are transparent, the discard check is
  66. * disabled and no tiles are discarded. If any of them have a non-transparent color, any
  67. * tile that has the same values in these pixel locations is discarded. The end result of
  68. * these defaults should be correct tile discarding for a standard Bing Maps server. To ensure
  69. * that no tiles are discarded, construct and pass a {@link NeverTileDiscardPolicy} for this
  70. * parameter.
  71. * @param {Proxy} [options.proxy] A proxy to use for requests. This object is
  72. * expected to have a getURL function which returns the proxied URL, if needed.
  73. *
  74. * @see ArcGisMapServerImageryProvider
  75. * @see GoogleEarthImageryProvider
  76. * @see OpenStreetMapImageryProvider
  77. * @see SingleTileImageryProvider
  78. * @see TileMapServiceImageryProvider
  79. * @see WebMapServiceImageryProvider
  80. *
  81. * @see {@link http://msdn.microsoft.com/en-us/library/ff701713.aspx|Bing Maps REST Services}
  82. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  83. *
  84. * @example
  85. * var bing = new Cesium.BingMapsImageryProvider({
  86. * url : '//dev.virtualearth.net',
  87. * key : 'get-yours-at-https://www.bingmapsportal.com/',
  88. * mapStyle : Cesium.BingMapsStyle.AERIAL
  89. * });
  90. */
  91. var BingMapsImageryProvider = function BingMapsImageryProvider(options) {
  92. options = defaultValue(options, {});
  93. //>>includeStart('debug', pragmas.debug);
  94. if (!defined(options.url)) {
  95. throw new DeveloperError('options.url is required.');
  96. }
  97. //>>includeEnd('debug');
  98. this._key = BingMapsApi.getKey(options.key);
  99. this._url = options.url;
  100. this._tileProtocol = options.tileProtocol;
  101. this._mapStyle = defaultValue(options.mapStyle, BingMapsStyle.AERIAL);
  102. this._culture = defaultValue(options.culture, '');
  103. this._tileDiscardPolicy = options.tileDiscardPolicy;
  104. this._proxy = options.proxy;
  105. this._credit = new Credit('Bing Imagery', BingMapsImageryProvider._logoData, 'http://www.bing.com');
  106. /**
  107. * The default {@link ImageryLayer#gamma} to use for imagery layers created for this provider.
  108. * By default, this is set to 1.3 for the "aerial" and "aerial with labels" map styles and 1.0 for
  109. * all others. Changing this value after creating an {@link ImageryLayer} for this provider will have
  110. * no effect. Instead, set the layer's {@link ImageryLayer#gamma} property.
  111. *
  112. * @type {Number}
  113. * @default 1.0
  114. */
  115. this.defaultGamma = 1.0;
  116. if (this._mapStyle === BingMapsStyle.AERIAL || this._mapStyle === BingMapsStyle.AERIAL_WITH_LABELS) {
  117. this.defaultGamma = 1.3;
  118. }
  119. this._tilingScheme = new WebMercatorTilingScheme({
  120. numberOfLevelZeroTilesX : 2,
  121. numberOfLevelZeroTilesY : 2
  122. });
  123. this._tileWidth = undefined;
  124. this._tileHeight = undefined;
  125. this._maximumLevel = undefined;
  126. this._imageUrlTemplate = undefined;
  127. this._imageUrlSubdomains = undefined;
  128. this._errorEvent = new Event();
  129. this._ready = false;
  130. var metadataUrl = this._url + '/REST/v1/Imagery/Metadata/' + this._mapStyle + '?incl=ImageryProviders&key=' + this._key;
  131. var that = this;
  132. var metadataError;
  133. function metadataSuccess(data) {
  134. var resource = data.resourceSets[0].resources[0];
  135. that._tileWidth = resource.imageWidth;
  136. that._tileHeight = resource.imageHeight;
  137. that._maximumLevel = resource.zoomMax - 1;
  138. that._imageUrlSubdomains = resource.imageUrlSubdomains;
  139. that._imageUrlTemplate = resource.imageUrl.replace('{culture}', that._culture);
  140. var tileProtocol = that._tileProtocol;
  141. if (!defined(tileProtocol)) {
  142. // use the document's protocol, unless it's not http or https
  143. var documentProtocol = document.location.protocol;
  144. tileProtocol = /^http/.test(documentProtocol) ? documentProtocol : 'http:';
  145. }
  146. that._imageUrlTemplate = that._imageUrlTemplate.replace(/^http:/, tileProtocol);
  147. // Install the default tile discard policy if none has been supplied.
  148. if (!defined(that._tileDiscardPolicy)) {
  149. that._tileDiscardPolicy = new DiscardMissingTileImagePolicy({
  150. missingImageUrl : buildImageUrl(that, 0, 0, that._maximumLevel),
  151. pixelsToCheck : [new Cartesian2(0, 0), new Cartesian2(120, 140), new Cartesian2(130, 160), new Cartesian2(200, 50), new Cartesian2(200, 200)],
  152. disableCheckIfAllPixelsAreTransparent : true
  153. });
  154. }
  155. var attributionList = that._attributionList = resource.imageryProviders;
  156. if (!attributionList) {
  157. attributionList = that._attributionList = [];
  158. }
  159. for (var attributionIndex = 0, attributionLength = attributionList.length; attributionIndex < attributionLength; ++attributionIndex) {
  160. var attribution = attributionList[attributionIndex];
  161. attribution.credit = new Credit(attribution.attribution);
  162. var coverageAreas = attribution.coverageAreas;
  163. for (var areaIndex = 0, areaLength = attribution.coverageAreas.length; areaIndex < areaLength; ++areaIndex) {
  164. var area = coverageAreas[areaIndex];
  165. var bbox = area.bbox;
  166. area.bbox = new Rectangle(
  167. CesiumMath.toRadians(bbox[1]),
  168. CesiumMath.toRadians(bbox[0]),
  169. CesiumMath.toRadians(bbox[3]),
  170. CesiumMath.toRadians(bbox[2]));
  171. }
  172. }
  173. that._ready = true;
  174. TileProviderError.handleSuccess(metadataError);
  175. }
  176. function metadataFailure(e) {
  177. var message = 'An error occurred while accessing ' + metadataUrl + '.';
  178. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  179. }
  180. function requestMetadata() {
  181. var metadata = jsonp(metadataUrl, {
  182. callbackParameterName : 'jsonp',
  183. proxy : that._proxy
  184. });
  185. when(metadata, metadataSuccess, metadataFailure);
  186. }
  187. requestMetadata();
  188. };
  189. defineProperties(BingMapsImageryProvider.prototype, {
  190. /**
  191. * Gets the name of the BingMaps server url hosting the imagery.
  192. * @memberof BingMapsImageryProvider.prototype
  193. * @type {String}
  194. * @readonly
  195. */
  196. url : {
  197. get : function() {
  198. return this._url;
  199. }
  200. },
  201. /**
  202. * Gets the proxy used by this provider.
  203. * @memberof BingMapsImageryProvider.prototype
  204. * @type {Proxy}
  205. * @readonly
  206. */
  207. proxy : {
  208. get : function() {
  209. return this._proxy;
  210. }
  211. },
  212. /**
  213. * Gets the Bing Maps key.
  214. * @memberof BingMapsImageryProvider.prototype
  215. * @type {String}
  216. * @readonly
  217. */
  218. key : {
  219. get : function() {
  220. return this._key;
  221. }
  222. },
  223. /**
  224. * Gets the type of Bing Maps imagery to load.
  225. * @memberof BingMapsImageryProvider.prototype
  226. * @type {BingMapsStyle}
  227. * @readonly
  228. */
  229. mapStyle : {
  230. get : function() {
  231. return this._mapStyle;
  232. }
  233. },
  234. /**
  235. * The culture to use when requesting Bing Maps imagery. Not
  236. * all cultures are supported. See {@link http://msdn.microsoft.com/en-us/library/hh441729.aspx}
  237. * for information on the supported cultures.
  238. * @memberof BingMapsImageryProvider.prototype
  239. * @type {String}
  240. * @readonly
  241. */
  242. culture : {
  243. get : function() {
  244. return this._culture;
  245. }
  246. },
  247. /**
  248. * Gets the width of each tile, in pixels. This function should
  249. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  250. * @memberof BingMapsImageryProvider.prototype
  251. * @type {Number}
  252. * @readonly
  253. */
  254. tileWidth : {
  255. get : function() {
  256. //>>includeStart('debug', pragmas.debug);
  257. if (!this._ready) {
  258. throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.');
  259. }
  260. //>>includeEnd('debug');
  261. return this._tileWidth;
  262. }
  263. },
  264. /**
  265. * Gets the height of each tile, in pixels. This function should
  266. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  267. * @memberof BingMapsImageryProvider.prototype
  268. * @type {Number}
  269. * @readonly
  270. */
  271. tileHeight: {
  272. get : function() {
  273. //>>includeStart('debug', pragmas.debug);
  274. if (!this._ready) {
  275. throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.');
  276. }
  277. //>>includeEnd('debug');
  278. return this._tileHeight;
  279. }
  280. },
  281. /**
  282. * Gets the maximum level-of-detail that can be requested. This function should
  283. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  284. * @memberof BingMapsImageryProvider.prototype
  285. * @type {Number}
  286. * @readonly
  287. */
  288. maximumLevel : {
  289. get : function() {
  290. //>>includeStart('debug', pragmas.debug);
  291. if (!this._ready) {
  292. throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.');
  293. }
  294. //>>includeEnd('debug');
  295. return this._maximumLevel;
  296. }
  297. },
  298. /**
  299. * Gets the minimum level-of-detail that can be requested. This function should
  300. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  301. * @memberof BingMapsImageryProvider.prototype
  302. * @type {Number}
  303. * @readonly
  304. */
  305. minimumLevel : {
  306. get : function() {
  307. //>>includeStart('debug', pragmas.debug);
  308. if (!this._ready) {
  309. throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.');
  310. }
  311. //>>includeEnd('debug');
  312. return 0;
  313. }
  314. },
  315. /**
  316. * Gets the tiling scheme used by this provider. This function should
  317. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  318. * @memberof BingMapsImageryProvider.prototype
  319. * @type {TilingScheme}
  320. * @readonly
  321. */
  322. tilingScheme : {
  323. get : function() {
  324. //>>includeStart('debug', pragmas.debug);
  325. if (!this._ready) {
  326. throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.');
  327. }
  328. //>>includeEnd('debug');
  329. return this._tilingScheme;
  330. }
  331. },
  332. /**
  333. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  334. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  335. * @memberof BingMapsImageryProvider.prototype
  336. * @type {Rectangle}
  337. * @readonly
  338. */
  339. rectangle : {
  340. get : function() {
  341. //>>includeStart('debug', pragmas.debug);
  342. if (!this._ready) {
  343. throw new DeveloperError('rectangle must not be called before the imagery provider is ready.');
  344. }
  345. //>>includeEnd('debug');
  346. return this._tilingScheme.rectangle;
  347. }
  348. },
  349. /**
  350. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  351. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  352. * returns undefined, no tiles are filtered. This function should
  353. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  354. * @memberof BingMapsImageryProvider.prototype
  355. * @type {TileDiscardPolicy}
  356. * @readonly
  357. */
  358. tileDiscardPolicy : {
  359. get : function() {
  360. //>>includeStart('debug', pragmas.debug);
  361. if (!this._ready) {
  362. throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.');
  363. }
  364. //>>includeEnd('debug');
  365. return this._tileDiscardPolicy;
  366. }
  367. },
  368. /**
  369. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  370. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  371. * are passed an instance of {@link TileProviderError}.
  372. * @memberof BingMapsImageryProvider.prototype
  373. * @type {Event}
  374. * @readonly
  375. */
  376. errorEvent : {
  377. get : function() {
  378. return this._errorEvent;
  379. }
  380. },
  381. /**
  382. * Gets a value indicating whether or not the provider is ready for use.
  383. * @memberof BingMapsImageryProvider.prototype
  384. * @type {Boolean}
  385. * @readonly
  386. */
  387. ready : {
  388. get : function() {
  389. return this._ready;
  390. }
  391. },
  392. /**
  393. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  394. * the source of the imagery. This function should not be called before {@link BingMapsImageryProvider#ready} returns true.
  395. * @memberof BingMapsImageryProvider.prototype
  396. * @type {Credit}
  397. * @readonly
  398. */
  399. credit : {
  400. get : function() {
  401. return this._credit;
  402. }
  403. },
  404. /**
  405. * Gets a value indicating whether or not the images provided by this imagery provider
  406. * include an alpha channel. If this property is false, an alpha channel, if present, will
  407. * be ignored. If this property is true, any images without an alpha channel will be treated
  408. * as if their alpha is 1.0 everywhere. Setting this property to false reduces memory usage
  409. * and texture upload time.
  410. * @memberof BingMapsImageryProvider.prototype
  411. * @type {Boolean}
  412. * @readonly
  413. */
  414. hasAlphaChannel : {
  415. get : function() {
  416. return false;
  417. }
  418. }
  419. });
  420. var rectangleScratch = new Rectangle();
  421. /**
  422. * Gets the credits to be displayed when a given tile is displayed.
  423. *
  424. * @param {Number} x The tile X coordinate.
  425. * @param {Number} y The tile Y coordinate.
  426. * @param {Number} level The tile level;
  427. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  428. *
  429. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  430. */
  431. BingMapsImageryProvider.prototype.getTileCredits = function(x, y, level) {
  432. if (!this._ready) {
  433. throw new DeveloperError('getTileCredits must not be called before the imagery provider is ready.');
  434. }
  435. var rectangle = this._tilingScheme.tileXYToRectangle(x, y, level, rectangleScratch);
  436. return getRectangleAttribution(this._attributionList, level, rectangle);
  437. };
  438. /**
  439. * Requests the image for a given tile. This function should
  440. * not be called before {@link BingMapsImageryProvider#ready} returns true.
  441. *
  442. * @param {Number} x The tile X coordinate.
  443. * @param {Number} y The tile Y coordinate.
  444. * @param {Number} level The tile level.
  445. * @returns {Promise} A promise for the image that will resolve when the image is available, or
  446. * undefined if there are too many active requests to the server, and the request
  447. * should be retried later. The resolved image may be either an
  448. * Image or a Canvas DOM object.
  449. *
  450. * @exception {DeveloperError} <code>requestImage</code> must not be called before the imagery provider is ready.
  451. */
  452. BingMapsImageryProvider.prototype.requestImage = function(x, y, level) {
  453. //>>includeStart('debug', pragmas.debug);
  454. if (!this._ready) {
  455. throw new DeveloperError('requestImage must not be called before the imagery provider is ready.');
  456. }
  457. //>>includeEnd('debug');
  458. var url = buildImageUrl(this, x, y, level);
  459. return ImageryProvider.loadImage(this, url);
  460. };
  461. /**
  462. * Picking features is not currently supported by this imagery provider, so this function simply returns
  463. * undefined.
  464. *
  465. * @param {Number} x The tile X coordinate.
  466. * @param {Number} y The tile Y coordinate.
  467. * @param {Number} level The tile level.
  468. * @param {Number} longitude The longitude at which to pick features.
  469. * @param {Number} latitude The latitude at which to pick features.
  470. * @return {Promise} A promise for the picked features that will resolve when the asynchronous
  471. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  472. * instances. The array may be empty if no features are found at the given location.
  473. * It may also be undefined if picking is not supported.
  474. */
  475. BingMapsImageryProvider.prototype.pickFeatures = function() {
  476. return undefined;
  477. };
  478. BingMapsImageryProvider._logoData = 'data:image/png;base64,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';
  479. /**
  480. * Converts a tiles (x, y, level) position into a quadkey used to request an image
  481. * from a Bing Maps server.
  482. *
  483. * @param {Number} x The tile's x coordinate.
  484. * @param {Number} y The tile's y coordinate.
  485. * @param {Number} level The tile's zoom level.
  486. *
  487. * @see {@link http://msdn.microsoft.com/en-us/library/bb259689.aspx|Bing Maps Tile System}
  488. * @see BingMapsImageryProvider#quadKeyToTileXY
  489. */
  490. BingMapsImageryProvider.tileXYToQuadKey = function(x, y, level) {
  491. var quadkey = '';
  492. for ( var i = level; i >= 0; --i) {
  493. var bitmask = 1 << i;
  494. var digit = 0;
  495. if ((x & bitmask) !== 0) {
  496. digit |= 1;
  497. }
  498. if ((y & bitmask) !== 0) {
  499. digit |= 2;
  500. }
  501. quadkey += digit;
  502. }
  503. return quadkey;
  504. };
  505. /**
  506. * Converts a tile's quadkey used to request an image from a Bing Maps server into the
  507. * (x, y, level) position.
  508. *
  509. * @param {String} quadkey The tile's quad key
  510. *
  511. * @see {@link http://msdn.microsoft.com/en-us/library/bb259689.aspx|Bing Maps Tile System}
  512. * @see BingMapsImageryProvider#tileXYToQuadKey
  513. */
  514. BingMapsImageryProvider.quadKeyToTileXY = function(quadkey) {
  515. var x = 0;
  516. var y = 0;
  517. var level = quadkey.length - 1;
  518. for ( var i = level; i >= 0; --i) {
  519. var bitmask = 1 << i;
  520. var digit = +quadkey[level - i];
  521. if ((digit & 1) !== 0) {
  522. x |= bitmask;
  523. }
  524. if ((digit & 2) !== 0) {
  525. y |= bitmask;
  526. }
  527. }
  528. return {
  529. x : x,
  530. y : y,
  531. level : level
  532. };
  533. };
  534. function buildImageUrl(imageryProvider, x, y, level) {
  535. var imageUrl = imageryProvider._imageUrlTemplate;
  536. var quadkey = BingMapsImageryProvider.tileXYToQuadKey(x, y, level);
  537. imageUrl = imageUrl.replace('{quadkey}', quadkey);
  538. var subdomains = imageryProvider._imageUrlSubdomains;
  539. var subdomainIndex = (x + y + level) % subdomains.length;
  540. imageUrl = imageUrl.replace('{subdomain}', subdomains[subdomainIndex]);
  541. var proxy = imageryProvider._proxy;
  542. if (defined(proxy)) {
  543. imageUrl = proxy.getURL(imageUrl);
  544. }
  545. return imageUrl;
  546. }
  547. var intersectionScratch = new Rectangle();
  548. function getRectangleAttribution(attributionList, level, rectangle) {
  549. // Bing levels start at 1, while ours start at 0.
  550. ++level;
  551. var result = [];
  552. for (var attributionIndex = 0, attributionLength = attributionList.length; attributionIndex < attributionLength; ++attributionIndex) {
  553. var attribution = attributionList[attributionIndex];
  554. var coverageAreas = attribution.coverageAreas;
  555. var included = false;
  556. for (var areaIndex = 0, areaLength = attribution.coverageAreas.length; !included && areaIndex < areaLength; ++areaIndex) {
  557. var area = coverageAreas[areaIndex];
  558. if (level >= area.zoomMin && level <= area.zoomMax) {
  559. var intersection = Rectangle.intersection(rectangle, area.bbox, intersectionScratch);
  560. if (defined(intersection)) {
  561. included = true;
  562. }
  563. }
  564. }
  565. if (included) {
  566. result.push(attribution.credit);
  567. }
  568. }
  569. return result;
  570. }
  571. return BingMapsImageryProvider;
  572. });