forked from MapComplete/MapComplete
		
	Repair import flow
This commit is contained in:
		
							parent
							
								
									8c7bb92f8a
								
							
						
					
					
						commit
						e1cdb75001
					
				
					 7 changed files with 85 additions and 74 deletions
				
			
		
							
								
								
									
										20
									
								
								UI/Base/DivContainer.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								UI/Base/DivContainer.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| import { UIElement } from "../UIElement" | ||||
| import BaseUIElement from "../BaseUIElement" | ||||
| 
 | ||||
| /** | ||||
|  * Introduces a new element which has an ID | ||||
|  * Mostly a workaround for the import viewer | ||||
|  */ | ||||
| export default class DivContainer extends BaseUIElement { | ||||
|     private readonly _id: string | ||||
| 
 | ||||
|     constructor(id: string) { | ||||
|         super() | ||||
|         this._id = id | ||||
|     } | ||||
|     protected InnerConstructElement(): HTMLElement { | ||||
|         const e = document.createElement("div") | ||||
|         e.id = this._id | ||||
|         return e | ||||
|     } | ||||
| } | ||||
|  | @ -21,6 +21,8 @@ import { VariableUiElement } from "../Base/VariableUIElement" | |||
| import * as known_layers from "../../assets/generated/known_layers.json" | ||||
| import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" | ||||
| import Translations from "../i18n/Translations" | ||||
| import { Feature } from "geojson" | ||||
| import DivContainer from "../Base/DivContainer" | ||||
| 
 | ||||
