Full code cleanup

This commit is contained in:
Pieter Vander Vennet 2022-01-26 21:40:38 +01:00
parent 3a4a2a2016
commit fa971ffbbf
300 changed files with 16352 additions and 19284 deletions

View file

@ -64,7 +64,7 @@ export default class AvailableBaseLayersImplementation implements AvailableBaseL
console.warn("Editor layer index: name not defined on ", props)
continue
}
const leafletLayer: () => TileLayer = () => AvailableBaseLayersImplementation.CreateBackgroundLayer(
props.id,
@ -189,13 +189,13 @@ export default class AvailableBaseLayersImplementation implements AvailableBaseL
attribution: attribution,
maxZoom: Math.max(21, maxZoom ?? 19),
maxNativeZoom: maxZoom ?? 19,
minZoom: 1,
minZoom: 1,
// @ts-ignore
wmts: isWMTS ?? false,
subdomains: domains
});
}
public AvailableLayersAt(location: UIEventSource<Loc>): UIEventSource<BaseLayer[]> {
return UIEventSource.ListStabilized(location.map(
(currentLocation) => {
@ -209,50 +209,50 @@ export default class AvailableBaseLayersImplementation implements AvailableBaseL
public SelectBestLayerAccordingTo(location: UIEventSource<Loc>, preferedCategory: UIEventSource<string | string[]>): UIEventSource<BaseLayer> {
return this.AvailableLayersAt(location)
.map(available => {
// First float all 'best layers' to the top
available.sort((a, b) => {
if (a.isBest && b.isBest) {
return 0;
}
if (!a.isBest) {
return 1
}
return -1;
}
)
if (preferedCategory.data === undefined) {
return available[0]
}
let prefered: string []
if (typeof preferedCategory.data === "string") {
prefered = [preferedCategory.data]
} else {
prefered = preferedCategory.data;
}
prefered.reverse();
for (const category of prefered) {
//Then sort all 'photo'-layers to the top. Stability of the sorting will force a 'best' photo layer on top
// First float all 'best layers' to the top
available.sort((a, b) => {
if (a.category === category && b.category === category) {
if (a.isBest && b.isBest) {
return 0;
}
if (a.category !== category) {
if (!a.isBest) {
return 1
}
return -1;
}
)
}
return available[0]
}, [preferedCategory])
if (preferedCategory.data === undefined) {
return available[0]
}
let prefered: string []
if (typeof preferedCategory.data === "string") {
prefered = [preferedCategory.data]
} else {
prefered = preferedCategory.data;
}
prefered.reverse();
for (const category of prefered) {
//Then sort all 'photo'-layers to the top. Stability of the sorting will force a 'best' photo layer on top
available.sort((a, b) => {
if (a.category === category && b.category === category) {
return 0;
}
if (a.category !== category) {
return 1
}
return -1;
}
)
}
return available[0]
}, [preferedCategory])
}
private CalculateAvailableLayersAt(lon: number, lat: number): BaseLayer[] {
const availableLayers = [this.osmCarto]
const globalLayers = [];

View file

@ -11,11 +11,11 @@ export interface GeoLocationPointProperties {
"user:location": "yes",
"date": string,
"latitude": number
"longitude":number,
"longitude": number,
"speed": number,
"accuracy": number
"heading": number
"altitude":number
"altitude": number
}
export default class GeoLocationHandler extends VariableUiElement {

View file

@ -64,22 +64,6 @@ export default class DetermineLayout {
return layoutToUse
}
private static prepCustomTheme(json: any): LayoutConfigJson{
const knownLayersDict = new Map<string, LayerConfigJson>()
for (const key in known_layers["default"]) {
const layer = known_layers["default"][key]
knownLayersDict.set(layer.id, layer)
}
const converState = {
tagRenderings: SharedTagRenderings.SharedTagRenderingJson,
sharedLayers: knownLayersDict
}
json = new FixLegacyTheme().convertStrict(converState, json, "While loading a dynamic theme")
json = new PrepareTheme().convertStrict(converState, json, "While preparing a dynamic theme")
console.log("The layoutconfig is ", json)
return json
}
public static LoadLayoutFromHash(
userLayoutParam: UIEventSource<string>
): LayoutConfig | null {
@ -148,6 +132,22 @@ export default class DetermineLayout {
.AttachTo("centermessage");
}
private static prepCustomTheme(json: any): LayoutConfigJson {
const knownLayersDict = new Map<string, LayerConfigJson>()
for (const key in known_layers["default"]) {
const layer = known_layers["default"][key]
knownLayersDict.set(layer.id, layer)
}
const converState = {
tagRenderings: SharedTagRenderings.SharedTagRenderingJson,
sharedLayers: knownLayersDict
}
json = new FixLegacyTheme().convertStrict(converState, json, "While loading a dynamic theme")
json = new PrepareTheme().convertStrict(converState, json, "While preparing a dynamic theme")
console.log("The layoutconfig is ", json)
return json
}
private static async LoadRemoteTheme(link: string): Promise<LayoutConfig | null> {
console.log("Downloading map theme from ", link);
@ -160,7 +160,7 @@ export default class DetermineLayout {
try {
parsed.id = link;
const layoutToUse = DetermineLayout.prepCustomTheme(parsed)
return new LayoutConfig(layoutToUse,false)
return new LayoutConfig(layoutToUse, false)
} catch (e) {
console.error(e)
DetermineLayout.ShowErrorOnCustomTheme(

View file

@ -94,7 +94,7 @@ class IntersectionFunc implements ExtraFunction {
for (const otherFeature of tile) {
const intersections = GeoOperations.LineIntersections(feat, otherFeature)
if(intersections.length === 0){
if (intersections.length === 0) {
continue
}
result.push({feat: otherFeature, intersections})
@ -154,28 +154,12 @@ class ClosestObjectFunc implements ExtraFunction {
class ClosestNObjectFunc implements ExtraFunction {
_f(params, feature) {
return (features, amount, uniqueTag, maxDistanceInMeters) => {
let distance: number = Number(maxDistanceInMeters)
if (isNaN(distance)) {
distance = undefined
}
return ClosestNObjectFunc.GetClosestNFeatures(params, feature, features, {
maxFeatures: Number(amount),
uniqueTag: uniqueTag,
maxDistance: distance
});
}
}
_name = "closestn"
_doc = "Given either a list of geojson features or a single layer name, gives the n closest objects which are nearest to the feature (excluding the feature itself). In the case of ways/polygons, only the centerpoint is considered. " +
"Returns a list of `{feat: geojson, distance:number}` the empty list if nothing is found (or not yet loaded)\n\n" +
"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.
*
@ -311,6 +295,21 @@ class ClosestNObjectFunc implements ExtraFunction {
return closestFeatures;
}
_f(params, feature) {
return (features, amount, uniqueTag, maxDistanceInMeters) => {
let distance: number = Number(maxDistanceInMeters)
if (isNaN(distance)) {
distance = undefined
}
return ClosestNObjectFunc.GetClosestNFeatures(params, feature, features, {
maxFeatures: Number(amount),
uniqueTag: uniqueTag,
maxDistance: distance
});
}
}
}
@ -401,7 +400,7 @@ export class ExtraFunctions {
];
public static FullPatchFeature(params: ExtraFuncParams, feature) {
if(feature._is_patched){
if (feature._is_patched) {
return
}
feature._is_patched = true

View file

@ -14,7 +14,7 @@ class MetatagUpdater {
private source: FeatureSourceForLayer & Tiled;
private readonly params: ExtraFuncParams
private state: { allElements?: ElementStorage };
private readonly isDirty = new UIEventSource(false)
constructor(source: FeatureSourceForLayer & Tiled, state: { allElements?: ElementStorage }, featurePipeline: FeaturePipeline) {
@ -31,14 +31,14 @@ class MetatagUpdater {
if (oldBbox === undefined) {
self.neededLayerBboxes.set(layerId, bbox);
} else if (!bbox.isContainedIn(oldBbox)) {
self.neededLayerBboxes.set(layerId,oldBbox.unionWith(bbox))
self.neededLayerBboxes.set(layerId, oldBbox.unionWith(bbox))
}
return featurePipeline.GetFeaturesWithin(layerId, bbox)
},
memberships: featurePipeline.relationTracker
}
this.isDirty.stabilized(100).addCallback(dirty => {
if(dirty){
if (dirty) {
self.updateMetaTags()
}
})
@ -46,10 +46,10 @@ class MetatagUpdater {
}
public requestUpdate(){
public requestUpdate() {
this.isDirty.setData(true)
}
private updateMetaTags() {
const features = this.source.features.data
@ -74,7 +74,8 @@ export default class MetaTagRecalculator {
};
private _featurePipeline: FeaturePipeline;
private readonly _alreadyRegistered: Set<FeatureSourceForLayer & Tiled> = new Set<FeatureSourceForLayer & Tiled>()
private readonly _notifiers : MetatagUpdater[] = []
private readonly _notifiers: MetatagUpdater[] = []
/**
* The meta tag recalculator receives tiles of layers.
* It keeps track of which sources have had their share calculated, and which should be re-updated if some other data is loaded
@ -92,16 +93,16 @@ private readonly _notifiers : MetatagUpdater[] = []
return;
}
this._alreadyRegistered.add(source)
this._notifiers.push(new MetatagUpdater(source,this._state,this._featurePipeline))
this._notifiers.push(new MetatagUpdater(source, this._state, this._featurePipeline))
const self = this;
source.features.addCallbackAndRunD(_ => {
const layerName = source.layer.layerDef.id
for (const updater of self._notifiers ) {
for (const updater of self._notifiers) {
const neededBbox = updater.neededLayerBboxes.get(layerName)
if(neededBbox == undefined){
if (neededBbox == undefined) {
continue
}
if(source.bbox === undefined || neededBbox.overlapsWith(source.bbox)){
if (source.bbox === undefined || neededBbox.overlapsWith(source.bbox)) {
updater.requestUpdate()
}
}

View file

@ -41,7 +41,7 @@ export default class SaveTileToLocalStorageActor {
})
}
public LoadTilesFromDisk(currentBounds: UIEventSource<BBox>, location: UIEventSource<Loc>,
registerFreshness: (tileId: number, freshness: Date) => void,
registerTile: ((src: FeatureSource & Tiled) => void)) {
@ -55,7 +55,7 @@ export default class SaveTileToLocalStorageActor {
}
currentBounds.addCallbackAndRunD(bbox => {
if(self._layer.minzoomVisible > location.data.zoom){
if (self._layer.minzoomVisible > location.data.zoom) {
// Not enough zoom
return;
}
@ -119,9 +119,9 @@ export default class SaveTileToLocalStorageActor {
}
private SetIdb(tileIndex, data) {
try{
try {
IdbLocalStorage.SetDirectly(this._layer.id + "_" + tileIndex, data)
}catch(e){
} catch (e) {
console.error("Could not save tile to indexed-db: ", e, "tileIndex is:", tileIndex, "for layer", this._layer.id)
}
}

View file

@ -43,40 +43,33 @@ export default class FeaturePipeline {
public readonly timeout: UIEventSource<number>;
public readonly somethingLoaded: UIEventSource<boolean> = new UIEventSource<boolean>(false)
public readonly newDataLoadedSignal: UIEventSource<FeatureSource> = new UIEventSource<FeatureSource>(undefined)
public readonly relationTracker: RelationsTracker
/**
* Keeps track of all raw OSM-nodes.
* Only initialized if 'type_node' is defined as layer
*/
public readonly fullNodeDatabase?: FullNodeDatabaseSource
private readonly overpassUpdater: OverpassFeatureSource
private state: MapState;
public readonly relationTracker: RelationsTracker
private readonly perLayerHierarchy: Map<string, TileHierarchyMerger>;
/**
* Keeps track of the age of the loaded data.
* Has one freshness-Calculator for every layer
* @private
*/
private readonly freshnesses = new Map<string, TileFreshnessCalculator>();
private readonly oldestAllowedDate: Date;
private readonly osmSourceZoomLevel
private readonly localStorageSavers = new Map<string, SaveTileToLocalStorageActor>()
/**
* Keeps track of all raw OSM-nodes.
* Only initialized if 'type_node' is defined as layer
*/
public readonly fullNodeDatabase? : FullNodeDatabaseSource
constructor(
handleFeatureSource: (source: FeatureSourceForLayer & Tiled) => void,
state: MapState,
options? : {
options?: {
/*Used for metatagging - will receive all the sources with changeGeometry applied but without filtering*/
handleRawFeatureSource: (source: FeatureSourceForLayer) => void
}
) {
) {
this.state = state;
const self = this
@ -104,7 +97,7 @@ export default class FeaturePipeline {
return location.zoom >= minzoom;
}
);
const neededTilesFromOsm = this.getNeededTilesFromOsm(this.sufficientlyZoomed)
const perLayerHierarchy = new Map<string, TileHierarchyMerger>()
@ -114,10 +107,10 @@ export default class FeaturePipeline {
function patchedHandleFeatureSource(src: FeatureSourceForLayer & IndexedFeatureSource & Tiled) {
// This will already contain the merged features for this tile. In other words, this will only be triggered once for every tile
const withChanges = new ChangeGeometryApplicator(src, state.changes);
const srcFiltered = new FilteringFeatureSource(state, src.tileIndex,withChanges)
const srcFiltered = new FilteringFeatureSource(state, src.tileIndex, withChanges)
handleFeatureSource(srcFiltered)
if(options?.handleRawFeatureSource){
if (options?.handleRawFeatureSource) {
options.handleRawFeatureSource(withChanges)
}
self.somethingLoaded.setData(true)
@ -267,7 +260,7 @@ export default class FeaturePipeline {
})
})
if(this.fullNodeDatabase !== undefined){
if (this.fullNodeDatabase !== undefined) {
osmFeatureSource.rawDataHandlers.push((osmJson, tileId) => this.fullNodeDatabase.handleOsmJson(osmJson, tileId))
}
@ -289,7 +282,7 @@ export default class FeaturePipeline {
self.localStorageSavers.get(tile.layer.layerDef.id)?.addTile(tile)
perLayerHierarchy.get(source.layer.layerDef.id).registerTile(new RememberingSource(tile))
tile.features.addCallbackAndRunD(f => {
if(f.length === 0){
if (f.length === 0) {
return
}
self.onNewDataLoaded(tile)
@ -298,9 +291,11 @@ export default class FeaturePipeline {
}
}),
updater,
{handleLeftovers: (leftOvers) => {
console.warn("Overpass returned a few non-matched features:", leftOvers)
}})
{
handleLeftovers: (leftOvers) => {
console.warn("Overpass returned a few non-matched features:", leftOvers)
}
})
// Also load points/lines that are newly added.
@ -308,7 +303,7 @@ export default class FeaturePipeline {
newGeometry.features.addCallbackAndRun(geometries => {
console.debug("New geometries are:", geometries)
})
new RegisteringAllFromFeatureSourceActor(newGeometry, state.allElements)
// A NewGeometryFromChangesFeatureSource does not split per layer, so we do this next
new PerLayerFeatureSourceSplitter(state.filteredLayers,
@ -322,9 +317,11 @@ export default class FeaturePipeline {
},
newGeometry,
{handleLeftovers: (leftOvers) => {
console.warn("Got some leftovers from the filteredLayers: ", leftOvers)
}}
{
handleLeftovers: (leftOvers) => {
console.warn("Got some leftovers from the filteredLayers: ", leftOvers)
}
}
)
this.runningQuery = updater.runningQuery.map(
@ -337,10 +334,6 @@ export default class FeaturePipeline {
}
private onNewDataLoaded(src: FeatureSource){
this.newDataLoadedSignal.setData(src)
}
public GetAllFeaturesWithin(bbox: BBox): any[][] {
const self = this
const tiles = []
@ -369,6 +362,10 @@ export default class FeaturePipeline {
})
}
private onNewDataLoaded(src: FeatureSource) {
this.newDataLoadedSignal.setData(src)
}
private freshnessForVisibleLayers(z: number, x: number, y: number): Date {
let oldestDate = undefined;
for (const flayer of this.state.filteredLayers.data) {
@ -378,11 +375,11 @@ export default class FeaturePipeline {
if (this.state.locationControl.data.zoom < flayer.layerDef.minzoom) {
continue;
}
if(flayer.layerDef.maxAgeOfCache === 0){
if (flayer.layerDef.maxAgeOfCache === 0) {
return undefined;
}
const freshnessCalc = this.freshnesses.get(flayer.layerDef.id)
if(freshnessCalc === undefined){
if (freshnessCalc === undefined) {
console.warn("No freshness tracker found for ", flayer.layerDef.id)
return undefined
}

View file

@ -19,8 +19,8 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
};
private readonly _alreadyRegistered = new Set<UIEventSource<any>>();
private readonly _is_dirty = new UIEventSource(false)
private previousFeatureSet : Set<any> = undefined;
private previousFeatureSet: Set<any> = undefined;
constructor(
state: {
locationControl: UIEventSource<{ zoom: number }>,
@ -54,7 +54,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
self.update()
}
})
metataggingUpdated?.addCallback(_ => {
self._is_dirty.setData(true)
})
@ -66,7 +66,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
const self = this;
const layer = this.upstream.layer;
const features: { feature: any; freshness: Date }[] = (this.upstream.features.data ?? []);
const includedFeatureIds = new Set<string>();
const includedFeatureIds = new Set<string>();
const newFeatures = (features ?? []).filter((f) => {
self.registerCallback(f.feature)
@ -97,29 +97,29 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
const previousSet = this.previousFeatureSet;
this._is_dirty.setData(false)
// Is there any difference between the two sets?
if(previousSet !== undefined && previousSet.size === includedFeatureIds.size){
if (previousSet !== undefined && previousSet.size === includedFeatureIds.size) {
// The size of the sets is the same - they _might_ be identical
const newItemFound = Array.from(includedFeatureIds).some(id => !previousSet.has(id))
if(!newItemFound){
if (!newItemFound) {
// We know that:
// - The sets have the same size
// - Every item from the new set has been found in the old set
// which means they are identical!
return;
}
}
// Something new has been found!
this.features.setData(newFeatures);
}
private registerCallback(feature: any) {
const src = this.state?.allElements?.addOrGetElement(feature)
if(src == undefined){
if (src == undefined) {
return
}
if (this._alreadyRegistered.has(src)) {

View file

@ -65,7 +65,7 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
for (const kv of change.tags) {
feat.tags[kv.k] = kv.v
}
const geojson= feat.asGeoJson();
const geojson = feat.asGeoJson();
allElementStorage.addOrGetElement(geojson)
self.features.data.push({feature: geojson, freshness: new Date()})
self.features.ping()
@ -81,7 +81,7 @@ export class NewGeometryFromChangesFeatureSource implements FeatureSource {
continue;
}
try {
const tags = {}
for (const kv of change.tags) {

View file

@ -10,7 +10,7 @@ export default class SimpleFeatureSource implements FeatureSourceForLayer, Tiled
public readonly bbox: BBox = BBox.global;
public readonly tileIndex: number;
constructor(layer: FilteredLayer, tileIndex: number, featureSource?: UIEventSource<{ feature:any; freshness: Date }[]>) {
constructor(layer: FilteredLayer, tileIndex: number, featureSource?: UIEventSource<{ feature: any; freshness: Date }[]>) {
this.name = "SimpleFeatureSource(" + layer.layerDef.id + ")"
this.layer = layer
this.tileIndex = tileIndex ?? 0;

View file

@ -40,7 +40,7 @@ export default class DynamicGeoJsonTileSource extends DynamicTileSource {
json => {
const data = new Map<number, Set<number>>();
for (const x in json) {
if(x === "zoom"){
if (x === "zoom") {
continue
}
data.set(Number(x), new Set(json[x]))
@ -91,7 +91,7 @@ export default class DynamicGeoJsonTileSource extends DynamicTileSource {
public static RegisterWhitelist(url: string, json: any) {
const data = new Map<number, Set<number>>();
for (const x in json) {
if(x === "zoom"){
if (x === "zoom") {
continue
}
data.set(Number(x), new Set(json[x]))

View file

@ -44,11 +44,11 @@ export default class DynamicTileSource implements TileHierarchy<FeatureSourceFor
return undefined
}
const tileRange = Tiles.TileRangeBetween(zoomlevel, bounds.getNorth(), bounds.getEast(), bounds.getSouth(), bounds.getWest())
if(tileRange.total > 10000){
if (tileRange.total > 10000) {
console.error("Got a really big tilerange, bounds and location might be out of sync")
return undefined
}
const needed = Tiles.MapRange(tileRange, (x, y) => Tiles.tile_index(zoomlevel, x, y)).filter(i => !self._loadedTiles.has(i))
if (needed.length === 0) {
return undefined

View file

@ -45,8 +45,8 @@ export default class FullNodeDatabaseSource implements TileHierarchy<FeatureSour
for (const nodeId of osmWay.nodes) {
if (!this.parentWays.has(nodeId)) {
const src = new UIEventSource<OsmWay[]>([])
this.parentWays.set(nodeId,src)
const src = new UIEventSource<OsmWay[]>([])
this.parentWays.set(nodeId, src)
src.addCallback(parentWays => {
const tgs = nodesById.get(nodeId).tags
tgs ["parent_ways"] = JSON.stringify(parentWays.map(w => w.tags))

View file

@ -89,8 +89,8 @@ export default class OsmFeatureSource {
if (z > 20) {
throw "This is an absurd high zoom level"
}
if( z < 14){
if (z < 14) {
throw `Zoom ${z} is too much for OSM to handle! Use a higher zoom level!`
}

View file

@ -558,19 +558,19 @@ export class GeoOperations {
const prevCoordinate = coordinates[i - 1]
const distP = GeoOperations.distanceBetween(coordinate, prevCoordinate)
if(distP < 0.1){
if (distP < 0.1) {
coordinates.splice(i, 1)
continue
}
if(i == coordinates.length - 2){
if (i == coordinates.length - 2) {
const distN = GeoOperations.distanceBetween(coordinate, nextCoordinate)
if(distN < 0.1){
if (distN < 0.1) {
coordinates.splice(i, 1)
continue
}
}
const bearingN = turf.bearing(coordinate, nextCoordinate)
const bearingP = turf.bearing(prevCoordinate, coordinate)
const diff = Math.abs(bearingN - bearingP)
@ -683,8 +683,8 @@ export class GeoOperations {
throw "CalculateIntersection fallthrough: can not calculate an intersection between features"
}
}

View file

@ -14,6 +14,7 @@ export default class MetaTagging {
private static errorPrintCount = 0;
private static readonly stopErrorOutputAt = 10;
private static retaggingFuncCache = new Map<string, ((feature: any) => void)[]>()
/**
* This method (re)calculates all metatags and calculated tags on every given object.
@ -24,7 +25,7 @@ export default class MetaTagging {
public static addMetatags(features: { feature: any; freshness: Date }[],
params: ExtraFuncParams,
layer: LayerConfig,
state?: {allElements?: ElementStorage},
state?: { allElements?: ElementStorage },
options?: {
includeDates?: true | boolean,
includeNonDates?: true | boolean
@ -56,7 +57,7 @@ export default class MetaTagging {
const feature = ff.feature
const freshness = ff.freshness
let somethingChanged = false
let definedTags = new Set(Object.getOwnPropertyNames( feature.properties ))
let definedTags = new Set(Object.getOwnPropertyNames(feature.properties))
for (const metatag of metatagsToApply) {
try {
if (!metatag.keys.some(key => feature.properties[key] === undefined)) {
@ -65,7 +66,7 @@ export default class MetaTagging {
}
if (metatag.isLazy) {
if(!metatag.keys.some(key => !definedTags.has(key))) {
if (!metatag.keys.some(key => !definedTags.has(key))) {
// All keys are defined - lets skip!
continue
}
@ -104,7 +105,7 @@ export default class MetaTagging {
}
return atLeastOneFeatureChanged
}
private static createFunctionsForFeature(layerId: string, calculatedTags: [string, string, boolean][]): ((feature: any) => void)[] {
const functions: ((feature: any) => any)[] = [];
for (const entry of calculatedTags) {
@ -128,7 +129,7 @@ export default class MetaTagging {
delete feat.properties[key]
feat.properties[key] = result;
return result
}catch(e){
} 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++;
@ -138,10 +139,10 @@ export default class MetaTagging {
}
return undefined;
}
}
if(isStrict){
}
if (isStrict) {
functions.push(calculateAndAssign)
continue
}
@ -166,8 +167,6 @@ export default class MetaTagging {
return functions;
}
private static retaggingFuncCache = new Map<string, ((feature: any) => void)[]>()
/**
* Creates the function which adds all the calculated tags to a feature. Called once per layer
* @param layer
@ -182,7 +181,7 @@ export default class MetaTagging {
return undefined;
}
let functions :((feature: any) => void)[] = MetaTagging.retaggingFuncCache.get(layer.id);
let functions: ((feature: any) => void)[] = MetaTagging.retaggingFuncCache.get(layer.id);
if (functions === undefined) {
functions = MetaTagging.createFunctionsForFeature(layer.id, calculatedTags)
MetaTagging.retaggingFuncCache.set(layer.id, functions)

View file

@ -11,7 +11,7 @@ export default class ChangeLocationAction extends OsmChangeAction {
theme: string,
reason: string
}) {
super(id,true);
super(id, true);
if (!id.startsWith("node/")) {
throw "Invalid ID: only 'node/number' is accepted"
}
@ -19,7 +19,7 @@ export default class ChangeLocationAction extends OsmChangeAction {
this._newLonLat = newLonLat;
this._meta = meta;
}
protected async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
const d: ChangeDescription = {

View file

@ -19,7 +19,7 @@ export default class ChangeTagAction extends OsmChangeAction {
this._currentTags = currentTags;
this._meta = meta;
}
/**
* Doublechecks that no stupid values are added
*/

View file

@ -14,35 +14,36 @@ import {TagUtils} from "../../Tags/TagUtils";
* More or less the same as 'CreateNewWay', except that it'll try to reuse already existing points
*/
export default class CreateMultiPolygonWithPointReuseAction extends OsmCreateAction {
private readonly _tags: Tag[];
public newElementId: string = undefined;
public newElementIdNumber: number = undefined;
public newElementIdNumber: number = undefined;
private readonly _tags: Tag[];
private readonly createOuterWay: CreateWayWithPointReuseAction
private readonly createInnerWays : CreateNewWayAction[]
private readonly geojsonPreview: any;
private readonly createInnerWays: CreateNewWayAction[]
private readonly geojsonPreview: any;
private readonly theme: string;
private readonly changeType: "import" | "create" | string;
constructor(tags: Tag[],
outerRingCoordinates: [number, number][],
innerRingsCoordinates: [number, number][][],
innerRingsCoordinates: [number, number][][],
state: FeaturePipelineState,
config: MergePointConfig[],
changeType: "import" | "create" | string
) {
super(null,true);
this._tags = [...tags, new Tag("type","multipolygon")];
super(null, true);
this._tags = [...tags, new Tag("type", "multipolygon")];
this.changeType = changeType;
this.theme = state.layoutToUse.id
this. createOuterWay = new CreateWayWithPointReuseAction([], outerRingCoordinates, state, config)
this. createInnerWays = innerRingsCoordinates.map(ringCoordinates =>
new CreateNewWayAction([],
ringCoordinates.map(([lon, lat] )=> ({lat, lon})),
{theme: state.layoutToUse.id}))
this.geojsonPreview = {
this.createOuterWay = new CreateWayWithPointReuseAction([], outerRingCoordinates, state, config)
this.createInnerWays = innerRingsCoordinates.map(ringCoordinates =>
new CreateNewWayAction([],
ringCoordinates.map(([lon, lat]) => ({lat, lon})),
{theme: state.layoutToUse.id}))
this.geojsonPreview = {
type: "Feature",
properties: TagUtils.changeAsProperties(new And(this._tags).asChange({})),
geometry:{
geometry: {
type: "Polygon",
coordinates: [
outerRingCoordinates,
@ -59,7 +60,7 @@ private readonly geojsonPreview: any;
freshness: new Date(),
feature: this.geojsonPreview
})
return outerPreview
return outerPreview
}
protected async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> {
@ -72,14 +73,14 @@ private readonly geojsonPreview: any;
this.newElementIdNumber = changes.getNewID();
this.newElementId = "relation/"+this.newElementIdNumber
this.newElementId = "relation/" + this.newElementIdNumber
descriptions.push({
type:"relation",
type: "relation",
id: this.newElementIdNumber,
tags: new And(this._tags).asChange({}),
meta: {
theme: this.theme,
changeType:this.changeType
changeType: this.changeType
},
changes: {
members: [
@ -93,8 +94,8 @@ private readonly geojsonPreview: any;
]
}
})
return descriptions
}

View file

@ -33,7 +33,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
changeType: "create" | "import" | null,
specialMotivation?: string
}) {
super(null,basicTags !== undefined && basicTags.length > 0)
super(null, basicTags !== undefined && basicTags.length > 0)
this._basicTags = basicTags;
this._lat = lat;
this._lon = lon;
@ -46,7 +46,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
this.meta = {
theme: options.theme,
changeType: options.changeType,
}
}

View file

@ -25,7 +25,7 @@ export default class CreateNewWayAction extends OsmCreateAction {
options: {
theme: string
}) {
super(null,true)
super(null, true)
this.coordinates = coordinates;
this.tags = tags;
this._options = options;
@ -56,7 +56,7 @@ export default class CreateNewWayAction extends OsmCreateAction {
const id = changes.getNewID()
this.newElementIdNumber = id
this.newElementIdNumber = id
const newWay = <ChangeDescription>{
id,
type: "way",

View file

@ -20,14 +20,14 @@ export interface MergePointConfig {
/**
* CreateWayWithPointreuse will create a 'CoordinateInfo' for _every_ point in the way to be created.
*
*
* The CoordinateInfo indicates the action to take, e.g.:
*
*
* - Create a new point
* - Reuse an existing OSM point (and don't move it)
* - Reuse an existing OSM point (and leave it where it is)
* - Reuse another Coordinate info (and don't do anything else with it)
*
*
*/
interface CoordinateInfo {
/**
@ -56,6 +56,8 @@ interface CoordinateInfo {
* More or less the same as 'CreateNewWay', except that it'll try to reuse already existing points
*/
export default class CreateWayWithPointReuseAction extends OsmCreateAction {
public newElementId: string = undefined;
public newElementIdNumber: number = undefined
private readonly _tags: Tag[];
/**
* lngLat-coordinates
@ -64,20 +66,17 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction {
private _coordinateInfo: CoordinateInfo[];
private _state: FeaturePipelineState;
private _config: MergePointConfig[];
public newElementId: string = undefined;
public newElementIdNumber: number = undefined
constructor(tags: Tag[],
coordinates: [number, number][],
state: FeaturePipelineState,
config: MergePointConfig[]
) {
super(null,true);
super(null, true);
this._tags = tags;
this._state = state;
this._config = config;
// The main logic of this class: the coordinateInfo contains all the changes
this._coordinateInfo = this.CalculateClosebyNodes(coordinates);
@ -117,7 +116,7 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction {
"move": "yes",
"osm-id": reusedPoint.node.properties.id,
"id": "new-geometry-move-existing" + i,
"distance":GeoOperations.distanceBetween(coordinateInfo.lngLat, reusedPoint.node.geometry.coordinates)
"distance": GeoOperations.distanceBetween(coordinateInfo.lngLat, reusedPoint.node.geometry.coordinates)
},
geometry: {
type: "LineString",
@ -136,7 +135,7 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction {
"move": "no",
"osm-id": reusedPoint.node.properties.id,
"id": "new-geometry-reuse-existing" + i,
"distance":GeoOperations.distanceBetween(coordinateInfo.lngLat, reusedPoint.node.geometry.coordinates)
"distance": GeoOperations.distanceBetween(coordinateInfo.lngLat, reusedPoint.node.geometry.coordinates)
},
geometry: {
type: "LineString",
@ -238,7 +237,7 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction {
const newWay = new CreateNewWayAction(this._tags, nodeIdsToUse, {
theme
})
allChanges.push(...(await newWay.CreateChangeDescriptions(changes)))
this.newElementId = newWay.newElementId
this.newElementIdNumber = newWay.newElementIdNumber
@ -266,7 +265,7 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction {
}[]
}[] = coordinates.map(_ => undefined)
// First loop: gather all information...
for (let i = 0; i < coordinates.length; i++) {
@ -328,7 +327,7 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction {
}
// Second loop: figure out which point moves where without creating conflicts
let conflictFree = true;
do {
@ -348,8 +347,8 @@ export default class CreateWayWithPointReuseAction extends OsmCreateAction {
if (other.closebyNodes === undefined || other.closebyNodes[0] === undefined) {
continue
}
if(coorInfo.closebyNodes[0] === undefined){
if (coorInfo.closebyNodes[0] === undefined) {
continue
}

View file

@ -26,7 +26,7 @@ export default class DeleteAction extends OsmChangeAction {
specialMotivation: string
},
hardDelete: boolean) {
super(id,true)
super(id, true)
this._id = id;
this._hardDelete = hardDelete;
this.meta = {...meta, changeType: "deletion"};
@ -51,7 +51,7 @@ export default class DeleteAction extends OsmChangeAction {
return await new ChangeTagAction(
this._id, this._softDeletionTags, osmObject.tags,
{
... this.meta,
...this.meta,
changeType: "soft-delete"
}
).CreateChangeDescriptions(changes)

View file

@ -7,7 +7,6 @@ import {ChangeDescription} from "./ChangeDescription";
export default abstract class OsmChangeAction {
private isUsed = false
public readonly trackStatistics: boolean;
/**
* The ID of the object that is the center of this change.
@ -15,7 +14,8 @@ export default abstract class OsmChangeAction {
* Undefined if such an id does not make sense
*/
public readonly mainObjectId: string;
private isUsed = false
constructor(mainObjectId: string, trackStatistics: boolean = true) {
this.trackStatistics = trackStatistics;
this.mainObjectId = mainObjectId
@ -32,9 +32,9 @@ export default abstract class OsmChangeAction {
protected abstract CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]>
}
export abstract class OsmCreateAction extends OsmChangeAction{
export abstract class OsmCreateAction extends OsmChangeAction {
public newElementId : string
public newElementId: string
public newElementIdNumber: number
}

View file

@ -16,10 +16,11 @@ abstract class AbstractRelationSplitHandler extends OsmChangeAction {
protected readonly _theme: string;
constructor(input: RelationSplitInput, theme: string) {
super("relation/"+input.relation.id, false)
super("relation/" + input.relation.id, false)
this._input = input;
this._theme = theme;
}
/**
* Returns which node should border the member at the given index
*/

View file

@ -468,12 +468,12 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
proj.sort((a, b) => {
// Sort descending
const diff = b.projectAfterIndex - a.projectAfterIndex;
if(diff !== 0){
if (diff !== 0) {
return diff
}
return b.distance - a.distance;
})
for (const reprojectedNode of proj) {

View file

@ -26,7 +26,7 @@ export default class SplitAction extends OsmChangeAction {
* @param toleranceInMeters: if a splitpoint closer then this amount of meters to an existing point, the existing point will be used to split the line instead of a new point
*/
constructor(wayId: string, splitPointCoordinates: [number, number][], meta: { theme: string }, toleranceInMeters = 5) {
super(wayId,true)
super(wayId, true)
this.wayId = wayId;
this._splitPointsCoordinates = splitPointCoordinates
this._toleranceInMeters = toleranceInMeters;

View file

@ -27,16 +27,13 @@ export class Changes {
public features = new UIEventSource<{ feature: any, freshness: Date }[]>([]);
public readonly pendingChanges: UIEventSource<ChangeDescription[]> = LocalStorageSource.GetParsed<ChangeDescription[]>("pending-changes", [])
public readonly allChanges = new UIEventSource<ChangeDescription[]>(undefined)
public readonly state: { allElements: ElementStorage; historicalUserLocations: FeatureSource; osmConnection: OsmConnection }
public readonly extraComment: UIEventSource<string> = new UIEventSource(undefined)
private _nextId: number = -1; // Newly assigned ID's are negative
private readonly isUploading = new UIEventSource(false);
private readonly previouslyCreated: OsmObject[] = []
private readonly _leftRightSensitive: boolean;
public readonly state: { allElements: ElementStorage; historicalUserLocations: FeatureSource; osmConnection: OsmConnection }
public readonly extraComment:UIEventSource<string> = new UIEventSource(undefined)
constructor(
state?: {
allElements: ElementStorage,
@ -107,7 +104,7 @@ export class Changes {
* Uploads all the pending changes in one go.
* Triggered by the 'PendingChangeUploader'-actor in Actors
*/
public async flushChanges(flushreason: string = undefined, openChangeset?: UIEventSource<number>) : Promise<void>{
public async flushChanges(flushreason: string = undefined, openChangeset?: UIEventSource<number>): Promise<void> {
if (this.pendingChanges.data.length === 0) {
return;
}
@ -116,19 +113,37 @@ export class Changes {
return;
}
console.log("Uploading changes due to: ", flushreason)
this.isUploading.setData(true)
try {
const csNumber = await this.flushChangesAsync(openChangeset)
this.isUploading.setData(false)
console.log("Changes flushed. Your changeset is "+csNumber);
console.log("Changes flushed. Your changeset is " + csNumber);
} catch (e) {
this.isUploading.setData(false)
console.error("Flushing changes failed due to", e);
}
}
public async applyAction(action: OsmChangeAction): Promise<void> {
const changeDescriptions = await action.Perform(this)
changeDescriptions[0].meta.distanceToObject = this.calculateDistanceToChanges(action, changeDescriptions)
this.applyChanges(changeDescriptions)
}
public applyChanges(changes: ChangeDescription[]) {
console.log("Received changes:", changes)
this.pendingChanges.data.push(...changes);
this.pendingChanges.ping();
this.allChanges.data.push(...changes)
this.allChanges.ping()
}
public registerIdRewrites(mappings: Map<string, string>): void {
CreateNewNodeAction.registerIdRewrites(mappings)
}
private calculateDistanceToChanges(change: OsmChangeAction, changeDescriptions: ChangeDescription[]) {
const locations = this.state?.historicalUserLocations?.features?.data
@ -140,7 +155,7 @@ export class Changes {
// Probably irrelevant, such as a new helper node
return;
}
const now = new Date()
const recentLocationPoints = locations.map(ff => ff.feature)
.filter(feat => feat.geometry.type === "Point")
@ -188,26 +203,6 @@ export class Changes {
))
}
public async applyAction(action: OsmChangeAction): Promise<void> {
const changeDescriptions = await action.Perform(this)
changeDescriptions[0].meta.distanceToObject = this.calculateDistanceToChanges(action, changeDescriptions)
this.applyChanges(changeDescriptions)
}
public applyChanges(changes: ChangeDescription[]) {
console.log("Received changes:", changes)
this.pendingChanges.data.push(...changes);
this.pendingChanges.ping();
this.allChanges.data.push(...changes)
this.allChanges.ping()
}
public registerIdRewrites(mappings: Map<string, string>): void {
CreateNewNodeAction.registerIdRewrites(mappings)
}
/**
* UPload the selected changes to OSM.
* Returns 'true' if successfull and if they can be removed
@ -287,10 +282,10 @@ export class Changes {
// This method is only called with changedescriptions for this theme
const theme = pending[0].meta.theme
let comment = "Adding data with #MapComplete for theme #" + theme
if(this.extraComment.data !== undefined){
comment+="\n\n"+this.extraComment.data
if (this.extraComment.data !== undefined) {
comment += "\n\n" + this.extraComment.data
}
const metatags: ChangesetTag[] = [{
key: "comment",
value: comment
@ -329,10 +324,10 @@ export class Changes {
pendingPerTheme.get(theme).push(changeDescription)
}
const successes = await Promise.all(Array.from(pendingPerTheme,
async ([theme, pendingChanges]) => {
const successes = await Promise.all(Array.from(pendingPerTheme,
async ([theme, pendingChanges]) => {
try {
if(openChangeset === undefined){
if (openChangeset === undefined) {
openChangeset = this.state.osmConnection.GetPreference("current-open-changeset-" + theme).map(
str => {
const n = Number(str);
@ -342,9 +337,9 @@ export class Changes {
return n
}, [], n => "" + n
);
console.log("Using current-open-changeset-"+theme+" from the preferences, got "+openChangeset.data)
console.log("Using current-open-changeset-" + theme + " from the preferences, got " + openChangeset.data)
}
return await self.flushSelectChanges(pendingChanges, openChangeset);
} catch (e) {
console.error("Could not upload some changes:", e)
@ -395,7 +390,7 @@ export class Changes {
// Might be a failed fetch for simply this object
throw "Did not get an object that should be known: " + id
}
if(change.changes === undefined){
if (change.changes === undefined) {
// This object is a change to a newly created object. However, we have not seen the creation changedescription yet!
throw "Not a creation of the object"
}
@ -522,7 +517,7 @@ export class Changes {
})
console.debug("Calculated the pending changes: ", result.newObjects.length,"new; ", result.modifiedObjects.length,"modified;",result.deletedObjects,"deleted")
console.debug("Calculated the pending changes: ", result.newObjects.length, "new; ", result.modifiedObjects.length, "modified;", result.deletedObjects, "deleted")
return result
}
}

View file

@ -61,7 +61,7 @@ export class ChangesetHandler {
if (!extraMetaTags.some(tag => tag.key === "comment") || !extraMetaTags.some(tag => tag.key === "theme")) {
throw "The meta tags should at least contain a `comment` and a `theme`"
}
if (this.userDetails.data.csCount == 0) {
// The user became a contributor!
this.userDetails.data.csCount = 1;

View file

@ -122,6 +122,34 @@ export class OsmPreferences {
return pref;
}
public ClearPreferences() {
let isRunning = false;
const self = this;
this.preferences.addCallbackAndRun(prefs => {
if (Object.keys(prefs).length == 0) {
return;
}
if (isRunning) {
return
}
isRunning = true
const prefixes = ["mapcomplete-installed-theme", "mapcomplete-installed-themes-", "mapcomplete-current-open-changeset", "mapcomplete-personal-theme-layer"]
for (const key in prefs) {
for (const prefix of prefixes) {
// console.log(key)
if (key.startsWith(prefix)) {
console.log("Clearing ", key)
self.GetPreference(key, "").setData("")
}
}
}
isRunning = false;
return true;
})
}
private UpdatePreferences() {
const self = this;
this.auth.xhr({
@ -184,34 +212,6 @@ export class OsmPreferences {
console.debug(`Preference ${k} written!`);
});
}
public ClearPreferences(){
let isRunning = false;
const self = this;
this.preferences.addCallbackAndRun(prefs => {
if(Object.keys(prefs).length == 0){
return;
}
if (isRunning) {
return
}
isRunning = true
const prefixes = ["mapcomplete-installed-theme","mapcomplete-installed-themes-","mapcomplete-current-open-changeset","mapcomplete-personal-theme-layer"]
for (const key in prefs) {
for (const prefix of prefixes) {
// console.log(key)
if (key.startsWith(prefix)) {
console.log("Clearing ", key)
self.GetPreference(key, "").setData("")
}
}
}
isRunning = false;
return true;
})
}
}

View file

@ -125,7 +125,8 @@ export default class SimpleMetaTaggers {
return changed
}
)
public static readonly lazyTags: string[] = [].concat(...SimpleMetaTaggers.metatags.filter(tagger => tagger.isLazy)
.map(tagger => tagger.keys));
private static readonly cardinalDirections = {
N: 0, NNE: 22.5, NE: 45, ENE: 67.5,
E: 90, ESE: 112.5, SE: 135, SSE: 157.5,
@ -290,27 +291,27 @@ export default class SimpleMetaTaggers {
// isOpen is irrelevant
return false
}
if(feature.properties.opening_hours === "24/7"){
if (feature.properties.opening_hours === "24/7") {
feature.properties._isOpen = "yes"
return true;
}
Object.defineProperty(feature.properties, "_isOpen", {
enumerable: false,
configurable: true,
get: () => {
if(feature.properties.id === "node/7464543832"){
console.log("Getting _isOpen for ", feature.properties.i)
if (feature.properties.id === "node/7464543832") {
console.log("Getting _isOpen for ", feature.properties.i)
}
delete feature.properties._isOpen
feature.properties._isOpen = undefined
const tagsSource = state.allElements.getEventSourceById(feature.properties.id);
tagsSource.addCallbackAndRunD(tags => {
// Install a listener to the tags...
if (tags.opening_hours === undefined){
if (tags.opening_hours === undefined) {
return;
}
if(tags._country === undefined) {
if (tags._country === undefined) {
return;
}
try {
@ -322,7 +323,7 @@ export default class SimpleMetaTaggers {
country_code: tags._country.toLowerCase()
}
}, {tag_key: "opening_hours"});
// AUtomatically triggered on the next change (and a bit below)
const updateTags = () => {
const oldValueIsOpen = tags["_isOpen"];
@ -442,8 +443,6 @@ export default class SimpleMetaTaggers {
SimpleMetaTaggers.geometryType
];
public static readonly lazyTags: string[] = [].concat(...SimpleMetaTaggers.metatags.filter(tagger => tagger.isLazy)
.map(tagger => tagger.keys));
/**
* Edits the given object to rewrite 'both'-tagging into a 'left-right' tagging scheme.

View file

@ -49,7 +49,7 @@ export default class ElementsState extends FeatureSwitchState {
super(layoutToUse);
// @ts-ignore
this.changes = new Changes(this,layoutToUse?.isLeftRightSensitive() ?? false)
this.changes = new Changes(this, layoutToUse?.isLeftRightSensitive() ?? false)
{
// -- Location control initialization
const zoom = UIEventSource.asFloat(

View file

@ -20,7 +20,8 @@ export default class FeaturePipelineState extends MapState {
*/
public readonly featurePipeline: FeaturePipeline;
private readonly featureAggregator: TileHierarchyAggregator;
private readonly metatagRecalculator : MetaTagRecalculator
private readonly metatagRecalculator: MetaTagRecalculator
constructor(layoutToUse: LayoutConfig) {
super(layoutToUse);
@ -33,21 +34,21 @@ private readonly metatagRecalculator : MetaTagRecalculator
* We are a bit in a bind:
* There is the featurePipeline, which creates some sources during construction
* THere is the metatagger, which needs to have these sources registered AND which takes a FeaturePipeline as argument
*
*
* This is a bit of a catch-22 (except that it isn't)
* The sources that are registered in the constructor are saved into 'registeredSources' temporary
*
* The sources that are registered in the constructor are saved into 'registeredSources' temporary
*
*/
const sourcesToRegister = []
function registerRaw(source: FeatureSourceForLayer & Tiled){
if(self.metatagRecalculator === undefined){
function registerRaw(source: FeatureSourceForLayer & Tiled) {
if (self.metatagRecalculator === undefined) {
sourcesToRegister.push(source)
}else{
} else {
self.metatagRecalculator.registerSource(source)
}
}
function registerSource(source: FeatureSourceForLayer & Tiled) {
clusterCounter.addTile(source)
@ -127,7 +128,7 @@ private readonly metatagRecalculator : MetaTagRecalculator
this.metatagRecalculator.registerSource(this.currentView, true)
sourcesToRegister.forEach(source => self.metatagRecalculator.registerSource(source))
new SelectedFeatureHandler(Hash.hash, this)
this.AddClusteringToMap(this.leafletMap)

View file

@ -223,7 +223,7 @@ export default class MapState extends UserRelatedState {
private initGpsLocation() {
// Initialize the gps layer data. This is emtpy for now, the actual writing happens in the Geolocationhandler
let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location")[0]
if(gpsLayerDef === undefined){
if (gpsLayerDef === undefined) {
return
}
this.currentUserLocation = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0));
@ -269,7 +269,7 @@ export default class MapState extends UserRelatedState {
let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location_history")[0]
if(gpsLayerDef !== undefined){
if (gpsLayerDef !== undefined) {
this.historicalUserLocations = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0), features);
}
@ -299,7 +299,7 @@ export default class MapState extends UserRelatedState {
}]
})
let gpsLineLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_track")[0]
if(gpsLineLayerDef !== undefined){
if (gpsLineLayerDef !== undefined) {
this.historicalUserLocationsTrack = new SimpleFeatureSource(gpsLineLayerDef, Tiles.tile_index(0, 0, 0), asLine);
}
}

View file

@ -96,14 +96,14 @@ export default class UserRelatedState extends ElementsState {
// We wait till we are logged in
return
}
if(self.osmConnection.isLoggedIn.data == false){
if (self.osmConnection.isLoggedIn.data == false) {
return;
}
if (currentThemes.some(installed => installed.id === this.layoutToUse.id)) {
// Already added to the 'installed theme' list
return;
return;
}
console.log("Current installed themes are", this.installedThemes.data)
@ -115,13 +115,11 @@ export default class UserRelatedState extends ElementsState {
})
self.installedThemes.ping()
console.log("Registered " + self.layoutToUse.id + " as installed themes")
})
}
// Important: the favourite layers are initialized _after_ the installed themes, as these might contain an installedTheme
this.favouriteLayers = LocalStorageSource.Get("favouriteLayers")
.syncWith(this.osmConnection.GetLongPreference("favouriteLayers"))

View file

@ -117,7 +117,7 @@ export class And extends TagsFilter {
}
return result;
}
AsJson() {
return {
and: this.and.map(a => a.AsJson())

View file

@ -38,7 +38,7 @@ export default class ComparingTag implements TagsFilter {
usedKeys(): string[] {
return [this._key];
}
AsJson() {
return this.asHumanString(false, false, {})
}

View file

@ -65,7 +65,7 @@ export class Or extends TagsFilter {
}
return result;
}
AsJson() {
return {
or: this.or.map(o => o.AsJson())

View file

@ -46,13 +46,13 @@ export class Tag extends TagsFilter {
if (shorten) {
v = Utils.EllipsesAfter(v, 25);
}
if(v === "" || v === undefined){
if (v === "" || v === undefined) {
// This tag will be removed if in the properties, so we indicate this with special rendering
if(currentProperties !== undefined && (currentProperties[this.key] ?? "") === ""){
if (currentProperties !== undefined && (currentProperties[this.key] ?? "") === "") {
// This tag is not present in the current properties, so this tag doesn't change anything
return ""
}
return "<span class='line-through'>"+this.key+"</span>"
return "<span class='line-through'>" + this.key + "</span>"
}
if (linkToWiki) {
return `<a href='https://wiki.openstreetmap.org/wiki/Key:${this.key}' target='_blank'>${this.key}</a>` +
@ -83,7 +83,7 @@ export class Tag extends TagsFilter {
asChange(properties: any): { k: string; v: string }[] {
return [{k: this.key, v: this.value}];
}
AsJson() {
return this.asHumanString(false, false)
}

View file

@ -245,7 +245,7 @@ export class TagUtils {
}
return new RegexTag(
split[0],
new RegExp("^" + split[1] + "$"),
new RegExp("^" + split[1] + "$"),
true
);
}

View file

@ -11,7 +11,7 @@ export class UIEventSource<T> {
constructor(data: T, tag: string = "") {
this.tag = tag;
this.data = data;
if(tag === undefined || tag === ""){
if (tag === undefined || tag === "") {
const callstack = new Error().stack.split("\n")
this.tag = callstack[1]
}
@ -42,7 +42,7 @@ export class UIEventSource<T> {
source.addCallback((latestData) => {
sink.setData(latestData?.data);
latestData.addCallback(data => {
if(source.data !== latestData){
if (source.data !== latestData) {
return true;
}
sink.setData(data)
@ -243,8 +243,8 @@ export class UIEventSource<T> {
}
}
let endTime = new Date().getTime() / 1000
if((endTime - startTime) > 500){
console.trace("Warning: a ping of ",this.tag," took more then 500ms; this is probably a performance issue")
if ((endTime - startTime) > 500) {
console.trace("Warning: a ping of ", this.tag, " took more then 500ms; this is probably a performance issue")
}
if (toDelete !== undefined) {
for (const toDeleteElement of toDelete) {
@ -297,10 +297,10 @@ export class UIEventSource<T> {
const stack = new Error().stack.split("\n");
const callee = stack[1]
const newSource = new UIEventSource<J>(
f(this.data),
"map(" + this.tag + ")@"+callee
"map(" + this.tag + ")@" + callee
);
const update = function () {

View file

@ -7,24 +7,24 @@ import {Utils} from "../../Utils";
*/
export class IdbLocalStorage {
public static Get<T>(key: string, options?: { defaultValue?: T , whenLoaded?: (t: T) => void}): UIEventSource<T>{
const src = new UIEventSource<T>(options?.defaultValue, "idb-local-storage:"+key)
if(Utils.runningFromConsole){
public static Get<T>(key: string, options?: { defaultValue?: T, whenLoaded?: (t: T) => void }): UIEventSource<T> {
const src = new UIEventSource<T>(options?.defaultValue, "idb-local-storage:" + key)
if (Utils.runningFromConsole) {
return src;
}
idb.get(key).then(v => {
src.setData(v ?? options?.defaultValue);
if(options?.whenLoaded !== undefined){
if (options?.whenLoaded !== undefined) {
options?.whenLoaded(v)
}
})
src.addCallback(v => idb.set(key, v))
return src;
}
public static SetDirectly(key: string, value){
public static SetDirectly(key: string, value) {
idb.set(key, value)
}

View file

@ -7,15 +7,12 @@ import {Utils} from "../../Utils";
export class QueryParameters {
static defaults = {}
static documentation = {}
private static order: string [] = ["layout", "test", "z", "lat", "lon"];
private static _wasInitialized: Set<string> = new Set()
private static knownSources = {};
private static initialized = false;
static defaults = {}
static documentation = {}
public static GetQueryParameter(key: string, deflt: string, documentation?: string): UIEventSource<string> {
if (!this.initialized) {
@ -40,7 +37,6 @@ export class QueryParameters {
}
public static wasInitialized(key: string): boolean {
return QueryParameters._wasInitialized.has(key)
}