forked from MapComplete/MapComplete
First version of automatic dependency injection
This commit is contained in:
parent
2dc6d4658f
commit
62f280feae
3 changed files with 81 additions and 32 deletions
|
@ -1,7 +1,7 @@
|
|||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import SourceConfig from "./SourceConfig";
|
||||
import TagRenderingConfig from "./TagRenderingConfig";
|
||||
import PresetConfig from "./PresetConfig";
|
||||
import PresetConfig, {PreciseInput} from "./PresetConfig";
|
||||
import {LayerConfigJson} from "./Json/LayerConfigJson";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
|
@ -26,19 +26,19 @@ import * as icons from "../../assets/tagRenderings/icons.json"
|
|||
|
||||
export default class LayerConfig extends WithContextLoader {
|
||||
|
||||
id: string;
|
||||
name: Translation;
|
||||
description: Translation;
|
||||
source: SourceConfig;
|
||||
calculatedTags: [string, string][];
|
||||
doNotDownload: boolean;
|
||||
passAllFeatures: boolean;
|
||||
isShown: TagRenderingConfig;
|
||||
minzoom: number;
|
||||
minzoomVisible: number;
|
||||
maxzoom: number;
|
||||
title?: TagRenderingConfig;
|
||||
titleIcons: TagRenderingConfig[];
|
||||
public readonly id: string;
|
||||
public readonly name: Translation;
|
||||
public readonly description: Translation;
|
||||
public readonly source: SourceConfig;
|
||||
public readonly calculatedTags: [string, string][];
|
||||
public readonly doNotDownload: boolean;
|
||||
public readonly passAllFeatures: boolean;
|
||||
public readonly isShown: TagRenderingConfig;
|
||||
public readonly minzoom: number;
|
||||
public readonly minzoomVisible: number;
|
||||
public readonly maxzoom: number;
|
||||
public readonly title?: TagRenderingConfig;
|
||||
public readonly titleIcons: TagRenderingConfig[];
|
||||
|
||||
public readonly mapRendering: PointRenderingConfig[]
|
||||
public readonly lineRendering: LineRenderingConfig[]
|
||||
|
@ -52,10 +52,10 @@ export default class LayerConfig extends WithContextLoader {
|
|||
*/
|
||||
public readonly maxAgeOfCache: number
|
||||
|
||||
presets: PresetConfig[];
|
||||
public readonly presets: PresetConfig[];
|
||||
|
||||
tagRenderings: TagRenderingConfig[];
|
||||
filters: FilterConfig[];
|
||||
public readonly tagRenderings: TagRenderingConfig[];
|
||||
public readonly filters: FilterConfig[];
|
||||
|
||||
constructor(
|
||||
json: LayerConfigJson,
|
||||
|
@ -151,8 +151,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
throw "Presets should be a list of items (at " + context + ")"
|
||||
}
|
||||
this.presets = (json.presets ?? []).map((pr, i) => {
|
||||
|
||||
let preciseInput: any = {
|
||||
let preciseInput: PreciseInput = {
|
||||
preferredBackground: ["photo"],
|
||||
snapToLayers: undefined,
|
||||
maxSnapDistance: undefined
|
||||
|
@ -163,6 +162,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
preferredBackground: undefined
|
||||
}
|
||||
}
|
||||
|
||||
let snapToLayers: string[];
|
||||
if (typeof pr.preciseInput.snapToLayer === "string") {
|
||||
snapToLayers = [pr.preciseInput.snapToLayer]
|
||||
|
@ -178,7 +178,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
}
|
||||
preciseInput = {
|
||||
preferredBackground: preferredBackground,
|
||||
snapToLayers: snapToLayers,
|
||||
snapToLayers,
|
||||
maxSnapDistance: pr.preciseInput.maxSnapDistance ?? 10
|
||||
}
|
||||
}
|
||||
|
@ -439,6 +439,10 @@ export default class LayerConfig extends WithContextLoader {
|
|||
]
|
||||
}
|
||||
|
||||
for (const dep of Array.from(this.getDependencies())) {
|
||||
extraProps.push(new Combine(["This layer will automatically load ", new Link(dep, "#"+dep)," into the layout as it depends on it."]))
|
||||
}
|
||||
|
||||
return new Combine([
|
||||
new Title(this.id, 3),
|
||||
this.description,
|
||||
|
@ -478,4 +482,23 @@ export default class LayerConfig extends WithContextLoader {
|
|||
public isLeftRightSensitive(): boolean {
|
||||
return this.lineRendering.some(lr => lr.leftRightSensitive)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of all other layer-ids that this layer needs to function.
|
||||
* E.g. if this layers does snap to another layer in the preset, this other layer id will be mentioned
|
||||
*/
|
||||
public getDependencies(): Set<string>{
|
||||
const deps = new Set<string>()
|
||||
|
||||
for (const preset of this.presets ?? []) {
|
||||
if(preset.preciseInput?.snapToLayers === undefined){
|
||||
continue
|
||||
}
|
||||
preset.preciseInput?.snapToLayers?.forEach(id => {
|
||||
deps.add(id);
|
||||
})
|
||||
}
|
||||
|
||||
return deps
|
||||
}
|
||||
}
|
|
@ -166,7 +166,7 @@ export default class LayoutConfig {
|
|||
return
|
||||
} else {
|
||||
const shared = AllKnownLayers.sharedLayers.get(layer)
|
||||
if(shared === undefined){
|
||||
if (shared === undefined) {
|
||||
throw `Shared layer ${layer} not found (at ${context}.layers[${i}])`
|
||||
}
|
||||
result.push(shared)
|
||||
|
@ -212,15 +212,39 @@ export default class LayoutConfig {
|
|||
})
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Some special layers which are always included by default
|
||||
for (const defaultLayer of AllKnownLayers.added_by_default) {
|
||||
if(result.some(l => l?.id === defaultLayer)){
|
||||
if (result.some(l => l?.id === defaultLayer)) {
|
||||
continue; // Already added
|
||||
}
|
||||
result.push(AllKnownLayers.sharedLayers.get(defaultLayer))
|
||||
const sharedLayer = AllKnownLayers.sharedLayers.get(defaultLayer)
|
||||
if (sharedLayer !== undefined) {
|
||||
result.push(sharedLayer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let unmetDependencies: { dependency: string, layer: string }[] = []
|
||||
do {
|
||||
const dependencies: { dependency: string, layer: string }[] = [].concat(...result.map(l => Array.from(l.getDependencies()).map(d => ({
|
||||
dependency: d,
|
||||
layer: l.id
|
||||
}))))
|
||||
const loadedLayers = new Set(result.map(r => r.id))
|
||||
unmetDependencies = dependencies.filter(dep => !loadedLayers.has(dep.dependency))
|
||||
for (const unmetDependency of unmetDependencies) {
|
||||
|
||||
console.log("Recursively loading unmet dependency ", unmetDependency.dependency, "(needed by " + unmetDependency.layer + ")")
|
||||
const dep = AllKnownLayers.sharedLayers.get(unmetDependency.dependency)
|
||||
if (dep === undefined) {
|
||||
throw "The layer '" + unmetDependency.layer + "' needs '" + unmetDependency.dependency + "' to be loaded, but it could not be found as builtin layer (at " + context + ")"
|
||||
}
|
||||
result.unshift(dep)
|
||||
unmetDependencies = unmetDependencies.filter(d => d.dependency !== unmetDependency.dependency)
|
||||
}
|
||||
|
||||
} while (unmetDependencies.length > 0)
|
||||
return {layers: result, extractAllNodes: exportAllNodes}
|
||||
}
|
||||
|
||||
|
@ -300,9 +324,9 @@ export default class LayoutConfig {
|
|||
public isLeftRightSensitive() {
|
||||
return this.layers.some(l => l.isLeftRightSensitive())
|
||||
}
|
||||
|
||||
public getMatchingLayer(tags: any) : LayerConfig | undefined{
|
||||
if(tags === undefined){
|
||||
|
||||
public getMatchingLayer(tags: any): LayerConfig | undefined {
|
||||
if (tags === undefined) {
|
||||
return undefined
|
||||
}
|
||||
for (const layer of this.layers) {
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import {Tag} from "../../Logic/Tags/Tag";
|
||||
|
||||
export interface PreciseInput {
|
||||
preferredBackground?: string[],
|
||||
snapToLayers?: string[],
|
||||
maxSnapDistance?: number
|
||||
}
|
||||
|
||||
export default interface PresetConfig {
|
||||
title: Translation,
|
||||
tags: Tag[],
|
||||
|
@ -8,9 +14,5 @@ export default interface PresetConfig {
|
|||
/**
|
||||
* If precise input is set, then an extra map is shown in which the user can drag the map to the precise location
|
||||
*/
|
||||
preciseInput?: {
|
||||
preferredBackground?: string[],
|
||||
snapToLayers?: string[],
|
||||
maxSnapDistance?: number
|
||||
}
|
||||
preciseInput?: PreciseInput
|
||||
}
|
Loading…
Reference in a new issue