1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | import theConfig from '../../data/Config.js'; |
26 | import theTravelNotesData from '../../data/TravelNotesData.js'; |
27 | import theDataSearchEngine from '../../data/DataSearchEngine.js'; |
28 | import theGeometry from '../../core/lib/Geometry.js'; |
29 | import theApiKeysManager from '../../core/ApiKeysManager.js'; |
30 | import MapEditorViewer from './MapEditorViewer.js'; |
31 | import EditedRouteMouseOverEL from './editedRouteEL/EditedRouteMouseOverEL.js'; |
32 | import NoteBulletDragEndEL from './noteBulletEL/NoteBulletDragEndEL.js'; |
33 | import NoteBulletDragEL from './noteBulletEL/NoteBulletDragEL.js'; |
34 | import NoteBulletMouseEnterEL from './noteBulletEL/NoteBulletMouseEnterEL.js'; |
35 | import NoteBulletMouseLeaveEL from './noteBulletEL/NoteBulletMouseLeaveEL.js'; |
36 | import NoteMarkerContextMenuEL from './NoteMarkerEL/NoteMarkerContextMenuEL.js'; |
37 | import NoteMarkerDragEndEL from './NoteMarkerEL/NoteMarkerDragEndEL.js'; |
38 | import NoteMarkerDragEL from './NoteMarkerEL/NoteMarkerDragEL.js'; |
39 | import WayPointContextMenuEL from './wayPointEL/WayPointContextMenuEL.js'; |
40 | import WayPointDragEndEL from './wayPointEL/WayPointDragEndEL.js'; |
41 | import RouteMapContextMenuEL from './RouteEL/RouteMapContextMenuEL.js'; |
42 | import { ROUTE_EDITION_STATUS, LAT_LNG, INVALID_OBJ_ID, TWO, WAY_POINT_ICON_SIZE } from '../../main/Constants.js'; |
43 | import theDevice from '../lib/Device.js'; |
44 | |
45 | import { |
46 | LeafletCircleMarker, |
47 | LeafletDivIcon, |
48 | LeafletMarker, |
49 | LeafletPolyline, |
50 | LeafletRectangle, |
51 | LeafletDomEvent |
52 | } from '../../leaflet/LeafletImports.js'; |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | class MapEditor extends MapEditorViewer { |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | static get #MARKER_BOUNDS_PRECISION ( ) { return 0.01; } |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | #RemoveFromMap ( objId ) { |
78 | const layer = theTravelNotesData.mapObjects.get ( objId ); |
79 | if ( layer ) { |
80 | LeafletDomEvent.off ( layer ); |
81 | theTravelNotesData.map.removeLayer ( layer ); |
82 | theTravelNotesData.mapObjects.delete ( objId ); |
83 | } |
84 | } |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | constructor ( ) { |
91 | super ( ); |
92 | } |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | updateRoute ( removedRouteObjId, addedRouteObjId ) { |
104 | if ( INVALID_OBJ_ID !== removedRouteObjId ) { |
105 | const route = theDataSearchEngine.getRoute ( removedRouteObjId ); |
106 | this.#RemoveFromMap ( route.objId ); |
107 | |
108 | const notesIterator = route.notes.iterator; |
109 | while ( ! notesIterator.done ) { |
110 | this.#RemoveFromMap ( notesIterator.value.objId ); |
111 | } |
112 | |
113 | const wayPointsIterator = route.wayPoints.iterator; |
114 | while ( ! wayPointsIterator.done ) { |
115 | this.#RemoveFromMap ( wayPointsIterator.value.objId ); |
116 | } |
117 | } |
118 | if ( INVALID_OBJ_ID !== addedRouteObjId ) { |
119 | const route = this.addRoute ( addedRouteObjId ); |
120 | const polyline = theTravelNotesData.mapObjects.get ( addedRouteObjId ); |
121 | |
122 | if ( ! theTravelNotesData.travel.readOnly ) { |
123 | LeafletDomEvent.on ( polyline, 'contextmenu', RouteMapContextMenuEL.handleEvent ); |
124 | if ( ROUTE_EDITION_STATUS.notEdited !== route.editionStatus && ! theDevice.isTouch ) { |
125 | LeafletDomEvent.on ( polyline, 'mouseover', EditedRouteMouseOverEL.handleEvent ); |
126 | } |
127 | const notesIterator = route.notes.iterator; |
128 | while ( ! notesIterator.done ) { |
129 | const layerGroup = theTravelNotesData.mapObjects.get ( notesIterator.value.objId ); |
130 | const marker = layerGroup.getLayer ( layerGroup.markerId ); |
131 | const bullet = layerGroup.getLayer ( layerGroup.bulletId ); |
132 | LeafletDomEvent.on ( bullet, 'dragend', NoteBulletDragEndEL.handleEvent ); |
133 | LeafletDomEvent.on ( bullet, 'drag', NoteBulletDragEL.handleEvent ); |
134 | LeafletDomEvent.on ( bullet, 'mouseenter', NoteBulletMouseEnterEL.handleEvent ); |
135 | LeafletDomEvent.on ( bullet, 'mouseleave', NoteBulletMouseLeaveEL.handleEvent ); |
136 | LeafletDomEvent.on ( marker, 'contextmenu', NoteMarkerContextMenuEL.handleEvent ); |
137 | LeafletDomEvent.on ( marker, 'dragend', NoteMarkerDragEndEL.handleEvent ); |
138 | LeafletDomEvent.on ( marker, 'drag', NoteMarkerDragEL.handleEvent ); |
139 | } |
140 | } |
141 | |
142 | |
143 | if ( ! theTravelNotesData.travel.readOnly && ROUTE_EDITION_STATUS.notEdited !== route.editionStatus ) { |
144 | const wayPointsIterator = theTravelNotesData.travel.editedRoute.wayPoints.iterator; |
145 | while ( ! wayPointsIterator.done ) { |
146 | this.addWayPoint ( |
147 | wayPointsIterator.value, |
148 | wayPointsIterator .first ? 'A' : ( wayPointsIterator.last ? 'B' : wayPointsIterator.index ) |
149 | ); |
150 | } |
151 | } |
152 | } |
153 | } |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | updateRouteProperties ( routeObjId ) { |
162 | const polyline = theTravelNotesData.mapObjects.get ( routeObjId ); |
163 | const route = theDataSearchEngine.getRoute ( routeObjId ); |
164 | polyline.setStyle ( |
165 | { |
166 | color : route.color, |
167 | weight : route.width, |
168 | dashArray : route.dashString |
169 | } |
170 | ); |
171 | } |
172 | |
173 | |
174 | |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | |
181 | |
182 | updateNote ( removedNoteObjId, addedNoteObjId ) { |
183 | let isPopupOpen = false; |
184 | if ( INVALID_OBJ_ID !== removedNoteObjId ) { |
185 | const layerGroup = theTravelNotesData.mapObjects.get ( removedNoteObjId ); |
186 | if ( layerGroup ) { |
187 | isPopupOpen = layerGroup.getLayer ( layerGroup.markerId ).isPopupOpen ( ); |
188 | } |
189 | this.#RemoveFromMap ( removedNoteObjId ); |
190 | } |
191 | if ( INVALID_OBJ_ID !== addedNoteObjId ) { |
192 | const noteObjects = this.addNote ( addedNoteObjId ); |
193 | if ( isPopupOpen ) { |
194 | noteObjects.marker.openPopup ( ); |
195 | } |
196 | if ( ! theTravelNotesData.travel.readOnly ) { |
197 | LeafletDomEvent.on ( noteObjects.bullet, 'dragend', NoteBulletDragEndEL.handleEvent ); |
198 | LeafletDomEvent.on ( noteObjects.bullet, 'drag', NoteBulletDragEL.handleEvent ); |
199 | LeafletDomEvent.on ( noteObjects.bullet, 'mouseenter', NoteBulletMouseEnterEL.handleEvent ); |
200 | LeafletDomEvent.on ( noteObjects.bullet, 'mouseleave', NoteBulletMouseLeaveEL.handleEvent ); |
201 | LeafletDomEvent.on ( noteObjects.marker, 'contextmenu', NoteMarkerContextMenuEL.handleEvent ); |
202 | LeafletDomEvent.on ( noteObjects.marker, 'dragend', NoteMarkerDragEndEL.handleEvent ); |
203 | LeafletDomEvent.on ( noteObjects.marker, 'drag', NoteMarkerDragEL.handleEvent ); |
204 | } |
205 | } |
206 | } |
207 | |
208 | |
209 | |
210 | |
211 | |
212 | |
213 | |
214 | removeObject ( objId ) { this.#RemoveFromMap ( objId ); } |
215 | |
216 | |
217 | |
218 | |
219 | |
220 | |
221 | removeAllObjects ( ) { |
222 | theTravelNotesData.mapObjects.forEach ( |
223 | mapObject => { |
224 | LeafletDomEvent.off ( mapObject ); |
225 | theTravelNotesData.map.removeLayer ( mapObject ); |
226 | } |
227 | ); |
228 | theTravelNotesData.mapObjects.clear ( ); |
229 | } |
230 | |
231 | |
232 | |
233 | |
234 | |
235 | |
236 | |
237 | |
238 | addWayPoint ( wayPoint, letter ) { |
239 | if ( ( LAT_LNG.defaultValue === wayPoint.lat ) && ( LAT_LNG.defaultValue === wayPoint.lng ) ) { |
240 | return; |
241 | } |
242 | |
243 | |
244 | const iconHtml = '<div class="TravelNotes-Map-WayPoint TravelNotes-Map-WayPoint' + |
245 | ( 'A' === letter ? 'Start' : ( 'B' === letter ? 'End' : 'Via' ) ) + |
246 | '"></div><div class="TravelNotes-Map-WayPointText">' + letter + '</div>'; |
247 | |
248 | |
249 | const marker = new LeafletMarker ( |
250 | wayPoint.latLng, |
251 | { |
252 | icon : new LeafletDivIcon ( |
253 | { |
254 | iconSize : [ WAY_POINT_ICON_SIZE, WAY_POINT_ICON_SIZE ], |
255 | iconAnchor : [ |
256 | WAY_POINT_ICON_SIZE / TWO, |
257 | WAY_POINT_ICON_SIZE |
258 | ], |
259 | html : iconHtml, |
260 | className : 'TravelNotes-Map-WayPointStyle' |
261 | } |
262 | ), |
263 | draggable : true |
264 | } |
265 | ); |
266 | |
267 | marker.bindTooltip ( |
268 | tooltipWayPoint => theDataSearchEngine.getWayPoint ( tooltipWayPoint.objId ).fullName |
269 | ); |
270 | marker.getTooltip ( ).options.offset = [ |
271 | WAY_POINT_ICON_SIZE / TWO, |
272 | -WAY_POINT_ICON_SIZE / TWO |
273 | ]; |
274 | |
275 | LeafletDomEvent.on ( marker, 'contextmenu', WayPointContextMenuEL.handleEvent ); |
276 | |
277 | |
278 | marker.objId = wayPoint.objId; |
279 | this.addToMap ( wayPoint.objId, marker ); |
280 | |
281 | |
282 | LeafletDomEvent.on ( marker, 'dragend', WayPointDragEndEL.handleEvent ); |
283 | } |
284 | |
285 | |
286 | |
287 | |
288 | |
289 | |
290 | |
291 | |
292 | addItineraryPointMarker ( objId, latLng ) { |
293 | this.addToMap ( |
294 | objId, |
295 | new LeafletCircleMarker ( latLng, theConfig.itineraryPoint.marker ) |
296 | ); |
297 | } |
298 | |
299 | |
300 | |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | |
307 | |
308 | |
309 | addSearchPointMarker ( objId, latLng, geometry ) { |
310 | let showGeometry = false; |
311 | if ( geometry ) { |
312 | let latLngs = []; |
313 | geometry.forEach ( |
314 | geometryPart => { latLngs = latLngs.concat ( geometryPart ); } |
315 | ); |
316 | const geometryBounds = theGeometry.getLatLngBounds ( latLngs ); |
317 | const mapBounds = theTravelNotesData.map.getBounds ( ); |
318 | showGeometry = |
319 | ( |
320 | ( geometryBounds.getEast ( ) - geometryBounds.getWest ( ) ) |
321 | / |
322 | ( mapBounds.getEast ( ) - mapBounds.getWest ( ) ) |
323 | ) > MapEditor.#MARKER_BOUNDS_PRECISION |
324 | && |
325 | ( |
326 | ( geometryBounds.getNorth ( ) - geometryBounds.getSouth ( ) ) |
327 | / |
328 | ( mapBounds.getNorth ( ) - mapBounds.getSouth ( ) ) |
329 | ) > MapEditor.#MARKER_BOUNDS_PRECISION; |
330 | } |
331 | if ( showGeometry ) { |
332 | this.addToMap ( objId, new LeafletPolyline ( geometry, theConfig.osmSearch.searchPointPolyline ) ); |
333 | } |
334 | else { |
335 | this.addToMap ( objId, new LeafletCircleMarker ( latLng, theConfig.osmSearch.searchPointMarker ) ); |
336 | } |
337 | } |
338 | |
339 | |
340 | |
341 | |
342 | |
343 | |
344 | |
345 | |
346 | |
347 | addRectangle ( objId, bounds, properties ) { |
348 | this.addToMap ( |
349 | objId, |
350 | new LeafletRectangle ( bounds, properties ) |
351 | ); |
352 | } |
353 | |
354 | |
355 | |
356 | |
357 | |
358 | |
359 | |
360 | setLayer ( layer ) { |
361 | const url = theApiKeysManager.getUrl ( layer ); |
362 | if ( ! url ) { |
363 | return; |
364 | } |
365 | |
366 | super.setLayer ( layer, url ); |
367 | } |
368 | } |
369 | |
370 | |
371 | |
372 | |
373 | |
374 | |
375 | |
376 | |
377 | const theMapEditor = new MapEditor ( ); |
378 | |
379 | export default theMapEditor; |
380 | |
381 | |
382 | |