Performance: lazily download ELI when needed instead of bundling this in the download
This commit is contained in:
parent
b91b1378d1
commit
62070a64e2
14 changed files with 257 additions and 183 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "mapcomplete",
|
"name": "mapcomplete",
|
||||||
"version": "0.45.0",
|
"version": "0.45.1",
|
||||||
"repository": "https://github.com/pietervdvn/MapComplete",
|
"repository": "https://github.com/pietervdvn/MapComplete",
|
||||||
"description": "A small website to edit OSM easily",
|
"description": "A small website to edit OSM easily",
|
||||||
"bugs": "https://github.com/pietervdvn/MapComplete/issues",
|
"bugs": "https://github.com/pietervdvn/MapComplete/issues",
|
||||||
|
|
|
@ -99,8 +99,17 @@ class DownloadEli extends Script {
|
||||||
|
|
||||||
const contents =
|
const contents =
|
||||||
'{"type":"FeatureCollection",\n "features": [\n' +
|
'{"type":"FeatureCollection",\n "features": [\n' +
|
||||||
keptLayers.map((l) => JSON.stringify(l)).join(",\n") +
|
keptLayers.filter(l => l.properties.id !== "Bing").map((l) => JSON.stringify(l)).join(",\n") +
|
||||||
"\n]}"
|
"\n]}"
|
||||||
|
|
||||||
|
const bing = keptLayers.find(l => l.properties.id === "Bing")
|
||||||
|
if(bing){
|
||||||
|
const pth = target.replace(/.json$/, ".bing.json")
|
||||||
|
fs.writeFileSync(pth, JSON.stringify(bing), { encoding: "utf8" })
|
||||||
|
console.log("Written", pth)
|
||||||
|
}else{
|
||||||
|
console.log("No bing entry found")
|
||||||
|
}
|
||||||
fs.writeFileSync(target, contents, { encoding: "utf8" })
|
fs.writeFileSync(target, contents, { encoding: "utf8" })
|
||||||
console.log("Written", keptLayers.length + ", entries to the ELI")
|
console.log("Written", keptLayers.length + ", entries to the ELI")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Store, UIEventSource } from "../UIEventSource"
|
import { Store, UIEventSource } from "../UIEventSource"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
import { RasterLayerPolygon, RasterLayerUtils } from "../../Models/RasterLayers"
|
import { AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils } from "../../Models/RasterLayers"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a user pans around on the map, they might pan out of the range of the current background raster layer.
|
* When a user pans around on the map, they might pan out of the range of the current background raster layer.
|
||||||
|
@ -9,12 +9,24 @@ import { RasterLayerPolygon, RasterLayerUtils } from "../../Models/RasterLayers"
|
||||||
export default class BackgroundLayerResetter {
|
export default class BackgroundLayerResetter {
|
||||||
constructor(
|
constructor(
|
||||||
currentBackgroundLayer: UIEventSource<RasterLayerPolygon | undefined>,
|
currentBackgroundLayer: UIEventSource<RasterLayerPolygon | undefined>,
|
||||||
availableLayers: Store<RasterLayerPolygon[]>
|
availableLayers: {store: Store<RasterLayerPolygon[]>}
|
||||||
) {
|
) {
|
||||||
if (Utils.runningFromConsole) {
|
if (Utils.runningFromConsole) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentBackgroundLayer.addCallbackAndRunD(l => {
|
||||||
|
if(l.geometry !== undefined && AvailableRasterLayers.globalLayers.find(global => global.properties.id !== l.properties.id)){
|
||||||
|
BackgroundLayerResetter.installHandler(currentBackgroundLayer, availableLayers.store)
|
||||||
|
return true // unregister
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static installHandler( currentBackgroundLayer: UIEventSource<RasterLayerPolygon | undefined>,
|
||||||
|
availableLayers: Store<RasterLayerPolygon[]>
|
||||||
|
){
|
||||||
// Change the baseLayer back to OSM if we go out of the current range of the layer
|
// Change the baseLayer back to OSM if we go out of the current range of the layer
|
||||||
availableLayers.addCallbackAndRunD((availableLayers) => {
|
availableLayers.addCallbackAndRunD((availableLayers) => {
|
||||||
// We only check on move/on change of the availableLayers
|
// We only check on move/on change of the availableLayers
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Store, UIEventSource } from "../UIEventSource"
|
import { Store, UIEventSource } from "../UIEventSource"
|
||||||
import { RasterLayerPolygon } from "../../Models/RasterLayers"
|
import { AvailableRasterLayers, RasterLayerPolygon } from "../../Models/RasterLayers"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the appropriate raster layer as background for the given query parameter, theme setting, user preference or default value.
|
* Selects the appropriate raster layer as background for the given query parameter, theme setting, user preference or default value.
|
||||||
|
@ -8,7 +8,7 @@ import { RasterLayerPolygon } from "../../Models/RasterLayers"
|
||||||
*/
|
*/
|
||||||
export class PreferredRasterLayerSelector {
|
export class PreferredRasterLayerSelector {
|
||||||
private readonly _rasterLayerSetting: UIEventSource<RasterLayerPolygon>
|
private readonly _rasterLayerSetting: UIEventSource<RasterLayerPolygon>
|
||||||
private readonly _availableLayers: Store<RasterLayerPolygon[]>
|
private readonly _availableLayers: { store: Store<RasterLayerPolygon[]> }
|
||||||
private readonly _preferredBackgroundLayer: UIEventSource<
|
private readonly _preferredBackgroundLayer: UIEventSource<
|
||||||
string | "photo" | "map" | "osmbasedmap" | undefined
|
string | "photo" | "map" | "osmbasedmap" | undefined
|
||||||
>
|
>
|
||||||
|
@ -16,11 +16,11 @@ export class PreferredRasterLayerSelector {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
rasterLayerSetting: UIEventSource<RasterLayerPolygon>,
|
rasterLayerSetting: UIEventSource<RasterLayerPolygon>,
|
||||||
availableLayers: Store<RasterLayerPolygon[]>,
|
availableLayers: { store: Store<RasterLayerPolygon[]> },
|
||||||
queryParameter: UIEventSource<string>,
|
queryParameter: UIEventSource<string>,
|
||||||
preferredBackgroundLayer: UIEventSource<
|
preferredBackgroundLayer: UIEventSource<
|
||||||
string | "photo" | "map" | "osmbasedmap" | undefined
|
string | "photo" | "map" | "osmbasedmap" | undefined
|
||||||
>
|
>,
|
||||||
) {
|
) {
|
||||||
this._rasterLayerSetting = rasterLayerSetting
|
this._rasterLayerSetting = rasterLayerSetting
|
||||||
this._availableLayers = availableLayers
|
this._availableLayers = availableLayers
|
||||||
|
@ -47,7 +47,13 @@ export class PreferredRasterLayerSelector {
|
||||||
|
|
||||||
this._preferredBackgroundLayer.addCallbackD((_) => self.updateLayer())
|
this._preferredBackgroundLayer.addCallbackD((_) => self.updateLayer())
|
||||||
|
|
||||||
this._availableLayers.addCallbackD((_) => self.updateLayer())
|
rasterLayerSetting.addCallbackAndRunD(layer => {
|
||||||
|
if (AvailableRasterLayers.globalLayers.find(l => l.id === layer.properties.id)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this._availableLayers.store.addCallbackD((_) => self.updateLayer())
|
||||||
|
return true // unregister
|
||||||
|
})
|
||||||
self.updateLayer()
|
self.updateLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,9 +64,17 @@ export class PreferredRasterLayerSelector {
|
||||||
private updateLayer() {
|
private updateLayer() {
|
||||||
// What is the ID of the layer we have to (try to) load?
|
// What is the ID of the layer we have to (try to) load?
|
||||||
const targetLayerId = this._queryParameter.data ?? this._preferredBackgroundLayer.data
|
const targetLayerId = this._queryParameter.data ?? this._preferredBackgroundLayer.data
|
||||||
const available = this._availableLayers.data
|
if (targetLayerId === undefined || targetLayerId === "default") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const global = AvailableRasterLayers.globalLayers.find(l => l.properties.id === targetLayerId)
|
||||||
|
if (global) {
|
||||||
|
this._rasterLayerSetting.setData(global)
|
||||||
|
return
|
||||||
|
}
|
||||||
const isCategory =
|
const isCategory =
|
||||||
targetLayerId === "photo" || targetLayerId === "osmbasedmap" || targetLayerId === "map"
|
targetLayerId === "photo" || targetLayerId === "osmbasedmap" || targetLayerId === "map"
|
||||||
|
const available = this._availableLayers.store.data
|
||||||
const foundLayer = isCategory
|
const foundLayer = isCategory
|
||||||
? available.find((l) => l.properties.category === targetLayerId)
|
? available.find((l) => l.properties.category === targetLayerId)
|
||||||
: available.find((l) => l.properties.id === targetLayerId)
|
: available.find((l) => l.properties.id === targetLayerId)
|
||||||
|
|
|
@ -1,17 +1,33 @@
|
||||||
import { Feature, Polygon } from "geojson"
|
import { Feature, Polygon } from "geojson"
|
||||||
import * as editorlayerindex from "../assets/editor-layer-index.json"
|
|
||||||
import * as globallayers from "../assets/global-raster-layers.json"
|
import * as globallayers from "../assets/global-raster-layers.json"
|
||||||
|
import * as bingJson from "../assets/editor-layer-index.bing.json"
|
||||||
|
|
||||||
import { BBox } from "../Logic/BBox"
|
import { BBox } from "../Logic/BBox"
|
||||||
import { Store, Stores } from "../Logic/UIEventSource"
|
import { Store, Stores, UIEventSource } from "../Logic/UIEventSource"
|
||||||
import { GeoOperations } from "../Logic/GeoOperations"
|
import { GeoOperations } from "../Logic/GeoOperations"
|
||||||
import { RasterLayerProperties } from "./RasterLayerProperties"
|
import { RasterLayerProperties } from "./RasterLayerProperties"
|
||||||
import Constants from "./Constants"
|
import { Utils } from "../Utils"
|
||||||
|
|
||||||
|
export type EditorLayerIndex = (Feature<Polygon, EditorLayerIndexProperties> &
|
||||||
|
RasterLayerPolygon)[]
|
||||||
|
|
||||||
export class AvailableRasterLayers {
|
export class AvailableRasterLayers {
|
||||||
public static EditorLayerIndex: (Feature<Polygon, EditorLayerIndexProperties> &
|
private static _editorLayerIndex: EditorLayerIndex = undefined
|
||||||
RasterLayerPolygon)[] = (<any>editorlayerindex.features).filter(
|
private static _editorLayerIndexStore: UIEventSource<EditorLayerIndex> = new UIEventSource<EditorLayerIndex>(undefined)
|
||||||
(l) => l.properties.id !== "Bing"
|
|
||||||
)
|
public static async editorLayerIndex(): Promise<EditorLayerIndex> {
|
||||||
|
if(AvailableRasterLayers._editorLayerIndex !== undefined){
|
||||||
|
return AvailableRasterLayers._editorLayerIndex
|
||||||
|
}
|
||||||
|
console.debug("Downloading ELI")
|
||||||
|
const eli = await Utils.downloadJson<{ features: EditorLayerIndex }>("./src/assets/editor-layer-index.json")
|
||||||
|
this._editorLayerIndex = eli.features.filter(l => l.properties.id !== "Bing")
|
||||||
|
this._editorLayerIndexStore.set(this._editorLayerIndex)
|
||||||
|
return this._editorLayerIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static globalLayers: RasterLayerPolygon[] = globallayers.layers
|
public static globalLayers: RasterLayerPolygon[] = globallayers.layers
|
||||||
.filter(
|
.filter(
|
||||||
(properties) =>
|
(properties) =>
|
||||||
|
@ -25,9 +41,7 @@ export class AvailableRasterLayers {
|
||||||
geometry: BBox.global.asGeometry(),
|
geometry: BBox.global.asGeometry(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public static bing: RasterLayerPolygon = (<any>editorlayerindex.features).find(
|
public static bing = <RasterLayerPolygon> bingJson
|
||||||
(l) => l.properties.id === "Bing"
|
|
||||||
)
|
|
||||||
public static readonly osmCartoProperties: RasterLayerProperties = {
|
public static readonly osmCartoProperties: RasterLayerProperties = {
|
||||||
id: "osm",
|
id: "osm",
|
||||||
name: "OpenStreetMap",
|
name: "OpenStreetMap",
|
||||||
|
@ -56,17 +70,30 @@ export class AvailableRasterLayers {
|
||||||
return l.properties.id === "protomaps.sunny"
|
return l.properties.id === "protomaps.sunny"
|
||||||
})
|
})
|
||||||
|
|
||||||
public static layersAvailableAt(
|
public static layersAvailableAt( location: Store<{ lon: number; lat: number }>,
|
||||||
|
enableBing?: Store<boolean>): {store: Store<RasterLayerPolygon[]> } {
|
||||||
|
const store = {store: undefined}
|
||||||
|
Utils.AddLazyProperty(store, "store", () => AvailableRasterLayers._layersAvailableAt(location, enableBing))
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _layersAvailableAt(
|
||||||
location: Store<{ lon: number; lat: number }>,
|
location: Store<{ lon: number; lat: number }>,
|
||||||
enableBing?: Store<boolean>
|
enableBing?: Store<boolean>
|
||||||
): Store<RasterLayerPolygon[]> {
|
): Store<RasterLayerPolygon[]> {
|
||||||
|
|
||||||
|
this.editorLayerIndex() // start the download
|
||||||
const availableLayersBboxes = Stores.ListStabilized(
|
const availableLayersBboxes = Stores.ListStabilized(
|
||||||
location.mapD((loc) => {
|
location.mapD((loc) => {
|
||||||
|
const eli = AvailableRasterLayers._editorLayerIndexStore.data
|
||||||
|
if(!eli){
|
||||||
|
return []
|
||||||
|
}
|
||||||
const lonlat: [number, number] = [loc.lon, loc.lat]
|
const lonlat: [number, number] = [loc.lon, loc.lat]
|
||||||
return AvailableRasterLayers.EditorLayerIndex.filter((eliPolygon) =>
|
return eli.filter((eliPolygon) =>
|
||||||
BBox.get(eliPolygon).contains(lonlat)
|
BBox.get(eliPolygon).contains(lonlat)
|
||||||
)
|
)
|
||||||
})
|
}, [AvailableRasterLayers._editorLayerIndexStore])
|
||||||
)
|
)
|
||||||
return Stores.ListStabilized(
|
return Stores.ListStabilized(
|
||||||
availableLayersBboxes.map(
|
availableLayersBboxes.map(
|
||||||
|
@ -100,14 +127,6 @@ export class AvailableRasterLayers {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static allIds(): Set<string> {
|
|
||||||
const all: string[] = []
|
|
||||||
all.push(...AvailableRasterLayers.globalLayers.map((l) => l.properties.id))
|
|
||||||
all.push(...AvailableRasterLayers.EditorLayerIndex.map((l) => l.properties.id))
|
|
||||||
all.push(this.osmCarto.properties.id)
|
|
||||||
all.push(this.defaultBackgroundLayer.properties.id)
|
|
||||||
return new Set<string>(all)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RasterLayerUtils {
|
export class RasterLayerUtils {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { Utils } from "../../../Utils"
|
||||||
import { DetectDuplicatePresets, DoesImageExist, ValidateLanguageCompleteness } from "./Validation"
|
import { DetectDuplicatePresets, DoesImageExist, ValidateLanguageCompleteness } from "./Validation"
|
||||||
|
|
||||||
export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
private static readonly _availableLayers = AvailableRasterLayers.allIds()
|
|
||||||
/**
|
/**
|
||||||
* The paths where this layer is originally saved. Triggers some extra checks
|
* The paths where this layer is originally saved. Triggers some extra checks
|
||||||
* @private
|
* @private
|
||||||
|
@ -150,6 +149,8 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.defaultBackgroundId) {
|
if (json.defaultBackgroundId) {
|
||||||
|
/*
|
||||||
|
TODO re-enable this check
|
||||||
const backgroundId = json.defaultBackgroundId
|
const backgroundId = json.defaultBackgroundId
|
||||||
|
|
||||||
const isCategory =
|
const isCategory =
|
||||||
|
@ -165,7 +166,7 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
.slice(0, 5)
|
.slice(0, 5)
|
||||||
.join(", ")}`,
|
.join(", ")}`,
|
||||||
)
|
)
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < theme.layers.length; i++) {
|
for (let i = 0; i < theme.layers.length; i++) {
|
||||||
|
|
|
@ -19,8 +19,6 @@ import { Utils } from "../../Utils"
|
||||||
import { TagsFilter } from "../../Logic/Tags/TagsFilter"
|
import { TagsFilter } from "../../Logic/Tags/TagsFilter"
|
||||||
import FilterConfigJson from "./Json/FilterConfigJson"
|
import FilterConfigJson from "./Json/FilterConfigJson"
|
||||||
import { Overpass } from "../../Logic/Osm/Overpass"
|
import { Overpass } from "../../Logic/Osm/Overpass"
|
||||||
import { ImmutableStore } from "../../Logic/UIEventSource"
|
|
||||||
import { OsmTags } from "../OsmFeature"
|
|
||||||
import Constants from "../Constants"
|
import Constants from "../Constants"
|
||||||
import { QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson"
|
import { QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson"
|
||||||
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
import MarkdownUtils from "../../Utils/MarkdownUtils"
|
||||||
|
|
|
@ -2,11 +2,7 @@ import LayoutConfig from "./ThemeConfig/LayoutConfig"
|
||||||
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
||||||
import { Changes } from "../Logic/Osm/Changes"
|
import { Changes } from "../Logic/Osm/Changes"
|
||||||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||||
import {
|
import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource"
|
||||||
FeatureSource,
|
|
||||||
IndexedFeatureSource,
|
|
||||||
WritableFeatureSource,
|
|
||||||
} from "../Logic/FeatureSource/FeatureSource"
|
|
||||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||||
import { ExportableMap, MapProperties } from "./MapProperties"
|
import { ExportableMap, MapProperties } from "./MapProperties"
|
||||||
import LayerState from "../Logic/State/LayerState"
|
import LayerState from "../Logic/State/LayerState"
|
||||||
|
@ -50,9 +46,7 @@ import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter"
|
||||||
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"
|
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"
|
||||||
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
||||||
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
||||||
import NoElementsInViewDetector, {
|
import NoElementsInViewDetector, { FeatureViewState } from "../Logic/Actors/NoElementsInViewDetector"
|
||||||
FeatureViewState,
|
|
||||||
} from "../Logic/Actors/NoElementsInViewDetector"
|
|
||||||
import FilteredLayer from "./FilteredLayer"
|
import FilteredLayer from "./FilteredLayer"
|
||||||
import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector"
|
import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector"
|
||||||
import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager"
|
import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager"
|
||||||
|
@ -122,7 +116,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
||||||
readonly perLayerFiltered: ReadonlyMap<string, FilteringFeatureSource>
|
readonly perLayerFiltered: ReadonlyMap<string, FilteringFeatureSource>
|
||||||
|
|
||||||
readonly availableLayers: Store<RasterLayerPolygon[]>
|
readonly availableLayers: {store: Store<RasterLayerPolygon[]>}
|
||||||
readonly userRelatedState: UserRelatedState
|
readonly userRelatedState: UserRelatedState
|
||||||
readonly geolocation: GeoLocationHandler
|
readonly geolocation: GeoLocationHandler
|
||||||
readonly geolocationControl: GeolocationControlState
|
readonly geolocationControl: GeolocationControlState
|
||||||
|
@ -153,7 +147,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
public readonly visualFeedback: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
public readonly visualFeedback: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||||
public readonly toCacheSavers: ReadonlyMap<string, SaveFeatureSourceToLocalStorage>
|
public readonly toCacheSavers: ReadonlyMap<string, SaveFeatureSourceToLocalStorage>
|
||||||
|
|
||||||
public readonly nearbyImageSearcher
|
public readonly nearbyImageSearcher: CombinedFetcher
|
||||||
|
|
||||||
constructor(layout: LayoutConfig, mvtAvailableLayers: Set<string>) {
|
constructor(layout: LayoutConfig, mvtAvailableLayers: Set<string>) {
|
||||||
Utils.initDomPurify()
|
Utils.initDomPurify()
|
||||||
|
@ -375,9 +369,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
longAgo.setTime(new Date().getTime() - 5 * 365 * 24 * 60 * 60 * 1000)
|
longAgo.setTime(new Date().getTime() - 5 * 365 * 24 * 60 * 60 * 1000)
|
||||||
this.nearbyImageSearcher = new CombinedFetcher(50, longAgo, this.indexedFeatures)
|
this.nearbyImageSearcher = new CombinedFetcher(50, longAgo, this.indexedFeatures)
|
||||||
|
|
||||||
this.featureSummary = this.setupSummaryLayer(
|
this.featureSummary = this.setupSummaryLayer()
|
||||||
new LayerConfig(<LayerConfigJson>summaryLayer, "summaryLayer", true)
|
|
||||||
)
|
|
||||||
this.toCacheSavers = layout.enableCache ? this.initSaveToLocalStorage() : undefined
|
this.toCacheSavers = layout.enableCache ? this.initSaveToLocalStorage() : undefined
|
||||||
this.initActors()
|
this.initActors()
|
||||||
this.drawSpecialLayers()
|
this.drawSpecialLayers()
|
||||||
|
@ -647,7 +639,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const setLayerCategory = (category: EliCategory) => {
|
const setLayerCategory = (category: EliCategory) => {
|
||||||
const available = this.availableLayers.data
|
const available = this.availableLayers.store.data
|
||||||
const current = this.mapProperties.rasterLayer
|
const current = this.mapProperties.rasterLayer
|
||||||
const best = RasterLayerUtils.SelectBestLayerAccordingTo(
|
const best = RasterLayerUtils.SelectBestLayerAccordingTo(
|
||||||
available,
|
available,
|
||||||
|
@ -696,7 +688,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupSummaryLayer(summaryLayerConfig: LayerConfig): SummaryTileSourceRewriter {
|
private setupSummaryLayer(): SummaryTileSourceRewriter {
|
||||||
/**
|
/**
|
||||||
* MaxZoom for the summary layer
|
* MaxZoom for the summary layer
|
||||||
*/
|
*/
|
||||||
|
@ -723,8 +715,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const src = new SummaryTileSourceRewriter(summaryTileSource, this.layerState.filteredLayers)
|
return new SummaryTileSourceRewriter(summaryTileSource, this.layerState.filteredLayers)
|
||||||
return src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,7 +22,7 @@ class SingleBackgroundHandler {
|
||||||
constructor(
|
constructor(
|
||||||
map: Store<MLMap>,
|
map: Store<MLMap>,
|
||||||
targetLayer: RasterLayerPolygon,
|
targetLayer: RasterLayerPolygon,
|
||||||
background: UIEventSource<RasterLayerPolygon | undefined>
|
background: UIEventSource<RasterLayerPolygon | undefined>,
|
||||||
) {
|
) {
|
||||||
this._targetLayer = targetLayer
|
this._targetLayer = targetLayer
|
||||||
this._map = map
|
this._map = map
|
||||||
|
@ -57,10 +57,15 @@ class SingleBackgroundHandler {
|
||||||
"Removing raster layer",
|
"Removing raster layer",
|
||||||
this._targetLayer.properties.id,
|
this._targetLayer.properties.id,
|
||||||
"map moved and not been used for",
|
"map moved and not been used for",
|
||||||
SingleBackgroundHandler.DEACTIVATE_AFTER
|
SingleBackgroundHandler.DEACTIVATE_AFTER,
|
||||||
)
|
)
|
||||||
if (map.getLayer(<string>this._targetLayer.properties.id)) {
|
try {
|
||||||
map.removeLayer(<string>this._targetLayer.properties.id)
|
|
||||||
|
if (map.getLayer(<string>this._targetLayer.properties.id)) {
|
||||||
|
map.removeLayer(<string>this._targetLayer.properties.id)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Could not (try to) remove the raster layer", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +157,7 @@ class SingleBackgroundHandler {
|
||||||
"raster-opacity": 0,
|
"raster-opacity": 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
addLayerBeforeId
|
addLayerBeforeId,
|
||||||
)
|
)
|
||||||
this.opacity.addCallbackAndRun((o) => {
|
this.opacity.addCallbackAndRun((o) => {
|
||||||
try {
|
try {
|
||||||
|
@ -170,14 +175,14 @@ class SingleBackgroundHandler {
|
||||||
private fadeOut() {
|
private fadeOut() {
|
||||||
Stores.Chronic(
|
Stores.Chronic(
|
||||||
8,
|
8,
|
||||||
() => this.opacity.data > 0 && this._deactivationTime !== undefined
|
() => this.opacity.data > 0 && this._deactivationTime !== undefined,
|
||||||
).addCallback((_) => this.opacity.setData(Math.max(0, this.opacity.data - this.fadeStep)))
|
).addCallback((_) => this.opacity.setData(Math.max(0, this.opacity.data - this.fadeStep)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fadeIn() {
|
private fadeIn() {
|
||||||
Stores.Chronic(
|
Stores.Chronic(
|
||||||
8,
|
8,
|
||||||
() => this.opacity.data < 1.0 && this._deactivationTime === undefined
|
() => this.opacity.data < 1.0 && this._deactivationTime === undefined,
|
||||||
).addCallback((_) => this.opacity.setData(Math.min(1.0, this.opacity.data + this.fadeStep)))
|
).addCallback((_) => this.opacity.setData(Math.min(1.0, this.opacity.data + this.fadeStep)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +200,7 @@ export default class RasterLayerHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static prepareSource(
|
public static prepareSource(
|
||||||
layer: RasterLayerProperties
|
layer: RasterLayerProperties,
|
||||||
): RasterSourceSpecification | VectorSourceSpecification {
|
): RasterSourceSpecification | VectorSourceSpecification {
|
||||||
if (layer.type === "vector") {
|
if (layer.type === "vector") {
|
||||||
const vs: VectorSourceSpecification = {
|
const vs: VectorSourceSpecification = {
|
||||||
|
|
|
@ -12,11 +12,13 @@
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import Tr from "../Base/Tr.svelte"
|
import Tr from "../Base/Tr.svelte"
|
||||||
import TitledPanel from "../Base/TitledPanel.svelte"
|
import TitledPanel from "../Base/TitledPanel.svelte"
|
||||||
|
import Loading from "../Base/Loading.svelte"
|
||||||
|
|
||||||
export let availableLayers: Store<RasterLayerPolygon[]>
|
export let availableLayers: {store: Store<RasterLayerPolygon[]>}
|
||||||
export let mapproperties: MapProperties
|
export let mapproperties: MapProperties
|
||||||
export let userstate: UserRelatedState
|
export let userstate: UserRelatedState
|
||||||
export let map: Store<MlMap>
|
export let map: Store<MlMap>
|
||||||
|
let _availableLayers = availableLayers.store
|
||||||
/**
|
/**
|
||||||
* Used to toggle the background layers on/off
|
* Used to toggle the background layers on/off
|
||||||
*/
|
*/
|
||||||
|
@ -32,8 +34,8 @@
|
||||||
|
|
||||||
function availableForCategory(type: CategoryType): Store<RasterLayerPolygon[]> {
|
function availableForCategory(type: CategoryType): Store<RasterLayerPolygon[]> {
|
||||||
const keywords = categories[type]
|
const keywords = categories[type]
|
||||||
return availableLayers.mapD((available) =>
|
return _availableLayers.mapD((available) =>
|
||||||
available.filter((layer) => keywords.indexOf(<EliCategory>layer.properties.category) >= 0)
|
available.filter((layer) => keywords.indexOf(<EliCategory>layer.properties.category) >= 0),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,39 +55,42 @@
|
||||||
|
|
||||||
<TitledPanel>
|
<TitledPanel>
|
||||||
<Tr slot="title" t={Translations.t.general.backgroundMap} />
|
<Tr slot="title" t={Translations.t.general.backgroundMap} />
|
||||||
|
{#if $_availableLayers?.length < 1}
|
||||||
<div class="grid h-full w-full grid-cols-1 gap-2 md:grid-cols-2">
|
<Loading />
|
||||||
<RasterLayerPicker
|
{:else }
|
||||||
availableLayers={photoLayers}
|
<div class="grid h-full w-full grid-cols-1 gap-2 md:grid-cols-2">
|
||||||
favourite={getPref("photo")}
|
<RasterLayerPicker
|
||||||
{map}
|
availableLayers={$photoLayers}
|
||||||
{mapproperties}
|
favourite={getPref("photo")}
|
||||||
on:appliedLayer={onApply}
|
{map}
|
||||||
{visible}
|
{mapproperties}
|
||||||
/>
|
on:appliedLayer={onApply}
|
||||||
<RasterLayerPicker
|
{visible}
|
||||||
availableLayers={mapLayers}
|
/>
|
||||||
favourite={getPref("map")}
|
<RasterLayerPicker
|
||||||
{map}
|
availableLayers={$mapLayers}
|
||||||
{mapproperties}
|
favourite={getPref("map")}
|
||||||
on:appliedLayer={onApply}
|
{map}
|
||||||
{visible}
|
{mapproperties}
|
||||||
/>
|
on:appliedLayer={onApply}
|
||||||
<RasterLayerPicker
|
{visible}
|
||||||
availableLayers={osmbasedmapLayers}
|
/>
|
||||||
favourite={getPref("osmbasedmap")}
|
<RasterLayerPicker
|
||||||
{map}
|
availableLayers={$osmbasedmapLayers}
|
||||||
{mapproperties}
|
favourite={getPref("osmbasedmap")}
|
||||||
on:appliedLayer={onApply}
|
{map}
|
||||||
{visible}
|
{mapproperties}
|
||||||
/>
|
on:appliedLayer={onApply}
|
||||||
<RasterLayerPicker
|
{visible}
|
||||||
availableLayers={otherLayers}
|
/>
|
||||||
favourite={getPref("other")}
|
<RasterLayerPicker
|
||||||
{map}
|
availableLayers={$otherLayers}
|
||||||
{mapproperties}
|
favourite={getPref("other")}
|
||||||
on:appliedLayer={onApply}
|
{map}
|
||||||
{visible}
|
{mapproperties}
|
||||||
/>
|
on:appliedLayer={onApply}
|
||||||
</div>
|
{visible}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</TitledPanel>
|
</TitledPanel>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
/***
|
/***
|
||||||
* Chooses a background-layer out of available options
|
* Chooses a background-layer out of available options
|
||||||
*/
|
*/
|
||||||
export let availableLayers: Store<RasterLayerPolygon[]>
|
export let availableLayers: RasterLayerPolygon[]
|
||||||
export let mapproperties: MapProperties
|
export let mapproperties: MapProperties
|
||||||
export let map: Store<MlMap>
|
export let map: Store<MlMap>
|
||||||
|
|
||||||
|
@ -19,34 +19,26 @@
|
||||||
|
|
||||||
export let favourite: UIEventSource<string> | undefined = undefined
|
export let favourite: UIEventSource<string> | undefined = undefined
|
||||||
|
|
||||||
let rasterLayer = new UIEventSource<RasterLayerPolygon>(availableLayers.data?.[0])
|
let rasterLayer = new UIEventSource<RasterLayerPolygon>(availableLayers[0])
|
||||||
let hasLayers = true
|
let rasterLayerId = rasterLayer.sync(l => l?.properties?.id, [], id => availableLayers.find(l => l.properties.id === id))
|
||||||
onDestroy(
|
rasterLayer.setData(availableLayers[0])
|
||||||
availableLayers.addCallbackAndRun((layers) => {
|
$: rasterLayer.setData(availableLayers[0])
|
||||||
if (layers === undefined || layers.length === 0) {
|
|
||||||
hasLayers = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
hasLayers = true
|
|
||||||
rasterLayer.setData(layers[0])
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
if (favourite) {
|
if (favourite) {
|
||||||
onDestroy(
|
onDestroy(
|
||||||
favourite.addCallbackAndRunD((favourite) => {
|
favourite.addCallbackAndRunD((favourite) => {
|
||||||
const fav = availableLayers.data?.find((l) => l.properties.id === favourite)
|
const fav = availableLayers?.find((l) => l.properties.id === favourite)
|
||||||
if (!fav) {
|
if (!fav) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rasterLayer.setData(fav)
|
rasterLayer.setData(fav)
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
onDestroy(
|
onDestroy(
|
||||||
rasterLayer.addCallbackAndRunD((selected) => {
|
rasterLayer.addCallbackAndRunD((selected) => {
|
||||||
favourite?.setData(selected.properties.id)
|
favourite?.setData(selected.properties.id)
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,13 +48,14 @@
|
||||||
onDestroy(
|
onDestroy(
|
||||||
visible?.addCallbackAndRunD((visible) => {
|
visible?.addCallbackAndRunD((visible) => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
rasterLayerOnMap.setData(rasterLayer.data ?? availableLayers.data[0])
|
rasterLayerOnMap.setData(rasterLayer.data ?? availableLayers[0])
|
||||||
} else {
|
} else {
|
||||||
rasterLayerOnMap.setData(undefined)
|
rasterLayerOnMap.setData(undefined)
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function apply() {
|
function apply() {
|
||||||
mapproperties.rasterLayer.setData(rasterLayer.data)
|
mapproperties.rasterLayer.setData(rasterLayer.data)
|
||||||
dispatch("appliedLayer")
|
dispatch("appliedLayer")
|
||||||
|
@ -75,7 +68,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if hasLayers}
|
{#if availableLayers?.length > 0}
|
||||||
<form class="flex h-full w-full flex-col" on:submit|preventDefault={() => {}}>
|
<form class="flex h-full w-full flex-col" on:submit|preventDefault={() => {}}>
|
||||||
<button
|
<button
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
|
@ -92,9 +85,9 @@
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<select bind:value={$rasterLayer} class="w-full" on:keydown={handleKeyPress}>
|
<select bind:value={$rasterLayerId} class="w-full" on:keydown={handleKeyPress}>
|
||||||
{#each $availableLayers as availableLayer}
|
{#each availableLayers as availableLayer}
|
||||||
<option value={availableLayer}>
|
<option value={availableLayer.properties.id}>
|
||||||
{availableLayer.properties.name}
|
{availableLayer.properties.name}
|
||||||
</option>
|
</option>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -88,8 +88,6 @@ export interface SpecialVisualizationState {
|
||||||
readonly language: UIEventSource<string>
|
readonly language: UIEventSource<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly availableLayers: Store<RasterLayerPolygon[]>
|
|
||||||
|
|
||||||
readonly imageUploadManager: ImageUploadManager
|
readonly imageUploadManager: ImageUploadManager
|
||||||
|
|
||||||
readonly previewedImage: UIEventSource<ProvidedImage>
|
readonly previewedImage: UIEventSource<ProvidedImage>
|
||||||
|
|
1
src/assets/editor-layer-index.bing.json
Normal file
1
src/assets/editor-layer-index.bing.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"properties":{"name":"Bing Maps Aerial","id":"Bing","url":"https://ecn.t0.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=14634&pr=odbl&n=f","type":"bing","category":"photo","min_zoom":1,"max_zoom":22},"type":"Feature","geometry":null}
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue