智慧水务管理系统 - 精河县供水工程综合管理平台

BaseLayerPickerViewModel.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. import {
  2. Frozen,
  3. defined,
  4. DeveloperError,
  5. EllipsoidTerrainProvider,
  6. ImageryLayer,
  7. Terrain,
  8. } from "@cesium/engine";
  9. import knockout from "../ThirdParty/knockout.js";
  10. import createCommand from "../createCommand.js";
  11. /**
  12. * The view model for {@link BaseLayerPicker}.
  13. * @alias BaseLayerPickerViewModel
  14. * @constructor
  15. *
  16. * @param {object} options Object with the following properties:
  17. * @param {Globe} options.globe The Globe to use.
  18. * @param {ProviderViewModel[]} [options.imageryProviderViewModels=[]] The array of ProviderViewModel instances to use for imagery.
  19. * @param {ProviderViewModel} [options.selectedImageryProviderViewModel] The view model for the current base imagery layer, if not supplied the first available imagery layer is used.
  20. * @param {ProviderViewModel[]} [options.terrainProviderViewModels=[]] The array of ProviderViewModel instances to use for terrain.
  21. * @param {ProviderViewModel} [options.selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available terrain layer is used.
  22. *
  23. * @exception {DeveloperError} imageryProviderViewModels must be an array.
  24. * @exception {DeveloperError} terrainProviderViewModels must be an array.
  25. */
  26. function BaseLayerPickerViewModel(options) {
  27. options = options ?? Frozen.EMPTY_OBJECT;
  28. const globe = options.globe;
  29. const imageryProviderViewModels =
  30. options.imageryProviderViewModels ?? Frozen.EMPTY_ARRAY;
  31. const terrainProviderViewModels =
  32. options.terrainProviderViewModels ?? Frozen.EMPTY_ARRAY;
  33. //>>includeStart('debug', pragmas.debug);
  34. if (!defined(globe)) {
  35. throw new DeveloperError("globe is required");
  36. }
  37. //>>includeEnd('debug');
  38. this._globe = globe;
  39. /**
  40. * Gets or sets an array of ProviderViewModel instances available for imagery selection.
  41. * This property is observable.
  42. * @type {ProviderViewModel[]}
  43. */
  44. this.imageryProviderViewModels = imageryProviderViewModels.slice(0);
  45. /**
  46. * Gets or sets an array of ProviderViewModel instances available for terrain selection.
  47. * This property is observable.
  48. * @type {ProviderViewModel[]}
  49. */
  50. this.terrainProviderViewModels = terrainProviderViewModels.slice(0);
  51. /**
  52. * Gets or sets whether the imagery selection drop-down is currently visible.
  53. * @type {boolean}
  54. * @default false
  55. */
  56. this.dropDownVisible = false;
  57. knockout.track(this, [
  58. "imageryProviderViewModels",
  59. "terrainProviderViewModels",
  60. "dropDownVisible",
  61. ]);
  62. const imageryObservable = knockout.getObservable(
  63. this,
  64. "imageryProviderViewModels",
  65. );
  66. const imageryProviders = knockout.pureComputed(function () {
  67. const providers = imageryObservable();
  68. const categories = {};
  69. let i;
  70. for (i = 0; i < providers.length; i++) {
  71. const provider = providers[i];
  72. const category = provider.category;
  73. if (defined(categories[category])) {
  74. categories[category].push(provider);
  75. } else {
  76. categories[category] = [provider];
  77. }
  78. }
  79. const allCategoryNames = Object.keys(categories);
  80. const result = [];
  81. for (i = 0; i < allCategoryNames.length; i++) {
  82. const name = allCategoryNames[i];
  83. result.push({
  84. name: name,
  85. providers: categories[name],
  86. });
  87. }
  88. return result;
  89. });
  90. this._imageryProviders = imageryProviders;
  91. const terrainObservable = knockout.getObservable(
  92. this,
  93. "terrainProviderViewModels",
  94. );
  95. const terrainProviders = knockout.pureComputed(function () {
  96. const providers = terrainObservable();
  97. const categories = {};
  98. let i;
  99. for (i = 0; i < providers.length; i++) {
  100. const provider = providers[i];
  101. const category = provider.category;
  102. if (defined(categories[category])) {
  103. categories[category].push(provider);
  104. } else {
  105. categories[category] = [provider];
  106. }
  107. }
  108. const allCategoryNames = Object.keys(categories);
  109. const result = [];
  110. for (i = 0; i < allCategoryNames.length; i++) {
  111. const name = allCategoryNames[i];
  112. result.push({
  113. name: name,
  114. providers: categories[name],
  115. });
  116. }
  117. return result;
  118. });
  119. this._terrainProviders = terrainProviders;
  120. /**
  121. * Gets the button tooltip. This property is observable.
  122. * @type {string}
  123. */
  124. this.buttonTooltip = undefined;
  125. knockout.defineProperty(this, "buttonTooltip", function () {
  126. const selectedImagery = this.selectedImagery;
  127. const selectedTerrain = this.selectedTerrain;
  128. const imageryTip = defined(selectedImagery)
  129. ? selectedImagery.name
  130. : undefined;
  131. const terrainTip = defined(selectedTerrain)
  132. ? selectedTerrain.name
  133. : undefined;
  134. if (defined(imageryTip) && defined(terrainTip)) {
  135. return `${imageryTip}\n${terrainTip}`;
  136. } else if (defined(imageryTip)) {
  137. return imageryTip;
  138. }
  139. return terrainTip;
  140. });
  141. /**
  142. * Gets the button background image. This property is observable.
  143. * @type {string}
  144. */
  145. this.buttonImageUrl = undefined;
  146. knockout.defineProperty(this, "buttonImageUrl", function () {
  147. const selectedImagery = this.selectedImagery;
  148. if (defined(selectedImagery)) {
  149. return selectedImagery.iconUrl;
  150. }
  151. });
  152. /**
  153. * Gets or sets the currently selected imagery. This property is observable.
  154. * @type {ProviderViewModel}
  155. * @default undefined
  156. */
  157. this.selectedImagery = undefined;
  158. const selectedImageryViewModel = knockout.observable();
  159. this._currentImageryLayers = [];
  160. knockout.defineProperty(this, "selectedImagery", {
  161. get: function () {
  162. return selectedImageryViewModel();
  163. },
  164. set: function (value) {
  165. if (selectedImageryViewModel() === value) {
  166. this.dropDownVisible = false;
  167. return;
  168. }
  169. let i;
  170. const currentImageryLayers = this._currentImageryLayers;
  171. const currentImageryLayersLength = currentImageryLayers.length;
  172. const imageryLayers = this._globe.imageryLayers;
  173. let hadExistingBaseLayer = false;
  174. for (i = 0; i < currentImageryLayersLength; i++) {
  175. const layersLength = imageryLayers.length;
  176. for (let x = 0; x < layersLength; x++) {
  177. const layer = imageryLayers.get(x);
  178. if (layer === currentImageryLayers[i]) {
  179. imageryLayers.remove(layer);
  180. hadExistingBaseLayer = true;
  181. break;
  182. }
  183. }
  184. }
  185. if (defined(value)) {
  186. const newProviders = value.creationCommand();
  187. if (Array.isArray(newProviders)) {
  188. const newProvidersLength = newProviders.length;
  189. this._currentImageryLayers = [];
  190. for (i = newProvidersLength - 1; i >= 0; i--) {
  191. const layer = ImageryLayer.fromProviderAsync(newProviders[i]);
  192. imageryLayers.add(layer, 0);
  193. this._currentImageryLayers.push(layer);
  194. }
  195. } else {
  196. this._currentImageryLayers = [];
  197. const layer = ImageryLayer.fromProviderAsync(newProviders);
  198. layer.name = value.name;
  199. if (hadExistingBaseLayer) {
  200. imageryLayers.add(layer, 0);
  201. } else {
  202. const baseLayer = imageryLayers.get(0);
  203. if (defined(baseLayer)) {
  204. imageryLayers.remove(baseLayer);
  205. }
  206. imageryLayers.add(layer, 0);
  207. }
  208. this._currentImageryLayers.push(layer);
  209. }
  210. }
  211. selectedImageryViewModel(value);
  212. this.dropDownVisible = false;
  213. },
  214. });
  215. /**
  216. * Gets or sets the currently selected terrain. This property is observable.
  217. * @type {ProviderViewModel}
  218. * @default undefined
  219. */
  220. this.selectedTerrain = undefined;
  221. const selectedTerrainViewModel = knockout.observable();
  222. knockout.defineProperty(this, "selectedTerrain", {
  223. get: function () {
  224. return selectedTerrainViewModel();
  225. },
  226. set: function (value) {
  227. if (selectedTerrainViewModel() === value) {
  228. this.dropDownVisible = false;
  229. return;
  230. }
  231. let newProvider;
  232. if (defined(value)) {
  233. newProvider = value.creationCommand();
  234. }
  235. // If this is not a promise, we must set this synchronously to avoid overriding depthTestAgainstTerrain
  236. // See https://github.com/CesiumGS/cesium/issues/6991
  237. if (defined(newProvider) && !defined(newProvider.then)) {
  238. this._globe.depthTestAgainstTerrain = !(
  239. newProvider instanceof EllipsoidTerrainProvider
  240. );
  241. this._globe.terrainProvider = newProvider;
  242. } else if (defined(newProvider)) {
  243. let cancelUpdate = false;
  244. const removeCancelListener =
  245. this._globe.terrainProviderChanged.addEventListener(() => {
  246. cancelUpdate = true;
  247. removeCancelListener();
  248. });
  249. const terrain = new Terrain(newProvider);
  250. const removeEventListener = terrain.readyEvent.addEventListener(
  251. (terrainProvider) => {
  252. if (cancelUpdate) {
  253. // Early return in case something has changed outside of the picker.
  254. return;
  255. }
  256. this._globe.depthTestAgainstTerrain = !(
  257. terrainProvider instanceof EllipsoidTerrainProvider
  258. );
  259. this._globe.terrainProvider = terrainProvider;
  260. removeEventListener();
  261. },
  262. );
  263. }
  264. selectedTerrainViewModel(value);
  265. this.dropDownVisible = false;
  266. },
  267. });
  268. const that = this;
  269. this._toggleDropDown = createCommand(function () {
  270. that.dropDownVisible = !that.dropDownVisible;
  271. });
  272. this.selectedImagery =
  273. options.selectedImageryProviderViewModel ?? imageryProviderViewModels[0];
  274. this.selectedTerrain = options.selectedTerrainProviderViewModel;
  275. }
  276. Object.defineProperties(BaseLayerPickerViewModel.prototype, {
  277. /**
  278. * Gets the command to toggle the visibility of the drop down.
  279. * @memberof BaseLayerPickerViewModel.prototype
  280. *
  281. * @type {Command}
  282. */
  283. toggleDropDown: {
  284. get: function () {
  285. return this._toggleDropDown;
  286. },
  287. },
  288. /**
  289. * Gets the globe.
  290. * @memberof BaseLayerPickerViewModel.prototype
  291. *
  292. * @type {Globe}
  293. */
  294. globe: {
  295. get: function () {
  296. return this._globe;
  297. },
  298. },
  299. });
  300. export default BaseLayerPickerViewModel;