terriajs
Version:
Geospatial data visualization platform.
328 lines (283 loc) • 10.6 kB
JavaScript
'use strict';
/*global require*/
var URI = require('urijs');
var combine = require('terriajs-cesium/Source/Core/combine');
var clone = require('terriajs-cesium/Source/Core/clone');
var defined = require('terriajs-cesium/Source/Core/defined');
var defineProperties = require('terriajs-cesium/Source/Core/defineProperties');
var freezeObject = require('terriajs-cesium/Source/Core/freezeObject');
var knockout = require('terriajs-cesium/Source/ThirdParty/knockout');
var loadJson = require('../Core/loadJson');
var loadXML = require('../Core/loadXML');
var GeoJsonCatalogItem = require('./GeoJsonCatalogItem');
var CatalogItem = require('./CatalogItem');
var inherit = require('../Core/inherit');
var gmlToGeoJson = require('../Map/gmlToGeoJson');
var overrideProperty = require('../Core/overrideProperty');
var proxyCatalogItemUrl = require('./proxyCatalogItemUrl');
/**
* A {@link CatalogItem} representing a layer from a Web Feature Service (WFS) server.
*
* @alias WebFeatureServiceCatalogItem
* @constructor
* @extends CatalogItem
*
* @param {Terria} terria The Terria instance.
*/
var WebFeatureServiceCatalogItem = function(terria) {
CatalogItem.call(this, terria);
this._dataUrl = undefined;
this._dataUrlType = undefined;
this._metadataUrl = undefined;
this._geoJsonItem = undefined;
/**
* Gets or sets the WFS feature type names.
* @type {String}
*/
this.typeNames = '';
/**
* Gets or sets a value indicating whether we should request GeoJSON from the WFS server. If this property
* and {@link WebFeatureServiceCatalogItem#requestGeoJson} are both true, we'll request GeoJSON first and
* only fall back on trying GML if the GeoJSON request fails.
* @type {Boolean}
* @default true
*/
this.requestGeoJson = true;
/**
* Gets or sets a value indicating whether we should request GML from the WFS server. If this property
* and {@link WebFeatureServiceCatalogItem#requestGeoJson} are both true, we'll request GeoJSON first and
* only fall back on trying GML if the GeoJSON request fails.
* @type {Boolean}
* @default true
*/
this.requestGml = true;
/**
* Gets or sets the additional parameters to pass to the WFS server when requesting geometry.
* All parameter names must be entered in lowercase in order to be consistent with references in TerrisJS code.
* @type {Object}
*/
this.parameters = {};
knockout.track(this, ['_dataUrl', '_dataUrlType', '_metadataUrl', 'typeNames', 'requestGeoJson', 'requestGml']);
// dataUrl, metadataUrl, and legendUrl are derived from url if not explicitly specified.
overrideProperty(this, 'dataUrl', {
get : function() {
var url = this._dataUrl;
if (!defined(url)) {
url = this.url;
}
if (this.dataUrlType === 'wfs') {
url = new URI(cleanUrl(url))
.setQuery(combine({
'service': 'WFS',
'version': '1.1.0',
'request': 'GetFeature',
'typeName': this.typeNames,
'srsName': 'EPSG:4326',
'maxFeatures': '1000'
}, this.parameters))
.toString();
}
return url;
},
set : function(value) {
this._dataUrl = value;
}
});
overrideProperty(this, 'dataUrlType', {
get : function() {
if (defined(this._dataUrlType)) {
return this._dataUrlType;
} else {
return 'wfs';
}
},
set : function(value) {
this._dataUrlType = value;
}
});
overrideProperty(this, 'metadataUrl', {
get : function() {
if (defined(this._metadataUrl)) {
return this._metadataUrl;
}
return new URI(cleanUrl(this.url))
.setQuery(combine({
service: 'WFS',
version: '1.1.0',
request: 'GetCapabilities'
}, this.parameters))
.toString();
},
set : function(value) {
this._metadataUrl = value;
}
});
};
inherit(CatalogItem, WebFeatureServiceCatalogItem);
defineProperties(WebFeatureServiceCatalogItem.prototype, {
/**
* Gets the type of data item represented by this instance.
* @memberOf WebFeatureServiceCatalogItem.prototype
* @type {String}
*/
type : {
get : function() {
return 'wfs';
}
},
/**
* Gets a human-readable name for this type of data source, 'Web Feature Service (WFS)'.
* @memberOf WebFeatureServiceCatalogItem.prototype
* @type {String}
*/
typeName : {
get : function() {
return 'Web Feature Service (WFS)';
}
},
/**
* Gets the set of functions used to update individual properties in {@link CatalogMember#updateFromJson}.
* When a property name in the returned object literal matches the name of a property on this instance, the value
* will be called as a function and passed a reference to this instance, a reference to the source JSON object
* literal, and the name of the property.
* @memberOf WebFeatureServiceCatalogItem.prototype
* @type {Object}
*/
updaters : {
get : function() {
return WebFeatureServiceCatalogItem.defaultUpdaters;
}
},
/**
* Gets the set of functions used to serialize individual properties in {@link CatalogMember#serializeToJson}.
* When a property name on the model matches the name of a property in the serializers object literal,
* the value will be called as a function and passed a reference to the model, a reference to the destination
* JSON object literal, and the name of the property.
* @memberOf WebFeatureServiceCatalogItem.prototype
* @type {Object}
*/
serializers : {
get : function() {
return WebFeatureServiceCatalogItem.defaultSerializers;
}
},
/**
* Gets the data source associated with this catalog item.
* @memberOf WebFeatureServiceCatalogItem.prototype
* @type {DataSource}
*/
dataSource : {
get : function() {
return defined(this._geoJsonItem) ? this._geoJsonItem.dataSource : undefined;
}
}
});
WebFeatureServiceCatalogItem.defaultUpdaters = clone(CatalogItem.defaultUpdaters);
freezeObject(WebFeatureServiceCatalogItem.defaultUpdaters);
WebFeatureServiceCatalogItem.defaultSerializers = clone(CatalogItem.defaultSerializers);
// Serialize the underlying properties instead of the public views of them.
WebFeatureServiceCatalogItem.defaultSerializers.dataUrl = function(wfsItem, json, propertyName) {
json.dataUrl = wfsItem._dataUrl;
};
WebFeatureServiceCatalogItem.defaultSerializers.dataUrlType = function(wfsItem, json, propertyName) {
json.dataUrlType = wfsItem._dataUrlType;
};
WebFeatureServiceCatalogItem.defaultSerializers.metadataUrl = function(wfsItem, json, propertyName) {
json.metadataUrl = wfsItem._metadataUrl;
};
freezeObject(WebFeatureServiceCatalogItem.defaultSerializers);
WebFeatureServiceCatalogItem.prototype._getValuesThatInfluenceLoad = function() {
return [this.url, this.typeNames, this.requestGeoJson, this.requestGml, this.parameters];
};
WebFeatureServiceCatalogItem.prototype._load = function() {
this._geoJsonItem = new GeoJsonCatalogItem( this.terria);
var promise;
if (this.requestGeoJson) {
promise = loadGeoJson(this);
} else if (this.requestGml) {
promise = loadGml(this);
} else {
return;
}
this._geoJsonItem.data = promise;
var that = this;
return that._geoJsonItem.load().then(function() {
that.rectangle = that._geoJsonItem.rectangle;
});
};
WebFeatureServiceCatalogItem.prototype._enable = function() {
if (defined(this._geoJsonItem)) {
this._geoJsonItem._enable();
}
};
WebFeatureServiceCatalogItem.prototype._disable = function() {
if (defined(this._geoJsonItem)) {
this._geoJsonItem._disable();
}
};
WebFeatureServiceCatalogItem.prototype._show = function() {
if (defined(this._geoJsonItem)) {
this._geoJsonItem._show();
}
};
WebFeatureServiceCatalogItem.prototype._hide = function() {
if (defined(this._geoJsonItem)) {
this._geoJsonItem._hide();
}
};
WebFeatureServiceCatalogItem.prototype.showOnSeparateMap = function(globeOrMap) {
if (defined(this._geoJsonItem)) {
return this._geoJsonItem.showOnSeparateMap(globeOrMap);
}
};
function loadGeoJson(wfsItem) {
var promise = loadJson(buildGeoJsonUrl(wfsItem)).then(function(json) {
return json;
});
if (wfsItem.requestGml) {
promise = promise.otherwise(function() {
return loadGml(wfsItem);
});
}
return promise;
}
function loadGml(wfsItem) {
return loadXML(buildGmlUrl(wfsItem)).then(function(xml) {
return gmlToGeoJson(xml);
});
}
function buildGeoJsonUrl(wfsItem) {
var url = cleanAndProxyUrl(wfsItem, wfsItem.url);
return new URI(url)
.setQuery(combine({
service: 'WFS',
request: 'GetFeature',
typeName: wfsItem.typeNames,
version: '1.1.0',
outputFormat: 'JSON',
srsName: 'EPSG:4326'
}, wfsItem.parameters))
.toString();
}
function buildGmlUrl(wfsItem) {
var url = cleanAndProxyUrl(wfsItem, wfsItem.url);
return new URI(url)
.setQuery(combine({
service: 'WFS',
request: 'GetFeature',
typeName: wfsItem.typeNames,
version: '1.1.0',
srsName: 'EPSG:4326'
}, wfsItem.parameters))
.toString();
}
function cleanAndProxyUrl(catalogItem, url) {
return proxyCatalogItemUrl(catalogItem, cleanUrl(url));
}
function cleanUrl(url) {
// Strip off the search portion of the URL
var uri = new URI(url);
uri.search('');
return uri.toString();
}
module.exports = WebFeatureServiceCatalogItem;