Source: map/layer/GeoJSONLayer/GeoJSONLayer.js

  1. import { Layer } from "../Layer/Layer.js";
  2. import { saveAsFile } from "../../../utils/utils.js";
  3. import { GeoJSONLayerProxy } from "./GeoJSONLayer.proxy.js";
  4. import { GeoJSONLayerProxyLeaflet } from "./GeoJSONLayer.proxy.leaflet.js";
  5. import { EventManager } from "../../../events/EventManager.js";
  6. import { GeoJSONLayerSchema } from './GeoJSONLayer.schema.js';
  7. export { GeoJSONLayer }
  8. /**
  9. * GeoJSON Layer Implementation
  10. *
  11. * @author rhess <robin.hess@awi.de>
  12. * @memberof vef.map.layer
  13. */
  14. class GeoJSONLayer extends Layer {
  15. /**
  16. * Set all properties for the layer based on the options object.
  17. *
  18. * @param {object} config
  19. * @param {object} cache
  20. * @param {string} id
  21. */
  22. constructor(config, cache, id) {
  23. // calling parent constructor
  24. super(config, cache, id);
  25. this.setSchema_(GeoJSONLayerSchema.getSchema());
  26. // framework specific map implementations
  27. this.layerProxies_.leaflet = GeoJSONLayerProxyLeaflet;
  28. this.activeLayer_ = new GeoJSONLayerProxy();
  29. this.previousActiveLayer_ = null;
  30. }
  31. /**
  32. * create a map layer based on the service options
  33. *
  34. * @param {string} type e.g. "leaflet"
  35. * @private
  36. */
  37. createMapLayer_(type, options) {
  38. const proxy = super.createMapLayer_(type, this);
  39. if (proxy) {
  40. proxy.on("layerproxy_click", (e) => this.fire("layer_click", e));
  41. proxy.on("layerproxy_mouseover", (e) => this.fire("layer_mouseover", e));
  42. proxy.on("layerproxy_mouseout", (e) => this.fire("layer_mouseout", e));
  43. }
  44. return proxy;
  45. }
  46. /**
  47. * Helper method to update the mapLayer according to
  48. * the current state. Might be necessary after switching the map type
  49. *
  50. * @private
  51. */
  52. updateMapLayer_(type) {
  53. // init the event callbacks for the buttons in the popup
  54. if (this.editingEnabled && (this.popupEvents_.length == 0)) this.initPopupEvents_();
  55. if (this.activeLayer_ !== this.previousActiveLayer_) {
  56. this.activeLayer_.setData(this.geoJSON);
  57. }
  58. this.previousActiveLayer_ = this.activeLayer_;
  59. }
  60. setData(geoJson) {
  61. this.geoJSON = {
  62. type: "FeatureCollection",
  63. features: []
  64. };
  65. if (typeof geoJson == "string") {
  66. fetch(geoJson).then(response => response.json()).then(json => {
  67. this.geoJSON = json;
  68. this.activeLayer_.setData(this.geoJSON);
  69. })
  70. } else if (typeof geoJson == "object") {
  71. this.geoJSON = geoJson;
  72. } else {
  73. console.warn("Invalid or missing GeoJSON");
  74. }
  75. this.activeLayer_.setData(this.geoJSON);
  76. }
  77. /**
  78. * Set label of a feature
  79. * @param {object} feature
  80. * @param {string} label
  81. */
  82. setLabel(feature, label) {
  83. feature.properties.label = label;
  84. this.activeLayer_.updateTooltips(feature);
  85. }
  86. bringToFront() {
  87. this.activeLayer_.bringToFront();
  88. }
  89. bringToBack() {
  90. this.activeLayer_.bringToBack();
  91. }
  92. /**
  93. * Set color of a feature
  94. * @param {object} feature
  95. * @param {string} color
  96. */
  97. setColor(feature, color) {
  98. feature.properties.color = color;
  99. this.activeLayer_.updateStyle();
  100. }
  101. /**
  102. * init the event callbacks for the buttons in the popup
  103. * @private
  104. */
  105. initPopupEvents_() {
  106. let editing = false;
  107. this.popupEvents_ = [
  108. {
  109. title: "<i class='fas fa-draw-polygon'></i><br/>edit shape",
  110. callback: e => {
  111. if (editing) {
  112. this.stopEditing_(e.content.feature);
  113. } else {
  114. this.startEditing_(e.content.feature);
  115. }
  116. editing = !editing;
  117. },
  118. toggleMode: true,
  119. isEnabled: () => { return editing },
  120. width: "33%"
  121. },
  122. {
  123. title: "<i class='fas fa-download'></i><br/>export",
  124. callback: e => this.exportGeometry("download"),
  125. width: "34%"
  126. },
  127. {
  128. title: "<i class='fas fa-trash'></i><br/>remove",
  129. callback: e => this.fire("layer_request_remove", this),
  130. width: "33%"
  131. }
  132. ];
  133. }
  134. /**
  135. * start editing for a vector based layer
  136. * @private
  137. */
  138. startEditing_(feature) {
  139. this.activeLayer_.startEditing(feature);
  140. }
  141. /**
  142. * stop editing for a vector based layer
  143. * @private
  144. */
  145. stopEditing_(feature) {
  146. this.activeLayer_.stopEditing(feature);
  147. this.geoJSON = this.activeLayer_.getGeoJson();
  148. if (!("properties" in this.geoJSON)) this.geoJSON.properties = {};
  149. if (!("title" in this.geoJSON.properties)) this.geoJSON.properties.title = this.title;
  150. this.activeLayer_.setData(this.geoJSON);
  151. EventManager.fire("close_map_popup", {});
  152. }
  153. /**
  154. * Trigger a file download containing the geometry as a geojson file
  155. *
  156. * @param {string} mode supported values: "string", "object", "download" (default)
  157. */
  158. exportGeometry(mode) {
  159. // only export first feature, if only one feature exists
  160. let geoJSON = this.geoJSON;
  161. if (("features" in geoJSON) && (geoJSON.features.length == 1)) geoJSON = geoJSON.features[0];
  162. if (mode == "object") return this.geoJSON;
  163. const jsonString = JSON.stringify(this.geoJSON);
  164. if (mode == "string") return jsonString
  165. const blob = new Blob([jsonString], { type: "text/plain;charset=utf-8" });
  166. saveAsFile(blob, this.title + ".json");
  167. }
  168. /**
  169. * Get Info of the last clicked features
  170. * @returns {Promise} feature info
  171. */
  172. getFeatureInfo() {
  173. return new Promise(resolve => {
  174. resolve(this.activeLayer_.getClickedFeatures());
  175. });
  176. }
  177. /**
  178. * Set the transparency between 0 and 1
  179. * @param {number} opacity
  180. */
  181. setOpacity(opacity) {
  182. this.opacity = opacity;
  183. this.activeLayer_.updateStyle();
  184. }
  185. /**
  186. * Get the bounding box as an object
  187. * @returns {object} { min: {x, y}, max: {x, y}, crs: "CRS:84" }
  188. */
  189. getBounds() {
  190. const bounds = this.activeLayer_.getBounds();
  191. return (bounds) ? bounds : super.getBounds();
  192. }
  193. }