MapComplete/src/UI/InputElement/Helpers/NameSuggestionIndexInput.svelte

104 lines
3 KiB
Svelte
Raw Normal View History

2024-04-25 00:56:36 +02:00
<script lang="ts">
import type { Feature, MultiPolygon } from "geojson"
import { UIEventSource } from "../../../Logic/UIEventSource"
import * as nsi from "../../../../node_modules/name-suggestion-index/dist/nsi.json"
import * as nsiFeatures from "../../../../node_modules/name-suggestion-index/dist/featureCollection.json"
import { LocationConflation } from "@rapideditor/location-conflation"
import * as turf from "@turf/turf"
const nsiFile: NSIFile = nsi
const loco = new LocationConflation(nsiFeatures)
/**
* All props for this input helper
*/
export let value: UIEventSource<string> = new UIEventSource<string>(undefined)
export let feature: Feature
// Currently hardcoded, should be dynamic
let maintag = "amenity=atm"
let tag = "brand"
const path = `${tag}s/${maintag.split("=")[0]}/${maintag.split("=")[1]}`
let items = nsiFile.nsi[path].items
// Get the coordinates if the feature is a point, otherwise use the center
let lon: number
let lat: number
if (feature.geometry.type === "Point") {
const coordinates = feature.geometry.coordinates
lon = coordinates[0]
lat = coordinates[1]
} else {
lon = feature.bbox[0] + (feature.bbox[2] - feature.bbox[0]) / 2
lat = feature.bbox[1] + (feature.bbox[3] - feature.bbox[1]) / 2
}
// Filter the items
let filter = ""
$: filteredItems = items
.filter((item) => item.displayName.toLowerCase().includes(filter.toLowerCase()))
.filter((item) => {
// Check if the feature is in the location set using the location-conflation library
const resolvedSet = loco.resolveLocationSet(item.locationSet)
if (resolvedSet) {
const setFeature: Feature<MultiPolygon> = resolvedSet.feature
// We actually have a location set, so we can check if the feature is in it, by determining if our point is inside of the MultiPolygon using @turf/boolean-point-in-polygon
return turf.booleanPointInPolygon([lon, lat], setFeature.geometry)
}
return true
})
.slice(0, 25)
/**
* Some interfaces for the NSI files
*/
interface NSIFile {
_meta: {
version: string
generated: string
url: string
hash: string
}
nsi: {
[path: string]: NSIEntry
}
}
interface NSIEntry {
properties: {
path: string
skipCollection?: boolean
preserveTags?: string[]
exclude: unknown
}
items: NSIItem[]
}
interface NSIItem {
displayName: string
id: string
locationSet: unknown
tags: {
[key: string]: string
}
fromTemplate?: boolean
}
</script>
<div>
<input type="text" placeholder="Filter entries" bind:value={filter} />
<div class="flex h-32 w-full flex-wrap overflow-hidden">
{#each filteredItems as item}
<div
class="m-1 h-fit rounded-full border border-black p-4 text-center"
on:click={() => {
value.setData(item.tags[tag])
}}
>
{item.displayName}
</div>
{/each}
</div>
</div>