forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			150 lines
		
	
	
		
			No EOL
		
	
	
		
			6.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			No EOL
		
	
	
		
			6.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import Combine from "../Base/Combine";
 | |
| import {FlowStep} from "./FlowStep";
 | |
| import {BBox} from "../../Logic/BBox";
 | |
| import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
 | |
| import {UIEventSource} from "../../Logic/UIEventSource";
 | |
| import {DesugaringContext} from "../../Models/ThemeConfig/Conversion/Conversion";
 | |
| import CreateNoteImportLayer from "../../Models/ThemeConfig/Conversion/CreateNoteImportLayer";
 | |
| import FilteredLayer, {FilterState} from "../../Models/FilteredLayer";
 | |
| import GeoJsonSource from "../../Logic/FeatureSource/Sources/GeoJsonSource";
 | |
| import MetaTagging from "../../Logic/MetaTagging";
 | |
| import RelationsTracker from "../../Logic/Osm/RelationsTracker";
 | |
| import FilteringFeatureSource from "../../Logic/FeatureSource/Sources/FilteringFeatureSource";
 | |
| import Minimap from "../Base/Minimap";
 | |
| import ShowDataLayer from "../ShowDataLayer/ShowDataLayer";
 | |
| import FeatureInfoBox from "../Popup/FeatureInfoBox";
 | |
| import {ImportUtils} from "./ImportUtils";
 | |
| import * as import_candidate from "../../assets/layers/import_candidate/import_candidate.json";
 | |
| import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource";
 | |
| import Title from "../Base/Title";
 | |
| import Toggle from "../Input/Toggle";
 | |
| import Loading from "../Base/Loading";
 | |
| import {FixedUiElement} from "../Base/FixedUiElement";
 | |
| import {VariableUiElement} from "../Base/VariableUIElement";
 | |
| import * as known_layers from "../../assets/generated/known_layers.json"
 | |
| import {LayerConfigJson} from "../../Models/ThemeConfig/Json/LayerConfigJson";
 | |
| 
 | |
| /**
 | |
|  * Filters out points for which the import-note already exists, to prevent duplicates
 | |
|  */
 | |
| export class CompareToAlreadyExistingNotes extends Combine implements FlowStep<{ bbox: BBox, layer: LayerConfig, geojson: any }> {
 | |
| 
 | |
|     public IsValid: UIEventSource<boolean>
 | |
|     public Value: UIEventSource<{ bbox: BBox, layer: LayerConfig, geojson: any }>
 | |
| 
 | |
| 
 | |
|     constructor(state, params: { bbox: BBox, layer: LayerConfig, geojson: { features: any[] } }) {
 | |
| 
 | |
|         const layerConfig = known_layers.layers.filter(l => l.id === params.layer.id)[0]
 | |
|         if (layerConfig === undefined) {
 | |
|             console.error("WEIRD: layer not found in the builtin layer overview")
 | |
|         }
 | |
|         const importLayerJson = new CreateNoteImportLayer(365).convertStrict(<LayerConfigJson>layerConfig, "CompareToAlreadyExistingNotes")
 | |
|         const importLayer = new LayerConfig(importLayerJson, "import-layer-dynamic")
 | |
|         const flayer: FilteredLayer = {
 | |
|             appliedFilters: new UIEventSource<Map<string, FilterState>>(new Map<string, FilterState>()),
 | |
|             isDisplayed: new UIEventSource<boolean>(true),
 | |
|             layerDef: importLayer
 | |
|         }
 | |
|         const allNotesWithinBbox = new GeoJsonSource(flayer, params.bbox.padAbsolute(0.0001))
 | |
|         allNotesWithinBbox.features.map(f => MetaTagging.addMetatags(
 | |
|                 f,
 | |
|                 {
 | |
|                     memberships: new RelationsTracker(),
 | |
|                     getFeaturesWithin: (layerId, bbox: BBox) => [],
 | |
|                     getFeatureById: (id: string) => undefined
 | |
|                 },
 | |
|                 importLayer,
 | |
|                 state,
 | |
|                 {
 | |
|                     includeDates: true,
 | |
|                     // We assume that the non-dated metatags are already set by the cache generator
 | |
|                     includeNonDates: true
 | |
|                 }
 | |
|             )
 | |
|         )
 | |
|         const alreadyOpenImportNotes = new FilteringFeatureSource(state, undefined, allNotesWithinBbox)
 | |
|         alreadyOpenImportNotes.features.addCallbackD(features => console.log("Loaded and filtered features are", features))
 | |
|         const map = Minimap.createMiniMap()
 | |
|         map.SetClass("w-full").SetStyle("height: 500px")
 | |
| 
 | |
|         const comparisonMap = Minimap.createMiniMap({
 | |
|             location: map.location,
 | |
| 
 | |
|         })
 | |
|         comparisonMap.SetClass("w-full").SetStyle("height: 500px")
 | |
| 
 | |
|         new ShowDataLayer({
 | |
|             layerToShow: importLayer,
 | |
|             state,
 | |
|             zoomToFeatures: true,
 | |
|             leafletMap: map.leafletMap,
 | |
|             features: alreadyOpenImportNotes,
 | |
|             popup: (tags, layer) => new FeatureInfoBox(tags, layer, state)
 | |
|         })
 | |
| 
 | |
| 
 | |
|         const maxDistance = new UIEventSource<number>(5)
 | |
| 
 | |
|         const partitionedImportPoints = ImportUtils.partitionFeaturesIfNearby(params.geojson, alreadyOpenImportNotes.features
 | |
|             .map(ff => ({features: ff.map(ff => ff.feature)})), maxDistance)
 | |
| 
 | |
| 
 | |
|         new ShowDataLayer({
 | |
|             layerToShow: new LayerConfig(import_candidate),
 | |
|             state,
 | |
|             zoomToFeatures: true,
 | |
|             leafletMap: comparisonMap.leafletMap,
 | |
|             features: new StaticFeatureSource(partitionedImportPoints.map(p => p.hasNearby), false),
 | |
|             popup: (tags, layer) => new FeatureInfoBox(tags, layer, state)
 | |
|         })
 | |
| 
 | |
|         super([
 | |
|             new Title("Compare with already existing 'to-import'-notes"),
 | |
|             new VariableUiElement(
 | |
|                 alreadyOpenImportNotes.features.map(notesWithImport => {
 | |
|                     if (allNotesWithinBbox.features.data === undefined || allNotesWithinBbox.features.data.length === 0) {
 | |
|                         return new Loading("Fetching notes from OSM")
 | |
|                     }
 | |
|                     if (notesWithImport.length === 0) {
 | |
|                         return new FixedUiElement("No previous note to import found").SetClass("thanks")
 | |
|                     }
 | |
|                     return new Combine([
 | |
|                         map,
 | |
|                         "The following (red) elements are elements to import which are nearby a matching element that is already up for import. These won't be imported",
 | |
| 
 | |
|                         new Toggle(
 | |
|                             new FixedUiElement("All of the proposed points have (or had) an import note already").SetClass("alert w-full block").SetStyle("padding: 0.5rem"),
 | |
|                             new VariableUiElement(partitionedImportPoints.map(({noNearby}) => noNearby.length + " elements can be imported")).SetClass("thanks p-8"),
 | |
|                             partitionedImportPoints.map(({noNearby}) => noNearby.length === 0)
 | |
|                         ).SetClass("w-full"),
 | |
|                         comparisonMap,
 | |
|                     ]).SetClass("flex flex-col")
 | |
| 
 | |
|                 }, [allNotesWithinBbox.features])
 | |
|             ),
 | |
| 
 | |
| 
 | |
|         ]);
 | |
|         this.SetClass("flex flex-col")
 | |
|         this.Value = partitionedImportPoints.map(({noNearby}) => ({
 | |
|             geojson: {features: noNearby, type: "FeatureCollection"},
 | |
|             bbox: params.bbox,
 | |
|             layer: params.layer
 | |
|         }))
 | |
| 
 | |
|         this.IsValid = alreadyOpenImportNotes.features.map(ff => {
 | |
|             if (allNotesWithinBbox.features.data.length === 0) {
 | |
|                 // Not yet loaded
 | |
|                 return false
 | |
|             }
 | |
|             if (ff.length == 0) {
 | |
|                 // No import notes at all
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             return partitionedImportPoints.data.noNearby.length > 0; // at least _something_ can be imported
 | |
|         }, [partitionedImportPoints, allNotesWithinBbox.features])
 | |
|     }
 | |
| 
 | |
| } |