diff --git a/CHANGES.md b/CHANGES.md index 2ef016f2c36f..2f169c15f5ab 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,11 @@ Change Log ========== +### 1.51 - 2018-11-01 + +##### Additions :tada: +* Added WMS-T (time) support in WebMapServiceImageryProvider [#2581](https://github.com/AnalyticalGraphicsInc/cesium/issues/2581) + ### 1.50 - 2018-10-01 ##### Breaking Changes :mega: diff --git a/Source/Scene/WebMapServiceImageryProvider.js b/Source/Scene/WebMapServiceImageryProvider.js index 25c6a7f3b594..2320f842e861 100644 --- a/Source/Scene/WebMapServiceImageryProvider.js +++ b/Source/Scene/WebMapServiceImageryProvider.js @@ -8,6 +8,7 @@ define([ '../Core/Resource', '../Core/WebMercatorProjection', './GetFeatureInfoFormat', + './TimeDynamicImagery', './UrlTemplateImageryProvider' ], function( defaultValue, @@ -19,6 +20,7 @@ define([ Resource, WebMercatorProjection, GetFeatureInfoFormat, + TimeDynamicImagery, UrlTemplateImageryProvider) { 'use strict'; @@ -59,6 +61,8 @@ define([ * @param {String|String[]} [options.subdomains='abc'] The subdomains to use for the {s} placeholder in the URL template. * If this parameter is a single string, each character in the string is a subdomain. If it is * an array, each element in the array is a subdomain. + * @param {Clock} [options.clock] A Clock instance that is used when determining the value for the time dimension. Required when options.times is specified. + * @param {TimeIntervalCollection} [options.times] TimeIntervalCollection with its data property being an object containing time dynamic dimension and their values. * * @see ArcGisMapServerImageryProvider * @see BingMapsImageryProvider @@ -93,7 +97,12 @@ define([ } //>>includeEnd('debug'); + if (defined(options.times) && !defined(options.clock)) { + throw new DeveloperError('options.times was specified, so options.clock is required.'); + } + var resource = Resource.createIfNeeded(options.url); + var pickFeatureResource = resource.clone(); resource.setQueryParameters(WebMapServiceImageryProvider.DefaultParameters, true); @@ -107,6 +116,23 @@ define([ pickFeatureResource.setQueryParameters(objectToLowercase(options.getFeatureInfoParameters)); } + var that = this; + this._reload = undefined; + if (defined(options.times)) { + this._timeDynamicImagery = new TimeDynamicImagery({ + clock : options.clock, + times : options.times, + requestImageFunction : function(x, y, level, request, interval) { + return requestImage(that, x, y, level, request, interval); + }, + reloadFunction : function() { + if (defined(that._reload)) { + that._reload(); + } + } + }); + } + var parameters = {}; parameters.layers = options.layers; parameters.bbox = '{westProjected},{southProjected},{eastProjected},{northProjected}'; @@ -157,6 +183,28 @@ define([ }); } + function requestImage(imageryProvider, col, row, level, request, interval) { + var dynamicIntervalData = defined(interval) ? interval.data : undefined; + var tileProvider = imageryProvider._tileProvider; + + if (defined(dynamicIntervalData)) { + // We set the query parameters within the tile provider, because it is managing the query. + tileProvider._resource.setQueryParameters(dynamicIntervalData); + } + return tileProvider.requestImage(col, row, level, request); + } + + function pickFeatures(imageryProvider, x, y, level, longitude, latitude, interval) { + var dynamicIntervalData = defined(interval) ? interval.data : undefined; + var tileProvider = imageryProvider._tileProvider; + + if (defined(dynamicIntervalData)) { + // We set the query parameters within the tile provider, because it is managing the query. + tileProvider._pickFeaturesResource.setQueryParameters(dynamicIntervalData); + } + return tileProvider.pickFeatures(x, y, level, longitude, latitude); + } + defineProperties(WebMapServiceImageryProvider.prototype, { /** * Gets the URL of the WMS server. @@ -371,6 +419,35 @@ define([ set : function(enablePickFeatures) { this._tileProvider.enablePickFeatures = enablePickFeatures; } + }, + + /** + * Gets or sets a clock that is used to get keep the time used for time dynamic parameters. + * @memberof WebMapServiceImageryProvider.prototype + * @type {Clock} + */ + clock : { + get : function() { + return this._timeDynamicImagery.clock; + }, + set : function(value) { + this._timeDynamicImagery.clock = value; + } + }, + /** + * Gets or sets a time interval collection that is used to get time dynamic parameters. The data of each + * TimeInterval is an object containing the keys and values of the properties that are used during + * tile requests. + * @memberof WebMapServiceImageryProvider.prototype + * @type {TimeIntervalCollection} + */ + times : { + get : function() { + return this._timeDynamicImagery.times; + }, + set : function(value) { + this._timeDynamicImagery.times = value; + } } }); @@ -404,7 +481,28 @@ define([ * @exception {DeveloperError} requestImage must not be called before the imagery provider is ready. */ WebMapServiceImageryProvider.prototype.requestImage = function(x, y, level, request) { - return this._tileProvider.requestImage(x, y, level, request); + var result; + var timeDynamicImagery = this._timeDynamicImagery; + var currentInterval; + + // Try and load from cache + if (defined(timeDynamicImagery)) { + currentInterval = timeDynamicImagery.currentInterval; + result = timeDynamicImagery.getFromCache(x, y, level, request); + } + + // Couldn't load from cache + if (!defined(result)) { + result = requestImage(this, x, y, level, request, currentInterval); + } + + // If we are approaching an interval, preload this tile in the next interval + if (defined(result) && defined(timeDynamicImagery)) { + timeDynamicImagery.checkApproachingInterval(x, y, level, request); + } + + return result; + }; /** @@ -423,7 +521,10 @@ define([ * @exception {DeveloperError} pickFeatures must not be called before the imagery provider is ready. */ WebMapServiceImageryProvider.prototype.pickFeatures = function(x, y, level, longitude, latitude) { - return this._tileProvider.pickFeatures(x, y, level, longitude, latitude); + var timeDynamicImagery = this._timeDynamicImagery; + var currentInterval = defined(timeDynamicImagery) ? timeDynamicImagery.currentInterval : undefined; + + return pickFeatures(this, x, y, level, longitude, latitude, currentInterval); }; /** diff --git a/Specs/Scene/WebMapServiceImageryProviderSpec.js b/Specs/Scene/WebMapServiceImageryProviderSpec.js index f19f42223655..887388d89fa2 100644 --- a/Specs/Scene/WebMapServiceImageryProviderSpec.js +++ b/Specs/Scene/WebMapServiceImageryProviderSpec.js @@ -1,14 +1,20 @@ defineSuite([ 'Scene/WebMapServiceImageryProvider', 'Core/Cartographic', + 'Core/Clock', + 'Core/ClockStep', 'Core/DefaultProxy', 'Core/Ellipsoid', 'Core/GeographicTilingScheme', + 'Core/JulianDate', 'Core/Math', 'Core/queryToObject', 'Core/Rectangle', + 'Core/Request', 'Core/RequestScheduler', + 'Core/RequestState', 'Core/Resource', + 'Core/TimeIntervalCollection', 'Core/WebMercatorTilingScheme', 'Scene/GetFeatureInfoFormat', 'Scene/Imagery', @@ -21,14 +27,20 @@ defineSuite([ ], function( WebMapServiceImageryProvider, Cartographic, + Clock, + ClockStep, DefaultProxy, Ellipsoid, GeographicTilingScheme, + JulianDate, CesiumMath, queryToObject, Rectangle, + Request, RequestScheduler, + RequestState, Resource, + TimeIntervalCollection, WebMercatorTilingScheme, GetFeatureInfoFormat, Imagery, @@ -818,21 +830,21 @@ defineSuite([ }); describe('pickFeatures', function() { - it('works with GeoJSON responses', function() { + it('works with GeoJSON responses', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer' + url: 'made/up/wms/server', + layers: 'someLayer' }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-GeoJSON.json', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult.length).toBe(1); var firstResult = pickResult[0]; @@ -844,21 +856,21 @@ defineSuite([ }); }); - it('works with MapInfo MXP responses', function() { + it('works with MapInfo MXP responses', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer' + url: 'made/up/wms/server', + layers: 'someLayer' }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-MapInfoMXP.xml', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult.length).toBe(1); var firstResult = pickResult[0]; @@ -869,21 +881,21 @@ defineSuite([ }); }); - it('works with Esri WMS responses', function() { + it('works with Esri WMS responses', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer' + url: 'made/up/wms/server', + layers: 'someLayer' }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-Esri.xml', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult.length).toBe(1); var firstResult = pickResult[0]; @@ -894,21 +906,21 @@ defineSuite([ }); }); - it('works with THREDDS XML format', function() { + it('works with THREDDS XML format', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer' + url: 'made/up/wms/server', + layers: 'someLayer' }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-THREDDS.xml', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult.length).toBe(1); var firstResult = pickResult[0]; @@ -919,21 +931,21 @@ defineSuite([ }); }); - it('works with msGMLOutput format', function() { + it('works with msGMLOutput format', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer' + url: 'made/up/wms/server', + layers: 'someLayer' }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-msGMLOutput.xml', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult.length).toBe(1); var firstResult = pickResult[0]; @@ -944,21 +956,21 @@ defineSuite([ }); }); - it('works with unknown XML responses', function() { + it('works with unknown XML responses', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer' + url: 'made/up/wms/server', + layers: 'someLayer' }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-Unknown.xml', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult.length).toBe(1); var firstResult = pickResult[0]; @@ -969,109 +981,109 @@ defineSuite([ }); }); - it('resolves to undefined on a ServiceException', function() { + it('resolves to undefined on a ServiceException', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer' + url: 'made/up/wms/server', + layers: 'someLayer' }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-ServiceException.xml', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult).toBeUndefined(); }); }); }); - it('returns undefined if list of feature info formats is empty', function() { + it('returns undefined if list of feature info formats is empty', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer', - getFeatureInfoFormats : [] + url: 'made/up/wms/server', + layers: 'someLayer', + getFeatureInfoFormats: [] }); - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { + }).then(function () { expect(provider.pickFeatures(0, 0, 0, 0.5, 0.5)).toBeUndefined(); }); }); - it('returns undefined if enablePickFeatures is false', function() { + it('returns undefined if enablePickFeatures is false', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer', - enablePickFeatures : false + url: 'made/up/wms/server', + layers: 'someLayer', + enablePickFeatures: false }); expect(provider.enablePickFeatures).toBe(false); - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { + }).then(function () { expect(provider.pickFeatures(0, 0, 0, 0.5, 0.5)).toBeUndefined(); }); }); - it('returns undefined if enablePickFeatures is set to false after initialization', function() { + it('returns undefined if enablePickFeatures is set to false after initialization', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer', - enablePickFeatures : true + url: 'made/up/wms/server', + layers: 'someLayer', + enablePickFeatures: true }); provider.enablePickFeatures = false; expect(provider.enablePickFeatures).toBe(false); - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { + }).then(function () { expect(provider.pickFeatures(0, 0, 0, 0.5, 0.5)).toBeUndefined(); }); }); - it('does not return undefined if enablePickFeatures is set to true after initialization as false', function() { + it('does not return undefined if enablePickFeatures is set to true after initialization as false', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer', - enablePickFeatures : false + url: 'made/up/wms/server', + layers: 'someLayer', + enablePickFeatures: false }); provider.enablePickFeatures = true; expect(provider.enablePickFeatures).toBe(true); - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { + }).then(function () { expect(provider.pickFeatures(0, 0, 0, 0.5, 0.5)).not.toBeUndefined(); }); }); - it('requests XML exclusively if specified in getFeatureInfoFormats', function() { + it('requests XML exclusively if specified in getFeatureInfoFormats', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer', - getFeatureInfoFormats : [ + url: 'made/up/wms/server', + layers: 'someLayer', + getFeatureInfoFormats: [ new GetFeatureInfoFormat('xml') ] }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); expect(url).not.toContain('json'); Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-MapInfoMXP.xml', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult.length).toBe(1); var firstResult = pickResult[0]; @@ -1082,19 +1094,19 @@ defineSuite([ }); }); - it('requests GeoJSON exclusively if specified in getFeatureInfoFormats', function() { + it('requests GeoJSON exclusively if specified in getFeatureInfoFormats', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer', - getFeatureInfoFormats : [ + url: 'made/up/wms/server', + layers: 'someLayer', + getFeatureInfoFormats: [ new GetFeatureInfoFormat('json') ] }); - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + }).then(function () { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); if (url.indexOf('json') >= 0) { @@ -1105,14 +1117,14 @@ defineSuite([ } }; - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(features) { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (features) { expect(features.length).toBe(0); - }).otherwise(function() { + }).otherwise(function () { }); }); }); - it('uses custom GetFeatureInfo handling function if specified', function() { + it('uses custom GetFeatureInfo handling function if specified', function () { function fooProcessor(response) { var json = JSON.parse(response); expect(json.custom).toBe(true); @@ -1122,17 +1134,17 @@ defineSuite([ } var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer', - getFeatureInfoFormats : [ + url: 'made/up/wms/server', + layers: 'someLayer', + getFeatureInfoFormats: [ new GetFeatureInfoFormat('foo', 'application/foo', fooProcessor) ] }); - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + }).then(function () { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); if (url.indexOf(encodeURIComponent('application/foo')) < 0) { @@ -1142,20 +1154,20 @@ defineSuite([ return Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo-Custom.json', responseType, method, data, headers, deferred, overrideMimeType); }; - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(features) { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (features) { expect(features.length).toBe(1); expect(features[0].name).toEqual('Foo processed!'); }); }); }); - it('works with HTML response', function() { + it('works with HTML response', function () { var provider = new WebMapServiceImageryProvider({ - url : 'made/up/wms/server', - layers : 'someLayer' + url: 'made/up/wms/server', + layers: 'someLayer' }); - Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { + Resource._Implementations.loadWithXhr = function (url, responseType, method, data, headers, deferred, overrideMimeType) { expect(url).toContain('GetFeatureInfo'); if (url.indexOf(encodeURIComponent('text/html')) < 0) { deferred.reject(); @@ -1163,10 +1175,10 @@ defineSuite([ Resource._DefaultImplementations.loadWithXhr('Data/WMS/GetFeatureInfo.html', responseType, method, data, headers, deferred, overrideMimeType); }; - return pollToPromise(function() { + return pollToPromise(function () { return provider.ready; - }).then(function() { - return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function(pickResult) { + }).then(function () { + return provider.pickFeatures(0, 0, 0, 0.5, 0.5).then(function (pickResult) { expect(pickResult.length).toBe(1); var firstResult = pickResult[0]; @@ -1177,4 +1189,224 @@ defineSuite([ }); }); }); + + describe('verifyClockTimes', function() { + it('requires clock if times is specified', function() { + function createWithoutClock() { + return new WebMapServiceImageryProvider({ + layers : 'someLayer', + url : 'http://wms.invalid/', + times : new TimeIntervalCollection() + }); + } + + expect(createWithoutClock).toThrowDeveloperError(); + }); + + it('tiles preload on requestImage as we approach the next time interval', function() { + var times = TimeIntervalCollection.fromIso8601({ + iso8601: '2017-04-26/2017-04-30/P1D', + dataCallback: function(interval, index) { + return { + Time: JulianDate.toIso8601(interval.start) + }; + } + }); + var clock = new Clock({ + currentTime : JulianDate.fromIso8601('2017-04-26'), + shouldAnimate : true + }); + + var provider = new WebMapServiceImageryProvider({ + layers : 'someLayer', + style : 'someStyle', + url : 'http://wms.invalid/', + clock : clock, + times : times + }); + + Resource._Implementations.createImage = function(url, crossOrigin, deferred) { + Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred); + }; + + var entry; + return pollToPromise(function() { + return provider.ready; + }) + .then(function() { + clock.currentTime = JulianDate.fromIso8601('2017-04-26T23:59:56Z'); + return provider.requestImage(0, 0, 0, new Request()); + }) + .then(function() { + RequestScheduler.update(); + + // Test tile 0,0,0 was prefetched + var cache = provider._timeDynamicImagery._tileCache; + expect(cache['1']).toBeDefined(); + entry = cache['1']['0-0-0']; + expect(entry).toBeDefined(); + expect(entry.promise).toBeDefined(); + return entry.promise; + }) + .then(function() { + expect(entry.request).toBeDefined(); + expect(entry.request.state).toEqual(RequestState.RECEIVED); + }); + }); + + it('tiles preload onTick event as we approach the next time interval', function() { + var times = TimeIntervalCollection.fromIso8601({ + iso8601: '2017-04-26/2017-04-30/P1D', + dataCallback: function(interval, index) { + return { + Time: JulianDate.toIso8601(interval.start) + }; + } + }); + var clock = new Clock({ + currentTime : JulianDate.fromIso8601('2017-04-26'), + shouldAnimate : true + }); + + var provider = new WebMapServiceImageryProvider({ + layers : 'someLayer', + style : 'someStyle', + url : 'http://wms.invalid/', + clock : clock, + times : times + }); + + Resource._Implementations.createImage = function(url, crossOrigin, deferred) { + Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred); + }; + + var entry; + return pollToPromise(function() { + return provider.ready; + }) + .then(function() { + return provider.requestImage(0, 0, 0, new Request()); + }) + .then(function() { + // Test tile 0,0,0 wasn't prefetched + var cache = provider._timeDynamicImagery._tileCache; + expect(cache['1']).toBeUndefined(); + + // Update the clock and process any requests + clock.currentTime = JulianDate.fromIso8601('2017-04-26T23:59:55Z'); + clock.tick(); + RequestScheduler.update(); + + // Test tile 0,0,0 was prefetched + expect(cache['1']).toBeDefined(); + entry = cache['1']['0-0-0']; + expect(entry).toBeDefined(); + expect(entry.promise).toBeDefined(); + return entry.promise; + }) + .then(function() { + expect(entry.request).toBeDefined(); + expect(entry.request.state).toEqual(RequestState.RECEIVED); + }); + }); + + it('reload is called once we cross into next interval', function() { + var times = TimeIntervalCollection.fromIso8601({ + iso8601: '2017-04-26/2017-04-30/P1D', + dataCallback: function(interval, index) { + return { + Time: JulianDate.toIso8601(interval.start) + }; + } + }); + var clock = new Clock({ + currentTime : JulianDate.fromIso8601('2017-04-26'), + clockStep : ClockStep.TICK_DEPENDENT, + shouldAnimate : true + }); + + Resource._Implementations.createImage = function(url, crossOrigin, deferred) { + Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred); + }; + + var provider = new WebMapServiceImageryProvider({ + layers : 'someLayer', + style : 'someStyle', + url : 'http://wms.invalid/', + clock : clock, + times : times + }); + + provider._reload = jasmine.createSpy(); + spyOn(provider._timeDynamicImagery, 'getFromCache').and.callThrough(); + + return pollToPromise(function() { + return provider.ready; + }) + .then(function() { + clock.currentTime = JulianDate.fromIso8601('2017-04-26T23:59:59Z'); + return provider.requestImage(0, 0, 0, new Request()); + }) + .then(function() { + RequestScheduler.update(); + clock.tick(); + + return provider.requestImage(0, 0, 0, new Request()); + }) + .then(function() { + expect(provider._reload.calls.count()).toEqual(1); + + var calls = provider._timeDynamicImagery.getFromCache.calls.all(); + expect(calls.length).toBe(2); + expect(calls[0].returnValue).toBeUndefined(); + expect(calls[1].returnValue).toBeDefined(); + }); + }); + + it('Data in request comes from the time interval collection', function() { + var times = TimeIntervalCollection.fromIso8601({ + iso8601: '2017-04-26/2017-04-30/P1D', + dataCallback: function(interval, index) { + return { + Time: JulianDate.toIso8601(interval.start), + Test: 'testValue' + }; + } + }); + var clock = new Clock({ + currentTime : JulianDate.fromIso8601('2017-04-26'), + clockStep : ClockStep.TICK_DEPENDENT, + shouldAnimate : false + }); + + Resource._Implementations.createImage = function(url, crossOrigin, deferred) { + Resource._DefaultImplementations.createImage('Data/Images/Red16x16.png', crossOrigin, deferred); + }; + + var provider = new WebMapServiceImageryProvider({ + layers : 'someLayer', + style : 'someStyle', + url : 'http://wms.invalid/', + clock : clock, + times : times + }); + + provider._reload = jasmine.createSpy(); + spyOn(provider._timeDynamicImagery, 'getFromCache').and.callThrough(); + + return pollToPromise(function() { + return provider.ready; + }) + .then(function() { + return provider.requestImage(0, 0, 0, new Request()); + }) + .then(function() { + var queryParameters = provider._tileProvider._resource.queryParameters; + expect(queryParameters.Time).toEqual('2017-04-26T00:00:00Z'); + expect(queryParameters.Test).toEqual('testValue'); + + }); + }); + + }); });