import defaultValue from "../../Core/defaultValue.js"; import defined from "../../Core/defined.js"; import DeveloperError from "../../Core/DeveloperError.js"; import EllipsoidTerrainProvider from "../../Core/EllipsoidTerrainProvider.js"; import knockout from "../../ThirdParty/knockout.js"; import createCommand from "../createCommand.js"; /** * The view model for {@link BaseLayerPicker}. * @alias BaseLayerPickerViewModel * @constructor * * @param {Object} options Object with the following properties: * @param {Globe} options.globe The Globe to use. * @param {ProviderViewModel[]} [options.imageryProviderViewModels=[]] The array of ProviderViewModel instances to use for imagery. * @param {ProviderViewModel} [options.selectedImageryProviderViewModel] The view model for the current base imagery layer, if not supplied the first available imagery layer is used. * @param {ProviderViewModel[]} [options.terrainProviderViewModels=[]] The array of ProviderViewModel instances to use for terrain. * @param {ProviderViewModel} [options.selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available terrain layer is used. * * @exception {DeveloperError} imageryProviderViewModels must be an array. * @exception {DeveloperError} terrainProviderViewModels must be an array. */ function BaseLayerPickerViewModel(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); var globe = options.globe; var imageryProviderViewModels = defaultValue( options.imageryProviderViewModels, [] ); var terrainProviderViewModels = defaultValue( options.terrainProviderViewModels, [] ); //>>includeStart('debug', pragmas.debug); if (!defined(globe)) { throw new DeveloperError("globe is required"); } //>>includeEnd('debug'); this._globe = globe; /** * Gets or sets an array of ProviderViewModel instances available for imagery selection. * This property is observable. * @type {ProviderViewModel[]} */ this.imageryProviderViewModels = imageryProviderViewModels.slice(0); /** * Gets or sets an array of ProviderViewModel instances available for terrain selection. * This property is observable. * @type {ProviderViewModel[]} */ this.terrainProviderViewModels = terrainProviderViewModels.slice(0); /** * Gets or sets whether the imagery selection drop-down is currently visible. * @type {Boolean} * @default false */ this.dropDownVisible = false; knockout.track(this, [ "imageryProviderViewModels", "terrainProviderViewModels", "dropDownVisible", ]); var imageryObservable = knockout.getObservable( this, "imageryProviderViewModels" ); var imageryProviders = knockout.pureComputed(function () { var providers = imageryObservable(); var categories = {}; var i; for (i = 0; i < providers.length; i++) { var provider = providers[i]; var category = provider.category; if (defined(categories[category])) { categories[category].push(provider); } else { categories[category] = [provider]; } } var allCategoryNames = Object.keys(categories); var result = []; for (i = 0; i < allCategoryNames.length; i++) { var name = allCategoryNames[i]; result.push({ name: name, providers: categories[name], }); } return result; }); this._imageryProviders = imageryProviders; var terrainObservable = knockout.getObservable( this, "terrainProviderViewModels" ); var terrainProviders = knockout.pureComputed(function () { var providers = terrainObservable(); var categories = {}; var i; for (i = 0; i < providers.length; i++) { var provider = providers[i]; var category = provider.category; if (defined(categories[category])) { categories[category].push(provider); } else { categories[category] = [provider]; } } var allCategoryNames = Object.keys(categories); var result = []; for (i = 0; i < allCategoryNames.length; i++) { var name = allCategoryNames[i]; result.push({ name: name, providers: categories[name], }); } return result; }); this._terrainProviders = terrainProviders; /** * Gets the button tooltip. This property is observable. * @type {String} */ this.buttonTooltip = undefined; knockout.defineProperty(this, "buttonTooltip", function () { var selectedImagery = this.selectedImagery; var selectedTerrain = this.selectedTerrain; var imageryTip = defined(selectedImagery) ? selectedImagery.name : undefined; var terrainTip = defined(selectedTerrain) ? selectedTerrain.name : undefined; if (defined(imageryTip) && defined(terrainTip)) { return imageryTip + "\n" + terrainTip; } else if (defined(imageryTip)) { return imageryTip; } return terrainTip; }); /** * Gets the button background image. This property is observable. * @type {String} */ this.buttonImageUrl = undefined; knockout.defineProperty(this, "buttonImageUrl", function () { var selectedImagery = this.selectedImagery; if (defined(selectedImagery)) { return selectedImagery.iconUrl; } }); /** * Gets or sets the currently selected imagery. This property is observable. * @type {ProviderViewModel} * @default undefined */ this.selectedImagery = undefined; var selectedImageryViewModel = knockout.observable(); this._currentImageryProviders = []; knockout.defineProperty(this, "selectedImagery", { get: function () { return selectedImageryViewModel(); }, set: function (value) { if (selectedImageryViewModel() === value) { this.dropDownVisible = false; return; } var i; var currentImageryProviders = this._currentImageryProviders; var currentImageryProvidersLength = currentImageryProviders.length; var imageryLayers = this._globe.imageryLayers; var hadExistingBaseLayer = false; for (i = 0; i < currentImageryProvidersLength; i++) { var layersLength = imageryLayers.length; for (var x = 0; x < layersLength; x++) { var layer = imageryLayers.get(x); if (layer.imageryProvider === currentImageryProviders[i]) { imageryLayers.remove(layer); hadExistingBaseLayer = true; break; } } } if (defined(value)) { var newProviders = value.creationCommand(); if (Array.isArray(newProviders)) { var newProvidersLength = newProviders.length; for (i = newProvidersLength - 1; i >= 0; i--) { imageryLayers.addImageryProvider(newProviders[i], 0); } this._currentImageryProviders = newProviders.slice(0); } else { this._currentImageryProviders = [newProviders]; if (hadExistingBaseLayer) { imageryLayers.addImageryProvider(newProviders, 0); } else { var baseLayer = imageryLayers.get(0); if (defined(baseLayer)) { imageryLayers.remove(baseLayer); } imageryLayers.addImageryProvider(newProviders, 0); } } } selectedImageryViewModel(value); this.dropDownVisible = false; }, }); /** * Gets or sets the currently selected terrain. This property is observable. * @type {ProviderViewModel} * @default undefined */ this.selectedTerrain = undefined; var selectedTerrainViewModel = knockout.observable(); knockout.defineProperty(this, "selectedTerrain", { get: function () { return selectedTerrainViewModel(); }, set: function (value) { if (selectedTerrainViewModel() === value) { this.dropDownVisible = false; return; } var newProvider; if (defined(value)) { newProvider = value.creationCommand(); } this._globe.depthTestAgainstTerrain = !( newProvider instanceof EllipsoidTerrainProvider ); this._globe.terrainProvider = newProvider; selectedTerrainViewModel(value); this.dropDownVisible = false; }, }); var that = this; this._toggleDropDown = createCommand(function () { that.dropDownVisible = !that.dropDownVisible; }); this.selectedImagery = defaultValue( options.selectedImageryProviderViewModel, imageryProviderViewModels[0] ); this.selectedTerrain = defaultValue( options.selectedTerrainProviderViewModel, terrainProviderViewModels[0] ); } Object.defineProperties(BaseLayerPickerViewModel.prototype, { /** * Gets the command to toggle the visibility of the drop down. * @memberof BaseLayerPickerViewModel.prototype * * @type {Command} */ toggleDropDown: { get: function () { return this._toggleDropDown; }, }, /** * Gets the globe. * @memberof BaseLayerPickerViewModel.prototype * * @type {Globe} */ globe: { get: function () { return this._globe; }, }, }); export default BaseLayerPickerViewModel;