/* * L.TimeDimension.Layer.WMS: wms Layer associated to a TimeDimension */ L.TimeDimension.Layer.WMS = L.TimeDimension.Layer.extend({ initialize: function(layer, options) { L.TimeDimension.Layer.prototype.initialize.call(this, layer, options); this._timeCacheBackward = this.options.cacheBackward || this.options.cache || 0; this._timeCacheForward = this.options.cacheForward || this.options.cache || 0; this._wmsVersion = this.options.wmsVersion || this.options.version || layer.options.version || "1.1.1"; this._getCapabilitiesParams = this.options.getCapabilitiesParams || {}; this._getCapabilitiesAlternateUrl = this.options.getCapabilitiesUrl || null; this._getCapabilitiesAlternateLayerName = this.options.getCapabilitiesLayerName || null; this._proxy = this.options.proxy || null; this._updateTimeDimension = this.options.updateTimeDimension || false; this._setDefaultTime = this.options.setDefaultTime || false; this._updateTimeDimensionMode = this.options.updateTimeDimensionMode || 'intersect'; // 'union' or 'replace' this._layers = {}; this._defaultTime = 0; this._availableTimes = []; this._capabilitiesRequested = false; if (this._updateTimeDimension || this.options.requestTimeFromCapabilities) { this._requestTimeDimensionFromCapabilities(); } this._baseLayer.on('load', (function() { this._baseLayer.setLoaded(true); this.fire('timeload', { time: this._defaultTime }); }).bind(this)); }, getEvents: function() { var clearCache = L.bind(this._unvalidateCache, this); return { moveend: clearCache, zoomend: clearCache } }, eachLayer: function(method, context) { for (var prop in this._layers) { if (this._layers.hasOwnProperty(prop)) { method.call(context, this._layers[prop]); } } return L.TimeDimension.Layer.prototype.eachLayer.call(this, method, context); }, _onNewTimeLoading: function(ev) { // console.log('Layer._onNewTimeLoading: ' + this._baseLayer.wmsParams.layers + ' with time: ' + new Date(ev.time).toISOString()); var layer = this._getLayerForTime(ev.time); if (!this._map.hasLayer(layer)) { this._map.addLayer(layer); // console.log('Layer._onNewTimeLoading: layer added to map'); } }, isReady: function(time) { var layer = this._getLayerForTime(time); return layer.isLoaded(); }, onAdd: function(map) { L.TimeDimension.Layer.prototype.onAdd.call(this, map); if (this._availableTimes.length == 0) { this._requestTimeDimensionFromCapabilities(); } else { this._updateTimeDimensionAvailableTimes(); } }, _update: function() { if (!this._map) return; var time = this._timeDimension.getCurrentTime(); // It will get the layer for this time (create or get) // Then, the layer will be loaded if necessary, adding it to the map (and show it after loading). // If it already on the map (but probably hidden), it will be shown var layer = this._getLayerForTime(time); if (this._currentLayer == null) { this._currentLayer = layer; } if (!this._map.hasLayer(layer)) { this._map.addLayer(layer); } else { this._showLayer(layer, time); } }, setOpacity: function(opacity) { L.TimeDimension.Layer.prototype.setOpacity.apply(this, arguments); // apply to all preloaded caches for (var prop in this._layers) { if (this._layers.hasOwnProperty(prop) && this._layers[prop].setOpacity) { this._layers[prop].setOpacity(opacity); } } }, setZIndex: function(zIndex){ L.TimeDimension.Layer.prototype.setZIndex.apply(this, arguments); // apply to all preloaded caches for (var prop in this._layers) { if (this._layers.hasOwnProperty(prop) && this._layers[prop].setZIndex) { this._layers[prop].setZIndex(zIndex); } } }, setParams: function(params, noRedraw) { L.extend(this._baseLayer.options, params); if (this._baseLayer.setParams) { this._baseLayer.setParams(params, noRedraw); } for (var prop in this._layers) { if (this._layers.hasOwnProperty(prop) && this._layers[prop].setParams) { this._layers[prop].setLoaded(false); // mark it as unloaded this._layers[prop].setParams(params, noRedraw); } } return this; }, _unvalidateCache: function() { var time = this._timeDimension.getCurrentTime(); for (var prop in this._layers) { if (time != prop && this._layers.hasOwnProperty(prop)) { this._layers[prop].setLoaded(false); // mark it as unloaded this._layers[prop].redraw(); } } }, _evictCachedTimes: function(keepforward, keepbackward) { // Cache management var times = this._getLoadedTimes(); var strTime = String(this._currentTime); var index = times.indexOf(strTime); var remove = []; // remove times before current time if (keepbackward > -1) { var objectsToRemove = index - keepbackward; if (objectsToRemove > 0) { remove = times.splice(0, objectsToRemove); this._removeLayers(remove); } } if (keepforward > -1) { index = times.indexOf(strTime); var objectsToRemove = times.length - index - keepforward - 1; if (objectsToRemove > 0) { remove = times.splice(index + keepforward + 1, objectsToRemove); this._removeLayers(remove); } } }, _showLayer: function(layer, time) { if (this._currentLayer && this._currentLayer !== layer) { this._currentLayer.hide(); } layer.show(); if (this._currentLayer && this._currentLayer === layer) { return; } this._currentLayer = layer; this._currentTime = time; console.log('Show layer ' + layer.wmsParams.layers + ' with time: ' + new Date(time).toISOString()); this._evictCachedTimes(this._timeCacheForward, this._timeCacheBackward); }, _getLayerForTime: function(time) { if (time == 0 || time == this._defaultTime || time == null) { return this._baseLayer; } if (this._layers.hasOwnProperty(time)) { return this._layers[time]; } var nearestTime = this._getNearestTime(time); if (this._layers.hasOwnProperty(nearestTime)) { return this._layers[nearestTime]; } var newLayer = this._createLayerForTime(nearestTime); this._layers[time] = newLayer; newLayer.on('load', (function(layer, time) { layer.setLoaded(true); // this time entry should exists inside _layers // but it might be deleted by cache management if (!this._layers[time]) { this._layers[time] = layer; } if (this._timeDimension && time == this._timeDimension.getCurrentTime() && !this._timeDimension.isLoading()) { this._showLayer(layer, time); } // console.log('Loaded layer ' + layer.wmsParams.layers + ' with time: ' + new Date(time).toISOString()); this.fire('timeload', { time: time }); }).bind(this, newLayer, time)); // Hack to hide the layer when added to the map. // It will be shown when timeload event is fired from the map (after all layers are loaded) newLayer.onAdd = (function(map) { Object.getPrototypeOf(this).onAdd.call(this, map); this.hide(); }).bind(newLayer); return newLayer; }, _createLayerForTime:function(time){ var wmsParams = this._baseLayer.options; wmsParams.time = new Date(time).toISOString(); return new this._baseLayer.constructor(this._baseLayer.getURL(), wmsParams); }, _getLoadedTimes: function() { var result = []; for (var prop in this._layers) { if (this._layers.hasOwnProperty(prop)) { result.push(prop); } } return result.sort(function(a, b) { return a - b; }); }, _removeLayers: function(times) { for (var i = 0, l = times.length; i < l; i++) { if (this._map) this._map.removeLayer(this._layers[times[i]]); delete this._layers[times[i]]; } }, setMinimumForwardCache: function(value) { if (value > this._timeCacheForward) { this._timeCacheForward = value; } }, _requestTimeDimensionFromCapabilities: function() { if (this._capabilitiesRequested) { return; } this._capabilitiesRequested = true; var url = this._getCapabilitiesUrl(); if (this._proxy) { url = this._proxy + '?url=' + encodeURIComponent(url); } $.get(url, (function(data) { this._defaultTime = Date.parse(this._getDefaultTimeFromCapabilities(data)); this._setDefaultTime = this._setDefaultTime || (this._timeDimension && this._timeDimension.getAvailableTimes().length == 0); this.setAvailableTimes(this._parseTimeDimensionFromCapabilities(data)); if (this._setDefaultTime && this._timeDimension) { this._timeDimension.setCurrentTime(this._defaultTime); } }).bind(this)); }, _getCapabilitiesUrl: function() { var url = this._baseLayer.getURL(); if (this._getCapabilitiesAlternateUrl) url = this._getCapabilitiesAlternateUrl; var params = L.extend({}, this._getCapabilitiesParams, { 'request': 'GetCapabilities', 'service': 'WMS', 'version': this._wmsVersion }); url = url + L.Util.getParamString(params, url, params.uppercase); return url; }, _parseTimeDimensionFromCapabilities: function(xml) { var layers = $(xml).find('Layer[queryable="1"]'); var layerName = this._baseLayer.wmsParams.layers; if (this._getCapabilitiesAlternateLayerName) layerName = this._getCapabilitiesAlternateLayerName; var layerNameElement = layers.find("Name").filter(function(index) { return $(this).text() === layerName; }); var times = null; if (layerNameElement) { var layer = layerNameElement.parent(); times = this._getTimesFromLayerCapabilities(layer); if (!times) { times = this._getTimesFromLayerCapabilities(layer.parent()); } } return times; }, _getTimesFromLayerCapabilities: function(layer) { var times = null; var dimension = layer.find("Dimension[name='time']"); if (dimension && dimension.length && dimension[0].textContent.length) { times = dimension[0].textContent.trim(); } else { var extent = layer.find("Extent[name='time']"); if (extent && extent.length && extent[0].textContent.length) { times = extent[0].textContent.trim(); } } return times; }, _getDefaultTimeFromCapabilities: function(xml) { var layers = $(xml).find('Layer[queryable="1"]'); var layerName = this._baseLayer.wmsParams.layers; if (this._getCapabilitiesAlternateLayerName) layerName = this._getCapabilitiesAlternateLayerName; var layerNameElement = layers.find("Name").filter(function(index) { return $(this).text() === layerName; }); var defaultTime = 0; if (layerNameElement) { var layer = layerNameElement.parent(); defaultTime = this._getDefaultTimeFromLayerCapabilities(layer); if (defaultTime == 0) { defaultTime = this._getDefaultTimeFromLayerCapabilities(layer.parent()); } } return defaultTime; }, _getDefaultTimeFromLayerCapabilities: function(layer) { var defaultTime = 0; var dimension = layer.find("Dimension[name='time']"); if (dimension && dimension.attr("default")) { defaultTime = dimension.attr("default"); } else { var extent = layer.find("Extent[name='time']"); if (extent && extent.attr("default")) { defaultTime = extent.attr("default"); } } return defaultTime; }, setAvailableTimes: function(times) { this._availableTimes = L.TimeDimension.Util.parseTimesExpression(times); this._updateTimeDimensionAvailableTimes(); }, _updateTimeDimensionAvailableTimes: function() { if ((this._timeDimension && this._updateTimeDimension) || (this._timeDimension && this._timeDimension.getAvailableTimes().length == 0)) { this._timeDimension.setAvailableTimes(this._availableTimes, this._updateTimeDimensionMode); if (this._setDefaultTime && this._defaultTime > 0) { this._timeDimension.setCurrentTime(this._defaultTime); } } }, _getNearestTime: function(time) { if (this._layers.hasOwnProperty(time)) { return time; } if (this._availableTimes.length == 0) { return time; } var index = 0; var len = this._availableTimes.length; for (; index < len; index++) { if (time < this._availableTimes[index]) { break; } } // We've found the first index greater than the time. Get the previous if (index > 0) { index--; } if (time != this._availableTimes[index]) { console.log('Search layer time: ' + new Date(time).toISOString()); console.log('Return layer time: ' + new Date(this._availableTimes[index]).toISOString()); } return this._availableTimes[index]; }, }); if (!L.NonTiledLayer) { L.NonTiledLayer = (L.Layer || L.Class).extend({}); } L.NonTiledLayer.include({ _visible: true, _loaded: false, _originalUpdate: L.NonTiledLayer.prototype._update, _originalOnRemove: L.NonTiledLayer.prototype.onRemove, _update: function() { if (!this._visible && this._loaded) { return; } this._originalUpdate(); }, onRemove: function(map) { this._loaded = false; this._originalOnRemove(map); }, setLoaded: function(loaded) { this._loaded = loaded; }, isLoaded: function() { return this._loaded; }, hide: function() { this._visible = false; this._div.style.display = 'none'; }, show: function() { this._visible = true; this._div.style.display = 'block'; }, getURL: function() { return this._wmsUrl; } }); L.TileLayer.include({ _visible: true, _loaded: false, _originalUpdate: L.TileLayer.prototype._update, _update: function() { if (!this._visible && this._loaded) { return; } this._originalUpdate(); }, setLoaded: function(loaded) { this._loaded = loaded; }, isLoaded: function() { return this._loaded; }, hide: function() { this._visible = false; if (this._container) { this._container.style.display = 'none'; } }, show: function() { this._visible = true; if (this._container) { this._container.style.display = 'block'; } }, getURL: function() { return this._url; } }); L.timeDimension.layer.wms = function(layer, options) { return new L.TimeDimension.Layer.WMS(layer, options); };