1. 1 : /**
  2. 2 : * @mixin
  3. 3 : * @memberof module:geoflo
  4. 4 : * @name Painting
  5. 5 : * @description This module provides the painting functionality for the Geoflo application. It allows users to free-draw on the map.
  6. 6 : * @param {Object} mode - The mode object containing the type of mode.
  7. 7 : * @returns {Object} Returns the Painting object.
  8. 8 : */
  9. 9 : const Painting = function (mode) {
  10. 10 : const geoflo = this.geoflo;
  11. 11 :
  12. 12 : this.type = mode.type;
  13. 13 : this.feature = false;
  14. 14 : this.currentCoords = [];
  15. 15 :
  16. 16 : /**
  17. 17 : * @function
  18. 18 : * @memberof module:geoflo.Painting
  19. 19 : * @name activate
  20. 20 : * @description Activates the painting functionality by enabling painting mode and clearing the source data.
  21. 21 : * @returns {void}
  22. 22 : */
  23. 23 : this.activate = function () {
  24. 24 : this.deactivate();
  25. 25 : this.enabled = true;
  26. 26 : geoflo.options['painting'].enable = true;
  27. 27 : geoflo.map.getSource(geoflo.statics.constants.sources.SNAP).setData(turf.featureCollection([]));
  28. 28 : }
  29. 29 :
  30. 30 : /**
  31. 31 : * @function
  32. 32 : * @memberof module:geoflo.Painting
  33. 33 : * @name deactivate
  34. 34 : * @description This function deactivates the current feature by setting the 'enabled' property to false, disabling the painting tool, enabling drag pan on the map, and deleting the feature.
  35. 35 : * @returns {void}
  36. 36 : */
  37. 37 : this.deactivate = function () {
  38. 38 : this.enabled = false;
  39. 39 : geoflo.options['painting'].enable = false;
  40. 40 : geoflo.map.dragPan.enable();
  41. 41 : delete this.feature;
  42. 42 : }
  43. 43 :
  44. 44 : /**
  45. 45 : * @function
  46. 46 : * @memberof module:geoflo.Painting getFeature
  47. 47 : * @name getFeature
  48. 48 : * @description This function retrieves the current painted feature.
  49. 49 : * @returns {any} The painted feature.
  50. 50 : */
  51. 51 : this.getFeature = function () {
  52. 52 : return this.feature;
  53. 53 : }
  54. 54 :
  55. 55 : /**
  56. 56 : * @function
  57. 57 : * @memberof module:geoflo.Painting
  58. 58 : * @name setFeature
  59. 59 : * @description This function creates a feature based on the given type and coordinates. It updates the currentCoords array, sets the feature, and triggers a 'painting.start' event.
  60. 60 : * @param {Array} coords - The coordinates to set the feature at.
  61. 61 : * @returns {Object} The created feature.
  62. 62 : */
  63. 63 : this.setFeature = function (coords) {
  64. 64 : if (!this.type || !coords) return false;
  65. 65 : if (!geoflo.mouseIsDown) return geoflo.hotFeature;
  66. 66 :
  67. 67 : var type = this.type;
  68. 68 : var feature = setFeature(type, coords);
  69. 69 :
  70. 70 : if (!this.feature) {
  71. 71 : this.currentCoords = [];
  72. 72 : geoflo.startPoint = coords;
  73. 73 : geoflo.map.getSource(geoflo.statics.constants.sources.SNAP).setData(turf.featureCollection([feature]));
  74. 74 : geoflo.fire('painting.start', { type: type, coords: coords, feature: feature });
  75. 75 : }
  76. 76 :
  77. 77 : this.currentCoords.push(coords);
  78. 78 : this.feature = feature;
  79. 79 : return this.feature;
  80. 80 : }
  81. 81 :
  82. 82 : /**
  83. 83 : * @function
  84. 84 : * @memberof module:geoflo.Painting
  85. 85 : * @name updateFeature
  86. 86 : * @description This function updates the feature based on the provided coordinates. It handles different types of features like Rectangle, Circle, and others.
  87. 87 : * @param {Array} coords - The coordinates to update the feature with.
  88. 88 : * @returns {Object} The updated feature object.
  89. 89 : */
  90. 90 : this.updateFeature = function (coords) {
  91. 91 : if (!this.enabled) return geoflo.hotFeature;
  92. 92 : if (!this.feature) return this.setFeature(coords);
  93. 93 :
  94. 94 : var feature = this.feature;
  95. 95 : var type = this.type;
  96. 96 :
  97. 97 : this.currentCoords.push(coords);
  98. 98 :
  99. 99 : if (type === 'Rectangle') {
  100. 100 : updateCoordinate(feature, "0.1", coords[0], geoflo.mouseIsDown[1]);
  101. 101 : updateCoordinate(feature, "0.2", coords[0], coords[1]);
  102. 102 : updateCoordinate(feature, "0.3", geoflo.mouseIsDown[0], coords[1]);
  103. 103 : updateCoordinate(feature, "0.4", geoflo.mouseIsDown[0], geoflo.mouseIsDown[1] );
  104. 104 : } else if (type === 'Circle') {
  105. 105 : var center = feature.properties.center;
  106. 106 : if (!center || !center.length) return feature;
  107. 107 :
  108. 108 : const distanceInKm = turf.distance(turf.point(center), turf.point(coords), { units : 'kilometers'});
  109. 109 : const circleFeature = turf.circle(center, distanceInKm);
  110. 110 :
  111. 111 : feature.geometry.coordinates = circleFeature.geometry.coordinates;
  112. 112 : geoflo.Utilities.setProperty(feature, 'radiusInKm', distanceInKm);
  113. 113 : } else {
  114. 114 : feature.geometry.coordinates.push(coords);
  115. 115 : }
  116. 116 :
  117. 117 : geoflo.map.getSource(geoflo.statics.constants.sources.SNAP).setData(turf.featureCollection([this.feature]));
  118. 118 : geoflo.fire('painting.update', { type: type, coords: coords, feature: feature });
  119. 119 : return feature;
  120. 120 : }
  121. 121 :
  122. 122 : /**
  123. 123 : * @function
  124. 124 : * @memberof module:geoflo.Painting
  125. 125 : * @name handleUp
  126. 126 : * @description This function updates the feature based on the 'mouse up' event. It retrieves the current feature, updates the hot source, clones the updated feature, and sets the last click coordinates.
  127. 127 : * @param {Event} event - The event triggering the function.
  128. 128 : * @returns {Promise<Object>} The updated feature object.
  129. 129 : */
  130. 130 :
  131. 131 : this.handleUp = async function (event) {
  132. 132 : if (!this.feature) return false;
  133. 133 :
  134. 134 : var feature;
  135. 135 :
  136. 136 : if (geoflo.Exploring && geoflo.Exploring.enabled) this.feature = await geoflo.Exploring.getMatch(this.currentCoords, { set: true, start: geoflo.startPoint });
  137. 137 :
  138. 138 : feature = mode.updateHotSource(this.feature);
  139. 139 : feature = geoflo.Utilities.cloneDeep(feature);
  140. 140 :
  141. 141 : geoflo.lastClick = { coords: feature.geometry.coordinates[feature.geometry.coordinates.length - 1] };
  142. 142 : this.currentCoords = [];
  143. 143 : this.feature = feature;
  144. 144 : return feature;
  145. 145 : }
  146. 146 :
  147. 147 :
  148. 148 :
  149. 149 : if (geoflo.options['painting'].enable) this.activate();
  150. 150 :
  151. 151 :
  152. 152 :
  153. 153 : function setFeature (type, coords) {
  154. 154 : var feature;
  155. 155 :
  156. 156 : if (type === 'Rectangle') {
  157. 157 : feature = turf.polygon([[
  158. 158 : geoflo.mouseIsDown,
  159. 159 : coords,
  160. 160 : coords,
  161. 161 : geoflo.mouseIsDown
  162. 162 : ]]);
  163. 163 : } else if (type === 'Circle') {
  164. 164 : feature = turf.polygon([[
  165. 165 : geoflo.mouseIsDown,
  166. 166 : coords,
  167. 167 : coords,
  168. 168 : geoflo.mouseIsDown
  169. 169 : ]]);
  170. 170 :
  171. 171 : geoflo.Utilities.setProperty(feature, 'center', geoflo.mouseIsDown);
  172. 172 : } else {
  173. 173 : feature = turf.lineString([geoflo.mouseIsDown, coords]);
  174. 174 : }
  175. 175 :
  176. 176 : geoflo.Utilities.setProperty(feature, 'type', type);
  177. 177 : geoflo.Utilities.setProperty(feature, 'painting', 1);
  178. 178 : return feature;
  179. 179 : }
  180. 180 :
  181. 181 : function updateCoordinate (f, t, e, n) {
  182. 182 : var o = t.split(".")
  183. 183 : , r = parseInt(o[0], 10)
  184. 184 : , i = parseInt(o[1], 10);
  185. 185 : void 0 === f.geometry.coordinates[r] && (f.geometry.coordinates[r] = []),
  186. 186 : f.geometry.coordinates[r][i] = [e, n]
  187. 187 : }
  188. 188 : };
  189. 189 :
  190. 190 : export default Painting;