refactoring(maplibre): add pointRendering

This commit is contained in:
Pieter Vander Vennet 2023-03-23 00:58:21 +01:00
parent 4f2bbf4b54
commit 1b3609b13f
10 changed files with 316 additions and 122 deletions

View file

@ -186,6 +186,14 @@ export class BBox {
] ]
} }
toLngLat(): [[number, number], [number, number]] {
return [
[this.minLon, this.minLat],
[this.maxLon, this.maxLat],
]
}
public asGeoJson<T>(properties: T): Feature<Polygon, T> { public asGeoJson<T>(properties: T): Feature<Polygon, T> {
return { return {
type: "Feature", type: "Feature",

View file

@ -1,8 +1,6 @@
import UserRelatedState from "./UserRelatedState" import UserRelatedState from "./UserRelatedState"
import { Store, Stores, UIEventSource } from "../UIEventSource" import { Store, Stores, UIEventSource } from "../UIEventSource"
import BaseLayer from "../../Models/BaseLayer"
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
import AvailableBaseLayers from "../Actors/AvailableBaseLayers"
import Attribution from "../../UI/BigComponents/Attribution" import Attribution from "../../UI/BigComponents/Attribution"
import Minimap, { MinimapObj } from "../../UI/Base/Minimap" import Minimap, { MinimapObj } from "../../UI/Base/Minimap"
import { Tiles } from "../../Models/TileRange" import { Tiles } from "../../Models/TileRange"
@ -43,10 +41,6 @@ export default class MapState extends UserRelatedState {
The leaflet instance of the big basemap The leaflet instance of the big basemap
*/ */
public leafletMap = new UIEventSource<any /*L.Map*/>(undefined, "leafletmap") public leafletMap = new UIEventSource<any /*L.Map*/>(undefined, "leafletmap")
/**
* A list of currently available background layers
*/
public availableBackgroundLayers: Store<BaseLayer[]>
/** /**
* The current background layer * The current background layer

View file

@ -2,6 +2,8 @@ import { Feature, Polygon } from "geojson"
import * as editorlayerindex from "../assets/editor-layer-index.json" 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 { BBox } from "../Logic/BBox" import { BBox } from "../Logic/BBox"
import { Store, Stores } from "../Logic/UIEventSource"
import { GeoOperations } from "../Logic/GeoOperations"
export class AvailableRasterLayers { export class AvailableRasterLayers {
public static EditorLayerIndex: (Feature<Polygon, EditorLayerIndexProperties> & public static EditorLayerIndex: (Feature<Polygon, EditorLayerIndexProperties> &
@ -33,6 +35,35 @@ export class AvailableRasterLayers {
properties: AvailableRasterLayers.osmCartoProperties, properties: AvailableRasterLayers.osmCartoProperties,
geometry: BBox.global.asGeometry(), geometry: BBox.global.asGeometry(),
} }
public static layersAvailableAt(
location: Store<{ lon: number; lat: number }>
): Store<RasterLayerPolygon[]> {
const availableLayersBboxes = Stores.ListStabilized(
location.mapD((loc) => {
const lonlat: [number, number] = [loc.lon, loc.lat]
return AvailableRasterLayers.EditorLayerIndex.filter((eliPolygon) =>
BBox.get(eliPolygon).contains(lonlat)
)
})
)
const available = Stores.ListStabilized(
availableLayersBboxes.map((eliPolygons) => {
const loc = location.data
const lonlat: [number, number] = [loc.lon, loc.lat]
const matching: RasterLayerPolygon[] = eliPolygons.filter((eliPolygon) => {
if (eliPolygon.geometry === null) {
return true // global ELI-layer
}
return GeoOperations.inside(lonlat, eliPolygon)
})
matching.unshift(AvailableRasterLayers.osmCarto)
matching.push(...AvailableRasterLayers.globalLayers)
return matching
})
)
return available
}
} }
export class RasterLayerUtils { export class RasterLayerUtils {

View file

@ -5,12 +5,13 @@ import { TagUtils } from "../../Logic/Tags/TagUtils"
import { Utils } from "../../Utils" import { Utils } from "../../Utils"
import Svg from "../../Svg" import Svg from "../../Svg"
import WithContextLoader from "./WithContextLoader" import WithContextLoader from "./WithContextLoader"
import { UIEventSource } from "../../Logic/UIEventSource" import { Store } from "../../Logic/UIEventSource"
import BaseUIElement from "../../UI/BaseUIElement" import BaseUIElement from "../../UI/BaseUIElement"
import { FixedUiElement } from "../../UI/Base/FixedUiElement" import { FixedUiElement } from "../../UI/Base/FixedUiElement"
import Img from "../../UI/Base/Img" import Img from "../../UI/Base/Img"
import Combine from "../../UI/Base/Combine" import Combine from "../../UI/Base/Combine"
import { VariableUiElement } from "../../UI/Base/VariableUIElement" import { VariableUiElement } from "../../UI/Base/VariableUIElement"
import { OsmTags } from "../OsmFeature"
export default class PointRenderingConfig extends WithContextLoader { export default class PointRenderingConfig extends WithContextLoader {
private static readonly allowed_location_codes = new Set<string>([ private static readonly allowed_location_codes = new Set<string>([
@ -164,7 +165,7 @@ export default class PointRenderingConfig extends WithContextLoader {
return PointRenderingConfig.FromHtmlMulti(htmlDefs, rotation, false, defaultPin) return PointRenderingConfig.FromHtmlMulti(htmlDefs, rotation, false, defaultPin)
} }
public GetSimpleIcon(tags: UIEventSource<any>): BaseUIElement { public GetSimpleIcon(tags: Store<OsmTags>): BaseUIElement {
const self = this const self = this
if (this.icon === undefined) { if (this.icon === undefined) {
return undefined return undefined
@ -175,7 +176,7 @@ export default class PointRenderingConfig extends WithContextLoader {
} }
public GenerateLeafletStyle( public GenerateLeafletStyle(
tags: UIEventSource<any>, tags: Store<OsmTags>,
clickable: boolean, clickable: boolean,
options?: { options?: {
noSize?: false | boolean noSize?: false | boolean
@ -183,11 +184,7 @@ export default class PointRenderingConfig extends WithContextLoader {
} }
): { ): {
html: BaseUIElement html: BaseUIElement
iconSize: [number, number]
iconAnchor: [number, number] iconAnchor: [number, number]
popupAnchor: [number, number]
iconUrl: string
className: string
} { } {
function num(str, deflt = 40) { function num(str, deflt = 40) {
const n = Number(str) const n = Number(str)
@ -211,20 +208,21 @@ export default class PointRenderingConfig extends WithContextLoader {
let iconH = num(iconSize[1]) let iconH = num(iconSize[1])
const mode = iconSize[2]?.trim()?.toLowerCase() ?? "center" const mode = iconSize[2]?.trim()?.toLowerCase() ?? "center"
let anchorW = iconW / 2 // in MapLibre, the offset is relative to the _center_ of the object, with left = [-x, 0] and up = [0,-y]
let anchorW = 0
let anchorH = iconH / 2 let anchorH = iconH / 2
if (mode === "left") { if (mode === "left") {
anchorW = 0 anchorW = -iconW / 2
} }
if (mode === "right") { if (mode === "right") {
anchorW = iconW anchorW = iconW / 2
} }
if (mode === "top") { if (mode === "top") {
anchorH = 0 anchorH = -iconH / 2
} }
if (mode === "bottom") { if (mode === "bottom") {
anchorH = iconH anchorH = iconH / 2
} }
const icon = this.GetSimpleIcon(tags) const icon = this.GetSimpleIcon(tags)
@ -264,15 +262,11 @@ export default class PointRenderingConfig extends WithContextLoader {
} }
return { return {
html: htmlEl, html: htmlEl,
iconSize: [iconW, iconH],
iconAnchor: [anchorW, anchorH], iconAnchor: [anchorW, anchorH],
popupAnchor: [0, 3 - anchorH],
iconUrl: undefined,
className: clickable ? "leaflet-div-icon" : "leaflet-div-icon unclickable",
} }
} }
private GetBadges(tags: UIEventSource<any>): BaseUIElement { private GetBadges(tags: Store<OsmTags>): BaseUIElement {
if (this.iconBadges.length === 0) { if (this.iconBadges.length === 0) {
return undefined return undefined
} }
@ -304,7 +298,7 @@ export default class PointRenderingConfig extends WithContextLoader {
).SetClass("absolute bottom-0 right-1/3 h-1/2 w-0") ).SetClass("absolute bottom-0 right-1/3 h-1/2 w-0")
} }
private GetLabel(tags: UIEventSource<any>): BaseUIElement { private GetLabel(tags: Store<OsmTags>): BaseUIElement {
if (this.label === undefined) { if (this.label === undefined) {
return undefined return undefined
} }

View file

@ -3,8 +3,6 @@ import { UIEventSource } from "../../Logic/UIEventSource"
import Loc from "../../Models/Loc" import Loc from "../../Models/Loc"
import Svg from "../../Svg" import Svg from "../../Svg"
import Toggle from "../Input/Toggle" import Toggle from "../Input/Toggle"
import BaseLayer from "../../Models/BaseLayer"
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"
import BaseUIElement from "../BaseUIElement" import BaseUIElement from "../BaseUIElement"
import { GeoOperations } from "../../Logic/GeoOperations" import { GeoOperations } from "../../Logic/GeoOperations"
import Hotkeys from "../Base/Hotkeys" import Hotkeys from "../Base/Hotkeys"

View file

@ -18,14 +18,12 @@ import { Unit } from "../../Models/Unit"
import { FixedInputElement } from "./FixedInputElement" import { FixedInputElement } from "./FixedInputElement"
import WikidataSearchBox from "../Wikipedia/WikidataSearchBox" import WikidataSearchBox from "../Wikipedia/WikidataSearchBox"
import Wikidata from "../../Logic/Web/Wikidata" import Wikidata from "../../Logic/Web/Wikidata"
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"
import Table from "../Base/Table" import Table from "../Base/Table"
import Combine from "../Base/Combine" import Combine from "../Base/Combine"
import Title from "../Base/Title" import Title from "../Base/Title"
import InputElementMap from "./InputElementMap" import InputElementMap from "./InputElementMap"
import Translations from "../i18n/Translations" import Translations from "../i18n/Translations"
import { Translation } from "../i18n/Translation" import { Translation } from "../i18n/Translation"
import BaseLayer from "../../Models/BaseLayer"
import Locale from "../i18n/Locale" import Locale from "../i18n/Locale"
export class TextFieldDef { export class TextFieldDef {

View file

@ -1,65 +1,81 @@
import { Store, UIEventSource } from "../../Logic/UIEventSource" import { Store, UIEventSource } from "../../Logic/UIEventSource"
import type { Map as MLMap } from "maplibre-gl" import type { Map as MLMap } from "maplibre-gl"
import { import { RasterLayerPolygon, RasterLayerProperties } from "../../Models/RasterLayers"
EditorLayerIndexProperties,
RasterLayerPolygon,
RasterLayerProperties,
} from "../../Models/RasterLayers"
import { Utils } from "../../Utils" import { Utils } from "../../Utils"
import Loc from "../../Models/Loc" import { BBox } from "../../Logic/BBox"
export class MapLibreAdaptor { export interface MapState {
readonly location: UIEventSource<{ lon: number; lat: number }>
readonly zoom: UIEventSource<number>
readonly bounds: Store<BBox>
readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined>
}
export class MapLibreAdaptor implements MapState {
private readonly _maplibreMap: Store<MLMap> private readonly _maplibreMap: Store<MLMap>
private readonly _backgroundLayer?: Store<RasterLayerPolygon>
private _currentRasterLayer: string = undefined readonly location: UIEventSource<{ lon: number; lat: number }>
readonly zoom: UIEventSource<number>
readonly bounds: Store<BBox>
readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined>
private readonly _bounds: UIEventSource<BBox>
constructor( /**
maplibreMap: Store<MLMap>, * Used for internal bookkeeping (to remove a rasterLayer when done loading)
state?: { * @private
// availableBackgroundLayers: Store<BaseLayer[]> */
/** private _currentRasterLayer: string
* The current background layer constructor(maplibreMap: Store<MLMap>, state?: Partial<Omit<MapState, "bounds">>) {
*/
readonly backgroundLayer?: Store<RasterLayerPolygon>
readonly locationControl?: UIEventSource<Loc>
}
) {
this._maplibreMap = maplibreMap this._maplibreMap = maplibreMap
this._backgroundLayer = state.backgroundLayer
this.location = state?.location ?? new UIEventSource({ lon: 0, lat: 0 })
this.zoom = state?.zoom ?? new UIEventSource(1)
this._bounds = new UIEventSource(BBox.global)
this.bounds = this._bounds
this.rasterLayer =
state?.rasterLayer ?? new UIEventSource<RasterLayerPolygon | undefined>(undefined)
const self = this const self = this
this._backgroundLayer?.addCallback((_) => self.setBackground())
maplibreMap.addCallbackAndRunD((map) => { maplibreMap.addCallbackAndRunD((map) => {
map.on("load", () => { map.on("load", () => {
self.setBackground() self.setBackground()
}) })
if (state.locationControl) { self.MoveMapToCurrentLoc(this.location.data)
self.MoveMapToCurrentLoc(state.locationControl.data) self.SetZoom(this.zoom.data)
map.on("moveend", () => { map.on("moveend", () => {
const dt = state.locationControl.data const dt = this.location.data
dt.lon = map.getCenter().lng dt.lon = map.getCenter().lng
dt.lat = map.getCenter().lat dt.lat = map.getCenter().lat
dt.zoom = map.getZoom() this.location.ping()
state.locationControl.ping() this.zoom.setData(map.getZoom())
}) })
}
}) })
state.locationControl.addCallbackAndRunD((loc) => { this.rasterLayer.addCallback((_) =>
self.setBackground().catch((e) => {
console.error("Could not set background")
})
)
this.location.addCallbackAndRunD((loc) => {
self.MoveMapToCurrentLoc(loc) self.MoveMapToCurrentLoc(loc)
}) })
this.zoom.addCallbackAndRunD((z) => self.SetZoom(z))
} }
private SetZoom(z: number) {
private MoveMapToCurrentLoc(loc: Loc) { const map = this._maplibreMap.data
if (map === undefined || z === undefined) {
return
}
if (map.getZoom() !== z) {
map.setZoom(z)
}
}
private MoveMapToCurrentLoc(loc: { lat: number; lon: number }) {
const map = this._maplibreMap.data const map = this._maplibreMap.data
if (map === undefined || loc === undefined) { if (map === undefined || loc === undefined) {
return return
} }
if (map.getZoom() !== loc.zoom) {
map.setZoom(loc.zoom)
}
const center = map.getCenter() const center = map.getCenter()
if (center.lng !== loc.lon || center.lat !== loc.lat) { if (center.lng !== loc.lon || center.lat !== loc.lat) {
map.setCenter({ lng: loc.lon, lat: loc.lat }) map.setCenter({ lng: loc.lon, lat: loc.lat })
@ -120,14 +136,14 @@ export class MapLibreAdaptor {
if (map === undefined) { if (map === undefined) {
return return
} }
const background: RasterLayerProperties = this._backgroundLayer?.data?.properties const background: RasterLayerProperties = this.rasterLayer?.data?.properties
if (background !== undefined && this._currentRasterLayer === background.id) { if (background !== undefined && this._currentRasterLayer === background.id) {
// already the correct background layer, nothing to do // already the correct background layer, nothing to do
return return
} }
await this.awaitStyleIsLoaded() await this.awaitStyleIsLoaded()
if (background !== this._backgroundLayer?.data?.properties) { if (background !== this.rasterLayer?.data?.properties) {
// User selected another background in the meantime... abort // User selected another background in the meantime... abort
return return
} }

108
UI/Map/ShowDataLayer.ts Normal file
View file

@ -0,0 +1,108 @@
import { ImmutableStore, Store } from "../../Logic/UIEventSource"
import type { Map as MlMap } from "maplibre-gl"
import { Marker } from "maplibre-gl"
import { ShowDataLayerOptions } from "../ShowDataLayer/ShowDataLayerOptions"
import { GeoOperations } from "../../Logic/GeoOperations"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import PointRenderingConfig from "../../Models/ThemeConfig/PointRenderingConfig"
import { OsmFeature, OsmTags } from "../../Models/OsmFeature"
import FeatureSource from "../../Logic/FeatureSource/FeatureSource"
import { BBox } from "../../Logic/BBox"
class PointRenderingLayer {
private readonly _config: PointRenderingConfig
private readonly _fetchStore?: (id: string) => Store<OsmTags>
private readonly _map: MlMap
constructor(
map: MlMap,
features: FeatureSource,
config: PointRenderingConfig,
fetchStore?: (id: string) => Store<OsmTags>
) {
this._config = config
this._map = map
this._fetchStore = fetchStore
const cache: Map<string, Marker> = new Map<string, Marker>()
const self = this
features.features.addCallbackAndRunD((features) => {
const unseenKeys = new Set(cache.keys())
for (const { feature } of features) {
const id = feature.properties.id
unseenKeys.delete(id)
const loc = GeoOperations.centerpointCoordinates(feature)
if (cache.has(id)) {
console.log("Not creating a marker for ", id)
const cached = cache.get(id)
const oldLoc = cached.getLngLat()
console.log("OldLoc vs newLoc", oldLoc, loc)
if (loc[0] !== oldLoc.lng && loc[1] !== oldLoc.lat) {
cached.setLngLat(loc)
console.log("MOVED")
}
continue
}
console.log("Creating a marker for ", id)
const marker = self.addPoint(feature)
cache.set(id, marker)
}
for (const unseenKey of unseenKeys) {
cache.get(unseenKey).remove()
cache.delete(unseenKey)
}
})
}
private addPoint(feature: OsmFeature): Marker {
let store: Store<OsmTags>
if (this._fetchStore) {
store = this._fetchStore(feature.properties.id)
} else {
store = new ImmutableStore(feature.properties)
}
const { html, iconAnchor } = this._config.GenerateLeafletStyle(store, true)
html.SetClass("marker")
const el = html.ConstructElement()
el.addEventListener("click", function () {
window.alert("Hello world!")
})
return new Marker(el)
.setLngLat(GeoOperations.centerpointCoordinates(feature))
.setOffset(iconAnchor)
.addTo(this._map)
}
}
export class ShowDataLayer {
private readonly _map: Store<MlMap>
private _options: ShowDataLayerOptions & { layer: LayerConfig }
constructor(map: Store<MlMap>, options: ShowDataLayerOptions & { layer: LayerConfig }) {
this._map = map
this._options = options
const self = this
map.addCallbackAndRunD((map) => self.initDrawFeatures(map))
}
private initDrawFeatures(map: MlMap) {
for (const pointRenderingConfig of this._options.layer.mapRendering) {
new PointRenderingLayer(
map,
this._options.features,
pointRenderingConfig,
this._options.fetchStore
)
}
if (this._options.zoomToFeatures) {
const features = this._options.features.features.data
const bbox = BBox.bboxAroundAll(features.map((f) => BBox.get(f.feature)))
map.fitBounds(bbox.toLngLat(), {
padding: { top: 10, bottom: 10, left: 10, right: 10 },
})
}
}
}

View file

@ -3,13 +3,35 @@ import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { ElementStorage } from "../../Logic/ElementStorage" import { ElementStorage } from "../../Logic/ElementStorage"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import ScrollableFullScreen from "../Base/ScrollableFullScreen" import ScrollableFullScreen from "../Base/ScrollableFullScreen"
import { OsmTags } from "../../Models/OsmFeature"
export interface ShowDataLayerOptions { export interface ShowDataLayerOptions {
/**
* Features to show
*/
features: FeatureSource features: FeatureSource
/**
* Indication of the current selected element; overrides some filters
*/
selectedElement?: UIEventSource<any> selectedElement?: UIEventSource<any>
leafletMap: Store<L.Map> /**
popup?: undefined | ((tags: UIEventSource<any>, layer: LayerConfig) => ScrollableFullScreen) * What popup to build when a feature is selected
*/
buildPopup?:
| undefined
| ((tags: UIEventSource<any>, layer: LayerConfig) => ScrollableFullScreen)
/**
* If set, zoom to the features when initially loaded and when they are changed
*/
zoomToFeatures?: false | boolean zoomToFeatures?: false | boolean
doShowLayer?: Store<boolean> /**
state?: { allElements?: ElementStorage } * Toggles the layer on/off
*/
doShowLayer?: Store<true | boolean>
/**
* Function which fetches the relevant store
*/
fetchStore?: (id: string) => Store<OsmTags>
} }

123
test.ts
View file

@ -1,24 +1,23 @@
import SvelteUIElement from "./UI/Base/SvelteUIElement" import SvelteUIElement from "./UI/Base/SvelteUIElement"
import MaplibreMap from "./UI/Map/MaplibreMap.svelte" import MaplibreMap from "./UI/Map/MaplibreMap.svelte"
import { Store, Stores, UIEventSource } from "./Logic/UIEventSource" import { ImmutableStore, UIEventSource } from "./Logic/UIEventSource"
import { MapLibreAdaptor } from "./UI/Map/MapLibreAdaptor" import { MapLibreAdaptor } from "./UI/Map/MapLibreAdaptor"
import { import { AvailableRasterLayers, RasterLayerPolygon } from "./Models/RasterLayers"
EditorLayerIndexProperties,
RasterLayerPolygon,
RasterLayerProperties,
} from "./Models/RasterLayers"
import type { Map as MlMap } from "maplibre-gl" import type { Map as MlMap } from "maplibre-gl"
import { AvailableRasterLayers } from "./Models/RasterLayers"
import Loc from "./Models/Loc"
import { BBox } from "./Logic/BBox"
import { GeoOperations } from "./Logic/GeoOperations"
import RasterLayerPicker from "./UI/Map/RasterLayerPicker.svelte" import RasterLayerPicker from "./UI/Map/RasterLayerPicker.svelte"
import BackgroundLayerResetter from "./Logic/Actors/BackgroundLayerResetter" import BackgroundLayerResetter from "./Logic/Actors/BackgroundLayerResetter"
import { ShowDataLayer } from "./UI/Map/ShowDataLayer"
import StaticFeatureSource from "./Logic/FeatureSource/Sources/StaticFeatureSource"
import { Layer } from "leaflet"
import LayerConfig from "./Models/ThemeConfig/LayerConfig"
import * as bench from "./assets/generated/layers/bench.json"
import { Utils } from "./Utils"
import SimpleFeatureSource from "./Logic/FeatureSource/Sources/SimpleFeatureSource"
import { FilterState } from "./Models/FilteredLayer"
import { FixedUiElement } from "./UI/Base/FixedUiElement"
async function main() { async function main() {
const mlmap = new UIEventSource<MlMap>(undefined) const mlmap = new UIEventSource<MlMap>(undefined)
const locationControl = new UIEventSource<Loc>({ const location = new UIEventSource<{ lon: number; lat: number }>({
zoom: 14,
lat: 51.1, lat: 51.1,
lon: 3.1, lon: 3.1,
}) })
@ -29,44 +28,70 @@ async function main() {
.SetStyle("height: 50vh; width: 90%; margin: 1%") .SetStyle("height: 50vh; width: 90%; margin: 1%")
.AttachTo("maindiv") .AttachTo("maindiv")
const bg = new UIEventSource<RasterLayerPolygon>(undefined) const bg = new UIEventSource<RasterLayerPolygon>(undefined)
new MapLibreAdaptor(mlmap, { const mla = new MapLibreAdaptor(mlmap, {
backgroundLayer: bg, rasterLayer: bg,
locationControl, location,
}) })
const availableLayersBboxes = Stores.ListStabilized( const features = new UIEventSource([
locationControl.mapD((loc) => { {
const lonlat: [number, number] = [loc.lon, loc.lat] feature: {
return AvailableRasterLayers.EditorLayerIndex.filter((eliPolygon) => type: "Feature",
BBox.get(eliPolygon).contains(lonlat) properties: {
) hello: "world",
}) id: "" + 1,
) },
const availableLayers: Store<RasterLayerPolygon[]> = Stores.ListStabilized( geometry: {
availableLayersBboxes.map((eliPolygons) => { type: "Point",
const loc = locationControl.data coordinates: [3.1, 51.2],
const lonlat: [number, number] = [loc.lon, loc.lat] },
const matching: RasterLayerPolygon[] = eliPolygons.filter((eliPolygon) => { },
if (eliPolygon.geometry === null) { freshness: new Date(),
return true // global ELI-layer },
} ])
return GeoOperations.inside(lonlat, eliPolygon) const layer = new LayerConfig(bench)
}) const options = {
matching.unshift(AvailableRasterLayers.osmCarto) zoomToFeatures: false,
matching.push(...AvailableRasterLayers.globalLayers) features: new SimpleFeatureSource(
return matching {
}) layerDef: layer,
) isDisplayed: new UIEventSource<boolean>(true),
appliedFilters: new UIEventSource<Map<string, FilterState>>(undefined),
availableLayers.map((a) => },
console.log( 0,
"Availabe layers at current location:", features
a.map((al) => al.properties.id) ),
) layer,
) }
new ShowDataLayer(mlmap, options)
new BackgroundLayerResetter(bg, availableLayers) mla.zoom.set(9)
new SvelteUIElement(RasterLayerPicker, { availableLayers, value: bg }).AttachTo("extradiv") mla.location.set({ lon: 3.1, lat: 51.1 })
const availableLayers = AvailableRasterLayers.layersAvailableAt(location)
// new BackgroundLayerResetter(bg, availableLayers)
// new SvelteUIElement(RasterLayerPicker, { availableLayers, value: bg }).AttachTo("extradiv")
for (let i = 0; i <= 10; i++) {
await Utils.waitFor(1000)
features.ping()
new FixedUiElement("> " + (5 - i)).AttachTo("extradiv")
}
options.zoomToFeatures = false
features.setData([
{
feature: {
type: "Feature",
properties: {
hello: "world",
id: "" + 1,
},
geometry: {
type: "Point",
coordinates: [3.103, 51.10003],
},
},
freshness: new Date(),
},
])
new FixedUiElement("> OK").AttachTo("extradiv")
} }
main().then((_) => {}) main().then((_) => {})