Add search previews on the map

This commit is contained in:
Pieter Vander Vennet 2024-08-23 02:16:24 +02:00
parent 1c46a65c84
commit 4f52483a98
19 changed files with 315 additions and 87 deletions

View file

@ -7,23 +7,17 @@
import { LastClickFeatureSource } from "../../Logic/FeatureSource/Sources/LastClickFeatureSource"
import Loading from "./Loading.svelte"
import { onDestroy } from "svelte"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import { GeocodingUtils } from "../../Logic/Geocoding/GeocodingProvider"
import ThemeViewState from "../../Models/ThemeViewState"
export let state: SpecialVisualizationState
export let selected: Feature
let tags = state.featureProperties.getStore(selected.properties.id)
export let absolute = true
function getLayer(properties: Record<string, string>) {
if (properties.id === "settings") {
return UserRelatedState.usersettingsConfig
}
if (properties.id.startsWith(LastClickFeatureSource.newPointElementId)) {
return state.layout.layers.find((l) => l.id === "last_click")
}
if (properties.id === "location_track") {
return state.layout.layers.find((l) => l.id === "gps_track")
}
return state.layout.getMatchingLayer(properties)
function getLayer(properties: Record<string, string>): LayerConfig {
return state.getMatchingLayer(properties)
}
let layer = getLayer(selected.properties)

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
import type { Feature } from "geojson"
import Translations from "../i18n/Translations"
import Loading from "../Base/Loading.svelte"
@ -17,10 +17,14 @@
import type GeocodingProvider from "../../Logic/Geocoding/GeocodingProvider"
import SearchResults from "./SearchResults.svelte"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import MoreScreen from "./MoreScreen"
import type { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
import { focusWithArrows } from "../../Utils/focusWithArrows"
import ShowDataLayer from "../Map/ShowDataLayer"
import ThemeViewState from "../../Models/ThemeViewState"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import GeocodingFeatureSource from "../../Logic/Geocoding/GeocodingFeatureSource"
import type { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson.js"
export let perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer> | undefined = undefined
export let bounds: UIEventSource<BBox>
@ -29,11 +33,11 @@
export let geolocationState: GeoLocationState | undefined = undefined
export let clearAfterView: boolean = true
export let searcher: GeocodingProvider = new NominatimGeocoding()
export let state: SpecialVisualizationState
export let state: ThemeViewState
let searchContents: UIEventSource<string> = new UIEventSource<string>("")
export let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined)
onDestroy(
triggerSearch.addCallback((_) => {
triggerSearch.addCallback(() => {
performSearch()
})
)
@ -139,7 +143,18 @@
if (search.length === 0) {
return undefined
}
return searcher.suggest(search, { bbox: bounds.data })
return Stores.holdDefined(bounds.bindD(bbox => searcher.suggest(search, { bbox, limit: 15 })))
}
)
let geocededFeatures= new GeocodingFeatureSource(suggestions.stabilized(250))
state.featureProperties.trackFeatureSource(geocededFeatures)
new ShowDataLayer(
state.map,
{
layer: GeocodingUtils.searchLayer,
features: geocededFeatures,
selectedElement: state.selectedElement
}
)
@ -147,19 +162,18 @@
function checkFocus() {
window.requestAnimationFrame(() => {
if (geosearch.contains(document.activeElement)) {
if (geosearch?.contains(document.activeElement)) {
return
}
isFocused.setData(false)
})
}
document.addEventListener("focus",() => {
document.addEventListener("focus", () => {
checkFocus()
}, true /* use 'capturing' instead of bubbling, needed for focus-events*/)
</script>
<div bind:this={geosearch} use:focusWithArrows={"searchresult"}>

View file

@ -42,6 +42,7 @@
import BuildingOffice2 from "@babeard/svelte-heroicons/outline/BuildingOffice2"
import Train from "../../assets/svg/Train.svelte"
import Airport from "../../assets/svg/Airport.svelte"
import BuildingStorefront from "@babeard/svelte-heroicons/outline/BuildingStorefront"
/**
* Renders a single icon.
@ -159,6 +160,8 @@
<Train {color} class={clss}/>
{:else if icon === "airport"}
<Airport {color} class={clss}/>
{:else if icon === "building_storefront"}
<BuildingStorefront {color} class={clss}/>
{:else if Utils.isEmoji(icon)}
<span style={`font-size: ${emojiHeight}px; line-height: ${emojiHeight}px`}>
{icon}

View file

@ -4,7 +4,7 @@ import LayoutConfig, { MinimalLayoutInformation } from "../Models/ThemeConfig/La
import {
FeatureSource,
IndexedFeatureSource,
WritableFeatureSource,
WritableFeatureSource
} from "../Logic/FeatureSource/FeatureSource"
import { OsmConnection } from "../Logic/Osm/OsmConnection"
import { Changes } from "../Logic/Osm/Changes"
@ -97,8 +97,10 @@ export interface SpecialVisualizationState {
readonly geolocation: GeoLocationHandler
readonly recentlySearched: RecentSearch
getMatchingLayer(properties: Record<string, string>);
showCurrentLocationOn(map: Store<MlMap>): ShowDataLayer
reportError(message: string): Promise<void>
}
@ -134,7 +136,7 @@ export interface SpecialVisualization {
export type RenderingSpecification =
| string
| {
func: SpecialVisualization
args: string[]
style: string
}
func: SpecialVisualization
args: string[]
style: string
}

View file

@ -19,7 +19,7 @@
EyeIcon,
HeartIcon,
MenuIcon,
XCircleIcon,
XCircleIcon
} from "@rgossiaux/svelte-heroicons/solid"
import Tr from "./Base/Tr.svelte"
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte"
@ -72,6 +72,7 @@
import HotkeyTable from "./BigComponents/HotkeyTable.svelte"
import SelectedElementPanel from "./Base/SelectedElementPanel.svelte"
import type { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson"
import { GeocodingUtils } from "../Logic/Geocoding/GeocodingProvider"
export let state: ThemeViewState
let layout = state.layout
@ -98,22 +99,10 @@
})
let selectedLayer: Store<LayerConfig> = state.selectedElement.mapD((element) => {
const id = element.properties.id
if (id.startsWith("current_view")) {
if (element.properties.id.startsWith("current_view")) {
return currentViewLayer
}
if (id.startsWith("summary_")) {
console.log("Not selecting a summary object. The summary object is", element)
return undefined
}
if (id.startsWith(LastClickFeatureSource.newPointElementId)) {
return layout.layers.find((l) => l.id === "last_click")
}
if (id === "location_track") {
return layout.layers.find((l) => l.id === "gps_track")
}
return state.layout.getMatchingLayer(element.properties)
return state.getMatchingLayer(element.properties)
})
let currentZoom = state.mapProperties.zoom
let showCrosshair = state.userRelatedState.showCrosshair
@ -144,7 +133,7 @@
const bottomRight = mlmap.unproject([rect.right, rect.bottom])
const bbox = new BBox([
[topLeft.lng, topLeft.lat],
[bottomRight.lng, bottomRight.lat],
[bottomRight.lng, bottomRight.lat]
])
state.visualFeedbackViewportBounds.setData(bbox)
}