layer/layerRec/layerInterface.js

  1. 'use strict';
  2. // Controls Interface class is used to provide something to the UI that it can bind to.
  3. // It helps the UI keep in line with the layer state.
  4. // Due to bindings, we cannot destroy & recreate an interface when a legend item
  5. // goes from 'Unknown Placeholder' to 'Specific Layer Type'. This means we cannot
  6. // do object heirarchies, as to go from PlaceholderInterface to FeatureLayerInterface
  7. // would require a new object. Instead, we have a class that exposes all possible
  8. // methods and properties as error throwing stubs. Then we replace those functions
  9. // with real ones once we know the flavour of interface we want.
  10. class LayerInterface {
  11. /**
  12. * @param {Object} source object that provides info to the interface. usually a LayerRecord or FeatureClass
  13. */
  14. constructor (source) {
  15. this._source = source;
  16. // TODO revisit isPlaceholder after grand refactor
  17. this._isPlaceholder = true;
  18. }
  19. get isPlaceholder () { return this._isPlaceholder; } // returns Boolean
  20. // these expose ui controls available on the interface and indicate which ones are disabled
  21. get symbology () { return undefined; } // returns Array
  22. // can be group or node name
  23. get name () { return undefined; } // returns String
  24. // these are needed for the type flag
  25. get layerType () { return undefined; } // returns String
  26. get geometryType () { return undefined; } // returns String
  27. get featureCount () { return undefined; } // returns Integer
  28. get extent () { return undefined; } // returns Object (Esri Extent)
  29. // layer states
  30. get state () { return undefined; } // returns String
  31. // these return the current values of the corresponding controls
  32. get visibility () { return undefined; } // returns Boolean
  33. get opacity () { return undefined; } // returns Decimal
  34. get query () { return undefined; } // returns Boolean
  35. get snapshot () { return undefined; } // returns Boolean
  36. get highlightFeature () { return undefined; } // returns Boolean
  37. // fetches attributes for use in the datatable
  38. get formattedAttributes () { return undefined; } // returns Promise of Object
  39. // returns a feature name of an attribute set
  40. getFeatureName () { return undefined; } // returns String
  41. // formats an attribute to standard details
  42. attributesToDetails () { return undefined; } // returns Array
  43. // these set values to the corresponding controls
  44. // param: boolean
  45. setVisibility () { return undefined; }
  46. // param: numeric (between 0 and 1)
  47. setOpacity () { return undefined; }
  48. // param: boolean
  49. setQuery () { return undefined; }
  50. // param: integer, boolean (optional)
  51. fetchGraphic () { return undefined; } // returns promise that resolves with object containing graphics info
  52. // param: esriMap
  53. zoomToBoundary () { return undefined; } // returns promise that resolves after zoom completes
  54. // param: esriMap, array of lods, boolean, optional boolean
  55. zoomToScale () { return undefined; } // returns promise that resolves after zoom completes
  56. // param: Integer, esriMap, Object {x: Numeric, y: Numeric}
  57. zoomToGraphic () { return undefined; } // returns promise that resolves after zoom completes
  58. // param: string
  59. setDefinitionQuery () { return undefined; }
  60. // param: spatialReference object
  61. validateProjection () { return undefined; } // returns Boolean
  62. // param: integer
  63. isOffScale () { return undefined; } // returns Object {offScale: Boolean, zoomIn: Boolean}
  64. // updates what this interface is pointing to, in terms of layer data source.
  65. // often, the interface starts with a placeholder to avoid errors and return
  66. // defaults. This update happens after a layer has loaded, and new now want
  67. // the interface reading off the real FC.
  68. // TODO docs
  69. updateSource (newSource) {
  70. this._source = newSource;
  71. }
  72. convertToSingleLayer (layerRecord) {
  73. this._source = layerRecord;
  74. this._isPlaceholder = false;
  75. newProp(this, 'symbology', standardGetSymbology);
  76. newProp(this, 'state', standardGetState);
  77. newProp(this, 'visibility', standardGetVisibility);
  78. newProp(this, 'opacity', standardGetOpacity);
  79. newProp(this, 'query', standardGetQuery);
  80. newProp(this, 'name', standardGetName);
  81. newProp(this, 'geometryType', standardGetGeometryType);
  82. newProp(this, 'layerType', standardGetLayerType);
  83. newProp(this, 'featureCount', standardGetFeatureCount);
  84. newProp(this, 'extent', standardGetExtent);
  85. this.setVisibility = standardSetVisibility;
  86. this.setOpacity = standardSetOpacity;
  87. this.setQuery = standardSetQuery;
  88. this.zoomToBoundary = standardZoomToBoundary;
  89. this.validateProjection = standardValidateProjection;
  90. this.zoomToScale = standardZoomToScale;
  91. this.isOffScale = standardIsOffScale;
  92. }
  93. convertToFeatureLayer (layerRecord) {
  94. this.convertToSingleLayer(layerRecord);
  95. newProp(this, 'snapshot', featureGetSnapshot);
  96. newProp(this, 'formattedAttributes', standardGetFormattedAttributes);
  97. newProp(this, 'geometryType', featureGetGeometryType);
  98. newProp(this, 'featureCount', featureGetFeatureCount);
  99. newProp(this, 'highlightFeature', featureGetHighlightFeature);
  100. this.getFeatureName = featureGetFeatureName;
  101. this.attributesToDetails = featureAttributesToDetails;
  102. this.fetchGraphic = featureFetchGraphic;
  103. this.setDefinitionQuery = featureSetDefinitionQuery;
  104. this.zoomToGraphic = featureZoomToGraphic;
  105. }
  106. convertToDynamicLeaf (dynamicFC) {
  107. this._source = dynamicFC;
  108. this._isPlaceholder = false;
  109. newProp(this, 'symbology', dynamicLeafGetSymbology);
  110. newProp(this, 'state', dynamicLeafGetState);
  111. newProp(this, 'name', dynamicLeafGetName);
  112. newProp(this, 'visibility', dynamicLeafGetVisibility);
  113. newProp(this, 'opacity', dynamicLeafGetOpacity);
  114. newProp(this, 'query', dynamicLeafGetQuery);
  115. newProp(this, 'formattedAttributes', dynamicLeafGetFormattedAttributes);
  116. newProp(this, 'geometryType', dynamicLeafGetGeometryType);
  117. newProp(this, 'layerType', dynamicLeafGetLayerType);
  118. newProp(this, 'featureCount', dynamicLeafGetFeatureCount);
  119. newProp(this, 'extent', dynamicLeafGetExtent);
  120. newProp(this, 'highlightFeature', dynamicLeafGetHighlightFeature);
  121. this.setVisibility = dynamicLeafSetVisibility;
  122. this.setOpacity = dynamicLeafSetOpacity;
  123. this.setQuery = dynamicLeafSetQuery;
  124. this.zoomToBoundary = dynamicLeafZoomToBoundary;
  125. this.zoomToScale = dynamicLeafZoomToScale;
  126. this.getFeatureName = featureGetFeatureName;
  127. this.attributesToDetails = dynamicLeafAttributesToDetails;
  128. this.fetchGraphic = dynamicLeafFetchGraphic;
  129. this.setDefinitionQuery = dynamicLeafSetDefinitionQuery;
  130. this.isOffScale = dynamicLeafIsOffScale;
  131. this.zoomToGraphic = dynamicLeafZoomToGraphic;
  132. }
  133. convertToPlaceholder (placeholderFC) {
  134. this._source = placeholderFC;
  135. this._isPlaceholder = true;
  136. newProp(this, 'symbology', standardGetSymbology);
  137. newProp(this, 'name', standardGetName);
  138. newProp(this, 'state', standardGetState);
  139. newProp(this, 'layerType', standardGetLayerType);
  140. }
  141. // TODO we might need a `converToDynamicLayer`. It calls `converToSingleLayer` and then
  142. // removes zoomToScale method, as this method will fail if called directly on a
  143. // dynamic layer proxy. As is, nothing should ever make that call. But we can
  144. // do this to be safe.
  145. }
  146. /**
  147. * Worker function to add or override a get property on an object
  148. *
  149. * @function newProp
  150. * @private
  151. * @param {Object} target the object that will receive the new property
  152. * @param {String} propName name of the get property
  153. * @param {Function} getter the function defining the guts of the get property.
  154. */
  155. function newProp(target, propName, getter) {
  156. Object.defineProperty(target, propName, {
  157. get: getter,
  158. enumerable: true,
  159. configurable: true
  160. });
  161. }
  162. // these functions are upgrades to the duds above.
  163. // we don't use arrow notation, as we want the `this` to point at the object
  164. // that these functions get smashed into.
  165. function standardGetState() {
  166. /* jshint validthis: true */
  167. return this._source.state;
  168. }
  169. function dynamicLeafGetState() {
  170. /* jshint validthis: true */
  171. return this._source.state;
  172. }
  173. function standardGetVisibility() {
  174. /* jshint validthis: true */
  175. return this._source.visibility;
  176. }
  177. function dynamicLeafGetVisibility() {
  178. /* jshint validthis: true */
  179. return this._source.getVisibility();
  180. }
  181. function standardGetName() {
  182. /* jshint validthis: true */
  183. return this._source.name;
  184. }
  185. function dynamicLeafGetName() {
  186. /* jshint validthis: true */
  187. return this._source.name;
  188. }
  189. function standardGetOpacity() {
  190. /* jshint validthis: true */
  191. return this._source.opacity;
  192. }
  193. function dynamicLeafGetOpacity() {
  194. /* jshint validthis: true */
  195. return this._source.opacity;
  196. }
  197. function standardGetLayerType() {
  198. /* jshint validthis: true */
  199. return this._source.layerType;
  200. }
  201. function dynamicLeafGetLayerType() {
  202. /* jshint validthis: true */
  203. return this._source.layerType;
  204. }
  205. function standardGetExtent() {
  206. /* jshint validthis: true */
  207. return this._source.extent;
  208. }
  209. function dynamicLeafGetExtent() {
  210. /* jshint validthis: true */
  211. return this._source.extent;
  212. }
  213. function standardGetQuery() {
  214. /* jshint validthis: true */
  215. return this._source.isQueryable();
  216. }
  217. function dynamicLeafGetQuery() {
  218. /* jshint validthis: true */
  219. return this._source.queryable;
  220. }
  221. function standardGetFormattedAttributes() {
  222. /* jshint validthis: true */
  223. return this._source.getFormattedAttributes();
  224. }
  225. function dynamicLeafGetFormattedAttributes() {
  226. /* jshint validthis: true */
  227. // TODO code-wise this looks identical to standardGetFormattedAttributes.
  228. // however in this case, ._source is a DynamicFC, not a LayerRecord.
  229. // This is safer. Deleting this would avoid the duplication. Decide.
  230. return this._source.getFormattedAttributes();
  231. }
  232. function standardGetSymbology() {
  233. /* jshint validthis: true */
  234. return this._source.symbology;
  235. }
  236. function dynamicLeafGetSymbology() {
  237. /* jshint validthis: true */
  238. // TODO code-wise this looks identical to standardGetSymbology.
  239. // however in this case, ._source is a DynamicFC, not a LayerRecord.
  240. // This is safer. Deleting this would avoid the duplication. Decide.
  241. return this._source.symbology;
  242. }
  243. function standardGetGeometryType() {
  244. /* jshint validthis: true */
  245. return undefined;
  246. }
  247. function featureGetGeometryType() {
  248. /* jshint validthis: true */
  249. return this._source.getGeomType();
  250. }
  251. function dynamicLeafGetGeometryType() {
  252. /* jshint validthis: true */
  253. // TEST STATUS none
  254. return this._source.geomType;
  255. }
  256. function standardGetFeatureCount() {
  257. /* jshint validthis: true */
  258. return undefined;
  259. }
  260. function featureGetFeatureCount() {
  261. /* jshint validthis: true */
  262. return this._source.featureCount;
  263. }
  264. function dynamicLeafGetFeatureCount() {
  265. /* jshint validthis: true */
  266. return this._source.featureCount;
  267. }
  268. function standardSetVisibility(value) {
  269. /* jshint validthis: true */
  270. this._source.visibility = value;
  271. }
  272. function dynamicLeafSetVisibility(value) {
  273. /* jshint validthis: true */
  274. this._source.setVisibility(value);
  275. }
  276. function standardSetOpacity(value) {
  277. /* jshint validthis: true */
  278. this._source.opacity = value;
  279. }
  280. function dynamicLeafSetOpacity(value) {
  281. /* jshint validthis: true */
  282. this._source.opacity = value;
  283. }
  284. function standardSetQuery(value) {
  285. /* jshint validthis: true */
  286. this._source.setQueryable(value);
  287. }
  288. function dynamicLeafSetQuery(value) {
  289. /* jshint validthis: true */
  290. this._source.queryable = value;
  291. }
  292. function featureGetSnapshot() {
  293. /* jshint validthis: true */
  294. return this._source.isSnapshot;
  295. }
  296. function featureGetHighlightFeature() {
  297. return true;
  298. }
  299. function dynamicLeafGetHighlightFeature() {
  300. /* jshint validthis: true */
  301. return this._source.highlightFeature;
  302. }
  303. function standardZoomToBoundary(map) {
  304. /* jshint validthis: true */
  305. this._source.zoomToBoundary(map);
  306. }
  307. function dynamicLeafZoomToBoundary(map) {
  308. /* jshint validthis: true */
  309. this._source.zoomToBoundary(map);
  310. }
  311. function standardZoomToScale(map, lods, zoomIn, positionOverLayer = true) {
  312. /* jshint validthis: true */
  313. return this._source.zoomToScale(map, lods, zoomIn, positionOverLayer);
  314. }
  315. function dynamicLeafZoomToScale(map, lods, zoomIn, positionOverLayer = true) {
  316. /* jshint validthis: true */
  317. return this._source.zoomToScale(map, lods, zoomIn, positionOverLayer);
  318. }
  319. function featureGetFeatureName(objId, attribs) {
  320. /* jshint validthis: true */
  321. return this._source.getFeatureName(objId, attribs);
  322. }
  323. function featureAttributesToDetails(attribs, fields) {
  324. /* jshint validthis: true */
  325. return this._source.attributesToDetails(attribs, fields);
  326. }
  327. function dynamicLeafAttributesToDetails(attribs, fields) {
  328. /* jshint validthis: true */
  329. return this._source._parent.attributesToDetails(attribs, fields);
  330. }
  331. function featureFetchGraphic(oid, ignoreLocal = false) {
  332. /* jshint validthis: true */
  333. return this._source.fetchGraphic(oid, ignoreLocal);
  334. }
  335. function dynamicLeafFetchGraphic(oid, ignoreLocal = false) {
  336. /* jshint validthis: true */
  337. return this._source.fetchGraphic(oid, ignoreLocal);
  338. }
  339. function featureZoomToGraphic(oid, map, offsetFraction) {
  340. /* jshint validthis: true */
  341. return this._source.zoomToGraphic(oid, map, offsetFraction);
  342. }
  343. function dynamicLeafZoomToGraphic(oid, map, offsetFraction) {
  344. /* jshint validthis: true */
  345. return this._source.zoomToGraphic(oid, map, offsetFraction);
  346. }
  347. function featureSetDefinitionQuery(query) {
  348. /* jshint validthis: true */
  349. this._source.setDefinitionQuery(query);
  350. }
  351. function dynamicLeafSetDefinitionQuery(query) {
  352. /* jshint validthis: true */
  353. this._source.setDefinitionQuery(query);
  354. }
  355. function standardValidateProjection(spatialReference) {
  356. /* jshint validthis: true */
  357. return this._source.validateProjection(spatialReference);
  358. }
  359. function standardIsOffScale(mapScale) {
  360. /* jshint validthis: true */
  361. return this._source.isOffScale(mapScale);
  362. }
  363. function dynamicLeafIsOffScale(mapScale) {
  364. /* jshint validthis: true */
  365. return this._source.isOffScale(mapScale);
  366. }
  367. module.exports = () => ({
  368. LayerInterface
  369. });