UNPKG

terriajs

Version:

Geospatial data visualization platform.

285 lines (245 loc) 9.94 kB
'use strict'; /*global require*/ var clone = require('terriajs-cesium/Source/Core/clone'); var defaultValue = require('terriajs-cesium/Source/Core/defaultValue'); 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 RuntimeError = require('terriajs-cesium/Source/Core/RuntimeError'); var when = require('terriajs-cesium/Source/ThirdParty/when'); var inherit = require('../Core/inherit'); var overrideProperty = require('../Core/overrideProperty'); var CatalogItem = require('./CatalogItem'); var createCatalogMemberFromType = require('./createCatalogMemberFromType'); /** * A {@link CatalogItem} composed of multiple other catalog items. When this item is enabled or shown, the composed items are * enabled or shown as well. Other properties, including {@link CatalogItem#rectangle}, * {@link CatalogItem#clock}, and {@link CatalogItem#legendUrls}, are not composed in any way, so you should manually set those * properties on this object as appropriate. * * @alias CompositeCatalogItem * @constructor * @extends CatalogItem * * @param {Terria} terria The Terria instance. * @param {CatalogItem[]} [items] The items to compose. */ var CompositeCatalogItem = function(terria, items) { CatalogItem.call(this, terria); this.items = defined(items) ? items.slice() : []; knockout.track(this, ['items']); overrideProperty(this, 'legendUrls', { get: function() { if (!defined(this._legendUrls) || this._legendUrls.length === 0) { this._legendUrls = []; for (var i = 0; i < this.items.length; ++i) { if (this.items[i].legendUrls) { this._legendUrls = this._legendUrls.concat(this.items[i].legendUrls); } } } return this._legendUrls; } }); knockout.getObservable(this, 'items').subscribe(function() { for (var i = 0; i < this.items.length; ++i) { this.items[i].showInNowViewingWhenEnabled = false; } }, this); }; inherit(CatalogItem, CompositeCatalogItem); defineProperties(CompositeCatalogItem.prototype, { /** * Gets the type of data member represented by this instance. * @memberOf CompositeCatalogItem.prototype * @type {String} */ type : { get : function() { return 'composite'; } }, /** * Gets a human-readable name for this type of data source, such as 'Web Map Service (WMS)'. * @memberOf CompositeCatalogItem.prototype * @type {String} */ typeName : { get : function() { return 'Composite'; } }, /** * 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 CompositeCatalogItem.prototype * @type {Object} */ updaters : { get : function() { return CompositeCatalogItem.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 CompositeCatalogItem.prototype * @type {Object} */ serializers : { get : function() { return CompositeCatalogItem.defaultSerializers; } }, /** * Gets the set of names of the properties to be serialized for this object when {@link CatalogMember#serializeToJson} is called * for a share link. * @memberOf CompositeCatalogItem.prototype * @type {String[]} */ propertiesForSharing : { get : function() { return CompositeCatalogItem.defaultPropertiesForSharing; } }, /** * Gets a value indicating whether this data source, when enabled, can be reordered with respect to other data sources. * Data sources that cannot be reordered are typically displayed above reorderable data sources. * @memberOf CsvCatalogItem.prototype * @type {Boolean} */ supportsReordering : { get : function() { // we will use the heuristic that the composite supports reordering only // if all its subitems do var result = true; for (var itemIndex = 0; itemIndex < this.items.length; ++itemIndex) { var item = this.items[itemIndex]; result = result && item.supportsReordering; } return result; } } }); /** * Gets or sets the set of default updater functions to use in {@link CatalogMember#updateFromJson}. Types derived from this type * should expose this instance - cloned and modified if necesary - through their {@link CatalogMember#updaters} property. * @type {Object} */ // Adapted from CatalogGroup CompositeCatalogItem.defaultUpdaters = clone(CatalogItem.defaultUpdaters); CompositeCatalogItem.defaultUpdaters.items = function(compositeCatalogItem, json, propertyName, options) { // Let the item finish loading first. Otherwise, these changes could get clobbered by the load. return when(compositeCatalogItem.load(), function() { var promises = []; options = defaultValue(options, defaultValue.EMPTY_OBJECT); var items = json.items; for (var itemIndex = 0; itemIndex < items.length; ++itemIndex) { var item = items[itemIndex]; if (!defined(item.type)) { throw new RuntimeError('Each item must have a type.'); } if (item.type === 'composite') { throw new RuntimeError('Composites cannot include composite items.'); } var existingItem = createCatalogMemberFromType(item.type, compositeCatalogItem.terria); compositeCatalogItem.add(existingItem); promises.push(existingItem.updateFromJson(item, options)); } return when.all(promises); }); }; CompositeCatalogItem.defaultUpdaters.isLoading = function(compositeCatalogItem, json, propertyName) {}; freezeObject(CompositeCatalogItem.defaultUpdaters); /** * Gets or sets the set of default serializer functions to use in {@link CatalogMember#serializeToJson}. Types derived from this type * should expose this instance - cloned and modified if necesary - through their {@link CatalogMember#serializers} property. * @type {Object} */ CompositeCatalogItem.defaultSerializers = clone(CatalogItem.defaultSerializers); CompositeCatalogItem.defaultSerializers.items = function(compositeCatalogItem, json, propertyName, options) { var items = json.items = []; for (var i = 0; i < compositeCatalogItem.items.length; ++i) { var item = compositeCatalogItem.items[i].serializeToJson(options); if (defined(item)) { items.push(item); } } }; CompositeCatalogItem.defaultSerializers.isLoading = function(compositeCatalogItem, json, propertyName, options) {}; freezeObject(CompositeCatalogItem.defaultSerializers); /** * Gets or sets the default set of properties that are serialized when serializing a {@link CatalogItem}-derived object * for a share link. * @type {String[]} */ CompositeCatalogItem.defaultPropertiesForSharing = clone(CatalogItem.defaultPropertiesForSharing); CompositeCatalogItem.defaultPropertiesForSharing.push('items'); freezeObject(CompositeCatalogItem.defaultPropertiesForSharing); // CompositeCatalogItem.prototype._load = function() { return when.all( this.items.map(function(item) { return item.load(); }) ); }; CompositeCatalogItem.prototype._getValuesThatInfluenceLoad = function() { var result = []; for (var i = 0; i < this.items.length; ++i) { result.push.apply(result, this.items[i]._getValuesThatInfluenceLoad()); } return result; }; CompositeCatalogItem.prototype._enable = function() { var i; try { for (i = 0; i < this.items.length; ++i) { this.items[i]._enable(); } } catch(e) { for (var j = 0; j < i; ++j) { this.items[j]._disable(); } this.isEnabled = false; throw e; } }; CompositeCatalogItem.prototype._disable = function() { for (var i = 0; i < this.items.length; ++i) { this.items[i]._disable(); } }; CompositeCatalogItem.prototype._show = function() { var i; try { for (i = 0; i < this.items.length; ++i) { this.items[i]._show(); } } catch(e) { for (var j = 0; j < i; ++j) { this.items[j]._hide(); } this.isShown = false; throw e; } }; CompositeCatalogItem.prototype._hide = function() { for (var i = 0; i < this.items.length; ++i) { this.items[i]._hide(); } }; /** * Adds an item or group to this composite. * * @param {CatalogMember} item The item to add. */ CompositeCatalogItem.prototype.add = function(item) { this.items.push(item); }; module.exports = CompositeCatalogItem;