refactoring(maplibre): WIP

This commit is contained in:
Pieter Vander Vennet 2023-03-24 19:21:15 +01:00
parent 231d67361e
commit 4d48b1cf2b
89 changed files with 1166 additions and 3973 deletions

View file

@ -1,4 +1,4 @@
import { UIEventSource } from "../../Logic/UIEventSource"
import { ImmutableStore, UIEventSource } from "../../Logic/UIEventSource";
import Combine from "../Base/Combine"
import Translations from "../i18n/Translations"
import { VariableUiElement } from "../Base/VariableUIElement"
@ -24,13 +24,13 @@ export default class AddNewMarker extends Combine {
for (const preset of filteredLayer.layerDef.presets) {
const tags = TagUtils.KVtoProperties(preset.tags)
const icon = layer.mapRendering[0]
.GenerateLeafletStyle(new UIEventSource<any>(tags), false)
.RenderIcon(new ImmutableStore<any>(tags), false)
.html.SetClass("block relative")
.SetStyle("width: 42px; height: 42px;")
icons.push(icon)
if (last === undefined) {
last = layer.mapRendering[0]
.GenerateLeafletStyle(new UIEventSource<any>(tags), false)
.RenderIcon(new ImmutableStore<any>(tags), false)
.html.SetClass("block relative")
.SetStyle("width: 42px; height: 42px;")
}

View file

@ -1,92 +0,0 @@
import Link from "../Base/Link"
import Svg from "../../Svg"
import Combine from "../Base/Combine"
import { UIEventSource } from "../../Logic/UIEventSource"
import UserDetails from "../../Logic/Osm/OsmConnection"
import Constants from "../../Models/Constants"
import Loc from "../../Models/Loc"
import { VariableUiElement } from "../Base/VariableUIElement"
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
import { BBox } from "../../Logic/BBox"
import { Utils } from "../../Utils"
import Translations from "../i18n/Translations"
/**
* The bottom right attribution panel in the leaflet map
*/
export default class Attribution extends Combine {
constructor(
location: UIEventSource<Loc>,
userDetails: UIEventSource<UserDetails>,
layoutToUse: LayoutConfig,
currentBounds: UIEventSource<BBox>
) {
const mapComplete = new Link(
`Mapcomplete ${Constants.vNumber}`,
"https://github.com/pietervdvn/MapComplete",
true
)
const reportBug = new Link(
Svg.bug_ui().SetClass("small-image"),
"https://github.com/pietervdvn/MapComplete/issues",
true
)
const layoutId = layoutToUse?.id
const stats = new Link(
Svg.statistics_ui().SetClass("small-image"),
Utils.OsmChaLinkFor(31, layoutId),
true
)
const idLink = location.map(
(location) =>
`https://www.openstreetmap.org/edit?editor=id#map=${location?.zoom ?? 0}/${
location?.lat ?? 0
}/${location?.lon ?? 0}`
)
const editHere = new Link(Svg.pencil_ui().SetClass("small-image"), idLink, true)
const mapillaryLink = location.map(
(location) =>
`https://www.mapillary.com/app/?focus=map&lat=${location?.lat ?? 0}&lng=${
location?.lon ?? 0
}&z=${Math.max((location?.zoom ?? 2) - 1, 1)}`
)
const mapillary = new Link(
Svg.mapillary_black_ui().SetClass("small-image"),
mapillaryLink,
true
)
const mapDataByOsm = new Link(
Translations.t.general.attribution.mapDataByOsm,
"https://openstreetmap.org/copyright",
true
)
const editWithJosm = new VariableUiElement(
userDetails.map(
(userDetails) => {
if (userDetails.csCount < Constants.userJourney.tagsVisibleAndWikiLinked) {
return undefined
}
const bounds: any = currentBounds.data
if (bounds === undefined) {
return undefined
}
const top = bounds.getNorth()
const bottom = bounds.getSouth()
const right = bounds.getEast()
const left = bounds.getWest()
const josmLink = `http://127.0.0.1:8111/load_and_zoom?left=${left}&right=${right}&top=${top}&bottom=${bottom}`
return new Link(Svg.josm_logo_ui().SetClass("small-image"), josmLink, true)
},
[location, currentBounds]
)
)
super([mapComplete, reportBug, stats, editHere, editWithJosm, mapillary, mapDataByOsm])
this.SetClass("flex")
}
}

View file

@ -1,25 +1,19 @@
import { VariableUiElement } from "../Base/VariableUIElement"
import Svg from "../../Svg"
import { UIEventSource } from "../../Logic/UIEventSource"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
import { BBox } from "../../Logic/BBox"
import Loc from "../../Models/Loc"
import Hotkeys from "../Base/Hotkeys"
import Translations from "../i18n/Translations"
import Constants from "../../Models/Constants"
import { MapProperties } from "../../Models/MapProperties"
/**
* Displays an icon depending on the state of the geolocation.
* Will set the 'lock' if clicked twice
*/
export class GeolocationControl extends VariableUiElement {
constructor(
geolocationHandler: GeoLocationHandler,
state: {
locationControl: UIEventSource<Loc>
currentBounds: UIEventSource<BBox>
}
) {
constructor(geolocationHandler: GeoLocationHandler, state: MapProperties) {
const lastClick = new UIEventSource<Date>(undefined)
lastClick.addCallbackD((date) => {
geolocationHandler.geolocationState.requestMoment.setData(date)
@ -48,7 +42,7 @@ export class GeolocationControl extends VariableUiElement {
if (permission === "denied") {
return Svg.location_refused_svg()
}
if (geolocationState.isLocked.data) {
if (!geolocationState.allowMoving.data) {
return Svg.location_locked_svg()
}
@ -77,7 +71,7 @@ export class GeolocationControl extends VariableUiElement {
},
[
geolocationState.currentGPSLocation,
geolocationState.isLocked,
geolocationState.allowMoving,
geolocationHandler.mapHasMoved,
lastClickWithinThreeSecs,
lastRequestWithinTimeout,
@ -95,9 +89,9 @@ export class GeolocationControl extends VariableUiElement {
await geolocationState.requestPermission()
}
if (geolocationState.isLocked.data === true) {
if (geolocationState.allowMoving.data === false) {
// Unlock
geolocationState.isLocked.setData(false)
geolocationState.allowMoving.setData(true)
return
}
@ -109,21 +103,17 @@ export class GeolocationControl extends VariableUiElement {
// A location _is_ known! Let's move to this location
const currentLocation = geolocationState.currentGPSLocation.data
const inBounds = state.currentBounds.data.contains([
const inBounds = state.bounds.data.contains([
currentLocation.longitude,
currentLocation.latitude,
])
geolocationHandler.MoveMapToCurrentLocation()
if (inBounds) {
const lc = state.locationControl.data
state.locationControl.setData({
...lc,
zoom: lc.zoom + 3,
})
state.zoom.update((z) => z + 3)
}
if (lastClickWithinThreeSecs.data) {
geolocationState.isLocked.setData(true)
geolocationState.allowMoving.setData(false)
lastClick.setData(undefined)
return
}

View file

@ -11,7 +11,6 @@ import BackgroundMapSwitch from "./BackgroundMapSwitch"
import Lazy from "../Base/Lazy"
import { VariableUiElement } from "../Base/VariableUIElement"
import FeatureInfoBox from "../Popup/FeatureInfoBox"
import CopyrightPanel from "./CopyrightPanel"
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"
import Hotkeys from "../Base/Hotkeys"
import { DefaultGuiState } from "../DefaultGuiState"
@ -21,7 +20,7 @@ export default class LeftControls extends Combine {
const currentViewFL = state.currentView?.layer
const currentViewAction = new Toggle(
new Lazy(() => {
const feature: Store<any> = state.currentView.features.map((ffs) => ffs[0]?.feature)
const feature: Store<any> = state.currentView.features.map((ffs) => ffs[0])
const icon = new VariableUiElement(
feature.map((feature) => {
const defaultIcon = Svg.checkbox_empty_svg()

View file

@ -1,5 +1,5 @@
import FloorLevelInputElement from "../Input/FloorLevelInputElement"
import MapState, { GlobalFilter } from "../../Logic/State/MapState"
import MapState from "../../Logic/State/MapState"
import { TagsFilter } from "../../Logic/Tags/TagsFilter"
import { RegexTag } from "../../Logic/Tags/RegexTag"
import { Or } from "../../Logic/Tags/Or"
@ -11,6 +11,7 @@ import { BBox } from "../../Logic/BBox"
import { TagUtils } from "../../Logic/Tags/TagUtils"
import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline"
import { Store } from "../../Logic/UIEventSource"
import { GlobalFilter } from "../../Logic/State/GlobalFilter"
/***
* The element responsible for the level input element and picking the right level, showing and hiding at the right time, ...

View file

@ -9,30 +9,9 @@ import LevelSelector from "./LevelSelector"
import { GeolocationControl } from "./GeolocationControl"
export default class RightControls extends Combine {
constructor(
state: MapState & { featurePipeline: FeaturePipeline },
geolocationHandler: GeoLocationHandler
) {
const geolocationButton = Toggle.If(state.featureSwitchGeolocation, () =>
new MapControlButton(new GeolocationControl(geolocationHandler, state), {
dontStyle: true,
}).SetClass("p-1")
)
const plus = new MapControlButton(Svg.plus_svg()).onClick(() => {
state.locationControl.data.zoom++
state.locationControl.ping()
})
const min = new MapControlButton(Svg.min_svg()).onClick(() => {
state.locationControl.data.zoom--
state.locationControl.ping()
})
constructor(state: MapState & { featurePipeline: FeaturePipeline }) {
const levelSelector = new LevelSelector(state)
super(
[levelSelector, plus, min, geolocationButton].map((el) => el.SetClass("m-0.5 md:m-1"))
)
super([levelSelector].map((el) => el.SetClass("m-0.5 md:m-1")))
this.SetClass("flex flex-col items-center")
}
}

View file

@ -1,4 +1,4 @@
import { UIEventSource } from "../../Logic/UIEventSource"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { Translation } from "../i18n/Translation"
import Svg from "../../Svg"
import { TextField } from "../Input/TextField"
@ -7,10 +7,15 @@ import Translations from "../i18n/Translations"
import Hash from "../../Logic/Web/Hash"
import Combine from "../Base/Combine"
import Locale from "../i18n/Locale"
import { BBox } from "../../Logic/BBox"
export default class SearchAndGo extends Combine {
private readonly _searchField: TextField
constructor(state: { leafletMap: UIEventSource<any>; selectedElement?: UIEventSource<any> }) {
constructor(state: {
leafletMap: UIEventSource<any>
selectedElement?: UIEventSource<any>
bounds?: Store<BBox>
}) {
const goButton = Svg.search_ui().SetClass("w-8 h-8 full-rounded border-black float-right")
const placeholder = new UIEventSource<Translation>(Translations.t.general.search.search)
@ -49,7 +54,7 @@ export default class SearchAndGo extends Combine {
searchField.GetValue().setData("")
placeholder.setData(Translations.t.general.search.searching)
try {
const result = await Geocoding.Search(searchString)
const result = await Geocoding.Search(searchString, state.bounds.data)
console.log("Search result", result)
if (result.length == 0) {

View file

@ -1,7 +1,7 @@
/**
* Asks to add a feature at the last clicked location, at least if zoom is sufficient
*/
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
import Svg from "../../Svg"
import { SubtleButton } from "../Base/SubtleButton"
import Combine from "../Base/Combine"
@ -22,13 +22,12 @@ import { Changes } from "../../Logic/Osm/Changes"
import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline"
import { ElementStorage } from "../../Logic/ElementStorage"
import ConfirmLocationOfPoint from "../NewPoint/ConfirmLocationOfPoint"
import BaseLayer from "../../Models/BaseLayer"
import Loading from "../Base/Loading"
import Hash from "../../Logic/Web/Hash"
import { GlobalFilter } from "../../Logic/State/MapState"
import { WayId } from "../../Models/OsmFeature"
import { Tag } from "../../Logic/Tags/Tag"
import { LoginToggle } from "../Popup/LoginButton"
import { GlobalFilter } from "../../Models/GlobalFilter"
/*
* The SimpleAddUI is a single panel, which can have multiple states:
@ -288,7 +287,7 @@ export default class SimpleAddUI extends LoginToggle {
const tags = TagUtils.KVtoProperties(preset.tags ?? [])
let icon: () => BaseUIElement = () =>
layer.layerDef.mapRendering[0]
.GenerateLeafletStyle(new UIEventSource<any>(tags), false)
.RenderIcon(new ImmutableStore<any>(tags), false)
.html.SetClass("w-12 h-12 block relative")
const presetInfo: PresetInfo = {
layerToAddTo: layer,