| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  | import {TagsFilter, TagUtils} from "./Tags"; | 
					
						
							| 
									
										
										
										
											2020-08-17 17:23:15 +02:00
										 |  |  | import {UIEventSource} from "./UIEventSource"; | 
					
						
							| 
									
										
										
										
											2020-09-30 23:34:44 +02:00
										 |  |  | import * as L from "leaflet" | 
					
						
							|  |  |  | import {Layer} from "leaflet" | 
					
						
							| 
									
										
										
										
											2020-07-26 02:01:34 +02:00
										 |  |  | import {GeoOperations} from "./GeoOperations"; | 
					
						
							|  |  |  | import {UIElement} from "../UI/UIElement"; | 
					
						
							| 
									
										
										
										
											2020-10-02 19:00:24 +02:00
										 |  |  | import State from "../State"; | 
					
						
							| 
									
										
										
										
											2020-10-27 01:01:34 +01:00
										 |  |  | import LayerConfig from "../Customizations/JSON/LayerConfig"; | 
					
						
							| 
									
										
										
										
											2020-11-17 02:22:48 +01:00
										 |  |  | import Hash from "./Web/Hash"; | 
					
						
							| 
									
										
										
										
											2020-12-05 03:22:17 +01:00
										 |  |  | import LazyElement from "../UI/Base/LazyElement"; | 
					
						
							| 
									
										
										
										
											2020-07-30 09:59:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | /*** | 
					
						
							|  |  |  |  * A filtered layer is a layer which offers a 'set-data' function | 
					
						
							|  |  |  |  * It is initialized with a tagfilter. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * When geojson-data is given to 'setData', all the geojson matching the filter, is rendered on this layer. | 
					
						
							|  |  |  |  * If it is not rendered, it is returned in a 'leftOver'-geojson; which can be consumed by the next layer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This also makes sure that no objects are rendered twice if they are applicable on two layers | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export class FilteredLayer { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-22 00:50:30 +02:00
										 |  |  |     public readonly name: string | UIElement; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     public readonly filters: TagsFilter; | 
					
						
							| 
									
										
										
										
											2020-07-15 15:55:08 +02:00
										 |  |  |     public readonly isDisplayed: UIEventSource<boolean> = new UIEventSource(true); | 
					
						
							| 
									
										
										
										
											2020-10-27 01:01:34 +01:00
										 |  |  |     private readonly combinedIsDisplayed: UIEventSource<boolean>; | 
					
						
							|  |  |  |     public readonly layerDef: LayerConfig; | 
					
						
							| 
									
										
										
										
											2020-06-28 23:33:48 +02:00
										 |  |  |     private readonly _maxAllowedOverlap: number; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** The featurecollection from overpass | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |     private _dataFromOverpass: any[]; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     /** List of new elements, geojson features | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private _newElements = []; | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The leaflet layer object which should be removed on rerendering | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private _geolayer; | 
					
						
							| 
									
										
										
										
											2020-09-14 20:16:03 +02:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2020-07-22 01:07:32 +02:00
										 |  |  |     private _showOnPopup: (tags: UIEventSource<any>, feature: any) => UIElement; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-11 18:22:04 +02:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     constructor( | 
					
						
							| 
									
										
										
										
											2020-10-27 01:01:34 +01:00
										 |  |  |         layerDef: LayerConfig, | 
					
						
							| 
									
										
										
										
											2020-07-24 15:52:21 +02:00
										 |  |  |         showOnPopup: ((tags: UIEventSource<any>, feature: any) => UIElement) | 
					
						
							| 
									
										
										
										
											2020-06-29 16:21:36 +02:00
										 |  |  |     ) { | 
					
						
							| 
									
										
										
										
											2020-07-22 11:01:25 +02:00
										 |  |  |         this.layerDef = layerDef; | 
					
						
							| 
									
										
										
										
											2020-07-22 11:05:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 16:21:36 +02:00
										 |  |  |         this._showOnPopup = showOnPopup; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         this.name = name; | 
					
						
							| 
									
										
										
										
											2020-10-27 01:01:34 +01:00
										 |  |  |         this.filters = layerDef.overpassTags; | 
					
						
							|  |  |  |         this._maxAllowedOverlap = layerDef.hideUnderlayingFeaturesMinPercentage; | 
					
						
							| 
									
										
										
										
											2020-07-15 15:55:08 +02:00
										 |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |         this.combinedIsDisplayed = this.isDisplayed.map<boolean>(isDisplayed => { | 
					
						
							|  |  |  |                 return isDisplayed && State.state.locationControl.data.zoom >= self.layerDef.minzoom | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             [State.state.locationControl] | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         this.combinedIsDisplayed.addCallback(function (isDisplayed) { | 
					
						
							| 
									
										
										
										
											2021-01-02 21:03:40 +01:00
										 |  |  |             const map = State.state.leafletMap.data; | 
					
						
							| 
									
										
										
										
											2020-07-15 15:55:08 +02:00
										 |  |  |             if (self._geolayer !== undefined && self._geolayer !== null) { | 
					
						
							|  |  |  |                 if (isDisplayed) { | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  |                     self._geolayer.addTo(map); | 
					
						
							| 
									
										
										
										
											2020-07-15 15:55:08 +02:00
										 |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  |                     map.removeLayer(self._geolayer); | 
					
						
							| 
									
										
										
										
											2020-07-15 15:55:08 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The main function to load data into this layer. | 
					
						
							|  |  |  |      * The data that is NOT used by this layer, is returned as a geojson object; the other data is rendered | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public SetApplicableData(geojson: any): any { | 
					
						
							|  |  |  |         const leftoverFeatures = []; | 
					
						
							|  |  |  |         const selfFeatures = []; | 
					
						
							| 
									
										
										
										
											2020-07-22 00:50:30 +02:00
										 |  |  |         for (let feature of geojson.features) { | 
					
						
							| 
									
										
										
										
											2020-10-19 13:23:09 +02:00
										 |  |  |             const tags = TagUtils.proprtiesToKV(feature.properties); | 
					
						
							| 
									
										
										
										
											2020-11-17 02:22:48 +01:00
										 |  |  |             const matches = this.filters.matches(tags); | 
					
						
							|  |  |  |             if (matches) { | 
					
						
							| 
									
										
										
										
											2020-12-05 03:22:17 +01:00
										 |  |  |                selfFeatures.push(feature); | 
					
						
							| 
									
										
										
										
											2020-11-17 02:22:48 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |             if (!matches || this.layerDef.passAllFeatures) { | 
					
						
							| 
									
										
										
										
											2020-10-27 14:46:40 +01:00
										 |  |  |                 leftoverFeatures.push(feature); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |        this.RenderLayer(selfFeatures) | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const notShadowed = []; | 
					
						
							|  |  |  |         for (const feature of leftoverFeatures) { | 
					
						
							| 
									
										
										
										
											2020-07-18 20:40:51 +02:00
										 |  |  |             if (this._maxAllowedOverlap !== undefined && this._maxAllowedOverlap > 0) { | 
					
						
							| 
									
										
										
										
											2020-06-28 23:33:48 +02:00
										 |  |  |                 if (GeoOperations.featureIsContainedInAny(feature, selfFeatures, this._maxAllowedOverlap)) { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |                     // This feature is filtered away
 | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             notShadowed.push(feature); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |             type: "FeatureCollection", | 
					
						
							|  |  |  |             features: notShadowed | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public AddNewElement(element) { | 
					
						
							|  |  |  |         this._newElements.push(element); | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |         this.RenderLayer( this._dataFromOverpass); // Update the layer
 | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |     private RenderLayer(features) { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (this._geolayer !== undefined && this._geolayer !== null) { | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  |             // Remove the old geojson layer from the map - we'll reshow all the elements later on anyway
 | 
					
						
							| 
									
										
										
										
											2021-01-02 21:03:40 +01:00
										 |  |  |             State.state.leafletMap.data.removeLayer(this._geolayer); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |         // We fetch all the data we have to show:
 | 
					
						
							|  |  |  |         let fusedFeatures = this.ApplyWayHandling(this.FuseData(features)); | 
					
						
							| 
									
										
										
										
											2020-08-28 03:16:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |         // And we copy some features as points - if needed
 | 
					
						
							|  |  |  |         const data = { | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |             type: "FeatureCollection", | 
					
						
							|  |  |  |             features: fusedFeatures | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |         let self = this; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |         this._geolayer = L.geoJSON(data, { | 
					
						
							| 
									
										
										
										
											2020-11-27 01:39:54 +01:00
										 |  |  |             style: feature => { | 
					
						
							| 
									
										
										
										
											2020-12-05 03:22:17 +01:00
										 |  |  |                 const tagsSource = State.state.allElements.getEventSourceFor(feature); | 
					
						
							| 
									
										
										
										
											2020-11-27 01:39:54 +01:00
										 |  |  |                 return self.layerDef.GenerateLeafletStyle(tagsSource, self._showOnPopup !== undefined); | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |             pointToLayer: function (feature, latLng) { | 
					
						
							|  |  |  |                 // Point to layer converts the 'point' to a layer object - as the geojson layer natively cannot handle points
 | 
					
						
							|  |  |  |                 // Click handling is done in the next step
 | 
					
						
							| 
									
										
										
										
											2020-12-05 03:22:17 +01:00
										 |  |  |                 const tagSource = State.state.allElements.getEventSourceFor(feature); | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 01:39:54 +01:00
										 |  |  |                 const style = self.layerDef.GenerateLeafletStyle(tagSource, self._showOnPopup !== undefined); | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |                 let marker; | 
					
						
							|  |  |  |                 if (style.icon === undefined) { | 
					
						
							|  |  |  |                     marker = L.circle(latLng, { | 
					
						
							|  |  |  |                         radius: 25, | 
					
						
							|  |  |  |                         color: style.color | 
					
						
							| 
									
										
										
										
											2020-11-17 02:22:48 +01:00
										 |  |  |                     }); | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |                 } else if (style.icon.iconUrl.startsWith("$circle")) { | 
					
						
							|  |  |  |                     marker = L.circle(latLng, { | 
					
						
							|  |  |  |                         radius: 25, | 
					
						
							|  |  |  |                         color: style.color | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2020-12-06 00:20:27 +01:00
										 |  |  |                     style.icon.html.ListenTo(self.isDisplayed) | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |                     marker = L.marker(latLng, { | 
					
						
							| 
									
										
										
										
											2020-12-06 00:20:27 +01:00
										 |  |  |                         icon: L.divIcon({ | 
					
						
							|  |  |  |                             html: style.icon.html.Render(), | 
					
						
							|  |  |  |                             className: style.icon.className, | 
					
						
							|  |  |  |                             iconAnchor: style.icon.iconAnchor, | 
					
						
							|  |  |  |                             iconUrl: style.icon.iconUrl, | 
					
						
							|  |  |  |                             popupAnchor: style.icon.popupAnchor, | 
					
						
							|  |  |  |                             iconSize: style.icon.iconSize | 
					
						
							|  |  |  |                         }) | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |                     }); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return marker; | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             onEachFeature: function (feature, layer: Layer) { | 
					
						
							| 
									
										
										
										
											2020-11-17 02:22:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |                 if (self._showOnPopup === undefined) { | 
					
						
							|  |  |  |                     // No popup contents defined -> don't do anything
 | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 const popup = L.popup({ | 
					
						
							|  |  |  |                     autoPan: true, | 
					
						
							|  |  |  |                     closeOnEscapeKey: true, | 
					
						
							|  |  |  |                 }, layer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-05 03:22:17 +01:00
										 |  |  |                 const eventSource = State.state.allElements.getEventSourceFor(feature); | 
					
						
							|  |  |  |                 let uiElement: LazyElement = new LazyElement(() => self._showOnPopup(eventSource, feature)); | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |                 popup.setContent(uiElement.Render()); | 
					
						
							|  |  |  |                 layer.bindPopup(popup); | 
					
						
							|  |  |  |                 // We first render the UIelement (which'll still need an update later on...)
 | 
					
						
							|  |  |  |                 // But at least it'll be visible already
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 layer.on("click", (e) => { | 
					
						
							|  |  |  |                     // We set the element as selected...
 | 
					
						
							| 
									
										
										
										
											2020-12-05 03:22:17 +01:00
										 |  |  |                     uiElement.Activate(); | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |                     State.state.selectedElement.setData(feature); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) { | 
					
						
							| 
									
										
										
										
											2020-12-05 03:22:17 +01:00
										 |  |  |                     // This element is in the URL, so this is a share link
 | 
					
						
							|  |  |  |                     // We already open it
 | 
					
						
							|  |  |  |                     uiElement.Activate(); | 
					
						
							|  |  |  |                     popup.setContent(uiElement.Render()); | 
					
						
							|  |  |  |                 | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  |                     const center = GeoOperations.centerpoint(feature).geometry.coordinates; | 
					
						
							|  |  |  |                     popup.setLatLng({lat: center[1], lng: center[0]}); | 
					
						
							| 
									
										
										
										
											2021-01-02 21:03:40 +01:00
										 |  |  |                     popup.openOn(State.state.leafletMap.data); | 
					
						
							| 
									
										
										
										
											2020-11-20 14:00:37 +01:00
										 |  |  |                     State.state.selectedElement.setData(feature); | 
					
						
							|  |  |  |                     uiElement.Update(); | 
					
						
							| 
									
										
										
										
											2020-11-17 02:22:48 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-11-17 16:29:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-11-17 02:22:48 +01:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 01:13:18 +02:00
										 |  |  |         if (this.combinedIsDisplayed.data) { | 
					
						
							| 
									
										
										
										
											2021-01-02 21:03:40 +01:00
										 |  |  |             this._geolayer.addTo(State.state.leafletMap.data); | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private ApplyWayHandling(fusedFeatures: any[]) { | 
					
						
							|  |  |  |         if (this.layerDef.wayHandling === LayerConfig.WAYHANDLING_DEFAULT) { | 
					
						
							|  |  |  |             // We don't have to do anything special
 | 
					
						
							|  |  |  |             return fusedFeatures; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // We have to convert all the ways into centerpoints
 | 
					
						
							|  |  |  |         const existingPoints = []; | 
					
						
							|  |  |  |         const newPoints = []; | 
					
						
							|  |  |  |         const existingWays = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const feature of fusedFeatures) { | 
					
						
							|  |  |  |             if (feature.geometry.type === "Point") { | 
					
						
							|  |  |  |                 existingPoints.push(feature); | 
					
						
							|  |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2020-10-01 00:03:12 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             existingWays.push(feature); | 
					
						
							|  |  |  |             const centerPoint = GeoOperations.centerpoint(feature); | 
					
						
							|  |  |  |             newPoints.push(centerPoint); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fusedFeatures = existingPoints.concat(newPoints); | 
					
						
							|  |  |  |         if (this.layerDef.wayHandling === LayerConfig.WAYHANDLING_CENTER_AND_WAY) { | 
					
						
							|  |  |  |             fusedFeatures = fusedFeatures.concat(existingWays) | 
					
						
							| 
									
										
										
										
											2020-07-15 15:55:08 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |         return fusedFeatures; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |     //*Fuses the old and the new datasets*/
 | 
					
						
							|  |  |  |     private FuseData(data: any[]) { | 
					
						
							|  |  |  |         const oldData = this._dataFromOverpass ?? []; | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 01:59:30 +01:00
										 |  |  |         // We keep track of all the ids that are freshly loaded in order to avoid adding duplicates
 | 
					
						
							|  |  |  |         const idsFromOverpass: Set<number> = new Set<number>(); | 
					
						
							|  |  |  |         // A list of all the features to show
 | 
					
						
							|  |  |  |         const fusedFeatures = []; | 
					
						
							|  |  |  |         // First, we add all the fresh data:
 | 
					
						
							|  |  |  |         for (const feature of data) { | 
					
						
							|  |  |  |             idsFromOverpass.add(feature.properties.id); | 
					
						
							|  |  |  |             fusedFeatures.push(feature); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Now we add all the stale data
 | 
					
						
							|  |  |  |         for (const feature of oldData) { | 
					
						
							|  |  |  |             if (idsFromOverpass.has(feature.properties.id)) { | 
					
						
							|  |  |  |                 continue; // Feature already loaded and a fresher version is available
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             idsFromOverpass.add(feature.properties.id); | 
					
						
							|  |  |  |             fusedFeatures.push(feature); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this._dataFromOverpass = fusedFeatures; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const feature of this._newElements) { | 
					
						
							|  |  |  |             if (!idsFromOverpass.has(feature.properties.id)) { | 
					
						
							|  |  |  |                 // This element is not yet uploaded or not yet visible in overpass
 | 
					
						
							|  |  |  |                 // We include it in the layer
 | 
					
						
							|  |  |  |                 fusedFeatures.push(feature); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return fusedFeatures; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-24 00:35:19 +02:00
										 |  |  | } |