DataSourceCollection.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. import defaultValue from "../Core/defaultValue.js";
  2. import defined from "../Core/defined.js";
  3. import destroyObject from "../Core/destroyObject.js";
  4. import DeveloperError from "../Core/DeveloperError.js";
  5. import Event from "../Core/Event.js";
  6. import CesiumMath from "../Core/Math.js";
  7. /**
  8. * A collection of {@link DataSource} instances.
  9. * @alias DataSourceCollection
  10. * @constructor
  11. */
  12. function DataSourceCollection() {
  13. this._dataSources = [];
  14. this._dataSourceAdded = new Event();
  15. this._dataSourceRemoved = new Event();
  16. this._dataSourceMoved = new Event();
  17. }
  18. Object.defineProperties(DataSourceCollection.prototype, {
  19. /**
  20. * Gets the number of data sources in this collection.
  21. * @memberof DataSourceCollection.prototype
  22. * @type {number}
  23. * @readonly
  24. */
  25. length: {
  26. get: function () {
  27. return this._dataSources.length;
  28. },
  29. },
  30. /**
  31. * An event that is raised when a data source is added to the collection.
  32. * Event handlers are passed the data source that was added.
  33. * @memberof DataSourceCollection.prototype
  34. * @type {Event}
  35. * @readonly
  36. */
  37. dataSourceAdded: {
  38. get: function () {
  39. return this._dataSourceAdded;
  40. },
  41. },
  42. /**
  43. * An event that is raised when a data source is removed from the collection.
  44. * Event handlers are passed the data source that was removed.
  45. * @memberof DataSourceCollection.prototype
  46. * @type {Event}
  47. * @readonly
  48. */
  49. dataSourceRemoved: {
  50. get: function () {
  51. return this._dataSourceRemoved;
  52. },
  53. },
  54. /**
  55. * An event that is raised when a data source changes position in the collection. Event handlers are passed the data source
  56. * that was moved, its new index after the move, and its old index prior to the move.
  57. * @memberof DataSourceCollection.prototype
  58. * @type {Event}
  59. * @readonly
  60. */
  61. dataSourceMoved: {
  62. get: function () {
  63. return this._dataSourceMoved;
  64. },
  65. },
  66. });
  67. /**
  68. * Adds a data source to the collection.
  69. *
  70. * @param {DataSource|Promise<DataSource>} dataSource A data source or a promise to a data source to add to the collection.
  71. * When passing a promise, the data source will not actually be added
  72. * to the collection until the promise resolves successfully.
  73. * @returns {Promise<DataSource>} A Promise that resolves once the data source has been added to the collection.
  74. */
  75. DataSourceCollection.prototype.add = function (dataSource) {
  76. //>>includeStart('debug', pragmas.debug);
  77. if (!defined(dataSource)) {
  78. throw new DeveloperError("dataSource is required.");
  79. }
  80. //>>includeEnd('debug');
  81. const that = this;
  82. const dataSources = this._dataSources;
  83. return Promise.resolve(dataSource).then(function (value) {
  84. //Only add the data source if removeAll has not been called
  85. //Since it was added.
  86. if (dataSources === that._dataSources) {
  87. that._dataSources.push(value);
  88. that._dataSourceAdded.raiseEvent(that, value);
  89. }
  90. return value;
  91. });
  92. };
  93. /**
  94. * Removes a data source from this collection, if present.
  95. *
  96. * @param {DataSource} dataSource The data source to remove.
  97. * @param {boolean} [destroy=false] Whether to destroy the data source in addition to removing it.
  98. * @returns {boolean} true if the data source was in the collection and was removed,
  99. * false if the data source was not in the collection.
  100. */
  101. DataSourceCollection.prototype.remove = function (dataSource, destroy) {
  102. destroy = defaultValue(destroy, false);
  103. const index = this._dataSources.indexOf(dataSource);
  104. if (index !== -1) {
  105. this._dataSources.splice(index, 1);
  106. this._dataSourceRemoved.raiseEvent(this, dataSource);
  107. if (destroy && typeof dataSource.destroy === "function") {
  108. dataSource.destroy();
  109. }
  110. return true;
  111. }
  112. return false;
  113. };
  114. /**
  115. * Removes all data sources from this collection.
  116. *
  117. * @param {boolean} [destroy=false] whether to destroy the data sources in addition to removing them.
  118. */
  119. DataSourceCollection.prototype.removeAll = function (destroy) {
  120. destroy = defaultValue(destroy, false);
  121. const dataSources = this._dataSources;
  122. for (let i = 0, len = dataSources.length; i < len; ++i) {
  123. const dataSource = dataSources[i];
  124. this._dataSourceRemoved.raiseEvent(this, dataSource);
  125. if (destroy && typeof dataSource.destroy === "function") {
  126. dataSource.destroy();
  127. }
  128. }
  129. this._dataSources = [];
  130. };
  131. /**
  132. * Checks to see if the collection contains a given data source.
  133. *
  134. * @param {DataSource} dataSource The data source to check for.
  135. * @returns {boolean} true if the collection contains the data source, false otherwise.
  136. */
  137. DataSourceCollection.prototype.contains = function (dataSource) {
  138. return this.indexOf(dataSource) !== -1;
  139. };
  140. /**
  141. * Determines the index of a given data source in the collection.
  142. *
  143. * @param {DataSource} dataSource The data source to find the index of.
  144. * @returns {number} The index of the data source in the collection, or -1 if the data source does not exist in the collection.
  145. */
  146. DataSourceCollection.prototype.indexOf = function (dataSource) {
  147. return this._dataSources.indexOf(dataSource);
  148. };
  149. /**
  150. * Gets a data source by index from the collection.
  151. *
  152. * @param {number} index the index to retrieve.
  153. * @returns {DataSource} The data source at the specified index.
  154. */
  155. DataSourceCollection.prototype.get = function (index) {
  156. //>>includeStart('debug', pragmas.debug);
  157. if (!defined(index)) {
  158. throw new DeveloperError("index is required.");
  159. }
  160. //>>includeEnd('debug');
  161. return this._dataSources[index];
  162. };
  163. /**
  164. * Gets a data source by name from the collection.
  165. *
  166. * @param {string} name The name to retrieve.
  167. * @returns {DataSource[]} A list of all data sources matching the provided name.
  168. */
  169. DataSourceCollection.prototype.getByName = function (name) {
  170. //>>includeStart('debug', pragmas.debug);
  171. if (!defined(name)) {
  172. throw new DeveloperError("name is required.");
  173. }
  174. //>>includeEnd('debug');
  175. return this._dataSources.filter(function (dataSource) {
  176. return dataSource.name === name;
  177. });
  178. };
  179. function getIndex(dataSources, dataSource) {
  180. //>>includeStart('debug', pragmas.debug);
  181. if (!defined(dataSource)) {
  182. throw new DeveloperError("dataSource is required.");
  183. }
  184. //>>includeEnd('debug');
  185. const index = dataSources.indexOf(dataSource);
  186. //>>includeStart('debug', pragmas.debug);
  187. if (index === -1) {
  188. throw new DeveloperError("dataSource is not in this collection.");
  189. }
  190. //>>includeEnd('debug');
  191. return index;
  192. }
  193. function swapDataSources(collection, i, j) {
  194. const arr = collection._dataSources;
  195. const length = arr.length - 1;
  196. i = CesiumMath.clamp(i, 0, length);
  197. j = CesiumMath.clamp(j, 0, length);
  198. if (i === j) {
  199. return;
  200. }
  201. const temp = arr[i];
  202. arr[i] = arr[j];
  203. arr[j] = temp;
  204. collection.dataSourceMoved.raiseEvent(temp, j, i);
  205. }
  206. /**
  207. * Raises a data source up one position in the collection.
  208. *
  209. * @param {DataSource} dataSource The data source to move.
  210. *
  211. * @exception {DeveloperError} dataSource is not in this collection.
  212. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  213. */
  214. DataSourceCollection.prototype.raise = function (dataSource) {
  215. const index = getIndex(this._dataSources, dataSource);
  216. swapDataSources(this, index, index + 1);
  217. };
  218. /**
  219. * Lowers a data source down one position in the collection.
  220. *
  221. * @param {DataSource} dataSource The data source to move.
  222. *
  223. * @exception {DeveloperError} dataSource is not in this collection.
  224. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  225. */
  226. DataSourceCollection.prototype.lower = function (dataSource) {
  227. const index = getIndex(this._dataSources, dataSource);
  228. swapDataSources(this, index, index - 1);
  229. };
  230. /**
  231. * Raises a data source to the top of the collection.
  232. *
  233. * @param {DataSource} dataSource The data source to move.
  234. *
  235. * @exception {DeveloperError} dataSource is not in this collection.
  236. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  237. */
  238. DataSourceCollection.prototype.raiseToTop = function (dataSource) {
  239. const index = getIndex(this._dataSources, dataSource);
  240. if (index === this._dataSources.length - 1) {
  241. return;
  242. }
  243. this._dataSources.splice(index, 1);
  244. this._dataSources.push(dataSource);
  245. this.dataSourceMoved.raiseEvent(
  246. dataSource,
  247. this._dataSources.length - 1,
  248. index
  249. );
  250. };
  251. /**
  252. * Lowers a data source to the bottom of the collection.
  253. *
  254. * @param {DataSource} dataSource The data source to move.
  255. *
  256. * @exception {DeveloperError} dataSource is not in this collection.
  257. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  258. */
  259. DataSourceCollection.prototype.lowerToBottom = function (dataSource) {
  260. const index = getIndex(this._dataSources, dataSource);
  261. if (index === 0) {
  262. return;
  263. }
  264. this._dataSources.splice(index, 1);
  265. this._dataSources.splice(0, 0, dataSource);
  266. this.dataSourceMoved.raiseEvent(dataSource, 0, index);
  267. };
  268. /**
  269. * Returns true if this object was destroyed; otherwise, false.
  270. * If this object was destroyed, it should not be used; calling any function other than
  271. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  272. *
  273. * @returns {boolean} true if this object was destroyed; otherwise, false.
  274. *
  275. * @see DataSourceCollection#destroy
  276. */
  277. DataSourceCollection.prototype.isDestroyed = function () {
  278. return false;
  279. };
  280. /**
  281. * Destroys the resources held by all data sources in this collection. Explicitly destroying this
  282. * object allows for deterministic release of WebGL resources, instead of relying on the garbage
  283. * collector. Once this object is destroyed, it should not be used; calling any function other than
  284. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  285. * assign the return value (<code>undefined</code>) to the object as done in the example.
  286. *
  287. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  288. *
  289. *
  290. * @example
  291. * dataSourceCollection = dataSourceCollection && dataSourceCollection.destroy();
  292. *
  293. * @see DataSourceCollection#isDestroyed
  294. */
  295. DataSourceCollection.prototype.destroy = function () {
  296. this.removeAll(true);
  297. return destroyObject(this);
  298. };
  299. export default DataSourceCollection;