Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | 18x 18x 17x 16x 15x 14x 14x 14x 14x 14x 14x 14x 14x 14x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 9x 1x 9x 9x 9x 2x 2x 2x 9x 1x 1252x 1252x 1252x 1252x 1252x 1247x 1252x 3x 1x 29x 29x 29x 29x 29x 24x 24x 24x 24x 24x 24x 24x 5x 5x 3x 3x 3x 6x 3x 3x 3x 3x 1261x 8x 8x 8x 1257x 1257x 1257x 1257x 1257x 1257x 1257x 1x 1256x 1256x 2x 1254x 1254x 1254x 1254x 1254x 1254x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x | import Check from "../Core/Check.js";
import Frozen from "../Core/Frozen.js";
import defined from "../Core/defined.js";
import DeveloperError from "../Core/DeveloperError.js";
import JulianDate from "../Core/JulianDate.js";
import Request from "../Core/Request.js";
import RequestType from "../Core/RequestType.js";
/**
* Provides functionality for ImageryProviders that have time dynamic imagery
*
* @alias TimeDynamicImagery
* @constructor
*
* @param {object} options Object with the following properties:
* @param {Clock} options.clock A Clock instance that is used when determining the value for the time dimension. Required when <code>options.times</code> is specified.
* @param {TimeIntervalCollection} options.times TimeIntervalCollection with its <code>data</code> property being an object containing time dynamic dimension and their values.
* @param {Function} options.requestImageFunction A function that will request imagery tiles.
* @param {Function} options.reloadFunction A function that will be called when all imagery tiles need to be reloaded.
*/
function TimeDynamicImagery(options) {
options = options ?? Frozen.EMPTY_OBJECT;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.clock", options.clock);
Check.typeOf.object("options.times", options.times);
Check.typeOf.func(
"options.requestImageFunction",
options.requestImageFunction,
);
Check.typeOf.func("options.reloadFunction", options.reloadFunction);
//>>includeEnd('debug');
this._tileCache = {};
this._tilesRequestedForInterval = [];
const clock = (this._clock = options.clock);
this._times = options.times;
this._requestImageFunction = options.requestImageFunction;
this._reloadFunction = options.reloadFunction;
this._currentIntervalIndex = -1;
clock.onTick.addEventListener(this._clockOnTick, this);
this._clockOnTick(clock);
}
Object.defineProperties(TimeDynamicImagery.prototype, {
/**
* Gets or sets a clock that is used to get keep the time used for time dynamic parameters.
* @memberof TimeDynamicImagery.prototype
* @type {Clock}
*/
clock: {
get: function () {
return this._clock;
},
set: function (value) {
//>>includeStart('debug', pragmas.debug);
Iif (!defined(value)) {
throw new DeveloperError("value is required.");
}
//>>includeEnd('debug');
Eif (this._clock !== value) {
this._clock = value;
this._clockOnTick(value);
this._reloadFunction();
}
},
},
/**
* Gets or sets a time interval collection.
* @memberof TimeDynamicImagery.prototype
* @type {TimeIntervalCollection}
*/
times: {
get: function () {
return this._times;
},
set: function (value) {
//>>includeStart('debug', pragmas.debug);
Iif (!defined(value)) {
throw new DeveloperError("value is required.");
}
//>>includeEnd('debug');
Eif (this._times !== value) {
this._times = value;
this._clockOnTick(this._clock);
this._reloadFunction();
}
},
},
/**
* Gets the current interval.
* @memberof TimeDynamicImagery.prototype
* @type {TimeInterval}
*/
currentInterval: {
get: function () {
return this._times.get(this._currentIntervalIndex);
},
},
});
/**
* Gets the tile from the cache if its available.
*
* @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<HTMLImageElement>|undefined} A promise for the image that will resolve when the image is available, or
* undefined if the tile is not in the cache.
*/
TimeDynamicImagery.prototype.getFromCache = function (x, y, level, request) {
const key = getKey(x, y, level);
let result;
const cache = this._tileCache[this._currentIntervalIndex];
if (defined(cache) && defined(cache[key])) {
const item = cache[key];
result = item.promise.catch(function (e) {
// Set the correct state in case it was cancelled
request.state = item.request.state;
throw e;
});
delete cache[key];
}
return result;
};
/**
* Checks if the next interval is approaching and will start preload the tile if necessary. Otherwise it will
* just add the tile to a list to preload when we approach the next interval.
*
* @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.
*/
TimeDynamicImagery.prototype.checkApproachingInterval = function (
x,
y,
level,
request,
) {
const key = getKey(x, y, level);
const tilesRequestedForInterval = this._tilesRequestedForInterval;
// If we are approaching an interval, preload this tile in the next interval
const approachingInterval = getApproachingInterval(this);
const tile = {
key: key,
// Determines priority based on camera distance to the tile.
// Since the imagery regardless of time will be attached to the same tile we can just steal it.
priorityFunction: request.priorityFunction,
};
if (
!defined(approachingInterval) ||
!addToCache(this, tile, approachingInterval)
) {
// Add to recent request list if we aren't approaching and interval or the request was throttled
tilesRequestedForInterval.push(tile);
}
// Don't let the tile list get out of hand
if (tilesRequestedForInterval.length >= 512) {
tilesRequestedForInterval.splice(0, 256);
}
};
TimeDynamicImagery.prototype._clockOnTick = function (clock) {
const time = clock.currentTime;
const times = this._times;
const index = times.indexOf(time);
const currentIntervalIndex = this._currentIntervalIndex;
if (index !== currentIntervalIndex) {
// Cancel all outstanding requests and clear out caches not from current time interval
const currentCache = this._tileCache[currentIntervalIndex];
for (const t in currentCache) {
if (currentCache.hasOwnProperty(t)) {
currentCache[t].request.cancel();
}
}
delete this._tileCache[currentIntervalIndex];
this._tilesRequestedForInterval = [];
this._currentIntervalIndex = index;
this._reloadFunction();
return;
}
const approachingInterval = getApproachingInterval(this);
if (defined(approachingInterval)) {
// Start loading recent tiles from end of this._tilesRequestedForInterval
// We keep preloading until we hit a throttling limit.
const tilesRequested = this._tilesRequestedForInterval;
let success = true;
while (success) {
if (tilesRequested.length === 0) {
break;
}
const tile = tilesRequested.pop();
success = addToCache(this, tile, approachingInterval);
Iif (!success) {
tilesRequested.push(tile);
}
}
}
};
function getKey(x, y, level) {
return `${x}-${y}-${level}`;
}
function getKeyElements(key) {
const s = key.split("-");
Iif (s.length !== 3) {
return undefined;
}
return {
x: Number(s[0]),
y: Number(s[1]),
level: Number(s[2]),
};
}
function getApproachingInterval(that) {
const times = that._times;
Iif (!defined(times)) {
return undefined;
}
const clock = that._clock;
const time = clock.currentTime;
const isAnimating = clock.canAnimate && clock.shouldAnimate;
const multiplier = clock.multiplier;
if (!isAnimating && multiplier !== 0) {
return undefined;
}
let seconds;
let index = times.indexOf(time);
if (index < 0) {
return undefined;
}
const interval = times.get(index);
if (multiplier > 0) {
// animating forward
seconds = JulianDate.secondsDifference(interval.stop, time);
++index;
} else E{
//backwards
seconds = JulianDate.secondsDifference(interval.start, time); // Will be negative
--index;
}
seconds /= multiplier; // Will always be positive
// Less than 5 wall time seconds
return index >= 0 && seconds <= 5.0 ? times.get(index) : undefined;
}
function addToCache(that, tile, interval) {
const index = that._times.indexOf(interval.start);
const tileCache = that._tileCache;
let intervalTileCache = tileCache[index];
Eif (!defined(intervalTileCache)) {
intervalTileCache = tileCache[index] = {};
}
const key = tile.key;
Iif (defined(intervalTileCache[key])) {
return true; // Already in the cache
}
const keyElements = getKeyElements(key);
const request = new Request({
throttle: false,
throttleByServer: true,
type: RequestType.IMAGERY,
priorityFunction: tile.priorityFunction,
});
const promise = that._requestImageFunction(
keyElements.x,
keyElements.y,
keyElements.level,
request,
interval,
);
Iif (!defined(promise)) {
return false;
}
intervalTileCache[key] = {
promise: promise,
request: request,
};
return true;
}
export default TimeDynamicImagery;
|