diff --git a/CHANGES.md b/CHANGES.md
index 03a177007630..f63e15911dbb 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -30,6 +30,7 @@ _This is an npm-only release to fix a publishing issue_.
* `BingMapsImageryProvider` now uses `DiscardEmptyTileImagePolicy` by default to detect missing tiles as zero-length responses instead of inspecting pixel values. [#7810](https://github.com/AnalyticalGraphicsInc/cesium/pull/7810)
* Added support for the [AGI_articulations](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/AGI_articulations) vendor extension of glTF 2.0 to the Model primitive graphics API. [#7835](https://github.com/AnalyticalGraphicsInc/cesium/pull/7835)
* Reduce the number of Bing transactions and ion Bing sessions used when destroying and recreating the same imagery layer to 1. [#7848](https://github.com/AnalyticalGraphicsInc/cesium/pull/7848)
+* Added support for new Mapbox Style API. [#7698](https://github.com/AnalyticalGraphicsInc/cesium/pull/7698)
##### Fixes :wrench:
* Fixed an edge case where Cesium would provide ion access token credentials to non-ion servers if the actual asset entrypoint was being hosted by ion. [#7839](https://github.com/AnalyticalGraphicsInc/cesium/pull/7839)
diff --git a/Source/Scene/ImageryProvider.js b/Source/Scene/ImageryProvider.js
index addce4ab2f09..1a372ddc6a06 100644
--- a/Source/Scene/ImageryProvider.js
+++ b/Source/Scene/ImageryProvider.js
@@ -31,6 +31,7 @@ define([
* @see GoogleEarthEnterpriseMapsProvider
* @see GridImageryProvider
* @see MapboxImageryProvider
+ * @see MapboxStyleImageryProvider
* @see SingleTileImageryProvider
* @see TileCoordinatesImageryProvider
* @see UrlTemplateImageryProvider
diff --git a/Source/Scene/MapboxStyleImageryProvider.js b/Source/Scene/MapboxStyleImageryProvider.js
new file mode 100644
index 000000000000..753098bbf3c1
--- /dev/null
+++ b/Source/Scene/MapboxStyleImageryProvider.js
@@ -0,0 +1,371 @@
+define([
+ '../Core/Credit',
+ '../Core/defaultValue',
+ '../Core/defined',
+ '../Core/defineProperties',
+ '../Core/DeveloperError',
+ '../Core/MapboxApi',
+ '../Core/Resource',
+ './UrlTemplateImageryProvider'
+], function(
+ Credit,
+ defaultValue,
+ defined,
+ defineProperties,
+ DeveloperError,
+ MapboxApi,
+ Resource,
+ UrlTemplateImageryProvider) {
+'use strict';
+
+var trailingSlashRegex = /\/$/;
+var defaultCredit = new Credit('© Mapbox © OpenStreetMap Improve this map');
+
+/**
+ * Provides tiled imagery hosted by Mapbox.
+ *
+ * @alias MapboxStyleImageryProvider
+ * @constructor
+ *
+ * @param {Object} [options] Object with the following properties:
+ * @param {Resource|String} [options.url='https://api.mapbox.com/styles/v1/'] The Mapbox server url.
+ * @param {String} [options.username='mapbox'] The username of the map account.
+ * @param {String} options.styleId The Mapbox Style ID.
+ * @param {String} [options.accessToken] The public access token for the imagery.
+ * @param {Number} [options.tilesize=512] The size of the image tiles.
+ * @param {Boolean} [options.scaleFactor] Determines if tiles are rendered at a @2x scale factor.
+ * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
+ * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider. Take care when specifying
+ * this that the number of tiles at the minimum level is small, such as four or less. A larger number is likely
+ * to result in rendering problems.
+ * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit.
+ * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the image.
+ * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
+ *
+ *
+ * @example
+ * // Mapbox style provider
+ * var mapbox = new Cesium.MapboxStyleImageryProvider({
+ * styleId: 'streets-v11',
+ * accessToken: 'thisIsMyAccessToken'
+ * });
+ *
+ * @see {@link https://docs.mapbox.com/api/maps/#styles}
+ * @see {@link https://docs.mapbox.com/api/#access-tokens-and-token-scopes}
+ */
+function MapboxStyleImageryProvider(options) {
+ options = defaultValue(options, defaultValue.EMPTY_OBJECT);
+ var styleId = options.styleId;
+ //>>includeStart('debug', pragmas.debug);
+ if (!defined(styleId)) {
+ throw new DeveloperError('options.styleId is required.');
+ }
+ //>>includeEnd('debug');
+
+ var url = options.url;
+ if (!defined(url)) {
+ url = 'https://api.mapbox.com/styles/v1/';
+ }
+ this._url = url;
+
+ var resource = Resource.createIfNeeded(url);
+
+ var accessToken = MapboxApi.getAccessToken(options.accessToken);
+ this._styleId = styleId;
+ this._accessToken = accessToken;
+
+ this._accessTokenErrorCredit = Credit.clone(MapboxApi.getErrorCredit(options.accessToken));
+
+ var tilesize = defaultValue(options.tilesize, 512);
+ this._tilesize = tilesize;
+
+ var username = defaultValue(options.username, 'mapbox');
+ this._username = username;
+
+ var scaleFactor = defined(options.scaleFactor) ? '@2x' : '';
+
+ var templateUrl = resource.getUrlComponent();
+ if (!trailingSlashRegex.test(templateUrl)) {
+ templateUrl += '/';
+ }
+ templateUrl += this._username + '/' + styleId + '/tiles/' + this._tilesize + '/{z}/{x}/{y}' + scaleFactor;
+ resource.url = templateUrl;
+
+ resource.setQueryParameters({
+ access_token: accessToken
+ });
+
+ var credit;
+ if (defined(options.credit)) {
+ credit = options.credit;
+ if (typeof credit === 'string') {
+ credit = new Credit(credit);
+ }
+ } else {
+ credit = defaultCredit;
+ }
+
+ this._resource = resource;
+ this._imageryProvider = new UrlTemplateImageryProvider({
+ url: resource,
+ credit: credit,
+ ellipsoid: options.ellipsoid,
+ minimumLevel: options.minimumLevel,
+ maximumLevel: options.maximumLevel,
+ rectangle: options.rectangle
+ });
+}
+
+defineProperties(MapboxStyleImageryProvider.prototype, {
+ /**
+ * Gets the URL of the Mapbox server.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {String}
+ * @readonly
+ */
+ url : {
+ get : function() {
+ return this._url;
+ }
+ },
+
+ /**
+ * Gets a value indicating whether or not the provider is ready for use.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Boolean}
+ * @readonly
+ */
+ ready : {
+ get : function() {
+ return this._imageryProvider.ready;
+ }
+ },
+
+ /**
+ * Gets a promise that resolves to true when the provider is ready for use.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Promise.}
+ * @readonly
+ */
+ readyPromise : {
+ get : function() {
+ return this._imageryProvider.readyPromise;
+ }
+ },
+
+ /**
+ * Gets the rectangle, in radians, of the imagery provided by the instance. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Rectangle}
+ * @readonly
+ */
+ rectangle: {
+ get : function() {
+ return this._imageryProvider.rectangle;
+ }
+ },
+
+ /**
+ * Gets the width of each tile, in pixels. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Number}
+ * @readonly
+ */
+ tileWidth : {
+ get : function() {
+ return this._imageryProvider.tileWidth;
+ }
+ },
+
+ /**
+ * Gets the height of each tile, in pixels. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Number}
+ * @readonly
+ */
+ tileHeight : {
+ get : function() {
+ return this._imageryProvider.tileHeight;
+ }
+ },
+
+ /**
+ * Gets the maximum level-of-detail that can be requested. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Number}
+ * @readonly
+ */
+ maximumLevel : {
+ get : function() {
+ return this._imageryProvider.maximumLevel;
+ }
+ },
+
+ /**
+ * Gets the minimum level-of-detail that can be requested. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true. Generally,
+ * a minimum level should only be used when the rectangle of the imagery is small
+ * enough that the number of tiles at the minimum level is small. An imagery
+ * provider with more than a few tiles at the minimum level will lead to
+ * rendering problems.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Number}
+ * @readonly
+ */
+ minimumLevel : {
+ get : function() {
+ return this._imageryProvider.minimumLevel;
+ }
+ },
+
+ /**
+ * Gets the tiling scheme used by the provider. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {TilingScheme}
+ * @readonly
+ */
+ tilingScheme : {
+ get : function() {
+ return this._imageryProvider.tilingScheme;
+ }
+ },
+
+ /**
+ * Gets the tile discard policy. If not undefined, the discard policy is responsible
+ * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
+ * returns undefined, no tiles are filtered. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {TileDiscardPolicy}
+ * @readonly
+ */
+ tileDiscardPolicy : {
+ get : function() {
+ return this._imageryProvider.tileDiscardPolicy;
+ }
+ },
+
+ /**
+ * Gets an event that is raised when the imagery provider encounters an asynchronous error.. By subscribing
+ * to the event, you will be notified of the error and can potentially recover from it. Event listeners
+ * are passed an instance of {@link TileProviderError}.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Event}
+ * @readonly
+ */
+ errorEvent : {
+ get : function() {
+ return this._imageryProvider.errorEvent;
+ }
+ },
+
+ /**
+ * Gets the credit to display when this imagery provider is active. Typically this is used to credit
+ * the source of the imagery. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Credit}
+ * @readonly
+ */
+ credit : {
+ get : function() {
+ return this._imageryProvider.credit;
+ }
+ },
+
+ /**
+ * Gets the proxy used by this provider.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Proxy}
+ * @readonly
+ */
+ proxy : {
+ get : function() {
+ return this._imageryProvider.proxy;
+ }
+ },
+
+ /**
+ * Gets a value indicating whether or not the images provided by this imagery provider
+ * include an alpha channel. If this property is false, an alpha channel, if present, will
+ * be ignored. If this property is true, any images without an alpha channel will be treated
+ * as if their alpha is 1.0 everywhere. When this property is false, memory usage
+ * and texture upload time are reduced.
+ * @memberof MapboxStyleImageryProvider.prototype
+ * @type {Boolean}
+ * @readonly
+ */
+ hasAlphaChannel : {
+ get : function() {
+ return this._imageryProvider.hasAlphaChannel;
+ }
+ }
+});
+
+/**
+ * Gets the credits to be displayed when a given tile is displayed.
+ *
+ * @param {Number} x The tile X coordinate.
+ * @param {Number} y The tile Y coordinate.
+ * @param {Number} level The tile level;
+ * @returns {Credit[]} The credits to be displayed when the tile is displayed.
+ *
+ * @exception {DeveloperError} getTileCredits
must not be called before the imagery provider is ready.
+ */
+MapboxStyleImageryProvider.prototype.getTileCredits = function(x, y, level) {
+ if (defined(this._accessTokenErrorCredit)) {
+ return [this._accessTokenErrorCredit];
+ }
+};
+
+/**
+ * Requests the image for a given tile. This function should
+ * not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ *
+ * @param {Number} x The tile X coordinate.
+ * @param {Number} y The tile Y coordinate.
+ * @param {Number} level The tile level.
+ * @param {Request} [request] The request object. Intended for internal use only.
+ * @returns {Promise.|undefined} A promise for the image that will resolve when the image is available, or
+ * undefined if there are too many active requests to the server, and the request
+ * should be retried later. The resolved image may be either an
+ * Image or a Canvas DOM object.
+ *
+ * @exception {DeveloperError} requestImage
must not be called before the imagery provider is ready.
+ */
+MapboxStyleImageryProvider.prototype.requestImage = function(x, y, level, request) {
+ return this._imageryProvider.requestImage(x, y, level, request);
+};
+
+/**
+ * Asynchronously determines what features, if any, are located at a given longitude and latitude within
+ * a tile. This function should not be called before {@link MapboxStyleImageryProvider#ready} returns true.
+ * This function is optional, so it may not exist on all ImageryProviders.
+ *
+ *
+ * @param {Number} x The tile X coordinate.
+ * @param {Number} y The tile Y coordinate.
+ * @param {Number} level The tile level.
+ * @param {Number} longitude The longitude at which to pick features.
+ * @param {Number} latitude The latitude at which to pick features.
+ * @return {Promise.|undefined} A promise for the picked features that will resolve when the asynchronous
+ * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
+ * instances. The array may be empty if no features are found at the given location.
+ * It may also be undefined if picking is not supported.
+ *
+ * @exception {DeveloperError} pickFeatures
must not be called before the imagery provider is ready.
+ */
+MapboxStyleImageryProvider.prototype.pickFeatures = function(x, y, level, longitude, latitude) {
+ return this._imageryProvider.pickFeatures(x, y, level, longitude, latitude);
+};
+
+// Exposed for tests
+MapboxStyleImageryProvider._defaultCredit = defaultCredit;
+
+return MapboxStyleImageryProvider;
+});
diff --git a/Source/Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels.js b/Source/Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels.js
index ff82277b7ce7..25992e7f4260 100644
--- a/Source/Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels.js
+++ b/Source/Widgets/BaseLayerPicker/createDefaultImageryProviderViewModels.js
@@ -6,7 +6,7 @@ define([
'../../Scene/createTileMapServiceImageryProvider',
'../../Scene/createWorldImagery',
'../../Scene/IonImageryProvider',
- '../../Scene/MapboxImageryProvider',
+ '../../Scene/MapboxStyleImageryProvider',
'../BaseLayerPicker/ProviderViewModel'
], function(
buildModuleUrl,
@@ -16,7 +16,7 @@ define([
createTileMapServiceImageryProvider,
createWorldImagery,
IonImageryProvider,
- MapboxImageryProvider,
+ MapboxStyleImageryProvider,
ProviderViewModel) {
'use strict';
@@ -67,8 +67,8 @@ define([
iconUrl: buildModuleUrl('Widgets/Images/ImageryProviders/mapboxSatellite.png'),
category : 'Other',
creationFunction: function() {
- return new MapboxImageryProvider({
- mapId: 'mapbox.satellite'
+ return new MapboxStyleImageryProvider({
+ styleId: 'satellite-v9'
});
}
}));
@@ -79,8 +79,8 @@ define([
iconUrl: buildModuleUrl('Widgets/Images/ImageryProviders/mapboxTerrain.png'),
category : 'Other',
creationFunction: function() {
- return new MapboxImageryProvider({
- mapId: 'mapbox.streets'
+ return new MapboxStyleImageryProvider({
+ styleId: 'satellite-streets-v11'
});
}
}));
@@ -91,8 +91,8 @@ define([
iconUrl: buildModuleUrl('Widgets/Images/ImageryProviders/mapboxStreets.png'),
category : 'Other',
creationFunction: function() {
- return new MapboxImageryProvider({
- mapId: 'mapbox.streets-basic'
+ return new MapboxStyleImageryProvider({
+ styleId: 'streets-v11'
});
}
}));
diff --git a/Specs/Scene/MapboxStyleImageryProviderSpec.js b/Specs/Scene/MapboxStyleImageryProviderSpec.js
new file mode 100644
index 000000000000..347c25a804a4
--- /dev/null
+++ b/Specs/Scene/MapboxStyleImageryProviderSpec.js
@@ -0,0 +1,358 @@
+defineSuite([
+ 'Scene/MapboxStyleImageryProvider',
+ 'Core/Math',
+ 'Core/Rectangle',
+ 'Core/RequestScheduler',
+ 'Core/Resource',
+ 'Core/WebMercatorTilingScheme',
+ 'Scene/Imagery',
+ 'Scene/ImageryLayer',
+ 'Scene/ImageryProvider',
+ 'Scene/ImageryState',
+ 'Specs/pollToPromise'
+ ], function(
+ MapboxStyleImageryProvider,
+ CesiumMath,
+ Rectangle,
+ RequestScheduler,
+ Resource,
+ WebMercatorTilingScheme,
+ Imagery,
+ ImageryLayer,
+ ImageryProvider,
+ ImageryState,
+ pollToPromise) {
+ 'use strict';
+
+ beforeEach(function() {
+ RequestScheduler.clearForSpecs();
+ });
+
+ afterEach(function() {
+ Resource._Implementations.createImage = Resource._DefaultImplementations.createImage;
+ });
+
+ it('conforms to ImageryProvider interface', function() {
+ expect(MapboxStyleImageryProvider).toConformToInterface(ImageryProvider);
+ });
+
+ it('requires the styleId to be specified', function() {
+ expect(function() {
+ return new MapboxStyleImageryProvider({});
+ }).toThrowDeveloperError('styleId is required');
+ });
+
+ it('resolves readyPromise', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id'
+ });
+
+ return provider.readyPromise.then(function (result) {
+ expect(result).toBe(true);
+ expect(provider.ready).toBe(true);
+ });
+ });
+
+ it('resolves readyPromise with Resource', function() {
+ var resource = new Resource({
+ url : 'made/up/mapbox/server/'
+ });
+
+ var provider = new MapboxStyleImageryProvider({
+ url : resource,
+ styleId: 'test-id'
+ });
+
+ return provider.readyPromise.then(function (result) {
+ expect(result).toBe(true);
+ expect(provider.ready).toBe(true);
+ });
+ });
+
+ it('returns valid value for hasAlphaChannel', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id'
+ });
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ expect(typeof provider.hasAlphaChannel).toBe('boolean');
+ });
+ });
+
+ it('supports a slash at the end of the URL', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id'
+ });
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) {
+ expect(url).not.toContain('//');
+
+ // Just return any old image.
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ });
+
+ return provider.requestImage(0, 0, 0).then(function(image) {
+ expect(Resource._Implementations.createImage).toHaveBeenCalled();
+ expect(image).toBeImageOrImageBitmap();
+ });
+ });
+ });
+
+ it('supports no slash at the endof the URL', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server',
+ styleId: 'test-id'
+ });
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) {
+ expect(url).toContain('made/up/mapbox/server/');
+
+ // Just return any old image.
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ });
+
+ return provider.requestImage(0, 0, 0).then(function(image) {
+ expect(Resource._Implementations.createImage).toHaveBeenCalled();
+ expect(image).toBeImageOrImageBitmap();
+ });
+ });
+ });
+
+ it('requestImage returns a promise for an image and loads it for cross-origin use', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id'
+ });
+
+ expect(provider.url).toEqual('made/up/mapbox/server/');
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ expect(provider.tileWidth).toEqual(256);
+ expect(provider.tileHeight).toEqual(256);
+ expect(provider.maximumLevel).toBeUndefined();
+ expect(provider.tilingScheme).toBeInstanceOf(WebMercatorTilingScheme);
+ expect(provider.rectangle).toEqual(new WebMercatorTilingScheme().rectangle);
+
+ spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) {
+ // Just return any old image.
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ });
+
+ return provider.requestImage(0, 0, 0).then(function(image) {
+ expect(Resource._Implementations.createImage).toHaveBeenCalled();
+ expect(image).toBeImageOrImageBitmap();
+ });
+ });
+ });
+
+ it('rectangle passed to constructor does not affect tile numbering', function() {
+ var rectangle = new Rectangle(0.1, 0.2, 0.3, 0.4);
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id',
+ rectangle : rectangle
+ });
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ expect(provider.tileWidth).toEqual(256);
+ expect(provider.tileHeight).toEqual(256);
+ expect(provider.maximumLevel).toBeUndefined();
+ expect(provider.tilingScheme).toBeInstanceOf(WebMercatorTilingScheme);
+ expect(provider.rectangle).toEqualEpsilon(rectangle, CesiumMath.EPSILON14);
+ expect(provider.tileDiscardPolicy).toBeUndefined();
+
+ spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) {
+ expect(url).toContain('/0/0/0');
+
+ // Just return any old image.
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ });
+
+ return provider.requestImage(0, 0, 0).then(function(image) {
+ expect(Resource._Implementations.createImage).toHaveBeenCalled();
+ expect(image).toBeImageOrImageBitmap();
+ });
+ });
+ });
+
+ it('uses maximumLevel passed to constructor', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id',
+ maximumLevel : 5
+ });
+ expect(provider.maximumLevel).toEqual(5);
+ });
+
+ it('uses minimumLevel passed to constructor', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id',
+ minimumLevel : 1
+ });
+ expect(provider.minimumLevel).toEqual(1);
+ });
+
+ it('when no credit is supplied, the provider adds a default credit', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id'
+ });
+ expect(provider.credit).toBe(MapboxStyleImageryProvider._defaultCredit);
+ });
+
+ it('turns the supplied credit into a logo', function() {
+ var creditText = 'Thanks to our awesome made up source of this imagery!';
+ var providerWithCredit = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id',
+ credit: creditText
+ });
+ expect(providerWithCredit.credit.html).toEqual(creditText);
+ });
+
+ it('raises error event when image cannot be loaded', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url : 'made/up/mapbox/server/',
+ styleId: 'test-id'
+ });
+
+ var layer = new ImageryLayer(provider);
+
+ var tries = 0;
+ provider.errorEvent.addEventListener(function(error) {
+ expect(error.timesRetried).toEqual(tries);
+ ++tries;
+ if (tries < 3) {
+ error.retry = true;
+ }
+ setTimeout(function() {
+ RequestScheduler.update();
+ }, 1);
+ });
+
+ Resource._Implementations.createImage = function(url, crossOrigin, deferred) {
+ if (tries === 2) {
+ // Succeed after 2 tries
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ } else {
+ // fail
+ setTimeout(function() {
+ deferred.reject();
+ }, 1);
+ }
+ };
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ var imagery = new Imagery(layer, 0, 0, 0);
+ imagery.addReference();
+ layer._requestImagery(imagery);
+ RequestScheduler.update();
+
+ return pollToPromise(function() {
+ return imagery.state === ImageryState.RECEIVED;
+ }).then(function() {
+ expect(imagery.image).toBeImageOrImageBitmap();
+ expect(tries).toEqual(2);
+ imagery.releaseReference();
+ });
+ });
+ });
+
+ it('contains specified url', function() {
+ var provider = new MapboxStyleImageryProvider({
+ url: 'http://fake.map.com',
+ styleId: 'test-id'
+ });
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) {
+ expect(url).toContain('http://fake.map.com');
+
+ // Just return any old image.
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ });
+
+ return provider.requestImage(0, 0, 0);
+ });
+ });
+
+ it('contains specified username', function() {
+ var provider = new MapboxStyleImageryProvider({
+ styleId: 'test-id',
+ username: 'fakeUsername'
+ });
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) {
+ expect(url).toContain('https://api.mapbox.com/styles/v1/fakeUsername');
+
+ // Just return any old image.
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ });
+
+ return provider.requestImage(0, 0, 0);
+ });
+ });
+
+ it('contains specified tilesize', function() {
+ var provider = new MapboxStyleImageryProvider({
+ styleId: 'test-id',
+ tilesize: 256
+ });
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) {
+ expect(url).toContain('https://api.mapbox.com/styles/v1/mapbox/test-id/tiles/256');
+
+ // Just return any old image.
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ });
+
+ return provider.requestImage(0, 0, 0);
+ });
+ });
+
+ it('enables @2x scale factor', function() {
+ var provider = new MapboxStyleImageryProvider({
+ styleId: 'test-id',
+ scaleFactor: true
+ });
+
+ return pollToPromise(function() {
+ return provider.ready;
+ }).then(function() {
+ spyOn(Resource._Implementations, 'createImage').and.callFake(function(url, crossOrigin, deferred) {
+ expect(url).toContain('https://api.mapbox.com/styles/v1/mapbox/test-id/tiles/512/0/0/0@2x');
+
+ // Just return any old image.
+ Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred);
+ });
+
+ return provider.requestImage(0, 0, 0);
+ });
+ });
+});