| /** | ||||
|  * Filters out points for which the import-note already exists, to prevent duplicates | ||||
|  | @ -105,7 +107,7 @@ export class CompareToAlreadyExistingNotes | |||
|             zoomToFeatures: true, | ||||
|             leafletMap: comparisonMap.leafletMap, | ||||
|             features: StaticFeatureSource.fromGeojsonStore( | ||||
|                 partitionedImportPoints.map((p) => p.hasNearby) | ||||
|                 partitionedImportPoints.map((p) => <Feature[]>p.hasNearby) | ||||
|             ), | ||||
|             popup: (tags, layer) => new FeatureInfoBox(tags, layer, state), | ||||
|         }) | ||||
|  | @ -134,7 +136,7 @@ export class CompareToAlreadyExistingNotes | |||
|                         return new Combine([ | ||||
|                             t.mapExplanation.Subs(params.features), | ||||
|                             map, | ||||
| 
 | ||||
|                             new DivContainer("fullscreen"), | ||||
|                             new VariableUiElement( | ||||
|                                 partitionedImportPoints.map(({ noNearby, hasNearby }) => { | ||||
|                                     if (noNearby.length === 0) { | ||||
|  |  | |||
|  | @ -27,24 +27,26 @@ import { GeoOperations } from "../../Logic/GeoOperations" | |||
| import FeatureInfoBox from "../Popup/FeatureInfoBox" | ||||
| import { ImportUtils } from "./ImportUtils" | ||||
| import Translations from "../i18n/Translations" | ||||
| import ShowDataMultiLayer from "../ShowDataLayer/ShowDataMultiLayer" | ||||
| import FilteredLayer, { FilterState } from "../../Models/FilteredLayer" | ||||
| import { Feature, FeatureCollection } from "@turf/turf" | ||||
| import * as currentview from "../../assets/layers/current_view/current_view.json" | ||||
| import { CheckBox } from "../Input/Checkboxes" | ||||
| import BackgroundMapSwitch from "../BigComponents/BackgroundMapSwitch" | ||||
| import { Feature, FeatureCollection, Point } from "geojson" | ||||
| import DivContainer from "../Base/DivContainer" | ||||
| 
 | ||||
| /** | ||||
|  * Given the data to import, the bbox and the layer, will query overpass for similar items | ||||
|  */ | ||||
| export default class ConflationChecker | ||||
|     extends Combine | ||||
|     implements FlowStep<{ features: any[]; theme: string }> | ||||
|     implements FlowStep<{ features: Feature<Point>[]; theme: string }> | ||||
| { | ||||
|     public readonly IsValid | ||||
|     public readonly Value: Store<{ features: any[]; theme: string }> | ||||
|     public readonly Value: Store<{ features: Feature<Point>[]; theme: string }> | ||||
| 
 | ||||
|     constructor(state, params: { bbox: BBox; layer: LayerConfig; theme: string; features: any[] }) { | ||||
|     constructor( | ||||
|         state, | ||||
|         params: { bbox: BBox; layer: LayerConfig; theme: string; features: Feature<Point>[] } | ||||
|     ) { | ||||
|         const t = Translations.t.importHelper.conflationChecker | ||||
| 
 | ||||
|         const bbox = params.bbox.padAbsolute(0.0001) | ||||
|  | @ -175,15 +177,8 @@ export default class ConflationChecker | |||
|             features: StaticFeatureSource.fromGeojson([bbox.asGeoJson({})]), | ||||
|         }) | ||||
| 
 | ||||
|         new ShowDataMultiLayer({ | ||||
|             //layerToShow: layer,
 | ||||
|             layers: new UIEventSource<FilteredLayer[]>([ | ||||
|                 { | ||||
|                     layerDef: layer, | ||||
|                     isDisplayed: new UIEventSource<boolean>(true), | ||||
|                     appliedFilters: new UIEventSource<Map<string, FilterState>>(undefined), | ||||
|                 }, | ||||
|             ]), | ||||
|         new ShowDataLayer({ | ||||
|             layerToShow: layer, | ||||
|             state, | ||||
|             leafletMap: osmLiveData.leafletMap, | ||||
|             popup: (tags, layer) => new FeatureInfoBox(tags, layer, state, { setHash: false }), | ||||
|  | @ -239,7 +234,7 @@ export default class ConflationChecker | |||
| 
 | ||||
|         // Featuresource showing OSM-features which are nearby a toImport-feature
 | ||||
|         const toImportWithNearby = StaticFeatureSource.fromGeojsonStore( | ||||
|             paritionedImport.map((els) => els?.hasNearby ?? []) | ||||
|             paritionedImport.map((els) => <Feature[]>els?.hasNearby ?? []) | ||||
|         ) | ||||
|         toImportWithNearby.features.addCallback((nearby) => | ||||
|             console.log("The following features are near an already existing object:", nearby) | ||||
|  | @ -325,6 +320,7 @@ export default class ConflationChecker | |||
|                     }) | ||||
|                 ), | ||||
|             ]).SetClass("flex"), | ||||
|             new DivContainer("fullscreen"), | ||||
|             new Title(t.titleNearby), | ||||
|             new Combine([t.mapShowingNearbyIntro, nearbyCutoff]).SetClass("flex"), | ||||
|             new VariableUiElement( | ||||
|  | @ -369,7 +365,7 @@ export default class ConflationChecker | |||
| 
 | ||||
|         this.Value = paritionedImport.map((feats) => ({ | ||||
|             theme: params.theme, | ||||
|             features: feats?.noNearby, | ||||
|             features: <any>feats?.noNearby, | ||||
|             layer: params.layer, | ||||
|         })) | ||||
|         this.IsValid = this.Value.map((v) => v?.features !== undefined && v.features.length > 0) | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| import { Store } from "../../Logic/UIEventSource" | ||||
| import { GeoOperations } from "../../Logic/GeoOperations" | ||||
| import { Feature, Geometry } from "@turf/turf" | ||||
| import { Feature, Point } from "geojson" | ||||
| 
 | ||||
| export class ImportUtils { | ||||
|     public static partitionFeaturesIfNearby( | ||||
|         toPartitionFeatureCollection: { features: Feature<Geometry>[] }, | ||||
|         toPartitionFeatureCollection: { features: Feature[] }, | ||||
|         compareWith: Store<{ features: Feature[] }>, | ||||
|         cutoffDistanceInMeters: Store<number> | ||||
|     ): Store<{ hasNearby: Feature[]; noNearby: Feature[] }> { | ||||
|  | @ -25,7 +25,7 @@ export class ImportUtils { | |||
|                         (f) => | ||||
|                             maxDist >= | ||||
|                             GeoOperations.distanceBetween( | ||||
|                                 <any>toImportElement.geometry.coordinates, | ||||
|                                 <any>(<Point>toImportElement.geometry).coordinates, | ||||
|                                 GeoOperations.centerpointCoordinates(f) | ||||
|                             ) | ||||
|                     ) | ||||
|  |  | |||
|  | @ -25,6 +25,9 @@ import Title from "../Base/Title" | |||
| import CheckBoxes from "../Input/Checkboxes" | ||||
| import { AllTagsPanel } from "../AllTagsPanel" | ||||
| import BackgroundMapSwitch from "../BigComponents/BackgroundMapSwitch" | ||||
| import { Feature, Point } from "geojson" | ||||
| import DivContainer from "../Base/DivContainer" | ||||
| import ShowDataLayer from "../ShowDataLayer/ShowDataLayer" | ||||
| 
 | ||||
| class PreviewPanel extends ScrollableFullScreen { | ||||
|     constructor(tags: UIEventSource<any>) { | ||||
|  | @ -41,15 +44,12 @@ class PreviewPanel extends ScrollableFullScreen { | |||
|  */ | ||||
| export class MapPreview | ||||
|     extends Combine | ||||
|     implements FlowStep<{ bbox: BBox; layer: LayerConfig; features: any[] }> | ||||
|     implements FlowStep<{ bbox: BBox; layer: LayerConfig; features: Feature<Point>[] }> | ||||
| { | ||||
|     public readonly IsValid: Store<boolean> | ||||
|     public readonly Value: Store<{ bbox: BBox; layer: LayerConfig; features: any[] }> | ||||
| 
 | ||||
|     constructor( | ||||
|         state: UserRelatedState, | ||||
|         geojson: { features: { properties: any; geometry: { coordinates: [number, number] } }[] } | ||||
|     ) { | ||||
|     constructor(state: UserRelatedState, geojson: { features: Feature[] }) { | ||||
|         const t = Translations.t.importHelper.mapPreview | ||||
| 
 | ||||
|         const propertyKeys = new Set<string>() | ||||
|  | @ -90,22 +90,23 @@ export class MapPreview | |||
|             return copy | ||||
|         }) | ||||
| 
 | ||||
|         const matching: Store<{ properties: any; geometry: { coordinates: [number, number] } }[]> = | ||||
|             layerPicker.GetValue().map((layer: LayerConfig) => { | ||||
|                 if (layer === undefined) { | ||||
|                     return [] | ||||
|                 } | ||||
|                 const matching: { properties: any; geometry: { coordinates: [number, number] } }[] = | ||||
|                     [] | ||||
|         // Create a store which has only features matching the selected layer
 | ||||
|         const matching: Store<Feature[]> = layerPicker.GetValue().map((layer: LayerConfig) => { | ||||
|             if (layer === undefined) { | ||||
|                 console.log("No matching layer found") | ||||
|                 return [] | ||||
|             } | ||||
|             const matching: Feature[] = [] | ||||
| 
 | ||||
|                 for (const feature of withId) { | ||||
|                     if (layer.source.osmTags.matchesProperties(feature.properties)) { | ||||
|                         matching.push(feature) | ||||
|                     } | ||||
|             for (const feature of withId) { | ||||
|                 if (layer.source.osmTags.matchesProperties(feature.properties)) { | ||||
|                     matching.push(feature) | ||||
|                 } | ||||
|             } | ||||
|             console.log("Matching features: ", matching) | ||||
| 
 | ||||
|                 return matching | ||||
|             }) | ||||
|             return matching | ||||
|         }) | ||||
|         const background = new UIEventSource<BaseLayer>(AvailableBaseLayers.osmCarto) | ||||
|         const location = new UIEventSource<Loc>({ lat: 0, lon: 0, zoom: 1 }) | ||||
|         const currentBounds = new UIEventSource<BBox>(undefined) | ||||
|  | @ -130,25 +131,22 @@ export class MapPreview | |||
|         ) | ||||
|         map.SetClass("w-full").SetStyle("height: 500px") | ||||
| 
 | ||||
|         new ShowDataMultiLayer({ | ||||
|             layers: new UIEventSource<FilteredLayer[]>( | ||||
|                 AllKnownLayouts.AllPublicLayers() | ||||
|                     .filter((l) => l.source.geojsonSource === undefined) | ||||
|                     .map((l) => ({ | ||||
|                         layerDef: l, | ||||
|                         isDisplayed: new UIEventSource<boolean>(true), | ||||
|                         appliedFilters: new UIEventSource<Map<string, FilterState>>(undefined), | ||||
|                     })) | ||||
|             ), | ||||
|             zoomToFeatures: true, | ||||
|             features: StaticFeatureSource.fromDateless( | ||||
|                 matching.map((features) => features.map((feature) => ({ feature }))) | ||||
|             ), | ||||
|             leafletMap: map.leafletMap, | ||||
|             popup: (tag) => new PreviewPanel(tag).SetClass("font-lg"), | ||||
|         layerPicker.GetValue().addCallbackAndRunD((layerToShow) => { | ||||
|             new ShowDataLayer({ | ||||
|                 layerToShow, | ||||
|                 zoomToFeatures: true, | ||||
|                 features: StaticFeatureSource.fromDateless( | ||||
|                     matching.map((features) => features.map((feature) => ({ feature }))) | ||||
|                 ), | ||||
|                 leafletMap: map.leafletMap, | ||||
|                 popup: (tag) => new PreviewPanel(tag), | ||||
|             }) | ||||
|         }) | ||||
|         var bbox = matching.map((feats) => | ||||
|             BBox.bboxAroundAll(feats.map((f) => new BBox([f.geometry.coordinates]))) | ||||
| 
 | ||||
|         const bbox = matching.map((feats) => | ||||
|             BBox.bboxAroundAll( | ||||
|                 feats.map((f) => new BBox([(<Feature<Point>>f).geometry.coordinates])) | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|         const mismatchIndicator = new VariableUiElement( | ||||
|  | @ -171,10 +169,11 @@ export class MapPreview | |||
|         super([ | ||||
|             new Title(t.title, 1), | ||||
|             layerPicker, | ||||
|             new Toggle(t.autodetected.SetClass("thank"), undefined, autodetected), | ||||
|             new Toggle(t.autodetected.SetClass("thanks"), undefined, autodetected), | ||||
| 
 | ||||
|             mismatchIndicator, | ||||
|             map, | ||||
|             new DivContainer("fullscreen"), | ||||
|             layerControl, | ||||
|             confirm, | ||||
|         ]) | ||||
|  | @ -182,10 +181,10 @@ export class MapPreview | |||
|         this.Value = bbox.map( | ||||
|             (bbox) => ({ | ||||
|                 bbox, | ||||
|                 features: geojson.features, | ||||
|                 features: matching.data, | ||||
|                 layer: layerPicker.GetValue().data, | ||||
|             }), | ||||
|             [layerPicker.GetValue()] | ||||
|             [layerPicker.GetValue(), matching] | ||||
|         ) | ||||
| 
 | ||||
|         this.IsValid = matching.map( | ||||
|  |  | |||
|  | @ -10,24 +10,19 @@ import Histogram from "../BigComponents/Histogram" | |||
| import Toggleable from "../Base/Toggleable" | ||||
| import List from "../Base/List" | ||||
| import CheckBoxes from "../Input/Checkboxes" | ||||
| import { Feature, Point } from "geojson" | ||||
| 
 | ||||
| /** | ||||
|  * Shows the attributes by value, requests to check them of | ||||
|  */ | ||||
| export class PreviewAttributesPanel | ||||
|     extends Combine | ||||
|     implements | ||||
|         FlowStep<{ features: { properties: any; geometry: { coordinates: [number, number] } }[] }> | ||||
|     implements FlowStep<{ features: Feature<Point>[] }> | ||||
| { | ||||
|     public readonly IsValid: Store<boolean> | ||||
|     public readonly Value: Store<{ | ||||
|         features: { properties: any; geometry: { coordinates: [number, number] } }[] | ||||
|     }> | ||||
|     public readonly Value: Store<{ features: Feature<Point>[] }> | ||||
| 
 | ||||
|     constructor( | ||||
|         state: UserRelatedState, | ||||
|         geojson: { features: { properties: any; geometry: { coordinates: [number, number] } }[] } | ||||
|     ) { | ||||
|     constructor(state: UserRelatedState, geojson: { features: Feature<Point>[] }) { | ||||
|         const t = Translations.t.importHelper.previewAttributes | ||||
| 
 | ||||
|         const propertyKeys = new Set<string>() | ||||
|  | @ -93,9 +88,7 @@ export class PreviewAttributesPanel | |||
|             confirm, | ||||
|         ]) | ||||
| 
 | ||||
|         this.Value = new UIEventSource<{ | ||||
|             features: { properties: any; geometry: { coordinates: [number, number] } }[] | ||||
|         }>(geojson) | ||||
|         this.Value = new UIEventSource<{ features: Feature<Point>[] }>(geojson) | ||||
|         this.IsValid = confirm.GetValue().map((selected) => selected.length == 1) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ import { FlowStep } from "./FlowStep" | |||
| import { parse } from "papaparse" | ||||
| import { FixedUiElement } from "../Base/FixedUiElement" | ||||
| import { TagUtils } from "../../Logic/Tags/TagUtils" | ||||
| import { Feature, Point } from "geojson" | ||||
| 
 | ||||
| class FileSelector extends InputElementMap<FileList, { name: string; contents: Promise<string> }> { | ||||
|     constructor(label: BaseUIElement) { | ||||
|  | @ -40,7 +41,7 @@ export class RequestFile extends Combine implements FlowStep<{ features: any[] } | |||
|     /** | ||||
|      * The loaded GeoJSON | ||||
|      */ | ||||
|     public readonly Value: Store<{ features: any[] }> | ||||
|     public readonly Value: Store<{ features: Feature<Point>[] }> | ||||
| 
 | ||||
|     constructor() { | ||||
|         const t = Translations.t.importHelper.selectFile | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue