forked from MapComplete/MapComplete
Fix #596
This commit is contained in:
parent
5182085f35
commit
1e3206120c
6 changed files with 108 additions and 69 deletions
|
@ -311,7 +311,7 @@ export default class FeaturePipeline {
|
||||||
|
|
||||||
|
|
||||||
// Also load points/lines that are newly added.
|
// Also load points/lines that are newly added.
|
||||||
const newGeometry = new NewGeometryFromChangesFeatureSource(state.changes, state.osmConnection._oauth_config.url)
|
const newGeometry = new NewGeometryFromChangesFeatureSource(state.changes, state.allElements, state.osmConnection._oauth_config.url)
|
||||||
newGeometry.features.addCallbackAndRun(geometries => {
|
newGeometry.features.addCallbackAndRun(geometries => {
|
||||||
console.debug("New geometries are:", geometries)
|
console.debug("New geometries are:", geometries)
|
||||||
})
|
})
|
||||||
|
@ -323,7 +323,10 @@ export default class FeaturePipeline {
|
||||||
// We don't bother to split them over tiles as it'll contain little features by default, so we simply add them like this
|
// We don't bother to split them over tiles as it'll contain little features by default, so we simply add them like this
|
||||||
perLayerHierarchy.get(perLayer.layer.layerDef.id).registerTile(perLayer)
|
perLayerHierarchy.get(perLayer.layer.layerDef.id).registerTile(perLayer)
|
||||||
// AT last, we always apply the metatags whenever possible
|
// AT last, we always apply the metatags whenever possible
|
||||||
perLayer.features.addCallbackAndRunD(_ => self.onNewDataLoaded(perLayer))
|
perLayer.features.addCallbackAndRunD(feats => {
|
||||||
|
console.log("New feature for layer ", perLayer.layer.layerDef.id, ":", feats)
|
||||||
|
self.onNewDataLoaded(perLayer);
|
||||||
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
newGeometry,
|
newGeometry,
|
||||||
|
|
|
@ -41,6 +41,7 @@ export default class PerLayerFeatureSourceSplitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const f of features) {
|
for (const f of features) {
|
||||||
|
console.log("Classifying ", f.feature)
|
||||||
for (const layer of layers.data) {
|
for (const layer of layers.data) {
|
||||||
if (layer.layerDef.source.osmTags.matchesProperties(f.feature.properties)) {
|
if (layer.layerDef.source.osmTags.matchesProperties(f.feature.properties)) {
|
||||||
// We have found our matching layer!
|
// We have found our matching layer!
|
||||||
|
@ -50,8 +51,8 @@ export default class PerLayerFeatureSourceSplitter {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
noLayerFound.push(f)
|
|
||||||
}
|
}
|
||||||
|
noLayerFound.push(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, we have our features per layer as a list
|
// At this point, we have our features per layer as a list
|
||||||
|
|
|
@ -63,7 +63,6 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
|
||||||
}
|
}
|
||||||
|
|
||||||
private update() {
|
private update() {
|
||||||
console.log("FIltering", this.upstream.name)
|
|
||||||
const self = this;
|
const self = this;
|
||||||
const layer = this.upstream.layer;
|
const layer = this.upstream.layer;
|
||||||
const features: { feature: any; freshness: Date }[] = (this.upstream.features.data ?? []);
|
const features: { feature: any; freshness: Date }[] = (this.upstream.features.data ?? []);
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import {Changes} from "../../Osm/Changes";
|
import {Changes} from "../../Osm/Changes";
|
||||||
import {OsmNode, OsmRelation, OsmWay} from "../../Osm/OsmObject";
|
import {OsmNode, OsmObject, OsmRelation, OsmWay} from "../../Osm/OsmObject";
|
||||||
import FeatureSource from "../FeatureSource";
|
import FeatureSource from "../FeatureSource";
|
||||||
import {UIEventSource} from "../../UIEventSource";
|
import {UIEventSource} from "../../UIEventSource";
|
||||||
import {ChangeDescription} from "../../Osm/Actions/ChangeDescription";
|
import {ChangeDescription} from "../../Osm/Actions/ChangeDescription";
|
||||||
|
import {ElementStorage} from "../../ElementStorage";
|
||||||
|
|
||||||
export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
||||||
// This class name truly puts the 'Java' into 'Javascript'
|
// This class name truly puts the 'Java' into 'Javascript'
|
||||||
|
@ -13,79 +14,115 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
|
||||||
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
|
public readonly features: UIEventSource<{ feature: any; freshness: Date }[]> = new UIEventSource<{ feature: any; freshness: Date }[]>([]);
|
||||||
public readonly name: string = "newFeatures";
|
public readonly name: string = "newFeatures";
|
||||||
|
|
||||||
constructor(changes: Changes, backendUrl: string) {
|
constructor(changes: Changes, allElementStorage: ElementStorage, backendUrl: string) {
|
||||||
|
|
||||||
const seenChanges = new Set<ChangeDescription>();
|
const seenChanges = new Set<ChangeDescription>();
|
||||||
const features = this.features.data;
|
const features = this.features.data;
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
changes.pendingChanges
|
changes.pendingChanges.addCallbackAndRunD(changes => {
|
||||||
.map(changes => changes.filter(ch =>
|
if (changes.length === 0) {
|
||||||
// only new objects allowed
|
return;
|
||||||
ch.id < 0 &&
|
}
|
||||||
// The change is an update to the object (e.g. tags or geometry) - not the actual create
|
|
||||||
ch.changes !== undefined &&
|
const now = new Date();
|
||||||
// If tags is undefined, this is probably a new point that is part of a split road
|
let somethingChanged = false;
|
||||||
ch.tags !== undefined &&
|
|
||||||
// Already handled
|
function add(feature) {
|
||||||
!seenChanges.has(ch)))
|
feature.id = feature.properties.id
|
||||||
.addCallbackAndRunD(changes => {
|
features.push({
|
||||||
if (changes.length === 0) {
|
feature: feature,
|
||||||
return;
|
freshness: now
|
||||||
|
})
|
||||||
|
somethingChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const change of changes) {
|
||||||
|
if (seenChanges.has(change)) {
|
||||||
|
// Already handled
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seenChanges.add(change)
|
||||||
|
|
||||||
|
if (change.tags === undefined) {
|
||||||
|
// If tags is undefined, this is probably a new point that is part of a split road
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = new Date();
|
if (change.id > 0) {
|
||||||
|
// This is an already existing object
|
||||||
function add(feature) {
|
// In _most_ of the cases, this means that this _isn't_ a new object
|
||||||
feature.id = feature.properties.id
|
// However, when a point is snapped to an already existing point, we have to create a representation for this point!
|
||||||
features.push({
|
// For this, we introspect the change
|
||||||
feature: feature,
|
if (allElementStorage.has(change.id)) {
|
||||||
freshness: now
|
// const currentTags = allElementStorage.getEventSourceById(change.id).data
|
||||||
})
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
for (const change of changes) {
|
|
||||||
seenChanges.add(change)
|
|
||||||
try {
|
|
||||||
const tags = {}
|
|
||||||
for (const kv of change.tags) {
|
|
||||||
tags[kv.k] = kv.v
|
|
||||||
}
|
|
||||||
tags["id"] = change.type + "/" + change.id
|
|
||||||
|
|
||||||
tags["_backend"] = backendUrl
|
|
||||||
|
|
||||||
switch (change.type) {
|
|
||||||
case "node":
|
|
||||||
const n = new OsmNode(change.id)
|
|
||||||
n.tags = tags
|
|
||||||
n.lat = change.changes["lat"]
|
|
||||||
n.lon = change.changes["lon"]
|
|
||||||
const geojson = n.asGeoJson()
|
|
||||||
add(geojson)
|
|
||||||
break;
|
|
||||||
case "way":
|
|
||||||
const w = new OsmWay(change.id)
|
|
||||||
w.tags = tags
|
|
||||||
w.nodes = change.changes["nodes"]
|
|
||||||
w.coordinates = change.changes["coordinates"].map(coor => [coor[1], coor[0]])
|
|
||||||
add(w.asGeoJson())
|
|
||||||
break;
|
|
||||||
case "relation":
|
|
||||||
const r = new OsmRelation(change.id)
|
|
||||||
r.tags = tags
|
|
||||||
r.members = change.changes["members"]
|
|
||||||
add(r.asGeoJson())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Could not generate a new geometry to render on screen for:", e)
|
|
||||||
}
|
}
|
||||||
|
console.debug("Detected a reused point")
|
||||||
|
// The 'allElementsStore' does _not_ have this point yet, so we have to create it
|
||||||
|
OsmObject.DownloadObjectAsync(change.type + "/" + change.id).then(feat => {
|
||||||
|
console.log("Got the reused point:", feat)
|
||||||
|
for (const kv of change.tags) {
|
||||||
|
feat.tags[kv.k] = kv.v
|
||||||
|
}
|
||||||
|
const geojson= feat.asGeoJson();
|
||||||
|
allElementStorage.addOrGetElement(geojson)
|
||||||
|
self.features.data.push({feature: geojson, freshness: new Date()})
|
||||||
|
self.features.ping()
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
} else if (change.id < 0 && change.changes === undefined) {
|
||||||
|
// The geometry is not described - not a new point
|
||||||
|
if (change.id < 0) {
|
||||||
|
console.error("WARNING: got a new point without geometry!")
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tags = {}
|
||||||
|
for (const kv of change.tags) {
|
||||||
|
tags[kv.k] = kv.v
|
||||||
|
}
|
||||||
|
tags["id"] = change.type + "/" + change.id
|
||||||
|
|
||||||
|
tags["_backend"] = backendUrl
|
||||||
|
|
||||||
|
switch (change.type) {
|
||||||
|
case "node":
|
||||||
|
const n = new OsmNode(change.id)
|
||||||
|
n.tags = tags
|
||||||
|
n.lat = change.changes["lat"]
|
||||||
|
n.lon = change.changes["lon"]
|
||||||
|
const geojson = n.asGeoJson()
|
||||||
|
add(geojson)
|
||||||
|
break;
|
||||||
|
case "way":
|
||||||
|
const w = new OsmWay(change.id)
|
||||||
|
w.tags = tags
|
||||||
|
w.nodes = change.changes["nodes"]
|
||||||
|
w.coordinates = change.changes["coordinates"].map(coor => [coor[1], coor[0]])
|
||||||
|
add(w.asGeoJson())
|
||||||
|
break;
|
||||||
|
case "relation":
|
||||||
|
const r = new OsmRelation(change.id)
|
||||||
|
r.tags = tags
|
||||||
|
r.members = change.changes["members"]
|
||||||
|
add(r.asGeoJson())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Could not generate a new geometry to render on screen for:", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (somethingChanged) {
|
||||||
self.features.ping()
|
self.features.ping()
|
||||||
})
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -153,8 +153,7 @@ export default class CreateNoteImportLayer extends Conversion<LayerConfigJson, L
|
||||||
"mapRendering": [
|
"mapRendering": [
|
||||||
{
|
{
|
||||||
"location": [
|
"location": [
|
||||||
"point",
|
"point"
|
||||||
"centroid"
|
|
||||||
],
|
],
|
||||||
"icon": {
|
"icon": {
|
||||||
"render": "circle:white;help:black",
|
"render": "circle:white;help:black",
|
||||||
|
|
|
@ -230,7 +230,7 @@ export default class LayerConfig extends WithContextLoader {
|
||||||
if (this.lineRendering.length === 0 && this.mapRendering.length === 0) {
|
if (this.lineRendering.length === 0 && this.mapRendering.length === 0) {
|
||||||
console.log(json.mapRendering)
|
console.log(json.mapRendering)
|
||||||
throw("The layer " + this.id + " does not have any maprenderings defined and will thus not show up on the map at all. If this is intentional, set maprenderings to 'null' instead of '[]'")
|
throw("The layer " + this.id + " does not have any maprenderings defined and will thus not show up on the map at all. If this is intentional, set maprenderings to 'null' instead of '[]'")
|
||||||
} else if (!hasCenterRendering && this.lineRendering.length === 0) {
|
} else if (!hasCenterRendering && this.lineRendering.length === 0 && !this.source.geojsonSource?.startsWith("https://api.openstreetmap.org/api/0.6/notes.json")) {
|
||||||
throw "The layer " + this.id + " might not render ways. This might result in dropped information"
|
throw "The layer " + this.id + " might not render ways. This might result in dropped information"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue