forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			196 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import Combine from "../Base/Combine"
 | 
						|
import { FlowStep } from "./FlowStep"
 | 
						|
import { BBox } from "../../Logic/BBox"
 | 
						|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
 | 
						|
import { Store, UIEventSource } from "../../Logic/UIEventSource"
 | 
						|
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 Loading from "../Base/Loading"
 | 
						|
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"
 | 
						|
 | 
						|
/**
 | 
						|
 * Filters out points for which the import-note already exists, to prevent duplicates
 | 
						|
 */
 | 
						|
export class CompareToAlreadyExistingNotes
 | 
						|
    extends Combine
 | 
						|
    implements FlowStep<{ bbox: BBox; layer: LayerConfig; features: any[]; theme: string }>
 | 
						|
{
 | 
						|
    public IsValid: Store<boolean>
 | 
						|
    public Value: Store<{ bbox: BBox; layer: LayerConfig; features: any[]; theme: string }>
 | 
						|
 | 
						|
    constructor(state, params: { bbox: BBox; layer: LayerConfig; features: any[]; theme: string }) {
 | 
						|
        const t = Translations.t.importHelper.compareToAlreadyExistingNotes
 | 
						|
        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(150).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: () => [],
 | 
						|
                    getFeatureById: () => 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
 | 
						|
        )
 | 
						|
        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>(10)
 | 
						|
 | 
						|
        const partitionedImportPoints = ImportUtils.partitionFeaturesIfNearby(
 | 
						|
            params,
 | 
						|
            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: StaticFeatureSource.fromGeojsonStore(
 | 
						|
                partitionedImportPoints.map((p) => p.hasNearby)
 | 
						|
            ),
 | 
						|
            popup: (tags, layer) => new FeatureInfoBox(tags, layer, state),
 | 
						|
        })
 | 
						|
 | 
						|
        super([
 | 
						|
            new Title(t.titleLong),
 | 
						|
            new VariableUiElement(
 | 
						|
                alreadyOpenImportNotes.features.map(
 | 
						|
                    (notesWithImport) => {
 | 
						|
                        if (
 | 
						|
                            allNotesWithinBbox.state.data !== undefined &&
 | 
						|
                            allNotesWithinBbox.state.data["error"] !== undefined
 | 
						|
                        ) {
 | 
						|
                            const error = allNotesWithinBbox.state.data["error"]
 | 
						|
                            t.loadingFailed.Subs({ error })
 | 
						|
                        }
 | 
						|
                        if (
 | 
						|
                            allNotesWithinBbox.features.data === undefined ||
 | 
						|
                            allNotesWithinBbox.features.data.length === 0
 | 
						|
                        ) {
 | 
						|
                            return new Loading(t.loading)
 | 
						|
                        }
 | 
						|
                        if (notesWithImport.length === 0) {
 | 
						|
                            return t.noPreviousNotesFound.SetClass("thanks")
 | 
						|
                        }
 | 
						|
                        return new Combine([
 | 
						|
                            t.mapExplanation.Subs(params.features),
 | 
						|
                            map,
 | 
						|
 | 
						|
                            new VariableUiElement(
 | 
						|
                                partitionedImportPoints.map(({ noNearby, hasNearby }) => {
 | 
						|
                                    if (noNearby.length === 0) {
 | 
						|
                                        // Nothing can be imported
 | 
						|
                                        return t.completelyImported
 | 
						|
                                            .SetClass("alert w-full block")
 | 
						|
                                            .SetStyle("padding: 0.5rem")
 | 
						|
                                    }
 | 
						|
 | 
						|
                                    if (hasNearby.length === 0) {
 | 
						|
                                        // All points can be imported
 | 
						|
                                        return t.nothingNearby
 | 
						|
                                            .SetClass("thanks w-full block")
 | 
						|
                                            .SetStyle("padding: 0.5rem")
 | 
						|
                                    }
 | 
						|
 | 
						|
                                    return new Combine([
 | 
						|
                                        t.someNearby
 | 
						|
                                            .Subs({
 | 
						|
                                                hasNearby: hasNearby.length,
 | 
						|
                                                distance: maxDistance.data,
 | 
						|
                                            })
 | 
						|
                                            .SetClass("alert"),
 | 
						|
                                        t.wontBeImported,
 | 
						|
                                        comparisonMap.SetClass("w-full"),
 | 
						|
                                    ]).SetClass("w-full")
 | 
						|
                                })
 | 
						|
                            ),
 | 
						|
                        ]).SetClass("flex flex-col")
 | 
						|
                    },
 | 
						|
                    [allNotesWithinBbox.features, allNotesWithinBbox.state]
 | 
						|
                )
 | 
						|
            ),
 | 
						|
        ])
 | 
						|
        this.SetClass("flex flex-col")
 | 
						|
        this.Value = partitionedImportPoints.map(({ noNearby }) => ({
 | 
						|
            features: noNearby,
 | 
						|
            bbox: params.bbox,
 | 
						|
            layer: params.layer,
 | 
						|
            theme: params.theme,
 | 
						|
        }))
 | 
						|
 | 
						|
        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]
 | 
						|
        )
 | 
						|
    }
 | 
						|
}
 |