forked from MapComplete/MapComplete
Add special visualisation for automated actions, add missing_street-theme, various fixes
This commit is contained in:
parent
e61c25fd6e
commit
20ec12b23c
23 changed files with 1116 additions and 690 deletions
|
@ -134,6 +134,7 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
"If a 'unique tag key' is given, the tag with this key will only appear once (e.g. if 'name' is given, all features will have a different name)"
|
||||
_args = ["list of features or layer name or '*' to get all features", "amount of features", "unique tag key (optional)", "maxDistanceInMeters (optional)"]
|
||||
|
||||
|
||||
/**
|
||||
* Gets the closes N features, sorted by ascending distance.
|
||||
*
|
||||
|
@ -164,8 +165,11 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
|
||||
const selfCenter = GeoOperations.centerpointCoordinates(feature)
|
||||
let closestFeatures: { feat: any, distance: number }[] = [];
|
||||
|
||||
for (const featureList of features) {
|
||||
// Features is provided by 'getFeaturesWithin' which returns a list of lists of features, hence the double loop here
|
||||
for (const otherFeature of featureList) {
|
||||
|
||||
if (otherFeature === feature || otherFeature.properties.id === feature.properties.id) {
|
||||
continue; // We ignore self
|
||||
}
|
||||
|
@ -187,6 +191,7 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
}
|
||||
|
||||
if (closestFeatures.length === 0) {
|
||||
// This is the first matching feature we find - always add it
|
||||
closestFeatures.push({
|
||||
feat: otherFeature,
|
||||
distance: distance
|
||||
|
@ -194,6 +199,7 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (closestFeatures.length >= maxFeatures && closestFeatures[maxFeatures - 1].distance < distance) {
|
||||
// The last feature of the list (and thus the furthest away is still closer
|
||||
// No use for checking, as we already have plenty of features!
|
||||
|
@ -257,6 +263,8 @@ class ClosestNObjectFunc implements ExtraFunction {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
return closestFeatures;
|
||||
|
|
|
@ -126,7 +126,7 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
|||
|
||||
eventSource.setData(eventSource.data.concat(newFeatures))
|
||||
|
||||
}).catch(msg => console.error("Could not load geojon layer", url, "due to", msg))
|
||||
}).catch(msg => console.error("Could not load geojson layer", url, "due to", msg))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -107,51 +107,57 @@ export default class MetaTagging {
|
|||
}
|
||||
return atLeastOneFeatureChanged
|
||||
}
|
||||
|
||||
|
||||
public static createFunctionsForFeature(layerId: string, calculatedTags: [string, string][]): ((feature: any) => void)[] {
|
||||
public static createFunctionsForFeature(layerId: string, calculatedTags: [string, string, boolean][]): ((feature: any) => void)[] {
|
||||
const functions: ((feature: any) => void)[] = [];
|
||||
|
||||
for (const entry of calculatedTags) {
|
||||
const key = entry[0]
|
||||
const code = entry[1];
|
||||
const isStrict = entry[2]
|
||||
if (code === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const func = new Function("feat", "return " + code + ";");
|
||||
const calculateAndAssign = (feat) => {
|
||||
|
||||
|
||||
try {
|
||||
let result = new Function("feat", "return " + code + ";")(feat);
|
||||
if (result === "") {
|
||||
result === undefined
|
||||
}
|
||||
if (result !== undefined && typeof result !== "string") {
|
||||
// Make sure it is a string!
|
||||
result = JSON.stringify(result);
|
||||
}
|
||||
delete feat.properties[key]
|
||||
feat.properties[key] = result;
|
||||
return result;
|
||||
}catch(e){
|
||||
if (MetaTagging.errorPrintCount < MetaTagging.stopErrorOutputAt) {
|
||||
console.warn("Could not calculate a " + (isStrict ? "strict " : "") + " calculated tag for key " + key + " defined by " + code + " (in layer" + layerId + ") due to \n" + e + "\n. Are you the theme creator? Doublecheck your code. Note that the metatags might not be stable on new features", e, e.stack)
|
||||
MetaTagging.errorPrintCount++;
|
||||
if (MetaTagging.errorPrintCount == MetaTagging.stopErrorOutputAt) {
|
||||
console.error("Got ", MetaTagging.stopErrorOutputAt, " errors calculating this metatagging - stopping output now")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(isStrict){
|
||||
functions.push(calculateAndAssign)
|
||||
continue
|
||||
}
|
||||
|
||||
// Lazy function
|
||||
const f = (feature: any) => {
|
||||
|
||||
|
||||
delete feature.properties[key]
|
||||
Object.defineProperty(feature.properties, key, {
|
||||
configurable: true,
|
||||
enumerable: false, // By setting this as not enumerable, the localTileSaver will _not_ calculate this
|
||||
get: function () {
|
||||
try {
|
||||
// Lazyness for the win!
|
||||
let result = func(feature);
|
||||
|
||||
if (result === "") {
|
||||
result === undefined
|
||||
}
|
||||
if (result !== undefined && typeof result !== "string") {
|
||||
// Make sure it is a string!
|
||||
result = JSON.stringify(result);
|
||||
}
|
||||
delete feature.properties[key]
|
||||
feature.properties[key] = result;
|
||||
return result;
|
||||
} catch (e) {
|
||||
if (MetaTagging.errorPrintCount < MetaTagging.stopErrorOutputAt) {
|
||||
console.warn("Could not calculate a calculated tag for key " + key + " defined by " + code + " (in layer" + layerId + ") due to \n" + e + "\n. Are you the theme creator? Doublecheck your code. Note that the metatags might not be stable on new features", e, e.stack)
|
||||
MetaTagging.errorPrintCount++;
|
||||
if (MetaTagging.errorPrintCount == MetaTagging.stopErrorOutputAt) {
|
||||
console.error("Got ", MetaTagging.stopErrorOutputAt, " errors calculating this metatagging - stopping output now")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return calculateAndAssign(feature)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -167,7 +173,7 @@ export default class MetaTagging {
|
|||
private static createRetaggingFunc(layer: LayerConfig):
|
||||
((params: ExtraFuncParams, feature: any) => void) {
|
||||
|
||||
const calculatedTags: [string, string][] = layer.calculatedTags;
|
||||
const calculatedTags: [string, string, boolean][] = layer.calculatedTags;
|
||||
if (calculatedTags === undefined || calculatedTags.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ export class Changes {
|
|||
* Uploads all the pending changes in one go.
|
||||
* Triggered by the 'PendingChangeUploader'-actor in Actors
|
||||
*/
|
||||
public flushChanges(flushreason: string = undefined) {
|
||||
public async flushChanges(flushreason: string = undefined) : Promise<void>{
|
||||
if (this.pendingChanges.data.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -108,16 +108,14 @@ export class Changes {
|
|||
}
|
||||
console.log("Uploading changes due to: ", flushreason)
|
||||
this.isUploading.setData(true)
|
||||
|
||||
this.flushChangesAsync()
|
||||
.then(_ => {
|
||||
this.isUploading.setData(false)
|
||||
console.log("Changes flushed!");
|
||||
})
|
||||
.catch(e => {
|
||||
this.isUploading.setData(false)
|
||||
console.error("Flushing changes failed due to", e);
|
||||
})
|
||||
try {
|
||||
const csNumber = await this.flushChangesAsync()
|
||||
this.isUploading.setData(false)
|
||||
console.log("Changes flushed!");
|
||||
} catch (e) {
|
||||
this.isUploading.setData(false)
|
||||
console.error("Flushing changes failed due to", e);
|
||||
}
|
||||
}
|
||||
|
||||
private calculateDistanceToChanges(change: OsmChangeAction, changeDescriptions: ChangeDescription[]) {
|
||||
|
|
|
@ -17,7 +17,6 @@ import {FeatureSourceForLayer, Tiled} from "../FeatureSource/FeatureSource";
|
|||
import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource";
|
||||
import {LocalStorageSource} from "../Web/LocalStorageSource";
|
||||
import {GeoOperations} from "../GeoOperations";
|
||||
import StaticFeatureSource from "../FeatureSource/Sources/StaticFeatureSource";
|
||||
|
||||
/**
|
||||
* Contains all the leaflet-map related state
|
||||
|
@ -186,6 +185,7 @@ export default class MapState extends UserRelatedState {
|
|||
|
||||
|
||||
let i = 0
|
||||
const self = this;
|
||||
const features : UIEventSource<{ feature: any, freshness: Date }[]>= this.currentBounds.map(bounds => {
|
||||
if(bounds === undefined){
|
||||
return []
|
||||
|
@ -197,7 +197,8 @@ export default class MapState extends UserRelatedState {
|
|||
type: "Feature",
|
||||
properties:{
|
||||
id:"current_view-"+i,
|
||||
"current_view":"yes"
|
||||
"current_view":"yes",
|
||||
"zoom": ""+self.locationControl.data.zoom
|
||||
},
|
||||
geometry:{
|
||||
type:"Polygon",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue