forked from MapComplete/MapComplete
Refactoring: fix rendering of new roads, generated by a split
This commit is contained in:
parent
840990c08b
commit
8eb2c68f79
34 changed files with 443 additions and 333 deletions
|
@ -55,12 +55,13 @@ class SingleTileSaver {
|
|||
*/
|
||||
export default class SaveFeatureSourceToLocalStorage {
|
||||
constructor(
|
||||
backend: string,
|
||||
layername: string,
|
||||
zoomlevel: number,
|
||||
features: FeatureSource,
|
||||
featureProperties: FeaturePropertiesStore
|
||||
) {
|
||||
const storage = TileLocalStorage.construct<Feature[]>(layername)
|
||||
const storage = TileLocalStorage.construct<Feature[]>(backend, layername)
|
||||
const singleTileSavers: Map<number, SingleTileSaver> = new Map<number, SingleTileSaver>()
|
||||
features.features.addCallbackAndRunD((features) => {
|
||||
const sliced = GeoOperations.slice(zoomlevel, features)
|
||||
|
|
|
@ -17,14 +17,15 @@ export default class TileLocalStorage<T> {
|
|||
this._layername = layername
|
||||
}
|
||||
|
||||
public static construct<T>(layername: string): TileLocalStorage<T> {
|
||||
const cached = TileLocalStorage.perLayer[layername]
|
||||
public static construct<T>(backend: string, layername: string): TileLocalStorage<T> {
|
||||
const key = backend + "_" + layername
|
||||
const cached = TileLocalStorage.perLayer[key]
|
||||
if (cached) {
|
||||
return cached
|
||||
}
|
||||
|
||||
const tls = new TileLocalStorage<T>(layername)
|
||||
TileLocalStorage.perLayer[layername] = tls
|
||||
const tls = new TileLocalStorage<T>(key)
|
||||
TileLocalStorage.perLayer[key] = tls
|
||||
return tls
|
||||
}
|
||||
|
||||
|
@ -46,7 +47,7 @@ export default class TileLocalStorage<T> {
|
|||
return src
|
||||
}
|
||||
|
||||
private async SetIdb(tileIndex: number, data): Promise<void> {
|
||||
private async SetIdb(tileIndex: number, data: any): Promise<void> {
|
||||
try {
|
||||
await IdbLocalStorage.SetDirectly(this._layername + "_" + tileIndex, data)
|
||||
} catch (e) {
|
||||
|
|
|
@ -3,22 +3,18 @@
|
|||
*/
|
||||
import { Changes } from "../../Osm/Changes"
|
||||
import { UIEventSource } from "../../UIEventSource"
|
||||
import { FeatureSourceForLayer, IndexedFeatureSource } from "../FeatureSource"
|
||||
import FilteredLayer from "../../../Models/FilteredLayer"
|
||||
import { FeatureSource, IndexedFeatureSource } from "../FeatureSource"
|
||||
import { ChangeDescription, ChangeDescriptionTools } from "../../Osm/Actions/ChangeDescription"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
||||
public readonly features: UIEventSource<Feature[]> =
|
||||
new UIEventSource<Feature[]>([])
|
||||
public readonly layer: FilteredLayer
|
||||
export default class ChangeGeometryApplicator implements FeatureSource {
|
||||
public readonly features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([])
|
||||
private readonly source: IndexedFeatureSource
|
||||
private readonly changes: Changes
|
||||
|
||||
constructor(source: IndexedFeatureSource & FeatureSourceForLayer, changes: Changes) {
|
||||
constructor(source: IndexedFeatureSource, changes: Changes) {
|
||||
this.source = source
|
||||
this.changes = changes
|
||||
this.layer = source.layer
|
||||
|
||||
this.features = new UIEventSource<Feature[]>(undefined)
|
||||
|
||||
|
@ -30,10 +26,10 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
|||
|
||||
private update() {
|
||||
const upstreamFeatures = this.source.features.data
|
||||
const upstreamIds = this.source.containedIds.data
|
||||
const upstreamIds = this.source.featuresById.data
|
||||
const changesToApply = this.changes.allChanges.data?.filter(
|
||||
(ch) =>
|
||||
// Does upsteram have this element? If not, we skip
|
||||
// Does upstream have this element? If not, we skip
|
||||
upstreamIds.has(ch.type + "/" + ch.id) &&
|
||||
// Are any (geometry) changes defined?
|
||||
ch.changes !== undefined &&
|
||||
|
@ -61,7 +57,7 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
|||
for (const feature of upstreamFeatures) {
|
||||
const changesForFeature = changesPerId.get(feature.properties.id)
|
||||
if (changesForFeature === undefined) {
|
||||
// No changes for this element
|
||||
// No changes for this element - simply pass it along to downstream
|
||||
newFeatures.push(feature)
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Store, UIEventSource } from "../../UIEventSource"
|
||||
import { FeatureSource , IndexedFeatureSource } from "../FeatureSource"
|
||||
import { FeatureSource, IndexedFeatureSource } from "../FeatureSource"
|
||||
import { Feature } from "geojson"
|
||||
import { Utils } from "../../../Utils"
|
||||
|
||||
|
@ -19,6 +19,7 @@ export default class FeatureSourceMerger implements IndexedFeatureSource {
|
|||
this._featuresById = new UIEventSource<Map<string, Feature>>(undefined)
|
||||
this.featuresById = this._featuresById
|
||||
const self = this
|
||||
sources = Utils.NoNull(sources)
|
||||
for (let source of sources) {
|
||||
source.features.addCallback(() => {
|
||||
self.addData(sources.map((s) => s.features.data))
|
||||
|
@ -28,7 +29,7 @@ export default class FeatureSourceMerger implements IndexedFeatureSource {
|
|||
this._sources = sources
|
||||
}
|
||||
|
||||
protected addSource(source: FeatureSource) {
|
||||
public addSource(source: FeatureSource) {
|
||||
this._sources.push(source)
|
||||
source.features.addCallbackAndRun(() => {
|
||||
this.addData(this._sources.map((s) => s.features.data))
|
||||
|
|
|
@ -4,13 +4,14 @@ import { FeatureSource } from "../FeatureSource"
|
|||
import { Or } from "../../Tags/Or"
|
||||
import FeatureSwitchState from "../../State/FeatureSwitchState"
|
||||
import OverpassFeatureSource from "./OverpassFeatureSource"
|
||||
import { ImmutableStore, Store } from "../../UIEventSource"
|
||||
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
|
||||
import OsmFeatureSource from "./OsmFeatureSource"
|
||||
import FeatureSourceMerger from "./FeatureSourceMerger"
|
||||
import DynamicGeoJsonTileSource from "../TiledFeatureSource/DynamicGeoJsonTileSource"
|
||||
import { BBox } from "../../BBox"
|
||||
import LocalStorageFeatureSource from "../TiledFeatureSource/LocalStorageFeatureSource"
|
||||
import StaticFeatureSource from "./StaticFeatureSource"
|
||||
import { OsmPreferences } from "../../Osm/OsmPreferences"
|
||||
|
||||
/**
|
||||
* This source will fetch the needed data from various sources for the given layout.
|
||||
|
@ -18,15 +19,14 @@ import StaticFeatureSource from "./StaticFeatureSource"
|
|||
* Note that special layers (with `source=null` will be ignored)
|
||||
*/
|
||||
export default class LayoutSource extends FeatureSourceMerger {
|
||||
private readonly _isLoading: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
/**
|
||||
* Indicates if a data source is loading something
|
||||
* TODO fixme
|
||||
*/
|
||||
public readonly isLoading: Store<boolean> = new ImmutableStore(false)
|
||||
public readonly isLoading: Store<boolean> = this._isLoading
|
||||
constructor(
|
||||
layers: LayerConfig[],
|
||||
featureSwitches: FeatureSwitchState,
|
||||
newAndChangedElements: FeatureSource,
|
||||
mapProperties: { bounds: Store<BBox>; zoom: Store<number> },
|
||||
backend: string,
|
||||
isDisplayed: (id: string) => Store<boolean>
|
||||
|
@ -39,7 +39,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
const osmLayers = layers.filter((layer) => layer.source.geojsonSource === undefined)
|
||||
const fromCache = osmLayers.map(
|
||||
(l) =>
|
||||
new LocalStorageFeatureSource(l.id, 15, mapProperties, {
|
||||
new LocalStorageFeatureSource(backend, l.id, 15, mapProperties, {
|
||||
isActive: isDisplayed(l.id),
|
||||
})
|
||||
)
|
||||
|
@ -56,7 +56,17 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
)
|
||||
|
||||
const expiryInSeconds = Math.min(...(layers?.map((l) => l.maxAgeOfCache) ?? []))
|
||||
super(overpassSource, osmApiSource, newAndChangedElements, ...geojsonSources, ...fromCache)
|
||||
|
||||
super(overpassSource, osmApiSource, ...geojsonSources, ...fromCache)
|
||||
|
||||
const self = this
|
||||
function setIsLoading() {
|
||||
const loading = overpassSource?.runningQuery?.data && osmApiSource?.isRunning?.data
|
||||
self._isLoading.setData(loading)
|
||||
}
|
||||
|
||||
overpassSource?.runningQuery?.addCallbackAndRun((_) => setIsLoading())
|
||||
osmApiSource?.isRunning?.addCallbackAndRun((_) => setIsLoading())
|
||||
}
|
||||
|
||||
private static setupGeojsonSource(
|
||||
|
@ -83,9 +93,9 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
zoom: Store<number>,
|
||||
backend: string,
|
||||
featureSwitches: FeatureSwitchState
|
||||
): FeatureSource {
|
||||
): OsmFeatureSource | undefined {
|
||||
if (osmLayers.length == 0) {
|
||||
return new StaticFeatureSource(new ImmutableStore([]))
|
||||
return undefined
|
||||
}
|
||||
const minzoom = Math.min(...osmLayers.map((layer) => layer.minzoom))
|
||||
const isActive = zoom.mapD((z) => {
|
||||
|
@ -115,9 +125,9 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
bounds: Store<BBox>,
|
||||
zoom: Store<number>,
|
||||
featureSwitches: FeatureSwitchState
|
||||
): FeatureSource {
|
||||
): OverpassFeatureSource | undefined {
|
||||
if (osmLayers.length == 0) {
|
||||
return new StaticFeatureSource(new ImmutableStore([]))
|
||||
return undefined
|
||||
}
|
||||
const minzoom = Math.min(...osmLayers.map((layer) => layer.minzoom))
|
||||
const isActive = zoom.mapD((z) => {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { Changes } from "../../Osm/Changes"
|
||||
import { OsmNode, OsmObject, OsmRelation, OsmWay } from "../../Osm/OsmObject"
|
||||
import { FeatureSource } from "../FeatureSource"
|
||||
import { IndexedFeatureSource, WritableFeatureSource } from "../FeatureSource"
|
||||
import { UIEventSource } from "../../UIEventSource"
|
||||
import { ChangeDescription } from "../../Osm/Actions/ChangeDescription"
|
||||
import { ElementStorage } from "../../ElementStorage"
|
||||
import { OsmId, OsmTags } from "../../../Models/OsmFeature"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
||||
export class NewGeometryFromChangesFeatureSource implements WritableFeatureSource {
|
||||
// This class name truly puts the 'Java' into 'Javascript'
|
||||
|
||||
/**
|
||||
|
@ -18,7 +17,7 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
|||
*/
|
||||
public readonly features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([])
|
||||
|
||||
constructor(changes: Changes, allElementStorage: ElementStorage, backendUrl: string) {
|
||||
constructor(changes: Changes, allElementStorage: IndexedFeatureSource, backendUrl: string) {
|
||||
const seenChanges = new Set<ChangeDescription>()
|
||||
const features = this.features.data
|
||||
const self = this
|
||||
|
@ -53,7 +52,7 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
|||
// In _most_ of the cases, this means that this _isn't_ a new object
|
||||
// However, when a point is snapped to an already existing point, we have to create a representation for this point!
|
||||
// For this, we introspect the change
|
||||
if (allElementStorage.has(change.type + "/" + change.id)) {
|
||||
if (allElementStorage.featuresById.data.has(change.type + "/" + change.id)) {
|
||||
// The current point already exists, we don't have to do anything here
|
||||
continue
|
||||
}
|
||||
|
@ -65,7 +64,6 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
|||
feat.tags[kv.k] = kv.v
|
||||
}
|
||||
const geojson = feat.asGeoJson()
|
||||
allElementStorage.addOrGetElement(geojson)
|
||||
self.features.data.push(geojson)
|
||||
self.features.ping()
|
||||
})
|
||||
|
|
|
@ -41,7 +41,6 @@ export default class OsmFeatureSource extends FeatureSourceMerger {
|
|||
this.isActive = options.isActive ?? new ImmutableStore(true)
|
||||
this._backend = options.backend ?? "https://www.openstreetmap.org"
|
||||
this._bounds.addCallbackAndRunD((bbox) => this.loadData(bbox))
|
||||
console.log("Allowed tags are:", this.allowedTags)
|
||||
}
|
||||
|
||||
private async loadData(bbox: BBox) {
|
||||
|
@ -108,7 +107,7 @@ export default class OsmFeatureSource extends FeatureSourceMerger {
|
|||
}
|
||||
|
||||
private async LoadTile(z, x, y): Promise<void> {
|
||||
console.log("OsmFeatureSource: loading ", z, x, y)
|
||||
console.log("OsmFeatureSource: loading ", z, x, y, "from", this._backend)
|
||||
if (z >= 22) {
|
||||
throw "This is an absurd high zoom level"
|
||||
}
|
||||
|
|
|
@ -22,13 +22,18 @@ export interface SnappingOptions {
|
|||
* The resulting snap coordinates will be written into this UIEventSource
|
||||
*/
|
||||
snapLocation?: UIEventSource<{ lon: number; lat: number }>
|
||||
|
||||
/**
|
||||
* If the projected point is within `reusePointWithin`-meter of an already existing point
|
||||
*/
|
||||
reusePointWithin?: number
|
||||
}
|
||||
|
||||
export default class SnappingFeatureSource implements FeatureSource {
|
||||
public readonly features: Store<Feature<Point>[]>
|
||||
|
||||
private readonly _snappedTo: UIEventSource<string>
|
||||
/*Contains the id of the way it snapped to*/
|
||||
public readonly snappedTo: Store<string>
|
||||
private readonly _snappedTo: UIEventSource<string>
|
||||
|
||||
constructor(
|
||||
snapTo: FeatureSource,
|
||||
|
|
|
@ -7,6 +7,7 @@ import StaticFeatureSource from "../Sources/StaticFeatureSource"
|
|||
|
||||
export default class LocalStorageFeatureSource extends DynamicTileSource {
|
||||
constructor(
|
||||
backend: string,
|
||||
layername: string,
|
||||
zoomlevel: number,
|
||||
mapProperties: {
|
||||
|
@ -17,7 +18,7 @@ export default class LocalStorageFeatureSource extends DynamicTileSource {
|
|||
isActive?: Store<boolean>
|
||||
}
|
||||
) {
|
||||
const storage = TileLocalStorage.construct<Feature[]>(layername)
|
||||
const storage = TileLocalStorage.construct<Feature[]>(backend, layername)
|
||||
super(
|
||||
zoomlevel,
|
||||
(tileIndex) =>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue