forked from MapComplete/MapComplete
Refactoring: move download functionality for OsmObjects into a new object
This commit is contained in:
parent
8eb2c68f79
commit
1f9aacfb29
23 changed files with 633 additions and 901 deletions
|
@ -1,9 +1,5 @@
|
|||
import Combine from "../Base/Combine"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
import { BBox } from "../../Logic/BBox"
|
||||
import Loc from "../../Models/Loc"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import Translations from "../i18n/Translations"
|
||||
import { SubtleButton } from "../Base/SubtleButton"
|
||||
import Svg from "../../Svg"
|
||||
|
@ -11,7 +7,7 @@ import { Utils } from "../../Utils"
|
|||
import { MapillaryLink } from "./MapillaryLink"
|
||||
import { OpenIdEditor, OpenJosm } from "./CopyrightPanel"
|
||||
import Toggle from "../Input/Toggle"
|
||||
import { DefaultGuiState } from "../DefaultGuiState"
|
||||
import { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
|
||||
export class BackToThemeOverview extends Toggle {
|
||||
constructor(
|
||||
|
@ -35,14 +31,7 @@ export class BackToThemeOverview extends Toggle {
|
|||
}
|
||||
|
||||
export class ActionButtons extends Combine {
|
||||
constructor(state: {
|
||||
readonly layoutToUse: LayoutConfig
|
||||
readonly currentBounds: Store<BBox>
|
||||
readonly locationControl: Store<Loc>
|
||||
readonly osmConnection: OsmConnection
|
||||
readonly featureSwitchMoreQuests: Store<boolean>
|
||||
readonly defaultGuiState: DefaultGuiState
|
||||
}) {
|
||||
constructor(state:SpecialVisualizationState) {
|
||||
const imgSize = "h-6 w-6"
|
||||
const iconStyle = "height: 1.5rem; width: 1.5rem"
|
||||
const t = Translations.t.general.attribution
|
||||
|
@ -76,7 +65,7 @@ export class ActionButtons extends Combine {
|
|||
}),
|
||||
new OpenIdEditor(state, iconStyle),
|
||||
new MapillaryLink(state, iconStyle),
|
||||
new OpenJosm(state, iconStyle).SetClass("hidden-on-mobile"),
|
||||
new OpenJosm(state.osmConnection,state.mapProperties.bounds, iconStyle).SetClass("hidden-on-mobile"),
|
||||
])
|
||||
this.SetClass("block w-full link-no-underline")
|
||||
}
|
||||
|
|
|
@ -1,333 +0,0 @@
|
|||
import { ReadonlyInputElement } from "./InputElement"
|
||||
import Loc from "../../Models/Loc"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import Combine from "../Base/Combine"
|
||||
import Svg from "../../Svg"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import { BBox } from "../../Logic/BBox"
|
||||
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import matchpoint from "../../assets/layers/matchpoint/matchpoint.json"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import { RelationId, WayId } from "../../Models/OsmFeature"
|
||||
import { Feature, LineString, Polygon } from "geojson"
|
||||
import { OsmObject, OsmWay } from "../../Logic/Osm/OsmObject"
|
||||
|
||||
export default class LocationInput
|
||||
extends BaseUIElement
|
||||
implements ReadonlyInputElement<Loc>, MinimapObj
|
||||
{
|
||||
private static readonly matchLayer = new LayerConfig(
|
||||
matchpoint,
|
||||
"LocationInput.matchpoint",
|
||||
true
|
||||
)
|
||||
|
||||
public readonly snappedOnto: UIEventSource<Feature & { properties: { id: WayId } }> =
|
||||
new UIEventSource(undefined)
|
||||
public readonly _matching_layer: LayerConfig
|
||||
public readonly leafletMap: UIEventSource<any>
|
||||
public readonly bounds
|
||||
public readonly location
|
||||
private readonly _centerLocation: UIEventSource<Loc>
|
||||
private readonly mapBackground: UIEventSource<BaseLayer>
|
||||
/**
|
||||
* The features to which the input should be snapped
|
||||
* @private
|
||||
*/
|
||||
private readonly _snapTo: Store<
|
||||
(Feature<LineString | Polygon> & { properties: { id: WayId } })[]
|
||||
>
|
||||
/**
|
||||
* The features to which the input should be snapped without cleanup of relations and memberships
|
||||
* Used for rendering
|
||||
* @private
|
||||
*/
|
||||
private readonly _snapToRaw: Store<Feature[]>
|
||||
private readonly _value: Store<Loc>
|
||||
private readonly _snappedPoint: Store<any>
|
||||
private readonly _maxSnapDistance: number
|
||||
private readonly _snappedPointTags: any
|
||||
private readonly _bounds: UIEventSource<BBox>
|
||||
private readonly map: BaseUIElement & MinimapObj
|
||||
private readonly clickLocation: UIEventSource<Loc>
|
||||
private readonly _minZoom: number
|
||||
private readonly _state: {
|
||||
readonly filteredLayers: Store<FilteredLayer[]>
|
||||
readonly backgroundLayer: UIEventSource<BaseLayer>
|
||||
readonly layoutToUse: LayoutConfig
|
||||
readonly selectedElement: UIEventSource<any>
|
||||
readonly allElements: ElementStorage
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of geojson-features, will prepare these features to be snappable:
|
||||
* - points are removed
|
||||
* - LineStrings are passed as-is
|
||||
* - Multipolygons are decomposed into their member ways by downloading them
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private static async prepareSnapOnto(
|
||||
features: Feature[]
|
||||
): Promise<(Feature<LineString | Polygon> & { properties: { id: WayId } })[]> {
|
||||
const linesAndPolygon: Feature<LineString | Polygon>[] = <any>(
|
||||
features.filter((f) => f.geometry.type !== "Point")
|
||||
)
|
||||
// Clean the features: multipolygons are split into their it's members
|
||||
const linestrings: (Feature<LineString | Polygon> & { properties: { id: WayId } })[] = []
|
||||
for (const feature of linesAndPolygon) {
|
||||
if (feature.properties.id.startsWith("way")) {
|
||||
// A normal way - we continue
|
||||
linestrings.push(<any>feature)
|
||||
continue
|
||||
}
|
||||
|
||||
// We have a multipolygon, thus: a relation
|
||||
// Download the members
|
||||
const relation = await OsmObject.DownloadObjectAsync(
|
||||
<RelationId>feature.properties.id,
|
||||
60 * 60
|
||||
)
|
||||
const members: OsmWay[] = await Promise.all(
|
||||
relation.members
|
||||
.filter((m) => m.type === "way")
|
||||
.map((m) => OsmObject.DownloadObjectAsync(<WayId>("way/" + m.ref), 60 * 60))
|
||||
)
|
||||
linestrings.push(...members.map((m) => m.asGeoJson()))
|
||||
}
|
||||
return linestrings
|
||||
}
|
||||
|
||||
constructor(options?: {
|
||||
minZoom?: number
|
||||
mapBackground?: UIEventSource<BaseLayer>
|
||||
snapTo?: UIEventSource<Feature[]>
|
||||
renderLayerForSnappedPoint?: LayerConfig
|
||||
maxSnapDistance?: number
|
||||
snappedPointTags?: any
|
||||
requiresSnapping?: boolean
|
||||
centerLocation?: UIEventSource<Loc>
|
||||
bounds?: UIEventSource<BBox>
|
||||
state?: {
|
||||
readonly filteredLayers: Store<FilteredLayer[]>
|
||||
readonly backgroundLayer: UIEventSource<BaseLayer>
|
||||
readonly layoutToUse: LayoutConfig
|
||||
readonly selectedElement: UIEventSource<any>
|
||||
readonly allElements: ElementStorage
|
||||
}
|
||||
}) {
|
||||
super()
|
||||
this._snapToRaw = options?.snapTo?.map((feats) =>
|
||||
feats.filter((f) => f.feature.geometry.type !== "Point")
|
||||
)
|
||||
this._snapTo = options?.snapTo
|
||||
?.bind((features) =>
|
||||
UIEventSource.FromPromise(
|
||||
LocationInput.prepareSnapOnto(features.map((f) => f.feature))
|
||||
)
|
||||
)
|
||||
?.map((f) => f ?? [])
|
||||
this._maxSnapDistance = options?.maxSnapDistance
|
||||
this._centerLocation =
|
||||
options?.centerLocation ??
|
||||
new UIEventSource<Loc>({
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
zoom: 0,
|
||||
})
|
||||
this._snappedPointTags = options?.snappedPointTags
|
||||
this._bounds = options?.bounds
|
||||
this._minZoom = options?.minZoom
|
||||
this._state = options?.state
|
||||
const self = this
|
||||
if (this._snapTo === undefined) {
|
||||
this._value = this._centerLocation
|
||||
} else {
|
||||
this._matching_layer = options?.renderLayerForSnappedPoint ?? LocationInput.matchLayer
|
||||
|
||||
// Calculate the location of the point based by snapping it onto a way
|
||||
// As a side-effect, the actual snapped-onto way (if any) is saved into 'snappedOnto'
|
||||
this._snappedPoint = this._centerLocation.map(
|
||||
(loc) => {
|
||||
if (loc === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
// We reproject the location onto every 'snap-to-feature' and select the closest
|
||||
|
||||
let min = undefined
|
||||
let matchedWay: Feature<LineString | Polygon> & { properties: { id: WayId } } =
|
||||
undefined
|
||||
for (const feature of self._snapTo.data ?? []) {
|
||||
try {
|
||||
const nearestPointOnLine = GeoOperations.nearestPoint(feature, [
|
||||
loc.lon,
|
||||
loc.lat,
|
||||
])
|
||||
if (min === undefined) {
|
||||
min = { ...nearestPointOnLine }
|
||||
matchedWay = feature
|
||||
continue
|
||||
}
|
||||
|
||||
if (min.properties.dist > nearestPointOnLine.properties.dist) {
|
||||
min = { ...nearestPointOnLine }
|
||||
matchedWay = feature
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(
|
||||
"Snapping to a nearest point failed for ",
|
||||
feature,
|
||||
"due to ",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (min === undefined || min.properties.dist * 1000 > self._maxSnapDistance) {
|
||||
if (options?.requiresSnapping) {
|
||||
return undefined
|
||||
} else {
|
||||
// No match found - the original coordinates are returned as is
|
||||
return {
|
||||
type: "Feature",
|
||||
properties: options?.snappedPointTags ?? min.properties,
|
||||
geometry: { type: "Point", coordinates: [loc.lon, loc.lat] },
|
||||
}
|
||||
}
|
||||
}
|
||||
min.properties = options?.snappedPointTags ?? min.properties
|
||||
min.properties = {
|
||||
...min.properties,
|
||||
_referencing_ways: JSON.stringify([matchedWay.properties.id]),
|
||||
}
|
||||
self.snappedOnto.setData(<any>matchedWay)
|
||||
return min
|
||||
},
|
||||
[this._snapTo]
|
||||
)
|
||||
|
||||
this._value = this._snappedPoint.map((f) => {
|
||||
const [lon, lat] = f.geometry.coordinates
|
||||
return {
|
||||
lon: lon,
|
||||
lat: lat,
|
||||
zoom: undefined,
|
||||
}
|
||||
})
|
||||
}
|
||||
this.mapBackground =
|
||||
options?.mapBackground ??
|
||||
this._state?.backgroundLayer ??
|
||||
new UIEventSource<BaseLayer>(AvailableBaseLayers.osmCarto)
|
||||
this.SetClass("block h-full")
|
||||
|
||||
this.clickLocation = new UIEventSource<Loc>(undefined)
|
||||
this.map = Minimap.createMiniMap({
|
||||
location: this._centerLocation,
|
||||
background: this.mapBackground,
|
||||
attribution: this.mapBackground !== this._state?.backgroundLayer,
|
||||
lastClickLocation: this.clickLocation,
|
||||
bounds: this._bounds,
|
||||
addLayerControl: true,
|
||||
})
|
||||
this.leafletMap = this.map.leafletMap
|
||||
this.location = this.map.location
|
||||
}
|
||||
|
||||
GetValue(): Store<Loc> {
|
||||
return this._value
|
||||
}
|
||||
|
||||
IsValid(t: Loc): boolean {
|
||||
return t !== undefined
|
||||
}
|
||||
|
||||
installBounds(factor: number | BBox, showRange?: boolean): void {
|
||||
this.map.installBounds(factor, showRange)
|
||||
}
|
||||
|
||||
protected InnerConstructElement(): HTMLElement {
|
||||
try {
|
||||
const self = this
|
||||
const hasMoved = new UIEventSource(false)
|
||||
const startLocation = { ...this._centerLocation.data }
|
||||
this._centerLocation.addCallbackD((newLocation) => {
|
||||
const f = 100000
|
||||
const diff =
|
||||
Math.abs(newLocation.lon * f - startLocation.lon * f) +
|
||||
Math.abs(newLocation.lat * f - startLocation.lat * f)
|
||||
if (diff < 1) {
|
||||
return
|
||||
}
|
||||
hasMoved.setData(true)
|
||||
return true
|
||||
})
|
||||
this.clickLocation.addCallbackAndRunD((location) =>
|
||||
this._centerLocation.setData(location)
|
||||
)
|
||||
if (this._snapToRaw !== undefined) {
|
||||
// Show the lines to snap to
|
||||
new ShowDataMultiLayer({
|
||||
features: new StaticFeatureSource(this._snapToRaw),
|
||||
zoomToFeatures: false,
|
||||
leafletMap: this.map.leafletMap,
|
||||
layers: this._state.filteredLayers,
|
||||
})
|
||||
// Show the central point
|
||||
const matchPoint = this._snappedPoint.map((loc) => {
|
||||
if (loc === undefined) {
|
||||
return []
|
||||
}
|
||||
return [loc]
|
||||
})
|
||||
|
||||
// The 'matchlayer' is the layer which shows the target location
|
||||
new ShowDataLayer({
|
||||
features: new StaticFeatureSource(matchPoint),
|
||||
zoomToFeatures: false,
|
||||
leafletMap: this.map.leafletMap,
|
||||
layerToShow: this._matching_layer,
|
||||
state: this._state,
|
||||
selectedElement: this._state.selectedElement,
|
||||
})
|
||||
}
|
||||
this.mapBackground.map(
|
||||
(layer) => {
|
||||
const leaflet = this.map.leafletMap.data
|
||||
if (leaflet === undefined || layer === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
leaflet.setMaxZoom(layer.max_zoom)
|
||||
leaflet.setMinZoom(self._minZoom ?? layer.max_zoom - 2)
|
||||
leaflet.setZoom(layer.max_zoom - 1)
|
||||
},
|
||||
[this.map.leafletMap]
|
||||
)
|
||||
|
||||
return new Combine([
|
||||
new Combine([
|
||||
Svg.move_arrows_ui()
|
||||
.SetClass("block relative pointer-events-none")
|
||||
.SetStyle("left: -2.5rem; top: -2.5rem; width: 5rem; height: 5rem"),
|
||||
])
|
||||
.SetClass("block w-0 h-0 z-10 relative")
|
||||
.SetStyle(
|
||||
"background: rgba(255, 128, 128, 0.21); left: 50%; top: 50%; opacity: 0.5"
|
||||
),
|
||||
|
||||
this.map.SetClass("z-0 relative block w-full h-full bg-gray-100"),
|
||||
]).ConstructElement()
|
||||
} catch (e) {
|
||||
console.error("Could not generate LocationInputElement:", e)
|
||||
return new FixedUiElement("Constructing a locationInput failed due to" + e)
|
||||
.SetClass("alert")
|
||||
.ConstructElement()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,10 +21,9 @@
|
|||
import LoginButton from "../../Base/LoginButton.svelte";
|
||||
import NewPointLocationInput from "../../BigComponents/NewPointLocationInput.svelte";
|
||||
import CreateNewNodeAction from "../../../Logic/Osm/Actions/CreateNewNodeAction";
|
||||
import { OsmObject } from "../../../Logic/Osm/OsmObject";
|
||||
import { OsmWay } from "../../../Logic/Osm/OsmObject";
|
||||
import { Tag } from "../../../Logic/Tags/Tag";
|
||||
import type { WayId } from "../../../Models/OsmFeature";
|
||||
import { TagUtils } from "../../../Logic/Tags/TagUtils";
|
||||
import Loading from "../../Base/Loading.svelte";
|
||||
|
||||
export let coordinate: { lon: number, lat: number };
|
||||
|
@ -75,12 +74,19 @@
|
|||
const tags: Tag[] = selectedPreset.preset.tags;
|
||||
console.log("Creating new point at", location, "snapped to", snapTo, "with tags", tags);
|
||||
|
||||
const snapToWay = snapTo === undefined ? undefined : await OsmObject.DownloadObjectAsync(snapTo, 0);
|
||||
let snapToWay: undefined | OsmWay = undefined
|
||||
if(snapTo !== undefined){
|
||||
const downloaded = await state.osmObjectDownloader.DownloadObjectAsync(snapTo, 0);
|
||||
if(downloaded !== "deleted"){
|
||||
snapToWay = downloaded
|
||||
}
|
||||
}
|
||||
|
||||
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
||||
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon,
|
||||
{
|
||||
theme: state.layout?.id ?? "unkown",
|
||||
changeType: "create",
|
||||
snapOnto: snapToWay
|
||||
snapOnto: snapToWay
|
||||
});
|
||||
await state.changes.applyAction(newElementAction);
|
||||
// The 'changes' should have created a new point, which added this into the 'featureProperties'
|
||||
|
|
|
@ -11,7 +11,6 @@ import { Translation } from "../i18n/Translation"
|
|||
import BaseUIElement from "../BaseUIElement"
|
||||
import Constants from "../../Models/Constants"
|
||||
import DeleteConfig from "../../Models/ThemeConfig/DeleteConfig"
|
||||
import { OsmObject } from "../../Logic/Osm/OsmObject"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import OsmChangeAction from "../../Logic/Osm/Actions/OsmChangeAction"
|
||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
|
||||
|
@ -20,12 +19,12 @@ import { RadioButton } from "../Input/RadioButton"
|
|||
import { FixedInputElement } from "../Input/FixedInputElement"
|
||||
import Title from "../Base/Title"
|
||||
import { SubstitutedTranslation } from "../SubstitutedTranslation"
|
||||
import TagRenderingQuestion from "./TagRenderingQuestion"
|
||||
import { OsmId, OsmTags } from "../../Models/OsmFeature"
|
||||
import { LoginToggle } from "./LoginButton"
|
||||
import { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import SvelteUIElement from "../Base/SvelteUIElement";
|
||||
import TagHint from "./TagHint.svelte";
|
||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import TagHint from "./TagHint.svelte"
|
||||
import OsmObjectDownloader from "../../Logic/Osm/OsmObjectDownloader"
|
||||
|
||||
export default class DeleteWizard extends Toggle {
|
||||
/**
|
||||
|
@ -53,6 +52,7 @@ export default class DeleteWizard extends Toggle {
|
|||
const deleteAbility = new DeleteabilityChecker(
|
||||
id,
|
||||
state.osmConnection,
|
||||
state.osmObjectDownloader,
|
||||
options.neededChangesets
|
||||
)
|
||||
|
||||
|
@ -227,7 +227,10 @@ export default class DeleteWizard extends Toggle {
|
|||
// This is a retagging, not a deletion of any kind
|
||||
return new Combine([
|
||||
t.explanations.retagNoOtherThemes,
|
||||
new SvelteUIElement(TagHint, {osmConnection: state.osmConnection, tags: retag})
|
||||
new SvelteUIElement(TagHint, {
|
||||
osmConnection: state.osmConnection,
|
||||
tags: retag,
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -285,11 +288,18 @@ export default class DeleteWizard extends Toggle {
|
|||
|
||||
class DeleteabilityChecker {
|
||||
public readonly canBeDeleted: UIEventSource<{ canBeDeleted?: boolean; reason: Translation }>
|
||||
private readonly objectDownloader: OsmObjectDownloader
|
||||
private readonly _id: OsmId
|
||||
private readonly _allowDeletionAtChangesetCount: number
|
||||
private readonly _osmConnection: OsmConnection
|
||||
|
||||
constructor(id: OsmId, osmConnection: OsmConnection, allowDeletionAtChangesetCount?: number) {
|
||||
constructor(
|
||||
id: OsmId,
|
||||
osmConnection: OsmConnection,
|
||||
objectDownloader: OsmObjectDownloader,
|
||||
allowDeletionAtChangesetCount?: number
|
||||
) {
|
||||
this.objectDownloader = objectDownloader
|
||||
this._id = id
|
||||
this._osmConnection = osmConnection
|
||||
this._allowDeletionAtChangesetCount = allowDeletionAtChangesetCount ?? Number.MAX_VALUE
|
||||
|
@ -366,11 +376,13 @@ class DeleteabilityChecker {
|
|||
|
||||
if (allByMyself.data === null && useTheInternet) {
|
||||
// We kickoff the download here as it hasn't yet been downloaded. Note that this is mapped onto 'all by myself' above
|
||||
const hist = OsmObject.DownloadHistory(id).map((versions) =>
|
||||
versions.map((version) =>
|
||||
Number(version.tags["_last_edit:contributor:uid"])
|
||||
const hist = this.objectDownloader
|
||||
.DownloadHistory(id)
|
||||
.map((versions) =>
|
||||
versions.map((version) =>
|
||||
Number(version.tags["_last_edit:contributor:uid"])
|
||||
)
|
||||
)
|
||||
)
|
||||
hist.addCallbackAndRunD((hist) => previousEditors.setData(hist))
|
||||
}
|
||||
|
||||
|
@ -406,11 +418,11 @@ class DeleteabilityChecker {
|
|||
}
|
||||
|
||||
// All right! We have arrived at a point that we should query OSM again to check that the point isn't a part of ways or relations
|
||||
OsmObject.DownloadReferencingRelations(id).then((rels) => {
|
||||
this.objectDownloader.DownloadReferencingRelations(id).then((rels) => {
|
||||
hasRelations.setData(rels.length > 0)
|
||||
})
|
||||
|
||||
OsmObject.DownloadReferencingWays(id).then((ways) => {
|
||||
this.objectDownloader.DownloadReferencingWays(id).then((ways) => {
|
||||
hasWays.setData(ways.length > 0)
|
||||
})
|
||||
return true // unregister to only run once
|
||||
|
|
|
@ -233,13 +233,13 @@ export default class MoveWizard extends Toggle {
|
|||
} else if (id.startsWith("relation")) {
|
||||
moveDisallowedReason.setData(t.isRelation)
|
||||
} else if (id.indexOf("-") < 0) {
|
||||
OsmObject.DownloadReferencingWays(id).then((referencing) => {
|
||||
state.osmObjectDownloader.DownloadReferencingWays(id).then((referencing) => {
|
||||
if (referencing.length > 0) {
|
||||
console.log("Got a referencing way, move not allowed")
|
||||
moveDisallowedReason.setData(t.partOfAWay)
|
||||
}
|
||||
})
|
||||
OsmObject.DownloadReferencingRelations(id).then((partOf) => {
|
||||
state.osmObjectDownloader.DownloadReferencingRelations(id).then((partOf) => {
|
||||
if (partOf.length > 0) {
|
||||
moveDisallowedReason.setData(t.partOfRelation)
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ import { VariableUiElement } from "../Base/VariableUIElement"
|
|||
import { LoginToggle } from "./LoginButton"
|
||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import WaySplitMap from "../BigComponents/WaySplitMap.svelte"
|
||||
import { OsmObject } from "../../Logic/Osm/OsmObject"
|
||||
import { Feature, Point } from "geojson"
|
||||
import { WayId } from "../../Models/OsmFeature"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import { Changes } from "../../Logic/Osm/Changes"
|
||||
import { IndexedFeatureSource } from "../../Logic/FeatureSource/FeatureSource"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import OsmObjectDownloader from "../../Logic/Osm/OsmObjectDownloader"
|
||||
|
||||
export default class SplitRoadWizard extends Combine {
|
||||
public dialogIsOpened: UIEventSource<boolean>
|
||||
|
@ -34,6 +34,7 @@ export default class SplitRoadWizard extends Combine {
|
|||
state: {
|
||||
layout?: LayoutConfig
|
||||
osmConnection?: OsmConnection
|
||||
osmObjectDownloader?: OsmObjectDownloader
|
||||
changes?: Changes
|
||||
indexedFeatures?: IndexedFeatureSource
|
||||
selectedElement?: UIEventSource<Feature>
|
||||
|
@ -52,7 +53,15 @@ export default class SplitRoadWizard extends Combine {
|
|||
const leafletMap = new UIEventSource<BaseUIElement>(undefined)
|
||||
|
||||
function initMap() {
|
||||
SplitRoadWizard.setupMapComponent(id, splitPoints).then((mapComponent) =>
|
||||
;(async function (
|
||||
id: WayId,
|
||||
splitPoints: UIEventSource<Feature[]>
|
||||
): Promise<BaseUIElement> {
|
||||
return new SvelteUIElement(WaySplitMap, {
|
||||
osmWay: await state.osmObjectDownloader.DownloadObjectAsync(id),
|
||||
splitPoints,
|
||||
})
|
||||
})(id, splitPoints).then((mapComponent) =>
|
||||
leafletMap.setData(mapComponent.SetClass("w-full h-80"))
|
||||
)
|
||||
}
|
||||
|
@ -132,15 +141,4 @@ export default class SplitRoadWizard extends Combine {
|
|||
self.ScrollIntoView()
|
||||
})
|
||||
}
|
||||
|
||||
private static async setupMapComponent(
|
||||
id: WayId,
|
||||
splitPoints: UIEventSource<Feature[]>
|
||||
): Promise<BaseUIElement> {
|
||||
const osmWay = await OsmObject.DownloadObjectAsync(id)
|
||||
return new SvelteUIElement(WaySplitMap, {
|
||||
osmWay,
|
||||
splitPoints,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import { GeoIndexedStoreForLayer } from "../Logic/FeatureSource/Actors/GeoIndexe
|
|||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||
import FeatureSwitchState from "../Logic/State/FeatureSwitchState";
|
||||
import { MenuState } from "../Models/MenuState";
|
||||
import OsmObjectDownloader from "../Logic/Osm/OsmObjectDownloader";
|
||||
|
||||
/**
|
||||
* The state needed to render a special Visualisation.
|
||||
|
@ -39,6 +40,7 @@ export interface SpecialVisualizationState {
|
|||
readonly featureSwitchUserbadge: Store<boolean>
|
||||
readonly featureSwitchIsTesting: Store<boolean>
|
||||
readonly changes: Changes
|
||||
readonly osmObjectDownloader: OsmObjectDownloader
|
||||
/**
|
||||
* State of the main map
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue