forked from MapComplete/MapComplete
Refactoring(maplibre): remove 'freshness' and 'name' from FeatureSource to simplify the code
This commit is contained in:
parent
1b3609b13f
commit
231d67361e
30 changed files with 161 additions and 269 deletions
|
@ -101,7 +101,7 @@ export default class MetaTagRecalculator {
|
|||
}
|
||||
}
|
||||
|
||||
public registerSource(source: FeatureSourceForLayer & Tiled, recalculateOnEveryChange = false) {
|
||||
public registerSource(source: FeatureSourceForLayer & Tiled) {
|
||||
if (source === undefined) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import FeatureSource from "../FeatureSource"
|
||||
import { Store } from "../../UIEventSource"
|
||||
import { ElementStorage } from "../../ElementStorage"
|
||||
import FeatureSource from "../FeatureSource";
|
||||
import { Store } from "../../UIEventSource";
|
||||
import { ElementStorage } from "../../ElementStorage";
|
||||
import { Feature } from "geojson";
|
||||
|
||||
/**
|
||||
* Makes sure that every feature is added to the ElementsStorage, so that the tags-eventsource can be retrieved
|
||||
*/
|
||||
export default class RegisteringAllFromFeatureSourceActor {
|
||||
public readonly features: Store<{ feature: any; freshness: Date }[]>
|
||||
public readonly name
|
||||
public readonly features: Store<Feature[]>
|
||||
|
||||
constructor(source: FeatureSource, allElements: ElementStorage) {
|
||||
this.features = source.features
|
||||
this.name = "RegisteringSource of " + source.name
|
||||
this.features.addCallbackAndRunD((features) => {
|
||||
for (const feature of features) {
|
||||
allElements.addOrGetElement(feature.feature)
|
||||
allElements.addOrGetElement(<any> feature)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { BBox } from "../../BBox"
|
|||
import SimpleFeatureSource from "../Sources/SimpleFeatureSource"
|
||||
import FilteredLayer from "../../../Models/FilteredLayer"
|
||||
import Loc from "../../../Models/Loc"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
/***
|
||||
* Saves all the features that are passed in to localstorage, so they can be retrieved on the next run
|
||||
|
@ -82,7 +83,7 @@ export default class SaveTileToLocalStorageActor {
|
|||
continue
|
||||
}
|
||||
loadedTiles.add(key)
|
||||
this.GetIdb(key).then((features: { feature: any; freshness: Date }[]) => {
|
||||
this.GetIdb(key).then((features: Feature[]) => {
|
||||
if (features === undefined) {
|
||||
return
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ export default class SaveTileToLocalStorageActor {
|
|||
const src = new SimpleFeatureSource(
|
||||
self._flayer,
|
||||
key,
|
||||
new UIEventSource<{ feature: any; freshness: Date }[]>(features)
|
||||
new UIEventSource<Feature[]>(features)
|
||||
)
|
||||
registerTile(src)
|
||||
})
|
||||
|
|
|
@ -136,7 +136,7 @@ export default class FeaturePipeline {
|
|||
// Passthrough to passed function, except that it registers as well
|
||||
handleFeatureSource(src)
|
||||
src.features.addCallbackAndRunD((fs) => {
|
||||
fs.forEach((ff) => state.allElements.addOrGetElement(<any>ff.feature))
|
||||
fs.forEach((ff) => state.allElements.addOrGetElement(<any>ff))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ export default class FeaturePipeline {
|
|||
}
|
||||
return TileHierarchyTools.getTiles(requestedHierarchy, bbox)
|
||||
.filter((featureSource) => featureSource.features?.data !== undefined)
|
||||
.map((featureSource) => featureSource.features.data.map((fs) => fs.feature))
|
||||
.map((featureSource) => <OsmFeature[]>featureSource.features.data)
|
||||
}
|
||||
|
||||
public GetTilesPerLayerWithin(
|
||||
|
@ -639,10 +639,7 @@ export default class FeaturePipeline {
|
|||
* Inject a new point
|
||||
*/
|
||||
InjectNewPoint(geojson) {
|
||||
this.newGeometryHandler.features.data.push({
|
||||
feature: geojson,
|
||||
freshness: new Date(),
|
||||
})
|
||||
this.newGeometryHandler.features.data.push(geojson)
|
||||
this.newGeometryHandler.features.ping()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import { Store } from "../UIEventSource"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import { BBox } from "../BBox"
|
||||
import { Feature, Geometry } from "@turf/turf"
|
||||
import { OsmFeature } from "../../Models/OsmFeature"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export default interface FeatureSource {
|
||||
features: Store<{ feature: OsmFeature; freshness: Date }[]>
|
||||
/**
|
||||
* Mainly used for debuging
|
||||
*/
|
||||
name: string
|
||||
features: Store<Feature[]>
|
||||
}
|
||||
|
||||
export interface Tiled {
|
||||
|
|
|
@ -2,6 +2,7 @@ import FeatureSource, { FeatureSourceForLayer, Tiled } from "./FeatureSource"
|
|||
import { Store } from "../UIEventSource"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import SimpleFeatureSource from "./Sources/SimpleFeatureSource"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
/**
|
||||
* In some rare cases, some elements are shown on multiple layers (when 'passthrough' is enabled)
|
||||
|
@ -32,7 +33,7 @@ export default class PerLayerFeatureSourceSplitter {
|
|||
// We try to figure out (for each feature) in which feature store it should be saved.
|
||||
// Note that this splitter is only run when it is invoked by the overpass feature source, so we can't be sure in which layer it should go
|
||||
|
||||
const featuresPerLayer = new Map<string, { feature; freshness }[]>()
|
||||
const featuresPerLayer = new Map<string, Feature[]>()
|
||||
const noLayerFound = []
|
||||
|
||||
for (const layer of layers.data) {
|
||||
|
@ -42,7 +43,7 @@ export default class PerLayerFeatureSourceSplitter {
|
|||
for (const f of features) {
|
||||
let foundALayer = false
|
||||
for (const layer of layers.data) {
|
||||
if (layer.layerDef.source.osmTags.matchesProperties(f.feature.properties)) {
|
||||
if (layer.layerDef.source.osmTags.matchesProperties(f.properties)) {
|
||||
// We have found our matching layer!
|
||||
featuresPerLayer.get(layer.layerDef.id).push(f)
|
||||
foundALayer = true
|
||||
|
|
|
@ -6,11 +6,11 @@ import { UIEventSource } from "../../UIEventSource"
|
|||
import { FeatureSourceForLayer, IndexedFeatureSource } from "../FeatureSource"
|
||||
import FilteredLayer from "../../../Models/FilteredLayer"
|
||||
import { ChangeDescription, ChangeDescriptionTools } from "../../Osm/Actions/ChangeDescription"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
||||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> =
|
||||
new UIEventSource<{ feature: any; freshness: Date }[]>([])
|
||||
public readonly name: string
|
||||
public readonly features: UIEventSource<Feature[]> =
|
||||
new UIEventSource<Feature[]>([])
|
||||
public readonly layer: FilteredLayer
|
||||
private readonly source: IndexedFeatureSource
|
||||
private readonly changes: Changes
|
||||
|
@ -20,8 +20,7 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
|||
this.changes = changes
|
||||
this.layer = source.layer
|
||||
|
||||
this.name = "ChangesApplied(" + source.name + ")"
|
||||
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>(undefined)
|
||||
this.features = new UIEventSource<Feature[]>(undefined)
|
||||
|
||||
const self = this
|
||||
source.features.addCallbackAndRunD((_) => self.update())
|
||||
|
@ -58,9 +57,9 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
|||
changesPerId.set(key, [ch])
|
||||
}
|
||||
}
|
||||
const newFeatures: { feature: any; freshness: Date }[] = []
|
||||
const newFeatures: Feature[] = []
|
||||
for (const feature of upstreamFeatures) {
|
||||
const changesForFeature = changesPerId.get(feature.feature.properties.id)
|
||||
const changesForFeature = changesPerId.get(feature.properties.id)
|
||||
if (changesForFeature === undefined) {
|
||||
// No changes for this element
|
||||
newFeatures.push(feature)
|
||||
|
@ -73,7 +72,7 @@ export default class ChangeGeometryApplicator implements FeatureSourceForLayer {
|
|||
}
|
||||
// We only apply the last change as that one'll have the latest geometry
|
||||
const change = changesForFeature[changesForFeature.length - 1]
|
||||
copy.feature.geometry = ChangeDescriptionTools.getGeojsonGeometry(change)
|
||||
copy.geometry = ChangeDescriptionTools.getGeojsonGeometry(change)
|
||||
console.log(
|
||||
"Applying a geometry change onto:",
|
||||
feature,
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import { UIEventSource } from "../../UIEventSource"
|
||||
import FeatureSource, { FeatureSourceForLayer, IndexedFeatureSource, Tiled } from "../FeatureSource"
|
||||
import FilteredLayer from "../../../Models/FilteredLayer"
|
||||
import { Tiles } from "../../../Models/TileRange"
|
||||
import { BBox } from "../../BBox"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export default class FeatureSourceMerger
|
||||
implements FeatureSourceForLayer, Tiled, IndexedFeatureSource
|
||||
{
|
||||
public features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<
|
||||
{ feature: any; freshness: Date }[]
|
||||
>([])
|
||||
public readonly name
|
||||
public features: UIEventSource<Feature[]> = new UIEventSource([])
|
||||
public readonly layer: FilteredLayer
|
||||
public readonly tileIndex: number
|
||||
public readonly bbox: BBox
|
||||
|
@ -32,12 +29,6 @@ export default class FeatureSourceMerger
|
|||
this.bbox = bbox
|
||||
this._sources = sources
|
||||
this.layer = layer
|
||||
this.name =
|
||||
"FeatureSourceMerger(" +
|
||||
layer.layerDef.id +
|
||||
", " +
|
||||
Tiles.tile_from_index(tileIndex).join(",") +
|
||||
")"
|
||||
const self = this
|
||||
|
||||
const handledSources = new Set<FeatureSource>()
|
||||
|
@ -63,14 +54,11 @@ export default class FeatureSourceMerger
|
|||
|
||||
private Update() {
|
||||
let somethingChanged = false
|
||||
const all: Map<string, { feature: any; freshness: Date }> = new Map<
|
||||
string,
|
||||
{ feature: any; freshness: Date }
|
||||
>()
|
||||
const all: Map<string, Feature> = new Map()
|
||||
// We seed the dictionary with the previously loaded features
|
||||
const oldValues = this.features.data ?? []
|
||||
for (const oldValue of oldValues) {
|
||||
all.set(oldValue.feature.id, oldValue)
|
||||
all.set(oldValue.properties.id, oldValue)
|
||||
}
|
||||
|
||||
for (const source of this._sources.data) {
|
||||
|
@ -78,7 +66,7 @@ export default class FeatureSourceMerger
|
|||
continue
|
||||
}
|
||||
for (const f of source.features.data) {
|
||||
const id = f.feature.properties.id
|
||||
const id = f.properties.id
|
||||
if (!all.has(id)) {
|
||||
// This is a new feature
|
||||
somethingChanged = true
|
||||
|
@ -89,11 +77,11 @@ export default class FeatureSourceMerger
|
|||
// This value has been seen already, either in a previous run or by a previous datasource
|
||||
// Let's figure out if something changed
|
||||
const oldV = all.get(id)
|
||||
if (oldV.freshness < f.freshness) {
|
||||
// Jup, this feature is fresher
|
||||
all.set(id, f)
|
||||
somethingChanged = true
|
||||
if (oldV === f) {
|
||||
continue
|
||||
}
|
||||
all.set(id, f)
|
||||
somethingChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,10 @@ import { FeatureSourceForLayer, Tiled } from "../FeatureSource"
|
|||
import { BBox } from "../../BBox"
|
||||
import { ElementStorage } from "../../ElementStorage"
|
||||
import { TagsFilter } from "../../Tags/TagsFilter"
|
||||
import { OsmFeature } from "../../../Models/OsmFeature"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export default class FilteringFeatureSource implements FeatureSourceForLayer, Tiled {
|
||||
public features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<
|
||||
{ feature: any; freshness: Date }[]
|
||||
>([])
|
||||
public readonly name
|
||||
public features: UIEventSource<Feature[]> = new UIEventSource([])
|
||||
public readonly layer: FilteredLayer
|
||||
public readonly tileIndex: number
|
||||
public readonly bbox: BBox
|
||||
|
@ -36,7 +33,6 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
|||
upstream: FeatureSourceForLayer,
|
||||
metataggingUpdated?: UIEventSource<any>
|
||||
) {
|
||||
this.name = "FilteringFeatureSource(" + upstream.name + ")"
|
||||
this.tileIndex = tileIndex
|
||||
this.bbox = tileIndex === undefined ? undefined : BBox.fromTileIndex(tileIndex)
|
||||
this.upstream = upstream
|
||||
|
@ -73,15 +69,14 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
|||
private update() {
|
||||
const self = this
|
||||
const layer = this.upstream.layer
|
||||
const features: { feature: OsmFeature; freshness: Date }[] =
|
||||
this.upstream.features.data ?? []
|
||||
const features: Feature[] = this.upstream.features.data ?? []
|
||||
const includedFeatureIds = new Set<string>()
|
||||
const globalFilters = self.state.globalFilters?.data?.map((f) => f.filter)
|
||||
const newFeatures = (features ?? []).filter((f) => {
|
||||
self.registerCallback(f.feature)
|
||||
self.registerCallback(f)
|
||||
|
||||
const isShown: TagsFilter = layer.layerDef.isShown
|
||||
const tags = f.feature.properties
|
||||
const tags = f.properties
|
||||
if (isShown !== undefined && !isShown.matchesProperties(tags)) {
|
||||
return false
|
||||
}
|
||||
|
@ -92,10 +87,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
|||
const tagsFilter = Array.from(layer.appliedFilters?.data?.values() ?? [])
|
||||
for (const filter of tagsFilter) {
|
||||
const neededTags: TagsFilter = filter?.currentFilter
|
||||
if (
|
||||
neededTags !== undefined &&
|
||||
!neededTags.matchesProperties(f.feature.properties)
|
||||
) {
|
||||
if (neededTags !== undefined && !neededTags.matchesProperties(f.properties)) {
|
||||
// Hidden by the filter on the layer itself - we want to hide it no matter what
|
||||
return false
|
||||
}
|
||||
|
@ -103,16 +95,13 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
|||
|
||||
for (const filter of globalFilters ?? []) {
|
||||
const neededTags: TagsFilter = filter?.currentFilter
|
||||
if (
|
||||
neededTags !== undefined &&
|
||||
!neededTags.matchesProperties(f.feature.properties)
|
||||
) {
|
||||
if (neededTags !== undefined && !neededTags.matchesProperties(f.properties)) {
|
||||
// Hidden by the filter on the layer itself - we want to hide it no matter what
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
includedFeatureIds.add(f.feature.properties.id)
|
||||
includedFeatureIds.add(f.properties.id)
|
||||
return true
|
||||
})
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@ import { FeatureSourceForLayer, Tiled } from "../FeatureSource"
|
|||
import { Tiles } from "../../../Models/TileRange"
|
||||
import { BBox } from "../../BBox"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
||||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>
|
||||
public readonly features: UIEventSource<Feature[]>
|
||||
public readonly state = new UIEventSource<undefined | { error: string } | "loaded">(undefined)
|
||||
public readonly name
|
||||
public readonly isOsmCache: boolean
|
||||
|
@ -69,7 +70,7 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
|||
this.name = "GeoJsonSource of " + url
|
||||
|
||||
this.isOsmCache = flayer.layerDef.source.isOsmCacheLayer
|
||||
this.features = new UIEventSource<{ feature: any; freshness: Date }[]>([])
|
||||
this.features = new UIEventSource<Feature[]>([])
|
||||
this.LoadJSONFrom(url)
|
||||
}
|
||||
|
||||
|
@ -110,7 +111,7 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
|||
}
|
||||
|
||||
const time = new Date()
|
||||
const newFeatures: { feature: any; freshness: Date }[] = []
|
||||
const newFeatures: Feature[] = []
|
||||
let i = 0
|
||||
let skipped = 0
|
||||
for (const feature of json.features) {
|
||||
|
@ -146,7 +147,7 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
|||
freshness = new Date(props["_last_edit:timestamp"])
|
||||
}
|
||||
|
||||
newFeatures.push({ feature: feature, freshness: freshness })
|
||||
newFeatures.push(feature)
|
||||
}
|
||||
|
||||
if (newFeatures.length == 0) {
|
||||
|
|
|
@ -5,6 +5,7 @@ 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 {
|
||||
// This class name truly puts the 'Java' into 'Javascript'
|
||||
|
@ -15,9 +16,7 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
|||
* These elements are probably created by the 'SimpleAddUi' which generates a new point, but the import functionality might create a line or polygon too.
|
||||
* Other sources of new points are e.g. imports from nodes
|
||||
*/
|
||||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> =
|
||||
new UIEventSource<{ feature: any; freshness: Date }[]>([])
|
||||
public readonly name: string = "newFeatures"
|
||||
public readonly features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([])
|
||||
|
||||
constructor(changes: Changes, allElementStorage: ElementStorage, backendUrl: string) {
|
||||
const seenChanges = new Set<ChangeDescription>()
|
||||
|
@ -29,15 +28,11 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
|||
return
|
||||
}
|
||||
|
||||
const now = new Date()
|
||||
let somethingChanged = false
|
||||
|
||||
function add(feature) {
|
||||
feature.id = feature.properties.id
|
||||
features.push({
|
||||
feature: feature,
|
||||
freshness: now,
|
||||
})
|
||||
features.push(feature)
|
||||
somethingChanged = true
|
||||
}
|
||||
|
||||
|
@ -71,7 +66,7 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
|||
}
|
||||
const geojson = feat.asGeoJson()
|
||||
allElementStorage.addOrGetElement(geojson)
|
||||
self.features.data.push({ feature: geojson, freshness: new Date() })
|
||||
self.features.data.push(geojson)
|
||||
self.features.ping()
|
||||
})
|
||||
continue
|
||||
|
|
|
@ -5,28 +5,25 @@
|
|||
import FeatureSource, { Tiled } from "../FeatureSource"
|
||||
import { Store, UIEventSource } from "../../UIEventSource"
|
||||
import { BBox } from "../../BBox"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export default class RememberingSource implements FeatureSource, Tiled {
|
||||
public readonly features: Store<{ feature: any; freshness: Date }[]>
|
||||
public readonly name
|
||||
public readonly features: Store<Feature[]>
|
||||
public readonly tileIndex: number
|
||||
public readonly bbox: BBox
|
||||
|
||||
constructor(source: FeatureSource & Tiled) {
|
||||
const self = this
|
||||
this.name = "RememberingSource of " + source.name
|
||||
this.tileIndex = source.tileIndex
|
||||
this.bbox = source.bbox
|
||||
|
||||
const empty = []
|
||||
const featureSource = new UIEventSource<{ feature: any; freshness: Date }[]>(empty)
|
||||
const featureSource = new UIEventSource<Feature[]>(empty)
|
||||
this.features = featureSource
|
||||
source.features.addCallbackAndRunD((features) => {
|
||||
const oldFeatures = self.features?.data ?? empty
|
||||
// Then new ids
|
||||
const ids = new Set<string>(
|
||||
features.map((f) => f.feature.properties.id + f.feature.geometry.type)
|
||||
)
|
||||
const ids = new Set<string>(features.map((f) => f.properties.id + f.geometry.type))
|
||||
// the old data
|
||||
const oldData = oldFeatures.filter(
|
||||
(old) => !ids.has(old.feature.properties.id + old.feature.geometry.type)
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
/**
|
||||
* This feature source helps the ShowDataLayer class: it introduces the necessary extra features and indicates with what renderConfig it should be rendered.
|
||||
*/
|
||||
import { Store } from "../../UIEventSource"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
import FeatureSource from "../FeatureSource"
|
||||
import PointRenderingConfig from "../../../Models/ThemeConfig/PointRenderingConfig"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import LineRenderingConfig from "../../../Models/ThemeConfig/LineRenderingConfig"
|
||||
|
||||
/**
|
||||
* This feature source helps the ShowDataLayer class: it introduces the necessary extra features and indicates with what renderConfig it should be rendered.
|
||||
*/
|
||||
export default class RenderingMultiPlexerFeatureSource {
|
||||
public readonly features: Store<
|
||||
(any & {
|
||||
|
@ -64,8 +63,7 @@ export default class RenderingMultiPlexerFeatureSource {
|
|||
withIndex.push(patched)
|
||||
}
|
||||
|
||||
for (const f of features) {
|
||||
const feat = f.feature
|
||||
for (const feat of features) {
|
||||
if (feat === undefined) {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -2,23 +2,18 @@ import { UIEventSource } from "../../UIEventSource"
|
|||
import FilteredLayer from "../../../Models/FilteredLayer"
|
||||
import { FeatureSourceForLayer, Tiled } from "../FeatureSource"
|
||||
import { BBox } from "../../BBox"
|
||||
import { Feature } from "geojson"
|
||||
|
||||
export default class SimpleFeatureSource implements FeatureSourceForLayer, Tiled {
|
||||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>
|
||||
public readonly name: string = "SimpleFeatureSource"
|
||||
public readonly features: UIEventSource<Feature[]>
|
||||
public readonly layer: FilteredLayer
|
||||
public readonly bbox: BBox = BBox.global
|
||||
public readonly tileIndex: number
|
||||
|
||||
constructor(
|
||||
layer: FilteredLayer,
|
||||
tileIndex: number,
|
||||
featureSource?: UIEventSource<{ feature: any; freshness: Date }[]>
|
||||
) {
|
||||
this.name = "SimpleFeatureSource(" + layer.layerDef.id + ")"
|
||||
constructor(layer: FilteredLayer, tileIndex: number, featureSource?: UIEventSource<Feature[]>) {
|
||||
this.layer = layer
|
||||
this.tileIndex = tileIndex ?? 0
|
||||
this.bbox = BBox.fromTileIndex(this.tileIndex)
|
||||
this.features = featureSource ?? new UIEventSource<{ feature: any; freshness: Date }[]>([])
|
||||
this.features = featureSource ?? new UIEventSource<Feature[]>([])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,63 +8,34 @@ import { Feature } from "geojson"
|
|||
* A simple, read only feature store.
|
||||
*/
|
||||
export default class StaticFeatureSource implements FeatureSource {
|
||||
public readonly features: Store<{ feature: any; freshness: Date }[]>
|
||||
public readonly name: string
|
||||
public readonly features: Store<Feature[]>
|
||||
|
||||
constructor(
|
||||
features: Store<{ feature: Feature; freshness: Date }[]>,
|
||||
name = "StaticFeatureSource"
|
||||
features:
|
||||
| Store<Feature[]>
|
||||
| Feature[]
|
||||
| { features: Feature[] }
|
||||
| { features: Store<Feature[]> }
|
||||
) {
|
||||
if (features === undefined) {
|
||||
throw "Static feature source received undefined as source"
|
||||
}
|
||||
this.name = name
|
||||
this.features = features
|
||||
let feats: Feature[] | Store<Feature[]>
|
||||
if (features["features"]) {
|
||||
feats = features["features"]
|
||||
} else {
|
||||
feats = <Feature[] | Store<Feature[]>>features
|
||||
}
|
||||
|
||||
if (Array.isArray(feats)) {
|
||||
this.features = new ImmutableStore(feats)
|
||||
} else {
|
||||
this.features = feats
|
||||
}
|
||||
}
|
||||
|
||||
public static fromGeojsonAndDate(
|
||||
features: { feature: Feature; freshness: Date }[],
|
||||
name = "StaticFeatureSourceFromGeojsonAndDate"
|
||||
): StaticFeatureSource {
|
||||
return new StaticFeatureSource(new ImmutableStore(features), name)
|
||||
}
|
||||
|
||||
public static fromGeojson(
|
||||
geojson: Feature[],
|
||||
name = "StaticFeatureSourceFromGeojson"
|
||||
): StaticFeatureSource {
|
||||
const now = new Date()
|
||||
return StaticFeatureSource.fromGeojsonAndDate(
|
||||
geojson.map((feature) => ({ feature, freshness: now })),
|
||||
name
|
||||
)
|
||||
}
|
||||
|
||||
public static fromGeojsonStore(
|
||||
geojson: Store<Feature[]>,
|
||||
name = "StaticFeatureSourceFromGeojson"
|
||||
): StaticFeatureSource {
|
||||
const now = new Date()
|
||||
const mapped: Store<{ feature: Feature; freshness: Date }[]> = geojson.map((features) =>
|
||||
features.map((feature) => ({ feature, freshness: now }))
|
||||
)
|
||||
return new StaticFeatureSource(mapped, name)
|
||||
}
|
||||
|
||||
static fromDateless(
|
||||
featureSource: Store<{ feature: Feature }[]>,
|
||||
name = "StaticFeatureSourceFromDateless"
|
||||
) {
|
||||
const now = new Date()
|
||||
return new StaticFeatureSource(
|
||||
featureSource.map((features) =>
|
||||
features.map((feature) => ({
|
||||
feature: feature.feature,
|
||||
freshness: now,
|
||||
}))
|
||||
),
|
||||
name
|
||||
)
|
||||
public static fromGeojson(geojson: Feature[]): StaticFeatureSource {
|
||||
return new StaticFeatureSource(geojson)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,11 +47,7 @@ export class TiledStaticFeatureSource
|
|||
public readonly tileIndex: number
|
||||
public readonly layer: FilteredLayer
|
||||
|
||||
constructor(
|
||||
features: Store<{ feature: any; freshness: Date }[]>,
|
||||
layer: FilteredLayer,
|
||||
tileIndex: number = 0
|
||||
) {
|
||||
constructor(features: Store<Feature[]>, layer: FilteredLayer, tileIndex: number = 0) {
|
||||
super(features)
|
||||
this.tileIndex = tileIndex
|
||||
this.layer = layer
|
||||
|
|
|
@ -53,11 +53,9 @@ export default class FullNodeDatabaseSource implements TileHierarchy<FeatureSour
|
|||
src.ping()
|
||||
}
|
||||
}
|
||||
const now = new Date()
|
||||
const asGeojsonFeatures = Array.from(nodesById.values()).map((osmNode) => ({
|
||||
feature: osmNode.asGeoJson(),
|
||||
freshness: now,
|
||||
}))
|
||||
const asGeojsonFeatures = Array.from(nodesById.values()).map((osmNode) =>
|
||||
osmNode.asGeoJson()
|
||||
)
|
||||
|
||||
const featureSource = new SimpleFeatureSource(this.layer, tileId)
|
||||
featureSource.features.setData(asGeojsonFeatures)
|
||||
|
|
|
@ -175,7 +175,7 @@ export default class OsmFeatureSource {
|
|||
new PerLayerFeatureSourceSplitter(
|
||||
this.filteredLayers,
|
||||
this.handleTile,
|
||||
StaticFeatureSource.fromGeojson(geojson.features),
|
||||
new StaticFeatureSource(geojson.features),
|
||||
{
|
||||
tileIndex: index,
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import FilteredLayer from "../../../Models/FilteredLayer"
|
|||
import TileHierarchy from "./TileHierarchy"
|
||||
import { Tiles } from "../../../Models/TileRange"
|
||||
import { BBox } from "../../BBox"
|
||||
import { Feature } from "geojson";
|
||||
|
||||
/**
|
||||
* Contains all features in a tiled fashion.
|
||||
|
@ -29,7 +30,7 @@ export default class TiledFeatureSource
|
|||
|
||||
public readonly maxFeatureCount: number
|
||||
public readonly name
|
||||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>
|
||||
public readonly features: UIEventSource<Feature[]>
|
||||
public readonly containedIds: Store<Set<string>>
|
||||
|
||||
public readonly bbox: BBox
|
||||
|
@ -80,7 +81,7 @@ export default class TiledFeatureSource
|
|||
if (features === undefined) {
|
||||
return undefined
|
||||
}
|
||||
return new Set(features.map((f) => f.feature.properties.id))
|
||||
return new Set(features.map((f) => f.properties.id))
|
||||
})
|
||||
|
||||
// We register this tile, but only when there is some data in it
|
||||
|
@ -132,7 +133,7 @@ export default class TiledFeatureSource
|
|||
* @param features
|
||||
* @private
|
||||
*/
|
||||
private addFeatures(features: { feature: any; freshness: Date }[]) {
|
||||
private addFeatures(features: Feature[]) {
|
||||
if (features === undefined || features.length === 0) {
|
||||
return
|
||||
}
|
||||
|
@ -180,7 +181,7 @@ export default class TiledFeatureSource
|
|||
const overlapsboundary = []
|
||||
|
||||
for (const feature of features) {
|
||||
const bbox = BBox.get(feature.feature)
|
||||
const bbox = BBox.get(feature)
|
||||
|
||||
// There are a few strategies to deal with features that cross tile boundaries
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue