forked from MapComplete/MapComplete
Add overlay layer possibility, fix #515
This commit is contained in:
parent
7e053b3ada
commit
891c449058
12 changed files with 263 additions and 56 deletions
|
@ -39,8 +39,8 @@ import {Tiles} from "./Models/TileRange";
|
||||||
import {TileHierarchyAggregator} from "./UI/ShowDataLayer/TileHierarchyAggregator";
|
import {TileHierarchyAggregator} from "./UI/ShowDataLayer/TileHierarchyAggregator";
|
||||||
import FilterConfig from "./Models/ThemeConfig/FilterConfig";
|
import FilterConfig from "./Models/ThemeConfig/FilterConfig";
|
||||||
import FilteredLayer from "./Models/FilteredLayer";
|
import FilteredLayer from "./Models/FilteredLayer";
|
||||||
import {BBox} from "./Logic/BBox";
|
|
||||||
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
||||||
|
import ShowOverlayLayer from "./UI/ShowDataLayer/ShowOverlayLayer";
|
||||||
|
|
||||||
export class InitUiElements {
|
export class InitUiElements {
|
||||||
static InitAll(
|
static InitAll(
|
||||||
|
@ -176,10 +176,9 @@ export class InitUiElements {
|
||||||
State.state.osmConnection.userDetails
|
State.state.osmConnection.userDetails
|
||||||
.addCallbackAndRunD(_ => addHomeMarker());
|
.addCallbackAndRunD(_ => addHomeMarker());
|
||||||
State.state.leafletMap.addCallbackAndRunD(_ => addHomeMarker())
|
State.state.leafletMap.addCallbackAndRunD(_ => addHomeMarker())
|
||||||
|
|
||||||
|
|
||||||
InitUiElements.setupAllLayerElements();
|
InitUiElements.setupAllLayerElements();
|
||||||
State.state.locationControl.ping();
|
State.state.locationControl.ping();
|
||||||
|
|
||||||
new SelectedFeatureHandler(Hash.hash, State.state)
|
new SelectedFeatureHandler(Hash.hash, State.state)
|
||||||
|
|
||||||
|
@ -506,6 +505,21 @@ export class InitUiElements {
|
||||||
);
|
);
|
||||||
}, state
|
}, state
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const initialized =new Set()
|
||||||
|
|
||||||
|
for (const overlayToggle of State.state.overlayToggles) {
|
||||||
|
new ShowOverlayLayer(overlayToggle.config, state.leafletMap, overlayToggle.isDisplayed)
|
||||||
|
initialized.add(overlayToggle.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const tileLayerSource of state.layoutToUse.tileLayerSources) {
|
||||||
|
if (initialized.has(tileLayerSource)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
new ShowOverlayLayer(tileLayerSource, state.leafletMap)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static setupAllLayerElements() {
|
private static setupAllLayerElements() {
|
||||||
|
|
|
@ -68,6 +68,9 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
||||||
const self = this;
|
const self = this;
|
||||||
Utils.downloadJson(url)
|
Utils.downloadJson(url)
|
||||||
.then(json => {
|
.then(json => {
|
||||||
|
if(json.elements === undefined || json.elements === null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (json.elements === [] && json.remarks.indexOf("runtime error") > 0) {
|
if (json.elements === [] && json.remarks.indexOf("runtime error") > 0) {
|
||||||
self.onFail("Runtime error (timeout)", url)
|
self.onFail("Runtime error (timeout)", url)
|
||||||
return;
|
return;
|
||||||
|
@ -108,7 +111,7 @@ export default class GeoJsonSource implements FeatureSourceForLayer, Tiled {
|
||||||
newFeatures.push({feature: feature, freshness: freshness})
|
newFeatures.push({feature: feature, freshness: freshness})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFeatures.length == 0) {
|
if ( newFeatures.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
|
||||||
import {LayerConfigJson} from "./LayerConfigJson";
|
import {LayerConfigJson} from "./LayerConfigJson";
|
||||||
|
import TilesourceConfig from "../TilesourceConfig";
|
||||||
|
import TilesourceConfigJson from "./TilesourceConfigJson";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the entire theme.
|
* Defines the entire theme.
|
||||||
|
@ -155,6 +157,11 @@ export interface LayoutConfigJson {
|
||||||
*/
|
*/
|
||||||
defaultBackgroundId?: string;
|
defaultBackgroundId?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define some (overlay) slippy map tilesources
|
||||||
|
*/
|
||||||
|
tileLayerSources?: TilesourceConfigJson[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of seconds that a feature is allowed to stay in the cache.
|
* The number of seconds that a feature is allowed to stay in the cache.
|
||||||
* The caching flow is as following:
|
* The caching flow is as following:
|
||||||
|
|
36
Models/ThemeConfig/Json/TilesourceConfigJson.ts
Normal file
36
Models/ThemeConfig/Json/TilesourceConfigJson.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* Configuration for a tilesource config
|
||||||
|
*/
|
||||||
|
export default interface TilesourceConfigJson {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path, where {x}, {y} and {z} will be substituted
|
||||||
|
*/
|
||||||
|
source: string,
|
||||||
|
|
||||||
|
isOverlay?: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How this will be shown in the selection menu.
|
||||||
|
* Make undefined if this may not be toggled
|
||||||
|
*/
|
||||||
|
name?: any | string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only visible at this or a higher zoom level
|
||||||
|
*/
|
||||||
|
minZoom?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only visible at this or a lower zoom level
|
||||||
|
*/
|
||||||
|
maxZoom?: number
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default state, set to false to hide by default
|
||||||
|
*/
|
||||||
|
defaultState: boolean;
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import {Utils} from "../../Utils";
|
||||||
import LayerConfig from "./LayerConfig";
|
import LayerConfig from "./LayerConfig";
|
||||||
import {LayerConfigJson} from "./Json/LayerConfigJson";
|
import {LayerConfigJson} from "./Json/LayerConfigJson";
|
||||||
import Constants from "../Constants";
|
import Constants from "../Constants";
|
||||||
|
import TilesourceConfig from "./TilesourceConfig";
|
||||||
|
|
||||||
export default class LayoutConfig {
|
export default class LayoutConfig {
|
||||||
public readonly id: string;
|
public readonly id: string;
|
||||||
|
@ -27,6 +28,7 @@ export default class LayoutConfig {
|
||||||
public readonly roamingRenderings: TagRenderingConfig[];
|
public readonly roamingRenderings: TagRenderingConfig[];
|
||||||
public readonly defaultBackgroundId?: string;
|
public readonly defaultBackgroundId?: string;
|
||||||
public layers: LayerConfig[];
|
public layers: LayerConfig[];
|
||||||
|
public tileLayerSources: TilesourceConfig[]
|
||||||
public readonly clustering?: {
|
public readonly clustering?: {
|
||||||
maxZoom: number,
|
maxZoom: number,
|
||||||
minNeededElements: number,
|
minNeededElements: number,
|
||||||
|
@ -108,6 +110,7 @@ export default class LayoutConfig {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.defaultBackgroundId = json.defaultBackgroundId;
|
this.defaultBackgroundId = json.defaultBackgroundId;
|
||||||
|
this.tileLayerSources = (json.tileLayerSources??[]).map((config, i) => new TilesourceConfig(config, `${this.id}.tileLayerSources[${i}]`))
|
||||||
this.layers = LayoutConfig.ExtractLayers(json, official, context);
|
this.layers = LayoutConfig.ExtractLayers(json, official, context);
|
||||||
|
|
||||||
// ALl the layers are constructed, let them share tagRenderings now!
|
// ALl the layers are constructed, let them share tagRenderings now!
|
||||||
|
|
38
Models/ThemeConfig/TilesourceConfig.ts
Normal file
38
Models/ThemeConfig/TilesourceConfig.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import TilesourceConfigJson from "./Json/TilesourceConfigJson";
|
||||||
|
import Translations from "../../UI/i18n/Translations";
|
||||||
|
import {Translation} from "../../UI/i18n/Translation";
|
||||||
|
|
||||||
|
export default class TilesourceConfig {
|
||||||
|
public readonly source: string
|
||||||
|
public readonly isOverlay: boolean
|
||||||
|
public readonly name: Translation
|
||||||
|
public readonly minzoom: number
|
||||||
|
public readonly maxzoom: number
|
||||||
|
public readonly defaultState: boolean;
|
||||||
|
|
||||||
|
constructor(config: TilesourceConfigJson, ctx: string = "") {
|
||||||
|
|
||||||
|
this.source = config.source;
|
||||||
|
this.isOverlay = config.isOverlay ?? false;
|
||||||
|
this.name = Translations.T(config.name)
|
||||||
|
this.minzoom = config.minZoom ?? 0
|
||||||
|
this.maxzoom = config.maxZoom ?? 999
|
||||||
|
this.defaultState = config.defaultState ?? true;
|
||||||
|
if (this.minzoom > this.maxzoom) {
|
||||||
|
throw "Invalid tilesourceConfig: minzoom should be smaller then maxzoom (at " + ctx + ")"
|
||||||
|
}
|
||||||
|
if (this.minzoom < 0) {
|
||||||
|
throw "minzoom should be > 0 (at " + ctx + ")"
|
||||||
|
}
|
||||||
|
if (this.maxzoom < 0) {
|
||||||
|
throw "maxzoom should be > 0 (at " + ctx + ")"
|
||||||
|
}
|
||||||
|
if (this.source.indexOf("{zoom}") >= 0) {
|
||||||
|
throw "Invalid source url: use {z} instead of {zoom} (at " + ctx + ".source)"
|
||||||
|
}
|
||||||
|
if(!this.defaultState && config.name === undefined){
|
||||||
|
throw "Disabling an overlay without a name is not possible"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
State.ts
8
State.ts
|
@ -19,6 +19,7 @@ import ChangeToElementsActor from "./Logic/Actors/ChangeToElementsActor";
|
||||||
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig";
|
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig";
|
||||||
import {BBox} from "./Logic/BBox";
|
import {BBox} from "./Logic/BBox";
|
||||||
import SelectedElementTagsUpdater from "./Logic/Actors/SelectedElementTagsUpdater";
|
import SelectedElementTagsUpdater from "./Logic/Actors/SelectedElementTagsUpdater";
|
||||||
|
import TilesourceConfig from "./Models/ThemeConfig/TilesourceConfig";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the global state: a bunch of UI-event sources
|
* Contains the global state: a bunch of UI-event sources
|
||||||
|
@ -57,6 +58,8 @@ export default class State {
|
||||||
|
|
||||||
public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([], "filteredLayers");
|
public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([], "filteredLayers");
|
||||||
|
|
||||||
|
public overlayToggles : { config: TilesourceConfig, isDisplayed: UIEventSource<boolean>}[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The latest element that was selected
|
The latest element that was selected
|
||||||
*/
|
*/
|
||||||
|
@ -420,6 +423,11 @@ export default class State {
|
||||||
.ping();
|
.ping();
|
||||||
|
|
||||||
new TitleHandler(this);
|
new TitleHandler(this);
|
||||||
|
|
||||||
|
this.overlayToggles = this.layoutToUse.tileLayerSources.filter(c => c.name !== undefined).map(c => ({
|
||||||
|
config: c,
|
||||||
|
isDisplayed: new UIEventSource<boolean>(c.defaultState)
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
private static asFloat(source: UIEventSource<string>): UIEventSource<number> {
|
private static asFloat(source: UIEventSource<string>): UIEventSource<number> {
|
||||||
|
|
|
@ -13,21 +13,71 @@ import State from "../../State";
|
||||||
import FilteredLayer from "../../Models/FilteredLayer";
|
import FilteredLayer from "../../Models/FilteredLayer";
|
||||||
import BackgroundSelector from "./BackgroundSelector";
|
import BackgroundSelector from "./BackgroundSelector";
|
||||||
import FilterConfig from "../../Models/ThemeConfig/FilterConfig";
|
import FilterConfig from "../../Models/ThemeConfig/FilterConfig";
|
||||||
|
import TilesourceConfig from "../../Models/ThemeConfig/TilesourceConfig";
|
||||||
|
|
||||||
export default class FilterView extends VariableUiElement {
|
export default class FilterView extends VariableUiElement {
|
||||||
constructor(filteredLayer: UIEventSource<FilteredLayer[]>) {
|
constructor(filteredLayer: UIEventSource<FilteredLayer[]>, tileLayers: { config: TilesourceConfig, isDisplayed: UIEventSource<boolean> }[]) {
|
||||||
const backgroundSelector = new Toggle(
|
const backgroundSelector = new Toggle(
|
||||||
new BackgroundSelector(),
|
new BackgroundSelector(),
|
||||||
undefined,
|
undefined,
|
||||||
State.state.featureSwitchBackgroundSlection
|
State.state.featureSwitchBackgroundSlection
|
||||||
)
|
)
|
||||||
super(
|
super(
|
||||||
filteredLayer.map((filteredLayers) =>
|
filteredLayer.map((filteredLayers) => {
|
||||||
filteredLayers?.map(l => FilterView.createOneFilteredLayerElement(l)).concat(backgroundSelector)
|
let elements = filteredLayers?.map(l => FilterView.createOneFilteredLayerElement(l))
|
||||||
|
elements = elements.concat(tileLayers.map(tl => FilterView.createOverlayToggle(tl)))
|
||||||
|
return elements.concat(backgroundSelector);
|
||||||
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static createOverlayToggle(config: { config: TilesourceConfig, isDisplayed: UIEventSource<boolean> }) {
|
||||||
|
|
||||||
|
const iconStyle = "width:1.5rem;height:1.5rem;margin-left:1.25rem;flex-shrink: 0;";
|
||||||
|
|
||||||
|
const icon = new Combine([Svg.checkbox_filled]).SetStyle(iconStyle);
|
||||||
|
const iconUnselected = new Combine([Svg.checkbox_empty]).SetStyle(
|
||||||
|
iconStyle
|
||||||
|
);
|
||||||
|
const name: Translation = config.config.name.Clone();
|
||||||
|
|
||||||
|
const styledNameChecked = name
|
||||||
|
.Clone()
|
||||||
|
.SetStyle("font-size:large;padding-left:1.25rem");
|
||||||
|
|
||||||
|
const styledNameUnChecked = name
|
||||||
|
.Clone()
|
||||||
|
.SetStyle("font-size:large;padding-left:1.25rem");
|
||||||
|
|
||||||
|
const zoomStatus =
|
||||||
|
new Toggle(
|
||||||
|
undefined,
|
||||||
|
Translations.t.general.layerSelection.zoomInToSeeThisLayer.Clone()
|
||||||
|
.SetClass("alert")
|
||||||
|
.SetStyle("display: block ruby;width:min-content;"),
|
||||||
|
State.state.locationControl.map(location => location.zoom >= config.config.minzoom)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
const style =
|
||||||
|
"display:flex;align-items:center;padding:0.5rem 0;";
|
||||||
|
const layerChecked = new Combine([icon, styledNameChecked, zoomStatus])
|
||||||
|
.SetStyle(style)
|
||||||
|
.onClick(() => config.isDisplayed.setData(false));
|
||||||
|
|
||||||
|
const layerNotChecked = new Combine([iconUnselected, styledNameUnChecked])
|
||||||
|
.SetStyle(style)
|
||||||
|
.onClick(() => config.isDisplayed.setData(true));
|
||||||
|
|
||||||
|
|
||||||
|
return new Toggle(
|
||||||
|
layerChecked,
|
||||||
|
layerNotChecked,
|
||||||
|
config.isDisplayed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static createOneFilteredLayerElement(filteredLayer: FilteredLayer) {
|
private static createOneFilteredLayerElement(filteredLayer: FilteredLayer) {
|
||||||
if (filteredLayer.layerDef.name === undefined) {
|
if (filteredLayer.layerDef.name === undefined) {
|
||||||
// Name is not defined: we hide this one
|
// Name is not defined: we hide this one
|
||||||
|
@ -104,16 +154,16 @@ export default class FilterView extends VariableUiElement {
|
||||||
listFilterElements.forEach((inputElement, i) =>
|
listFilterElements.forEach((inputElement, i) =>
|
||||||
inputElement[1].addCallback((changed) => {
|
inputElement[1].addCallback((changed) => {
|
||||||
const oldValue = flayer.appliedFilters.data
|
const oldValue = flayer.appliedFilters.data
|
||||||
|
|
||||||
if(changed === undefined){
|
if (changed === undefined) {
|
||||||
// Lets figure out which filter should be removed
|
// Lets figure out which filter should be removed
|
||||||
// We know this inputElement corresponds with layer.filters[i]
|
// We know this inputElement corresponds with layer.filters[i]
|
||||||
// SO, if there is a value in 'oldValue' with this filter, we have to recalculated
|
// SO, if there is a value in 'oldValue' with this filter, we have to recalculated
|
||||||
if(!oldValue.some(f => f.filter === layer.filters[i])){
|
if (!oldValue.some(f => f.filter === layer.filters[i])) {
|
||||||
// The filter to remove is already gone, we can stop
|
// The filter to remove is already gone, we can stop
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}else if(oldValue.some(f => f.filter === changed.filter && f.selected === changed.selected)){
|
} else if (oldValue.some(f => f.filter === changed.filter && f.selected === changed.selected)) {
|
||||||
// The changed value is already there
|
// The changed value is already there
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -126,16 +176,16 @@ export default class FilterView extends VariableUiElement {
|
||||||
);
|
);
|
||||||
|
|
||||||
flayer.appliedFilters.addCallbackAndRun(appliedFilters => {
|
flayer.appliedFilters.addCallbackAndRun(appliedFilters => {
|
||||||
for (let i = 0; i < layer.filters.length; i++){
|
for (let i = 0; i < layer.filters.length; i++) {
|
||||||
const filter = layer.filters[i];
|
const filter = layer.filters[i];
|
||||||
let foundMatch = undefined
|
let foundMatch = undefined
|
||||||
for (const appliedFilter of appliedFilters) {
|
for (const appliedFilter of appliedFilters) {
|
||||||
if(appliedFilter.filter === filter){
|
if (appliedFilter.filter === filter) {
|
||||||
foundMatch = appliedFilter
|
foundMatch = appliedFilter
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listFilterElements[i][1].setData(foundMatch)
|
listFilterElements[i][1].setData(foundMatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +222,7 @@ export default class FilterView extends VariableUiElement {
|
||||||
let options = filterConfig.options;
|
let options = filterConfig.options;
|
||||||
|
|
||||||
const values = options.map((f, i) => ({
|
const values = options.map((f, i) => ({
|
||||||
filter: filterConfig, selected: i
|
filter: filterConfig, selected: i
|
||||||
}))
|
}))
|
||||||
const radio = new RadioButton(
|
const radio = new RadioButton(
|
||||||
options.map(
|
options.map(
|
||||||
|
@ -183,13 +233,13 @@ export default class FilterView extends VariableUiElement {
|
||||||
dontStyle: true
|
dontStyle: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return [radio,
|
return [radio,
|
||||||
radio.GetValue().map(
|
radio.GetValue().map(
|
||||||
i => values[i],
|
i => values[i],
|
||||||
[],
|
[],
|
||||||
selected => {
|
selected => {
|
||||||
return selected?.selected
|
return selected?.selected
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {BBox} from "../../Logic/BBox";
|
||||||
|
|
||||||
export default class LeftControls extends Combine {
|
export default class LeftControls extends Combine {
|
||||||
|
|
||||||
constructor(state: {featurePipeline: FeaturePipeline, currentBounds: UIEventSource<BBox>, locationControl: UIEventSource<Loc>}) {
|
constructor(state: {featurePipeline: FeaturePipeline, currentBounds: UIEventSource<BBox>, locationControl: UIEventSource<Loc>, overlayToggles: any}) {
|
||||||
|
|
||||||
const toggledCopyright = new ScrollableFullScreen(
|
const toggledCopyright = new ScrollableFullScreen(
|
||||||
() => Translations.t.general.attribution.attributionTitle.Clone(),
|
() => Translations.t.general.attribution.attributionTitle.Clone(),
|
||||||
|
@ -52,12 +52,11 @@ export default class LeftControls extends Combine {
|
||||||
[State.state.featureSwitchExportAsPdf])
|
[State.state.featureSwitchExportAsPdf])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const toggledFilter = new Toggle(
|
const toggledFilter = new Toggle(
|
||||||
new ScrollableFullScreen(
|
new ScrollableFullScreen(
|
||||||
() => Translations.t.general.layerSelection.title.Clone(),
|
() => Translations.t.general.layerSelection.title.Clone(),
|
||||||
() =>
|
() =>
|
||||||
new FilterView(State.state.filteredLayers).SetClass(
|
new FilterView(State.state.filteredLayers, state.overlayToggles).SetClass(
|
||||||
"block p-1 rounded-full"
|
"block p-1 rounded-full"
|
||||||
),
|
),
|
||||||
undefined,
|
undefined,
|
||||||
|
|
45
UI/ShowDataLayer/ShowOverlayLayer.ts
Normal file
45
UI/ShowDataLayer/ShowOverlayLayer.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import TilesourceConfig from "../../Models/ThemeConfig/TilesourceConfig";
|
||||||
|
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
|
import * as L from "leaflet";
|
||||||
|
|
||||||
|
export default class ShowOverlayLayer {
|
||||||
|
|
||||||
|
constructor(config: TilesourceConfig,
|
||||||
|
leafletMap: UIEventSource<any>,
|
||||||
|
isShown: UIEventSource<boolean> = undefined) {
|
||||||
|
|
||||||
|
leafletMap.map(leaflet => {
|
||||||
|
if(leaflet === undefined){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tileLayer = L.tileLayer(config.source,
|
||||||
|
{
|
||||||
|
attribution: "",
|
||||||
|
maxZoom: config.maxzoom,
|
||||||
|
minZoom: config.minzoom,
|
||||||
|
// @ts-ignore
|
||||||
|
wmts: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if(isShown === undefined){
|
||||||
|
tileLayer.addTo(leaflet)
|
||||||
|
}
|
||||||
|
|
||||||
|
isShown?.addCallbackAndRunD(isShown => {
|
||||||
|
if(isShown){
|
||||||
|
tileLayer.addTo(leaflet)
|
||||||
|
}else{
|
||||||
|
leaflet.removeLayer(tileLayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
} )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -25,6 +25,18 @@
|
||||||
"minNeededFeatures": 25,
|
"minNeededFeatures": 25,
|
||||||
"maxZoom": 16
|
"maxZoom": 16
|
||||||
},
|
},
|
||||||
|
"tileLayerSources": [
|
||||||
|
{
|
||||||
|
"source": "https://tiles.osmuk.org/PropertyBoundaries/{z}/{x}/{y}.png",
|
||||||
|
"isOverlay": true,
|
||||||
|
"minZoom": 18,
|
||||||
|
"maxZoom": 20,
|
||||||
|
"defaultState": false,
|
||||||
|
"name": {
|
||||||
|
"en": "Parcel boundaries"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"layers": [
|
"layers": [
|
||||||
{
|
{
|
||||||
"id": "to_import",
|
"id": "to_import",
|
||||||
|
|
52
test.ts
52
test.ts
|
@ -1,34 +1,26 @@
|
||||||
import MoveWizard from "./UI/Popup/MoveWizard";
|
|
||||||
import State from "./State";
|
|
||||||
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
|
||||||
import MinimapImplementation from "./UI/Base/MinimapImplementation";
|
import MinimapImplementation from "./UI/Base/MinimapImplementation";
|
||||||
import MoveConfig from "./Models/ThemeConfig/MoveConfig";
|
import Minimap from "./UI/Base/Minimap";
|
||||||
import {FixedUiElement} from "./UI/Base/FixedUiElement";
|
import ShowOverlayLayer from "./UI/ShowDataLayer/ShowOverlayLayer";
|
||||||
import Combine from "./UI/Base/Combine";
|
import TilesourceConfig from "./Models/ThemeConfig/TilesourceConfig";
|
||||||
|
import Loc from "./Models/Loc";
|
||||||
|
import {UIEventSource} from "./Logic/UIEventSource";
|
||||||
|
|
||||||
|
|
||||||
State.state = new State(AllKnownLayouts.allKnownLayouts.get("bookcases"))
|
|
||||||
const feature = {
|
|
||||||
"type": "Feature",
|
|
||||||
"properties": {
|
|
||||||
id: "node/14925464"
|
|
||||||
},
|
|
||||||
"geometry": {
|
|
||||||
"type": "Point",
|
|
||||||
"coordinates": [
|
|
||||||
4.21875,
|
|
||||||
50.958426723359935
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
MinimapImplementation.initialize()
|
MinimapImplementation.initialize()
|
||||||
new MoveWizard(
|
|
||||||
feature,
|
|
||||||
State.state,
|
|
||||||
new MoveConfig({
|
|
||||||
enableRelocation: false,
|
|
||||||
enableImproveAccuracy: true
|
|
||||||
}, "test")).AttachTo("maindiv")
|
|
||||||
|
|
||||||
*/
|
const map = Minimap.createMiniMap({
|
||||||
|
location: new UIEventSource<Loc>({
|
||||||
|
zoom: 19,
|
||||||
|
lat: 51.51896,
|
||||||
|
lon: -0.11267
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
map.SetStyle("height: 50rem")
|
||||||
|
map.AttachTo("maindiv")
|
||||||
|
|
||||||
|
new ShowOverlayLayer(new TilesourceConfig({
|
||||||
|
"source": "https://tiles.osmuk.org/PropertyBoundaries/{z}/{x}/{y}.png",
|
||||||
|
"isOverlay": true,
|
||||||
|
minZoom: 18,
|
||||||
|
maxZoom: 20
|
||||||
|
}), map)
|
Loading…
Add table
Add a link
Reference in a new issue