UNPKG

terriajs

Version:

Geospatial data visualization platform.

296 lines (257 loc) 9.42 kB
'use strict'; /*global require*/ var arraysAreEqual = require('../Core/arraysAreEqual'); 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 DeveloperError = require('terriajs-cesium/Source/Core/DeveloperError'); var knockout = require('terriajs-cesium/Source/ThirdParty/knockout'); var runLater = require('../Core/runLater'); var serializeToJson = require('../Core/serializeToJson'); var updateFromJson = require('../Core/updateFromJson'); var TerriaError = require('../Core/TerriaError'); /** * A parameter to a {@link CatalogFunction}. * * @alias FunctionParameter * @constructor * @abstract * * @param {Object} [options] Object with the following properties: * @param {Terria} options.terria The Terria instance. * @param {CatalogFunction} options.catalogFunction The function that this is a parameter to. * @param {String} options.id The unique ID of this parameter. * @param {String} [options.name] The name of this parameter. If not specified, the ID is used as the name. * @param {String} [options.description] The description of the parameter. * @param {Boolean} [options.isRequired] True if this parameter is required, false if it is optional. * @param {Object} [options.value] The initial value of the parameter. */ var FunctionParameter = function(options) { if (!defined(options) || !defined(options.terria)) { throw new DeveloperError('options.terria is required.'); } if (!defined(options.catalogFunction)) { throw new DeveloperError('options.catalogFunction is required.'); } if (!defined(options.id)) { throw new DeveloperError('options.id is required.'); } this._terria = options.terria; this._catalogFunction = options.catalogFunction; this._id = options.id; this._loadingPromise = undefined; this._lastLoadInfluencingValues = undefined; /** * Gets or sets a value indicating whether the parameter is currently loading. This property * is observable. * @type {Boolean} */ this.isLoading = false; /** * Gets or sets the name of the parameter. * @type {String} */ this.name = defaultValue(options.name, options.id); /** * Gets or sets the description of the parameter. * @type {String} */ this.description = options.description; /** * Gets or sets a value indicating whether this parameter is required. * @type {Boolean} * @default false */ this.isRequired = defaultValue(options.isRequired, false); /** * A converter that can be used to convert this parameter for use with a {@link CatalogFunction}. * The actual type and content of this property is defined by the catalog function. * @type {Any} */ this.converter = undefined; /** * Gets or sets the formatter (from the set defined by {@link FunctionParameter#availableFormatters}) * to use to format this parameter to pass to the {@link CatalogFunction}. * @type {String} */ this.formatter = 'default'; /** * Gets the default value for this parameter, or undefined if there is no default value. */ this._defaultValue = options.defaultValue; /** * Gets or sets the current value of this parameter. */ this.value = options.value; knockout.track(this, ['_value', 'formatter', '_defaultValue']); /** * Gets or sets the current value of this parameter. * @member {*} value * @memberof FunctionParameter.prototype */ knockout.defineProperty(this, 'value', { get: FunctionParameter.defaultValueGetter, set: FunctionParameter.defaultValueSetter }); /** * Gets the default value for this parameter, or undefined if there is no default value. * @member {*} defaultValue * @memberof FunctionParameter.prototype */ knockout.defineProperty(this, 'defaultValue', { get: function() { return this._defaultValue; }, set: function(value) { this._defaultValue = value; } }); }; FunctionParameter.defaultValueGetter = function() { if (!defined(this._value)) { return this.defaultValue; } return this._value; }; FunctionParameter.defaultValueSetter = function(value) { this._value = value; }; defineProperties(FunctionParameter.prototype, { /** * Gets the type of this parameter. * @memberof FunctionParameter.prototype * @type {String} */ type: { get: function() { throw new DeveloperError('FunctionParameter.type must be overridden in derived classes.'); } }, /** * Gets the Terria instance associated with this parameter. * @memberof FunctionParameter.prototype * @type {Terria} */ terria: { get: function() { return this._terria; } }, /** * Gets the function to which this is a parameter. * @memberof FunctionParameter.prototype * @type {CatalogFunction} */ catalogFunction: { get: function() { return this._catalogFunction; } }, /** * Gets the ID of the parameter. * @memberof FunctionParameter.prototype * @type {String} */ id: { get: function() { return this._id; } }, /** * Gets the formatters that are available to format the parameter's value. * @memberof FunctionParameter.prototype */ availableFormatters: { get: function() { if (this.constructor && this.constructor.AvailableFormatters) { return this.constructor.AvailableFormatters; } else { return { default: this.formatValueAsString.bind(this) }; } } } }); FunctionParameter.prototype.load = function() { if (!defined(this._load)) { // No loading required. return undefined; } if (defined(this._loadingPromise)) { // Load already in progress. return this._loadingPromise; } var loadInfluencingValues = []; if (defined(this._getValuesThatInfluenceLoad)) { loadInfluencingValues = this._getValuesThatInfluenceLoad(); } if (arraysAreEqual(loadInfluencingValues, this._lastLoadInfluencingValues)) { // Already loaded, and nothing has changed to force a re-load. return undefined; } this.isLoading = true; var that = this; this._loadingPromise = runLater(function() { that._lastLoadInfluencingValues = []; if (defined(that._getValuesThatInfluenceLoad)) { that._lastLoadInfluencingValues = that._getValuesThatInfluenceLoad(); } return that._load(); }).then(function() { that._loadingPromise = undefined; that.isLoading = false; }).otherwise(function(e) { that._lastLoadInfluencingValues = undefined; that._loadingPromise = undefined; that.isLoading = false; throw e; }); return this._loadingPromise; }; /** * Represents value as string. * @param {Object} [value] Value to format as string. If not specified, {@link FunctionParameter#value} is used. * @return {String} String representation of the value. */ FunctionParameter.prototype.formatValueAsString = function(value) { value = defaultValue(value, this._value); return defined(value) ? value.toString() : '-'; }; /** * Formats this value to pass to a service. The format is controlled by the * {@link FunctionParameter#formatter} property. * * @param {Object} [value] Value to format as string. If not specified, {@link FunctionParameter#value} is used. * @return {Any} The formatted value. */ FunctionParameter.prototype.formatForService = function(value) { const formatter = this.availableFormatters[this.formatter]; if (!formatter) { throw new TerriaError({ sender: this, title: 'Unknown formatter', message: `The function parameter formatter ${this.formatter} is unknown.\n\n` + 'Valid formatters are:\n\n' + ' * ' + Object.keys(this.availableFormatters).join('\n * ') }); } value = defaultValue(value, this._value); return formatter(value); }; /** * Updates the function parameter from a JSON object-literal description of it. * * @param {Object} json The JSON description. The JSON should be in the form of an object literal, not a string. * @returns {Promise} A promise that resolves when the update is complete. */ FunctionParameter.prototype.updateFromJson = function(json) { return updateFromJson(this, json); }; /** * Serializes the data item to JSON. * * @return {Object} The serialized JSON object-literal. */ FunctionParameter.prototype.serializeToJson = function() { var result = serializeToJson(this); result.type = this.type; return result; }; module.exports = FunctionParameter;