forked from MapComplete/MapComplete
Refactoring: fix filters, remove obsolete code
This commit is contained in:
parent
0241f89d3d
commit
97aaa8e941
9 changed files with 122 additions and 302 deletions
|
@ -18,6 +18,11 @@ import StaticFeatureSource from "./StaticFeatureSource"
|
||||||
* Note that special layers (with `source=null` will be ignored)
|
* Note that special layers (with `source=null` will be ignored)
|
||||||
*/
|
*/
|
||||||
export default class LayoutSource extends FeatureSourceMerger {
|
export default class LayoutSource extends FeatureSourceMerger {
|
||||||
|
/**
|
||||||
|
* Indicates if a data source is loading something
|
||||||
|
* TODO fixme
|
||||||
|
*/
|
||||||
|
public readonly isLoading: Store<boolean> = new ImmutableStore(false)
|
||||||
constructor(
|
constructor(
|
||||||
layers: LayerConfig[],
|
layers: LayerConfig[],
|
||||||
featureSwitches: FeatureSwitchState,
|
featureSwitches: FeatureSwitchState,
|
||||||
|
|
|
@ -31,6 +31,7 @@ export default class FilteredLayer {
|
||||||
* Contains the current properties a feature should fulfill in order to match the filter
|
* Contains the current properties a feature should fulfill in order to match the filter
|
||||||
*/
|
*/
|
||||||
readonly currentFilter: Store<TagsFilter | undefined>
|
readonly currentFilter: Store<TagsFilter | undefined>
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
layer: LayerConfig,
|
layer: LayerConfig,
|
||||||
appliedFilters?: Map<string, UIEventSource<undefined | number | string>>,
|
appliedFilters?: Map<string, UIEventSource<undefined | number | string>>,
|
||||||
|
@ -41,104 +42,34 @@ export default class FilteredLayer {
|
||||||
this.appliedFilters =
|
this.appliedFilters =
|
||||||
appliedFilters ?? new Map<string, UIEventSource<number | string | undefined>>()
|
appliedFilters ?? new Map<string, UIEventSource<number | string | undefined>>()
|
||||||
|
|
||||||
const hasFilter = new UIEventSource<boolean>(false)
|
|
||||||
const self = this
|
const self = this
|
||||||
const currentTags = new UIEventSource<TagsFilter>(undefined)
|
const currentTags = new UIEventSource<TagsFilter>(undefined)
|
||||||
|
|
||||||
this.appliedFilters.forEach((filterSrc) => {
|
this.appliedFilters.forEach((filterSrc) => {
|
||||||
filterSrc.addCallbackAndRun((filter) => {
|
filterSrc.addCallbackAndRun((_) => {
|
||||||
if ((filter ?? 0) !== 0) {
|
currentTags.setData(self.calculateCurrentTags())
|
||||||
hasFilter.setData(true)
|
|
||||||
currentTags.setData(self.calculateCurrentTags())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const hf = Array.from(self.appliedFilters.values()).some((f) => (f.data ?? 0) !== 0)
|
|
||||||
if (hf) {
|
|
||||||
currentTags.setData(self.calculateCurrentTags())
|
|
||||||
} else {
|
|
||||||
currentTags.setData(undefined)
|
|
||||||
}
|
|
||||||
hasFilter.setData(hf)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
this.hasFilter = currentTags.map((ct) => ct !== undefined)
|
||||||
currentTags.addCallbackAndRunD((t) => console.log("Current filter is", t))
|
|
||||||
|
|
||||||
this.currentFilter = currentTags
|
this.currentFilter = currentTags
|
||||||
}
|
}
|
||||||
|
|
||||||
private calculateCurrentTags(): TagsFilter {
|
|
||||||
let needed: TagsFilter[] = []
|
|
||||||
for (const filter of this.layerDef.filters) {
|
|
||||||
const state = this.appliedFilters.get(filter.id)
|
|
||||||
if (state.data === undefined) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (filter.options[0].fields.length > 0) {
|
|
||||||
const fieldProperties = FilteredLayer.stringToFieldProperties(<string>state.data)
|
|
||||||
const asTags = FilteredLayer.fieldsToTags(filter.options[0], fieldProperties)
|
|
||||||
needed.push(asTags)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
needed.push(filter.options[state.data].osmTags)
|
|
||||||
}
|
|
||||||
needed = Utils.NoNull(needed)
|
|
||||||
if (needed.length == 0) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
let tags: TagsFilter
|
|
||||||
|
|
||||||
if (needed.length == 1) {
|
|
||||||
tags = needed[1]
|
|
||||||
} else {
|
|
||||||
tags = new And(needed)
|
|
||||||
}
|
|
||||||
let optimized = tags.optimize()
|
|
||||||
if (optimized === true) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if (optimized === false) {
|
|
||||||
return tags
|
|
||||||
}
|
|
||||||
return optimized
|
|
||||||
}
|
|
||||||
|
|
||||||
public static fieldsToString(values: Record<string, string>): string {
|
public static fieldsToString(values: Record<string, string>): string {
|
||||||
|
for (const key in values) {
|
||||||
|
if (values[key] === "") {
|
||||||
|
delete values[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
return JSON.stringify(values)
|
return JSON.stringify(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static stringToFieldProperties(value: string): Record<string, string> {
|
public static stringToFieldProperties(value: string): Record<string, string> {
|
||||||
return JSON.parse(value)
|
const values = JSON.parse(value)
|
||||||
}
|
for (const key in values) {
|
||||||
|
if (values[key] === "") {
|
||||||
private static fieldsToTags(
|
delete values[key]
|
||||||
option: FilterConfigOption,
|
}
|
||||||
fieldstate: string | Record<string, string>
|
|
||||||
): TagsFilter {
|
|
||||||
let properties: Record<string, string>
|
|
||||||
if (typeof fieldstate === "string") {
|
|
||||||
properties = FilteredLayer.stringToFieldProperties(fieldstate)
|
|
||||||
} else {
|
|
||||||
properties = fieldstate
|
|
||||||
}
|
}
|
||||||
console.log("Building tagsspec with properties", properties)
|
return values
|
||||||
const tagsSpec = Utils.WalkJson(option.originalTagsSpec, (v) => {
|
|
||||||
if (typeof v !== "string") {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const key in properties) {
|
|
||||||
v = (<string>v).replace("{" + key + "}", properties[key])
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
|
||||||
})
|
|
||||||
return TagUtils.Tag(tagsSpec)
|
|
||||||
}
|
|
||||||
|
|
||||||
public disableAllFilters(): void {
|
|
||||||
this.appliedFilters.forEach((value) => value.setData(undefined))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -177,10 +108,42 @@ export default class FilteredLayer {
|
||||||
|
|
||||||
const appliedFilters = new Map<string, UIEventSource<undefined | number | string>>()
|
const appliedFilters = new Map<string, UIEventSource<undefined | number | string>>()
|
||||||
for (const subfilter of layer.filters) {
|
for (const subfilter of layer.filters) {
|
||||||
appliedFilters.set(subfilter.id, subfilter.initState())
|
appliedFilters.set(subfilter.id, subfilter.initState(layer.id))
|
||||||
}
|
}
|
||||||
return new FilteredLayer(layer, appliedFilters, isDisplayed)
|
return new FilteredLayer(layer, appliedFilters, isDisplayed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static fieldsToTags(
|
||||||
|
option: FilterConfigOption,
|
||||||
|
fieldstate: string | Record<string, string>
|
||||||
|
): TagsFilter | undefined {
|
||||||
|
let properties: Record<string, string>
|
||||||
|
if (typeof fieldstate === "string") {
|
||||||
|
properties = FilteredLayer.stringToFieldProperties(fieldstate)
|
||||||
|
} else {
|
||||||
|
properties = fieldstate
|
||||||
|
}
|
||||||
|
console.log("Building tagsspec with properties", properties)
|
||||||
|
const missingKeys = option.fields
|
||||||
|
.map((f) => f.name)
|
||||||
|
.filter((key) => properties[key] === undefined)
|
||||||
|
if (missingKeys.length > 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const tagsSpec = Utils.WalkJson(option.originalTagsSpec, (v) => {
|
||||||
|
if (typeof v !== "string") {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in properties) {
|
||||||
|
v = (<string>v).replace("{" + key + "}", properties[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
})
|
||||||
|
return TagUtils.Tag(tagsSpec)
|
||||||
|
}
|
||||||
|
|
||||||
private static getPref(
|
private static getPref(
|
||||||
osmConnection: OsmConnection,
|
osmConnection: OsmConnection,
|
||||||
key: string,
|
key: string,
|
||||||
|
@ -202,4 +165,49 @@ export default class FilteredLayer {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public disableAllFilters(): void {
|
||||||
|
this.appliedFilters.forEach((value) => value.setData(undefined))
|
||||||
|
}
|
||||||
|
|
||||||
|
private calculateCurrentTags(): TagsFilter {
|
||||||
|
let needed: TagsFilter[] = []
|
||||||
|
for (const filter of this.layerDef.filters) {
|
||||||
|
const state = this.appliedFilters.get(filter.id)
|
||||||
|
if (state.data === undefined) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (filter.options[0].fields.length > 0) {
|
||||||
|
// This is a filter with fields
|
||||||
|
// We calculate the fields
|
||||||
|
const fieldProperties = FilteredLayer.stringToFieldProperties(<string>state.data)
|
||||||
|
const asTags = FilteredLayer.fieldsToTags(filter.options[0], fieldProperties)
|
||||||
|
console.log("Current field properties:", state.data, fieldProperties, asTags)
|
||||||
|
if (asTags) {
|
||||||
|
needed.push(asTags)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
needed.push(filter.options[state.data].osmTags)
|
||||||
|
}
|
||||||
|
needed = Utils.NoNull(needed)
|
||||||
|
if (needed.length == 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
let tags: TagsFilter
|
||||||
|
|
||||||
|
if (needed.length == 1) {
|
||||||
|
tags = needed[0]
|
||||||
|
} else {
|
||||||
|
tags = new And(needed)
|
||||||
|
}
|
||||||
|
let optimized = tags.optimize()
|
||||||
|
if (optimized === true) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (optimized === false) {
|
||||||
|
return tags
|
||||||
|
}
|
||||||
|
return optimized
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,10 +144,12 @@ export default class FilterConfig {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public initState(): UIEventSource<undefined | number | string> {
|
public initState(layerId: string): UIEventSource<undefined | number | string> {
|
||||||
let defaultValue = ""
|
let defaultValue = ""
|
||||||
if (this.options.length > 1) {
|
if (this.options.length > 1) {
|
||||||
defaultValue = "" + (this.defaultSelection ?? 0)
|
defaultValue = "" + (this.defaultSelection ?? 0)
|
||||||
|
} else if (this.options[0].fields?.length > 0) {
|
||||||
|
defaultValue = "{}"
|
||||||
} else {
|
} else {
|
||||||
// Only a single option
|
// Only a single option
|
||||||
if (this.defaultSelection === 0) {
|
if (this.defaultSelection === 0) {
|
||||||
|
@ -157,7 +159,7 @@ export default class FilterConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const qp = QueryParameters.GetQueryParameter(
|
const qp = QueryParameters.GetQueryParameter(
|
||||||
"filter-" + this.id,
|
`filter-${layerId}-${this.id}`,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
"State of filter " + this.id
|
"State of filter " + this.id
|
||||||
)
|
)
|
||||||
|
|
|
@ -116,7 +116,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
const self = this
|
const self = this
|
||||||
this.layerState = new LayerState(this.osmConnection, layout.layers, layout.id)
|
this.layerState = new LayerState(this.osmConnection, layout.layers, layout.id)
|
||||||
this.newFeatures = new SimpleFeatureSource(undefined)
|
this.newFeatures = new SimpleFeatureSource(undefined)
|
||||||
this.indexedFeatures = new LayoutSource(
|
const layoutSource = new LayoutSource(
|
||||||
layout.layers,
|
layout.layers,
|
||||||
this.featureSwitches,
|
this.featureSwitches,
|
||||||
this.newFeatures,
|
this.newFeatures,
|
||||||
|
@ -124,6 +124,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
this.osmConnection.Backend(),
|
this.osmConnection.Backend(),
|
||||||
(id) => self.layerState.filteredLayers.get(id).isDisplayed
|
(id) => self.layerState.filteredLayers.get(id).isDisplayed
|
||||||
)
|
)
|
||||||
|
this.indexedFeatures = layoutSource
|
||||||
|
this.dataIsLoading = layoutSource.isLoading
|
||||||
const lastClick = (this.lastClickObject = new LastClickFeatureSource(
|
const lastClick = (this.lastClickObject = new LastClickFeatureSource(
|
||||||
this.mapProperties.lastClickLocation,
|
this.mapProperties.lastClickLocation,
|
||||||
this.layout
|
this.layout
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
/*If no snapping needed: the value is simply the map location;
|
/*If no snapping needed: the value is simply the map location;
|
||||||
* If snapping is needed: the value will be set later on by the snapping feature source
|
* If snapping is needed: the value will be set later on by the snapping feature source
|
||||||
* */
|
* */
|
||||||
location: snapToLayers.length === 0 ? value : new UIEventSource<{ lon: number; lat: number }>(coordinate),
|
location: snapToLayers?.length > 0 ? new UIEventSource<{ lon: number; lat: number }>(coordinate) :value,
|
||||||
bounds: new UIEventSource<BBox>(undefined),
|
bounds: new UIEventSource<BBox>(undefined),
|
||||||
allowMoving: new UIEventSource<boolean>(true),
|
allowMoving: new UIEventSource<boolean>(true),
|
||||||
allowZooming: new UIEventSource<boolean>(true),
|
allowZooming: new UIEventSource<boolean>(true),
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { Tag } from "../../Logic/Tags/Tag"
|
||||||
import { SpecialVisualizationState } from "../SpecialVisualization"
|
import { SpecialVisualizationState } from "../SpecialVisualization"
|
||||||
import { Feature } from "geojson"
|
import { Feature } from "geojson"
|
||||||
import { FixedUiElement } from "../Base/FixedUiElement"
|
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||||
|
import Combine from "../Base/Combine"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The SimpleAddUI is a single panel, which can have multiple states:
|
* The SimpleAddUI is a single panel, which can have multiple states:
|
||||||
|
@ -33,83 +34,8 @@ export interface PresetInfo extends PresetConfig {
|
||||||
boundsFactor?: 0.25 | number
|
boundsFactor?: 0.25 | number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class SimpleAddUI extends Toggle {
|
export default class SimpleAddUI extends Combine {
|
||||||
constructor(state: SpecialVisualizationState) {
|
constructor(state: SpecialVisualizationState) {
|
||||||
const takeLocationFrom = state.mapProperties.lastClickLocation
|
super([])
|
||||||
const selectedPreset = new UIEventSource<PresetInfo>(undefined)
|
|
||||||
|
|
||||||
takeLocationFrom.addCallback((_) => selectedPreset.setData(undefined))
|
|
||||||
|
|
||||||
async function createNewPoint(
|
|
||||||
tags: Tag[],
|
|
||||||
location: { lat: number; lon: number },
|
|
||||||
snapOntoWay?: OsmWay
|
|
||||||
): Promise<void> {
|
|
||||||
if (snapOntoWay) {
|
|
||||||
tags.push(new Tag("_referencing_ways", "way/" + snapOntoWay.id))
|
|
||||||
}
|
|
||||||
const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, {
|
|
||||||
theme: state.layout?.id ?? "unkown",
|
|
||||||
changeType: "create",
|
|
||||||
snapOnto: snapOntoWay,
|
|
||||||
})
|
|
||||||
await state.changes.applyAction(newElementAction)
|
|
||||||
selectedPreset.setData(undefined)
|
|
||||||
const selectedFeature: Feature = state.indexedFeatures.featuresById.data.get(
|
|
||||||
newElementAction.newElementId
|
|
||||||
)
|
|
||||||
state.selectedElement.setData(selectedFeature)
|
|
||||||
Hash.hash.setData(newElementAction.newElementId)
|
|
||||||
}
|
|
||||||
|
|
||||||
const addUi = new VariableUiElement(
|
|
||||||
selectedPreset.map((preset) => {
|
|
||||||
function confirm(
|
|
||||||
tags: any[],
|
|
||||||
location: { lat: number; lon: number },
|
|
||||||
snapOntoWayId?: WayId
|
|
||||||
) {
|
|
||||||
if (snapOntoWayId === undefined) {
|
|
||||||
createNewPoint(tags, location, undefined)
|
|
||||||
} else {
|
|
||||||
OsmObject.DownloadObject(snapOntoWayId).addCallbackAndRunD((way) => {
|
|
||||||
createNewPoint(tags, location, way)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancel() {
|
|
||||||
selectedPreset.setData(undefined)
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = Translations.t.general.add.addNew.Subs(
|
|
||||||
{ category: preset.name },
|
|
||||||
preset.name["context"]
|
|
||||||
)
|
|
||||||
return new FixedUiElement("ConfirmLocationOfPoint...") /*ConfirmLocationOfPoint(
|
|
||||||
state,
|
|
||||||
filterViewIsOpened,
|
|
||||||
preset,
|
|
||||||
message,
|
|
||||||
takeLocationFrom.data,
|
|
||||||
confirm,
|
|
||||||
cancel,
|
|
||||||
() => {
|
|
||||||
selectedPreset.setData(undefined)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cancelIcon: Svg.back_svg(),
|
|
||||||
cancelText: Translations.t.general.add.backToSelect,
|
|
||||||
}
|
|
||||||
)*/
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
super(
|
|
||||||
new Loading(Translations.t.general.add.stillLoading).SetClass("alert"),
|
|
||||||
addUi,
|
|
||||||
state.dataIsLoading
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,16 @@
|
||||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import BaseUIElement from "../BaseUIElement"
|
import BaseUIElement from "../BaseUIElement"
|
||||||
import LocationInput from "../Input/LocationInput"
|
|
||||||
import { BBox } from "../../Logic/BBox"
|
|
||||||
import { TagUtils } from "../../Logic/Tags/TagUtils"
|
|
||||||
import { SubtleButton } from "../Base/SubtleButton"
|
import { SubtleButton } from "../Base/SubtleButton"
|
||||||
import Combine from "../Base/Combine"
|
import Combine from "../Base/Combine"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import Svg from "../../Svg"
|
import Svg from "../../Svg"
|
||||||
import Toggle from "../Input/Toggle"
|
import Toggle from "../Input/Toggle"
|
||||||
import { PresetInfo } from "../BigComponents/SimpleAddUI"
|
import { PresetInfo } from "../BigComponents/SimpleAddUI"
|
||||||
import Title from "../Base/Title"
|
|
||||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||||
import { Tag } from "../../Logic/Tags/Tag"
|
import { Tag } from "../../Logic/Tags/Tag"
|
||||||
import { WayId } from "../../Models/OsmFeature"
|
import { WayId } from "../../Models/OsmFeature"
|
||||||
import { Translation } from "../i18n/Translation"
|
import { Translation } from "../i18n/Translation"
|
||||||
import { Feature } from "geojson"
|
|
||||||
import { AvailableRasterLayers } from "../../Models/RasterLayers"
|
|
||||||
import { SpecialVisualizationState } from "../SpecialVisualization"
|
import { SpecialVisualizationState } from "../SpecialVisualization"
|
||||||
import ClippedFeatureSource from "../../Logic/FeatureSource/Sources/ClippedFeatureSource"
|
|
||||||
|
|
||||||
export default class ConfirmLocationOfPoint extends Combine {
|
export default class ConfirmLocationOfPoint extends Combine {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -38,76 +31,6 @@ export default class ConfirmLocationOfPoint extends Combine {
|
||||||
cancelText?: string | Translation
|
cancelText?: string | Translation
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
let preciseInput: LocationInput = undefined
|
|
||||||
if (preset.preciseInput !== undefined) {
|
|
||||||
// Create location input
|
|
||||||
|
|
||||||
// We uncouple the event source
|
|
||||||
const zloc = { ...loc, zoom: 19 }
|
|
||||||
const locationSrc = new UIEventSource(zloc)
|
|
||||||
|
|
||||||
let backgroundLayer = new UIEventSource(
|
|
||||||
state?.mapProperties.rasterLayer?.data ?? AvailableRasterLayers.osmCarto
|
|
||||||
)
|
|
||||||
if (preset.preciseInput.preferredBackground) {
|
|
||||||
const defaultBackground = AvailableRasterLayers.SelectBestLayerAccordingTo(
|
|
||||||
locationSrc,
|
|
||||||
new UIEventSource<string | string[]>(preset.preciseInput.preferredBackground)
|
|
||||||
)
|
|
||||||
// Note that we _break the link_ here, as the minimap will take care of the switching!
|
|
||||||
backgroundLayer.setData(defaultBackground.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
let snapToFeatures: UIEventSource<Feature[]> = undefined
|
|
||||||
let mapBounds: UIEventSource<BBox> = undefined
|
|
||||||
if (preset.preciseInput.snapToLayers && preset.preciseInput.snapToLayers.length > 0) {
|
|
||||||
snapToFeatures = new UIEventSource<Feature[]>([])
|
|
||||||
mapBounds = new UIEventSource<BBox>(undefined)
|
|
||||||
}
|
|
||||||
|
|
||||||
const tags = TagUtils.KVtoProperties(preset.tags ?? [])
|
|
||||||
preciseInput = new LocationInput({
|
|
||||||
mapBackground: backgroundLayer,
|
|
||||||
centerLocation: locationSrc,
|
|
||||||
snapTo: snapToFeatures,
|
|
||||||
renderLayerForSnappedPoint: preset.layerToAddTo.layerDef,
|
|
||||||
snappedPointTags: tags,
|
|
||||||
maxSnapDistance: preset.preciseInput.maxSnapDistance,
|
|
||||||
bounds: mapBounds,
|
|
||||||
state: <any>state,
|
|
||||||
})
|
|
||||||
preciseInput.installBounds(preset.boundsFactor ?? 0.25, true)
|
|
||||||
preciseInput
|
|
||||||
.SetClass("rounded-xl overflow-hidden border border-gray")
|
|
||||||
.SetStyle("height: 18rem; max-height: 50vh")
|
|
||||||
|
|
||||||
if (preset.preciseInput.snapToLayers && preset.preciseInput.snapToLayers.length > 0) {
|
|
||||||
// We have to snap to certain layers.
|
|
||||||
// Lets fetch them
|
|
||||||
|
|
||||||
let loadedBbox: BBox = undefined
|
|
||||||
mapBounds?.addCallbackAndRunD((bbox) => {
|
|
||||||
if (loadedBbox !== undefined && bbox.isContainedIn(loadedBbox)) {
|
|
||||||
// All is already there
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bbox = bbox.pad(
|
|
||||||
Math.max(preset.boundsFactor ?? 0.25, 2),
|
|
||||||
Math.max(preset.boundsFactor ?? 0.25, 2)
|
|
||||||
)
|
|
||||||
loadedBbox = bbox
|
|
||||||
const sources = preset.preciseInput.snapToLayers.map(
|
|
||||||
(layerId) =>
|
|
||||||
new ClippedFeatureSource(
|
|
||||||
state.perLayer.get(layerId),
|
|
||||||
bbox.asGeoJson({})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let confirmButton: BaseUIElement = new SubtleButton(
|
let confirmButton: BaseUIElement = new SubtleButton(
|
||||||
preset.icon(),
|
preset.icon(),
|
||||||
new Combine([confirmText]).SetClass("flex flex-col")
|
new Combine([confirmText]).SetClass("flex flex-col")
|
||||||
|
@ -119,38 +42,12 @@ export default class ConfirmLocationOfPoint extends Combine {
|
||||||
.map((gf) => gf.onNewPoint.tags)
|
.map((gf) => gf.onNewPoint.tags)
|
||||||
const globalTags: Tag[] = [].concat(...globalFilterTagsToAdd)
|
const globalTags: Tag[] = [].concat(...globalFilterTagsToAdd)
|
||||||
console.log("Global tags to add are: ", globalTags)
|
console.log("Global tags to add are: ", globalTags)
|
||||||
confirm(
|
|
||||||
[...preset.tags, ...globalTags],
|
|
||||||
preciseInput?.GetValue()?.data ?? loc,
|
|
||||||
preciseInput?.snappedOnto?.data?.properties?.id
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (preciseInput !== undefined) {
|
confirmButton = new Combine([confirmButton])
|
||||||
confirmButton = new Combine([preciseInput, confirmButton])
|
|
||||||
} else {
|
|
||||||
confirmButton = new Combine([confirmButton])
|
|
||||||
}
|
|
||||||
|
|
||||||
let openLayerOrConfirm = confirmButton
|
let openLayerOrConfirm = confirmButton
|
||||||
|
|
||||||
const disableFilter = new SubtleButton(
|
|
||||||
new Combine([
|
|
||||||
Svg.filter_ui().SetClass("absolute w-full"),
|
|
||||||
Svg.cross_bottom_right_svg().SetClass("absolute red-svg"),
|
|
||||||
]).SetClass("relative"),
|
|
||||||
new Combine([
|
|
||||||
Translations.t.general.add.disableFiltersExplanation.Clone(),
|
|
||||||
Translations.t.general.add.disableFilters.Clone().SetClass("text-xl"),
|
|
||||||
]).SetClass("flex flex-col")
|
|
||||||
).onClick(() => {
|
|
||||||
const appliedFilters = preset.layerToAddTo.appliedFilters
|
|
||||||
appliedFilters.data.forEach((_, k) => appliedFilters.data.set(k, undefined))
|
|
||||||
appliedFilters.ping()
|
|
||||||
cancel()
|
|
||||||
closePopup()
|
|
||||||
})
|
|
||||||
|
|
||||||
// We assume the number of global filters won't change during the run of the program
|
// We assume the number of global filters won't change during the run of the program
|
||||||
for (let i = 0; i < state.globalFilters.data.length; i++) {
|
for (let i = 0; i < state.globalFilters.data.length; i++) {
|
||||||
const hasBeenCheckedOf = new UIEventSource(false)
|
const hasBeenCheckedOf = new UIEventSource(false)
|
||||||
|
@ -178,31 +75,6 @@ export default class ConfirmLocationOfPoint extends Combine {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If at least one filter is active which _might_ hide a newly added item, this blocks the preset and requests the filter to be disabled
|
super([openLayerOrConfirm])
|
||||||
const disableFiltersOrConfirm = new Toggle(openLayerOrConfirm, disableFilter)
|
|
||||||
|
|
||||||
const cancelButton = new SubtleButton(
|
|
||||||
options?.cancelIcon ?? Svg.close_ui(),
|
|
||||||
options?.cancelText ?? Translations.t.general.cancel
|
|
||||||
).onClick(cancel)
|
|
||||||
|
|
||||||
let examples: BaseUIElement = undefined
|
|
||||||
if (preset.exampleImages !== undefined && preset.exampleImages.length > 0) {
|
|
||||||
examples = new Combine([new Title()])
|
|
||||||
}
|
|
||||||
|
|
||||||
super([
|
|
||||||
new Toggle(
|
|
||||||
Translations.t.general.testing.SetClass("alert"),
|
|
||||||
undefined,
|
|
||||||
state.featureSwitchIsTesting
|
|
||||||
),
|
|
||||||
disableFiltersOrConfirm,
|
|
||||||
cancelButton,
|
|
||||||
preset.description,
|
|
||||||
examples,
|
|
||||||
])
|
|
||||||
|
|
||||||
this.SetClass("flex flex-col")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
let confirmedCategory = false;
|
let confirmedCategory = false;
|
||||||
$: if (selectedPreset === undefined) {
|
$: if (selectedPreset === undefined) {
|
||||||
confirmedCategory = false;
|
confirmedCategory = false;
|
||||||
creating = false
|
creating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let flayer: FilteredLayer = undefined;
|
let flayer: FilteredLayer = undefined;
|
||||||
|
@ -51,6 +51,7 @@
|
||||||
|
|
||||||
const zoom = state.mapProperties.zoom;
|
const zoom = state.mapProperties.zoom;
|
||||||
|
|
||||||
|
const isLoading = state.dataIsLoading;
|
||||||
let preciseCoordinate: UIEventSource<{ lon: number, lat: number }> = new UIEventSource(undefined);
|
let preciseCoordinate: UIEventSource<{ lon: number, lat: number }> = new UIEventSource(undefined);
|
||||||
let snappedToObject: UIEventSource<string> = new UIEventSource<string>(undefined);
|
let snappedToObject: UIEventSource<string> = new UIEventSource<string>(undefined);
|
||||||
|
|
||||||
|
@ -95,7 +96,6 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
state.newFeatures.features.ping();
|
state.newFeatures.features.ping();
|
||||||
console.log("New features:", state.newFeatures.features.data )
|
|
||||||
{
|
{
|
||||||
// Set some metainfo
|
// Set some metainfo
|
||||||
const tagsStore = state.featureProperties.getStore(newId);
|
const tagsStore = state.featureProperties.getStore(newId);
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
abort();
|
abort();
|
||||||
state.selectedElement.setData(feature);
|
state.selectedElement.setData(feature);
|
||||||
state.selectedLayer.setData(selectedPreset.layer);
|
state.selectedLayer.setData(selectedPreset.layer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -123,8 +123,13 @@
|
||||||
<LoginButton osmConnection={state.osmConnection} slot="not-logged-in">
|
<LoginButton osmConnection={state.osmConnection} slot="not-logged-in">
|
||||||
<Tr slot="message" t={Translations.t.general.add.pleaseLogin} />
|
<Tr slot="message" t={Translations.t.general.add.pleaseLogin} />
|
||||||
</LoginButton>
|
</LoginButton>
|
||||||
|
{#if $isLoading}
|
||||||
{#if $zoom < Constants.minZoomLevelToAddNewPoint}
|
<div class="alert">
|
||||||
|
<Loading>
|
||||||
|
<Tr t={Translations.t.general.add.stillLoading} />
|
||||||
|
</Loading>
|
||||||
|
</div>
|
||||||
|
{:else if $zoom < Constants.minZoomLevelToAddNewPoint}
|
||||||
<div class="alert">
|
<div class="alert">
|
||||||
<Tr t={Translations.t.general.add.zoomInFurther}></Tr>
|
<Tr t={Translations.t.general.add.zoomInFurther}></Tr>
|
||||||
</div>
|
</div>
|
||||||
|
|
2
test.ts
2
test.ts
|
@ -2,7 +2,7 @@ import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
||||||
import ThemeViewGUI from "./UI/ThemeViewGUI.svelte"
|
import ThemeViewGUI from "./UI/ThemeViewGUI.svelte"
|
||||||
import { FixedUiElement } from "./UI/Base/FixedUiElement"
|
import { FixedUiElement } from "./UI/Base/FixedUiElement"
|
||||||
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig"
|
import LayoutConfig from "./Models/ThemeConfig/LayoutConfig"
|
||||||
import * as theme from "./assets/generated/themes/aed.json"
|
import * as theme from "./assets/generated/themes/shops.json"
|
||||||
import ThemeViewState from "./Models/ThemeViewState"
|
import ThemeViewState from "./Models/ThemeViewState"
|
||||||
import Combine from "./UI/Base/Combine"
|
import Combine from "./UI/Base/Combine"
|
||||||
import SpecialVisualizations from "./UI/SpecialVisualizations"
|
import SpecialVisualizations from "./UI/SpecialVisualizations"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue