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