UX: fix #2089, improve background selection hotkeys and add emoji to indicate categories of background layers

This commit is contained in:
Pieter Vander Vennet 2024-08-23 03:47:04 +02:00
parent 5b67ccc9e2
commit 2dc386fd9a
15 changed files with 600 additions and 525 deletions

View file

@ -28,7 +28,7 @@ export class AvailableRasterLayers {
return this._editorLayerIndex
}
public static globalLayers: RasterLayerPolygon[] = globallayers.layers
public static globalLayers: ReadonlyArray<RasterLayerPolygon> = globallayers.layers
.filter(
(properties) =>
properties.id !== "osm.carto" && properties.id !== "Bing" /*Added separately*/
@ -140,28 +140,24 @@ export class RasterLayerUtils {
* @param available
* @param preferredCategory
* @param ignoreLayer
* @param skipLayers Skip the first N layers
*/
public static SelectBestLayerAccordingTo(
available: RasterLayerPolygon[],
preferredCategory: string,
ignoreLayer?: RasterLayerPolygon
ignoreLayer?: RasterLayerPolygon,
skipLayers: number = 0
): RasterLayerPolygon {
let secondBest: RasterLayerPolygon = undefined
for (const rasterLayer of available) {
if (rasterLayer === ignoreLayer) {
continue
}
const p = rasterLayer.properties
if (p.category === preferredCategory) {
if (p.best) {
return rasterLayer
}
if (!secondBest) {
secondBest = rasterLayer
}
}
const inCategory = available.filter(l => l.properties.category === preferredCategory)
const best : RasterLayerPolygon[] = inCategory.filter(l => l.properties.best)
const others : RasterLayerPolygon[] = inCategory.filter(l => !l.properties.best)
let all = best.concat(others)
console.log("Selected layers are:", all.map(l => l.properties.id))
if(others.length > skipLayers){
all = all.slice(skipLayers)
}
return secondBest
return all.find(l => l !== ignoreLayer)
}
}

View file

@ -161,7 +161,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.featureSwitches = new FeatureSwitchState(layout)
this.guistate = new MenuState(
this.featureSwitches.featureSwitchWelcomeMessage.data,
layout.id
layout.id,
)
this.map = new UIEventSource<MlMap>(undefined)
const geolocationState = new GeoLocationState()
@ -177,14 +177,14 @@ export default class ThemeViewState implements SpecialVisualizationState {
oauth_token: QueryParameters.GetQueryParameter(
"oauth_token",
undefined,
"Used to complete the login"
"Used to complete the login",
),
})
this.userRelatedState = new UserRelatedState(
this.osmConnection,
layout,
this.featureSwitches,
this.mapProperties
this.mapProperties,
)
this.userRelatedState.fixateNorth.addCallbackAndRunD((fixated) => {
this.mapProperties.allowRotating.setData(fixated !== "yes")
@ -195,20 +195,20 @@ export default class ThemeViewState implements SpecialVisualizationState {
geolocationState,
this.selectedElement,
this.mapProperties,
this.userRelatedState.gpsLocationHistoryRetentionTime
this.userRelatedState.gpsLocationHistoryRetentionTime,
)
this.geolocationControl = new GeolocationControlState(this.geolocation, this.mapProperties)
this.availableLayers = AvailableRasterLayers.layersAvailableAt(
this.mapProperties.location,
this.osmConnection.isLoggedIn
this.osmConnection.isLoggedIn,
)
this.layerState = new LayerState(
this.osmConnection,
layout.layers,
layout.id,
this.featureSwitches.featureSwitchLayerDefault
this.featureSwitches.featureSwitchLayerDefault,
)
{
@ -217,7 +217,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
const isDisplayed = QueryParameters.GetBooleanQueryParameter(
"overlay-" + rasterInfo.id,
rasterInfo.defaultState ?? true,
"Whether or not overlay layer " + rasterInfo.id + " is shown"
"Whether or not overlay layer " + rasterInfo.id + " is shown",
)
const state = { isDisplayed }
overlayLayerStates.set(rasterInfo.id, state)
@ -242,7 +242,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.osmConnection.Backend(),
(id) => this.layerState.filteredLayers.get(id).isDisplayed,
mvtAvailableLayers,
this.fullNodeDatabase
this.fullNodeDatabase,
)
let currentViewIndex = 0
@ -260,7 +260,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
id: "current_view_" + currentViewIndex,
}),
]
})
}),
)
this.featuresInView = new BBoxFeatureSource(layoutSource, this.mapProperties.bounds)
@ -278,19 +278,19 @@ export default class ThemeViewState implements SpecialVisualizationState {
featureSwitches: this.featureSwitches,
},
layout?.isLeftRightSensitive() ?? false,
(e) => this.reportError(e)
(e) => this.reportError(e),
)
this.historicalUserLocations = this.geolocation.historicalUserLocations
this.newFeatures = new NewGeometryFromChangesFeatureSource(
this.changes,
layoutSource,
this.featureProperties
this.featureProperties,
)
layoutSource.addSource(this.newFeatures)
const perLayer = new PerLayerFeatureSourceSplitter(
Array.from(this.layerState.filteredLayers.values()).filter(
(l) => l.layerDef?.source !== null
(l) => l.layerDef?.source !== null,
),
new ChangeGeometryApplicator(this.indexedFeatures, this.changes),
{
@ -301,10 +301,10 @@ export default class ThemeViewState implements SpecialVisualizationState {
"Got ",
features.length,
"leftover features, such as",
features[0].properties
features[0].properties,
)
},
}
},
)
this.perLayer = perLayer.perLayer
}
@ -344,12 +344,12 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.lastClickObject = new LastClickFeatureSource(
this.layout,
this.mapProperties.lastClickLocation,
this.userRelatedState.addNewFeatureMode
this.userRelatedState.addNewFeatureMode,
)
this.osmObjectDownloader = new OsmObjectDownloader(
this.osmConnection.Backend(),
this.changes
this.changes,
)
this.perLayerFiltered = this.showNormalDataOn(this.map)
@ -360,7 +360,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
currentZoom: this.mapProperties.zoom,
layerState: this.layerState,
bounds: this.visualFeedbackViewportBounds,
}
},
)
this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView
this.imageUploadManager = new ImageUploadManager(
@ -368,7 +368,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
Imgur.singleton,
this.featureProperties,
this.osmConnection,
this.changes
this.changes,
)
this.favourites = new FavouritesFeatureSource(this)
const longAgo = new Date()
@ -414,7 +414,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
LayoutSource.fromCacheZoomLevel,
fs,
this.featureProperties,
fs.layer.layerDef.maxAgeOfCache
fs.layer.layerDef.maxAgeOfCache,
)
toLocalStorage.set(layerId, storage)
})
@ -427,7 +427,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
const doShowLayer = this.mapProperties.zoom.map(
(z) =>
(fs.layer.isDisplayed?.data ?? true) && z >= (fs.layer.layerDef?.minzoom ?? 0),
[fs.layer.isDisplayed]
[fs.layer.isDisplayed],
)
if (!doShowLayer.data && this.featureSwitches.featureSwitchFilter.data === false) {
@ -444,7 +444,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
fs.layer,
fs,
(id) => this.featureProperties.getStore(id),
this.layerState.globalFilters
this.layerState.globalFilters,
)
filteringFeatureSource.set(layerName, filtered)
@ -588,7 +588,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
return
}
this.selectClosestAtCenter(0)
}
},
)
for (let i = 1; i < 9; i++) {
@ -606,7 +606,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
onUp: true,
},
doc,
() => this.selectClosestAtCenter(i - 1)
() => this.selectClosestAtCenter(i - 1),
)
}
@ -623,7 +623,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
if (this.featureSwitches.featureSwitchBackgroundSelection.data) {
this.guistate.backgroundLayerSelectionIsOpened.setData(true)
}
}
},
)
Hotkeys.RegisterHotkey(
{
@ -635,18 +635,11 @@ export default class ThemeViewState implements SpecialVisualizationState {
if (this.featureSwitches.featureSwitchFilter.data) {
this.guistate.openFilterView()
}
}
},
)
Hotkeys.RegisterHotkey(
{ shift: "O" },
Translations.t.hotkeyDocumentation.selectMapnik,
() => {
this.mapProperties.rasterLayer.setData(AvailableRasterLayers.osmCarto)
}
)
const setLayerCategory = (category: EliCategory) => {
const setLayerCategory = (category: EliCategory, skipLayers: number = 0) => {
const timeOfCall = new Date()
const available = this.availableLayers.store.addCallbackAndRunD((available) => {
this.availableLayers.store.addCallbackAndRunD((available) => {
const now = new Date()
const timeDiff = (now.getTime() - timeOfCall.getTime()) / 1000
if (timeDiff > 3) {
@ -656,9 +649,13 @@ export default class ThemeViewState implements SpecialVisualizationState {
const best = RasterLayerUtils.SelectBestLayerAccordingTo(
available,
category,
current.data
current.data,
skipLayers
)
console.log("Best layer for category", category, "is", best.properties.id)
if(!best){
return
}
console.log("Best layer for category", category, "is", best?.properties?.id)
current.setData(best)
})
}
@ -666,26 +663,43 @@ export default class ThemeViewState implements SpecialVisualizationState {
Hotkeys.RegisterHotkey(
{ nomod: "O" },
Translations.t.hotkeyDocumentation.selectOsmbasedmap,
() => setLayerCategory("osmbasedmap")
() => setLayerCategory("osmbasedmap"),
)
Hotkeys.RegisterHotkey(
{ nomod: "M" },
Translations.t.hotkeyDocumentation.selectMap,
() => setLayerCategory("map")
() => setLayerCategory("map"),
)
Hotkeys.RegisterHotkey(
{ nomod: "P" },
Translations.t.hotkeyDocumentation.selectAerial,
() => setLayerCategory("photo")
() => setLayerCategory("photo"),
)
Hotkeys.RegisterHotkey(
{ shift: "O" },
Translations.t.hotkeyDocumentation.selectOsmbasedmap,
() => setLayerCategory("osmbasedmap",2),
)
Hotkeys.RegisterHotkey(
{ shift: "M" },
Translations.t.hotkeyDocumentation.selectMap,
() => setLayerCategory("map",2),
)
Hotkeys.RegisterHotkey(
{ shift: "P" },
Translations.t.hotkeyDocumentation.selectAerial,
() => setLayerCategory("photo",2),
)
Hotkeys.RegisterHotkey(
{ nomod: "L" },
Translations.t.hotkeyDocumentation.geolocate,
() => {
this.geolocationControl.handleClick()
}
},
)
return true
})
@ -697,7 +711,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
Translations.t.hotkeyDocumentation.translationMode,
() => {
Locale.showLinkToWeblate.setData(!Locale.showLinkToWeblate.data)
}
},
)
}
@ -708,7 +722,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
const normalLayers = this.layout.layers.filter(
(l) =>
Constants.priviliged_layers.indexOf(<any>l.id) < 0 &&
!l.id.startsWith("note_import")
!l.id.startsWith("note_import"),
)
const maxzoom = Math.min(...normalLayers.map((l) => l.minzoom))
@ -716,7 +730,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
(l) =>
Constants.priviliged_layers.indexOf(<any>l.id) < 0 &&
l.source.geojsonSource === undefined &&
l.doCount
l.doCount,
)
const summaryTileSource = new SummaryTileSource(
Constants.SummaryServer,
@ -725,7 +739,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.mapProperties,
{
isActive: this.mapProperties.zoom.map((z) => z < maxzoom),
}
},
)
return new SummaryTileSourceRewriter(summaryTileSource, this.layerState.filteredLayers)
@ -746,12 +760,12 @@ export default class ThemeViewState implements SpecialVisualizationState {
gps_location_history: this.geolocation.historicalUserLocations,
gps_track: this.geolocation.historicalUserLocationsTrack,
selected_element: new StaticFeatureSource(
this.selectedElement.map((f) => (f === undefined ? empty : [f]))
this.selectedElement.map((f) => (f === undefined ? empty : [f])),
),
range: new StaticFeatureSource(
this.mapProperties.maxbounds.map((bbox) =>
bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({ id: "range" })]
)
bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({ id: "range" })],
),
),
current_view: this.currentView,
favourite: this.favourites,
@ -766,7 +780,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
ShowDataLayer.showRange(
this.map,
new StaticFeatureSource([bbox.asGeoJson({ id: "range" })]),
this.featureSwitches.featureSwitchIsTesting
this.featureSwitches.featureSwitchIsTesting,
)
}
const currentViewLayer = this.layout.layers.find((l) => l.id === "current_view")
@ -780,7 +794,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
currentViewLayer,
this.layout,
this.osmObjectDownloader,
this.featureProperties
this.featureProperties,
)
})
}
@ -824,20 +838,20 @@ export default class ThemeViewState implements SpecialVisualizationState {
const lastClickLayerConfig = new LayerConfig(
<LayerConfigJson>last_click_layerconfig,
"last_click"
"last_click",
)
const lastClickFiltered =
lastClickLayerConfig.isShown === undefined
? specialLayers.last_click
: specialLayers.last_click.features.mapD((fs) =>
fs.filter((f) => {
const matches = lastClickLayerConfig.isShown.matchesProperties(
f.properties
)
console.debug("LastClick ", f, "matches", matches)
return matches
})
)
fs.filter((f) => {
const matches = lastClickLayerConfig.isShown.matchesProperties(
f.properties,
)
console.debug("LastClick ", f, "matches", matches)
return matches
}),
)
new ShowDataLayer(this.map, {
features: new StaticFeatureSource(lastClickFiltered),
layer: lastClickLayerConfig,
@ -884,7 +898,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.mapProperties.rasterLayer,
this.availableLayers,
this.featureSwitches.backgroundLayerId,
this.userRelatedState.preferredBackgroundLayer
this.userRelatedState.preferredBackgroundLayer,
)
}
@ -900,7 +914,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
? ">>> _Not_ reporting error to report server as testmode is on"
: ">>> Reporting error to",
Constants.ErrorReportServer,
message
message,
)
if (isTesting) {
return