mapcomplete/Customizations/AllKnownLayouts.ts

287 lines
11 KiB
TypeScript
Raw Normal View History

2021-04-10 03:50:44 +02:00
import * as known_themes from "../assets/generated/known_layers_and_themes.json"
2022-09-08 21:40:48 +02:00
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
import BaseUIElement from "../UI/BaseUIElement"
import Combine from "../UI/Base/Combine"
import Title from "../UI/Base/Title"
import List from "../UI/Base/List"
import DependencyCalculator from "../Models/ThemeConfig/DependencyCalculator"
import Constants from "../Models/Constants"
import { Utils } from "../Utils"
import Link from "../UI/Base/Link"
import { LayoutConfigJson } from "../Models/ThemeConfig/Json/LayoutConfigJson"
import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson"
2020-07-05 18:59:47 +02:00
export class AllKnownLayouts {
2022-09-08 21:40:48 +02:00
public static allKnownLayouts: Map<string, LayoutConfig> = AllKnownLayouts.AllLayouts()
public static layoutsList: LayoutConfig[] = AllKnownLayouts.GenerateOrderedList(
AllKnownLayouts.allKnownLayouts
)
2022-01-26 21:40:38 +01:00
// Must be below the list...
2022-09-08 21:40:48 +02:00
private static sharedLayers: Map<string, LayerConfig> = AllKnownLayouts.getSharedLayers()
2021-04-10 03:50:44 +02:00
2022-05-21 01:02:03 +02:00
public static AllPublicLayers(options?: {
2022-09-08 21:40:48 +02:00
includeInlineLayers: true | boolean
}): LayerConfig[] {
2021-11-07 16:34:51 +01:00
const allLayers: LayerConfig[] = []
const seendIds = new Set<string>()
AllKnownLayouts.sharedLayers.forEach((layer, key) => {
seendIds.add(key)
allLayers.push(layer)
})
2022-05-21 01:02:03 +02:00
if (options?.includeInlineLayers ?? true) {
2022-09-08 21:40:48 +02:00
const publicLayouts = AllKnownLayouts.layoutsList.filter((l) => !l.hideFromOverview)
2022-05-21 01:02:03 +02:00
for (const layout of publicLayouts) {
if (layout.hideFromOverview) {
continue
}
2022-05-21 01:02:03 +02:00
for (const layer of layout.layers) {
if (seendIds.has(layer.id)) {
continue
}
seendIds.add(layer.id)
allLayers.push(layer)
}
}
}
2022-05-21 01:02:03 +02:00
return allLayers
}
2022-01-26 21:40:38 +01:00
2022-05-21 01:50:55 +02:00
/**
* Returns all themes which use the given layer, reverse sorted by minzoom. This sort maximizes the chances that the layer is prominently featured on the first theme
*/
2022-05-21 01:02:03 +02:00
public static themesUsingLayer(id: string, publicOnly = true): LayoutConfig[] {
2022-05-21 01:50:55 +02:00
const themes = AllKnownLayouts.layoutsList
2022-09-08 21:40:48 +02:00
.filter((l) => !(publicOnly && l.hideFromOverview) && l.id !== "personal")
.map((theme) => ({
theme,
minzoom: theme.layers.find((layer) => layer.id === id)?.minzoom,
}))
.filter((obj) => obj.minzoom !== undefined)
2022-05-21 01:50:55 +02:00
themes.sort((th0, th1) => th1.minzoom - th0.minzoom)
2022-09-08 21:40:48 +02:00
return themes.map((th) => th.theme)
2022-05-21 01:02:03 +02:00
}
2022-04-06 16:12:01 +02:00
/**
* Generates documentation for the layers.
* Inline layers are included (if the theme is public)
* @param callback
* @constructor
*/
2022-09-08 21:40:48 +02:00
public static GenOverviewsForSingleLayer(
callback: (layer: LayerConfig, element: BaseUIElement, inlineSource: string) => void
): void {
const allLayers: LayerConfig[] = Array.from(AllKnownLayouts.sharedLayers.values()).filter(
(layer) => Constants.priviliged_layers.indexOf(layer.id) < 0
)
const builtinLayerIds: Set<string> = new Set<string>()
2022-09-08 21:40:48 +02:00
allLayers.forEach((l) => builtinLayerIds.add(l.id))
const inlineLayers = new Map<string, string>()
2022-04-06 16:12:01 +02:00
for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) {
if (layout.hideFromOverview) {
continue
}
for (const layer of layout.layers) {
if (Constants.priviliged_layers.indexOf(layer.id) >= 0) {
continue
}
if (builtinLayerIds.has(layer.id)) {
continue
}
2022-05-21 01:02:03 +02:00
if (layer.source.geojsonSource !== undefined) {
2022-04-06 16:12:01 +02:00
// Not an OSM-source
continue
}
allLayers.push(layer)
builtinLayerIds.add(layer.id)
inlineLayers.set(layer.id, layout.id)
}
}
const themesPerLayer = new Map<string, string[]>()
for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) {
if (layout.hideFromOverview) {
continue
}
for (const layer of layout.layers) {
if (!builtinLayerIds.has(layer.id)) {
2022-04-06 16:12:01 +02:00
// This is an inline layer
continue
}
if (!themesPerLayer.has(layer.id)) {
themesPerLayer.set(layer.id, [])
}
themesPerLayer.get(layer.id).push(layout.id)
}
}
// Determine the cross-dependencies
2022-01-26 21:40:38 +01:00
const layerIsNeededBy: Map<string, string[]> = new Map<string, string[]>()
for (const layer of allLayers) {
for (const dep of DependencyCalculator.getLayerDependencies(layer)) {
const dependency = dep.neededLayer
2022-01-26 21:40:38 +01:00
if (!layerIsNeededBy.has(dependency)) {
layerIsNeededBy.set(dependency, [])
}
layerIsNeededBy.get(dependency).push(layer.id)
}
}
allLayers.forEach((layer) => {
2022-09-08 21:40:48 +02:00
const element = layer.GenerateDocumentation(
themesPerLayer.get(layer.id),
layerIsNeededBy,
DependencyCalculator.getLayerDependencies(layer)
)
2022-04-06 16:12:01 +02:00
callback(layer, element, inlineLayers.get(layer.id))
})
}
2021-11-07 16:34:51 +01:00
2022-04-06 16:12:01 +02:00
/**
* Generates the documentation for the layers overview page
* @constructor
*/
2021-11-08 02:36:01 +01:00
public static GenLayerOverviewText(): BaseUIElement {
2021-12-21 18:35:31 +01:00
for (const id of Constants.priviliged_layers) {
if (!AllKnownLayouts.sharedLayers.has(id)) {
2021-11-08 02:36:01 +01:00
throw "Priviliged layer definition not found: " + id
}
}
2021-12-04 21:44:18 +01:00
2022-09-08 21:40:48 +02:00
const allLayers: LayerConfig[] = Array.from(AllKnownLayouts.sharedLayers.values()).filter(
(layer) => Constants.priviliged_layers.indexOf(layer.id) < 0
)
2021-12-04 21:44:18 +01:00
const builtinLayerIds: Set<string> = new Set<string>()
2022-09-08 21:40:48 +02:00
allLayers.forEach((l) => builtinLayerIds.add(l.id))
2021-11-08 02:36:01 +01:00
const themesPerLayer = new Map<string, string[]>()
for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) {
for (const layer of layout.layers) {
2021-12-04 21:44:18 +01:00
if (!builtinLayerIds.has(layer.id)) {
continue
}
2021-11-08 02:36:01 +01:00
if (!themesPerLayer.has(layer.id)) {
themesPerLayer.set(layer.id, [])
}
themesPerLayer.get(layer.id).push(layout.id)
}
}
// Determine the cross-dependencies
2022-01-26 21:40:38 +01:00
const layerIsNeededBy: Map<string, string[]> = new Map<string, string[]>()
for (const layer of allLayers) {
for (const dep of DependencyCalculator.getLayerDependencies(layer)) {
const dependency = dep.neededLayer
2022-01-26 21:40:38 +01:00
if (!layerIsNeededBy.has(dependency)) {
layerIsNeededBy.set(dependency, [])
}
layerIsNeededBy.get(dependency).push(layer.id)
}
}
2022-01-26 21:40:38 +01:00
2021-11-08 02:36:01 +01:00
return new Combine([
new Title("Special and other useful layers", 1),
"MapComplete has a few data layers available in the theme which have special properties through builtin-hooks. Furthermore, there are some normal layers (which are built from normal Theme-config files) but are so general that they get a mention here.",
new Title("Priviliged layers", 1),
2022-09-08 21:40:48 +02:00
new List(Constants.priviliged_layers.map((id) => "[" + id + "](#" + id + ")")),
2021-12-21 18:35:31 +01:00
...Constants.priviliged_layers
2022-09-08 21:40:48 +02:00
.map((id) => AllKnownLayouts.sharedLayers.get(id))
.map((l) =>
l.GenerateDocumentation(
themesPerLayer.get(l.id),
layerIsNeededBy,
DependencyCalculator.getLayerDependencies(l),
Constants.added_by_default.indexOf(l.id) >= 0,
Constants.no_include.indexOf(l.id) < 0
)
),
2021-12-04 21:44:18 +01:00
new Title("Normal layers", 1),
"The following layers are included in MapComplete:",
2022-09-08 21:40:48 +02:00
new List(
Array.from(AllKnownLayouts.sharedLayers.keys()).map(
(id) => new Link(id, "./Layers/" + id + ".md")
)
),
2021-11-08 02:36:01 +01:00
])
}
2022-05-21 01:02:03 +02:00
public static GenerateDocumentationForTheme(theme: LayoutConfig): BaseUIElement {
return new Combine([
new Title(new Combine([theme.title, "(", theme.id + ")"]), 2),
theme.description,
"This theme contains the following layers:",
2022-09-08 21:40:48 +02:00
new List(theme.layers.map((l) => l.id)),
2022-05-21 01:02:03 +02:00
"Available languages:",
2022-09-08 21:40:48 +02:00
new List(theme.language),
2022-05-21 01:02:03 +02:00
])
}
2022-07-11 09:14:26 +02:00
public static getSharedLayers(): Map<string, LayerConfig> {
2022-09-08 21:40:48 +02:00
const sharedLayers = new Map<string, LayerConfig>()
2022-07-11 09:14:26 +02:00
for (const layer of known_themes["layers"]) {
2022-01-26 21:40:38 +01:00
try {
// @ts-ignore
const parsed = new LayerConfig(layer, "shared_layers")
2022-09-08 21:40:48 +02:00
sharedLayers.set(layer.id, parsed)
2022-01-26 21:40:38 +01:00
} catch (e) {
if (!Utils.runningFromConsole) {
2022-09-08 21:40:48 +02:00
console.error(
"CRITICAL: Could not parse a layer configuration!",
layer.id,
" due to",
e
)
2022-01-26 21:40:38 +01:00
}
}
}
2022-09-08 21:40:48 +02:00
return sharedLayers
2022-01-26 21:40:38 +01:00
}
2022-07-11 09:14:26 +02:00
public static getSharedLayersConfigs(): Map<string, LayerConfigJson> {
2022-09-08 21:40:48 +02:00
const sharedLayers = new Map<string, LayerConfigJson>()
2022-07-11 09:14:26 +02:00
for (const layer of known_themes["layers"]) {
2022-09-08 21:40:48 +02:00
// @ts-ignore
sharedLayers.set(layer.id, layer)
2022-07-11 09:14:26 +02:00
}
2022-09-08 21:40:48 +02:00
return sharedLayers
2022-07-11 09:14:26 +02:00
}
2021-04-10 03:50:44 +02:00
private static GenerateOrderedList(allKnownLayouts: Map<string, LayoutConfig>): LayoutConfig[] {
const list = []
allKnownLayouts.forEach((layout) => {
2021-12-21 18:35:31 +01:00
list.push(layout)
2021-04-10 03:50:44 +02:00
})
2022-09-08 21:40:48 +02:00
return list
2021-04-10 03:50:44 +02:00
}
2020-11-11 16:23:49 +01:00
private static AllLayouts(): Map<string, LayoutConfig> {
2022-09-08 21:40:48 +02:00
const dict: Map<string, LayoutConfig> = new Map()
2022-07-11 09:14:26 +02:00
for (const layoutConfigJson of known_themes["themes"]) {
2022-04-06 16:12:01 +02:00
const layout = new LayoutConfig(<LayoutConfigJson>layoutConfigJson, true)
2022-01-26 21:40:38 +01:00
dict.set(layout.id, layout)
for (let i = 0; i < layout.layers.length; i++) {
2022-09-08 21:40:48 +02:00
let layer = layout.layers[i]
if (typeof layer === "string") {
layer = AllKnownLayouts.sharedLayers.get(layer)
2022-01-26 21:40:38 +01:00
layout.layers[i] = layer
if (layer === undefined) {
console.log("Defined layers are ", AllKnownLayouts.sharedLayers.keys())
throw `Layer ${layer} was not found or defined - probably a type was made`
}
}
}
2020-07-25 01:07:02 +02:00
}
2022-09-08 21:40:48 +02:00
return dict
2020-07-05 18:59:47 +02:00
}
}