forked from MapComplete/MapComplete
105 lines
3.7 KiB
Svelte
105 lines
3.7 KiB
Svelte
<script lang="ts">
|
|
/**
|
|
* Used to quickly calculate a distance by dragging a map (and selecting start- and endpoints)
|
|
*/
|
|
|
|
import LocationInput from "./LocationInput.svelte"
|
|
import { UIEventSource, Store } from "../../../Logic/UIEventSource"
|
|
import type { MapProperties } from "../../../Models/MapProperties"
|
|
import ThemeViewState from "../../../Models/ThemeViewState"
|
|
import type { Feature } from "geojson"
|
|
import type { RasterLayerPolygon } from "../../../Models/RasterLayers"
|
|
import { RasterLayerUtils } from "../../../Models/RasterLayers"
|
|
import { eliCategory } from "../../../Models/RasterLayerProperties"
|
|
import { GeoOperations } from "../../../Logic/GeoOperations"
|
|
import OpenBackgroundSelectorButton from "../../BigComponents/OpenBackgroundSelectorButton.svelte"
|
|
import { Map as MlMap } from "maplibre-gl"
|
|
import StaticFeatureSource from "../../../Logic/FeatureSource/Sources/StaticFeatureSource"
|
|
import ShowDataLayer from "../../Map/ShowDataLayer"
|
|
import * as conflation from "../../../../assets/layers/conflation/conflation.json"
|
|
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
|
import Translations from "../../i18n/Translations"
|
|
import Tr from "../../Base/Tr.svelte"
|
|
|
|
export let value: UIEventSource<number>
|
|
export let feature: Feature
|
|
export let args: { background?: string; zoom?: number }
|
|
export let state: ThemeViewState = undefined
|
|
export let map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined)
|
|
|
|
let center = GeoOperations.centerpointCoordinates(feature)
|
|
export let initialCoordinate: { lon: number; lat: number } = { lon: center[0], lat: center[1] }
|
|
let mapLocation: UIEventSource<{ lon: number; lat: number }> = new UIEventSource(
|
|
initialCoordinate
|
|
)
|
|
let bg = args?.background
|
|
let rasterLayer = state?.mapProperties.rasterLayer
|
|
if (bg !== undefined) {
|
|
if (eliCategory.indexOf(bg) >= 0) {
|
|
const availableLayers = state.availableLayers.store.data
|
|
const startLayer: RasterLayerPolygon = RasterLayerUtils.SelectBestLayerAccordingTo(
|
|
availableLayers,
|
|
bg
|
|
)
|
|
rasterLayer = new UIEventSource(startLayer)
|
|
state?.mapProperties.rasterLayer.addCallbackD((layer) => rasterLayer.set(layer))
|
|
}
|
|
}
|
|
let mapProperties: Partial<MapProperties> = {
|
|
rasterLayer: rasterLayer,
|
|
location: mapLocation,
|
|
zoom: new UIEventSource(args?.zoom ?? 18),
|
|
}
|
|
|
|
let start: UIEventSource<{ lon: number; lat: number }> = new UIEventSource(undefined)
|
|
|
|
function selectStart() {
|
|
start.set(mapLocation.data)
|
|
}
|
|
|
|
let lengthFeature: Store<Feature[]> = start.map(
|
|
(start) => {
|
|
if (!start) {
|
|
return []
|
|
}
|
|
// A bit of a double task: calculate the actual value _and_ the map rendering
|
|
const end = mapLocation.data
|
|
const distance = GeoOperations.distanceBetween([start.lon, start.lat], [end.lon, end.lat])
|
|
value.set(distance.toFixed(2))
|
|
|
|
return <Feature[]>[
|
|
{
|
|
type: "Feature",
|
|
properties: {
|
|
id: "distance_line_" + distance,
|
|
distance: "" + distance,
|
|
},
|
|
geometry: {
|
|
type: "LineString",
|
|
coordinates: [
|
|
[start.lon, start.lat],
|
|
[end.lon, end.lat],
|
|
],
|
|
},
|
|
},
|
|
]
|
|
},
|
|
[mapLocation]
|
|
)
|
|
|
|
new ShowDataLayer(map, {
|
|
layer: new LayerConfig(conflation),
|
|
features: new StaticFeatureSource(lengthFeature),
|
|
})
|
|
</script>
|
|
|
|
<div class="relative h-64 w-full">
|
|
<LocationInput value={mapLocation} {mapProperties} {map} />
|
|
<div class="absolute bottom-0 left-0 p-4">
|
|
<OpenBackgroundSelectorButton {state} {map} />
|
|
</div>
|
|
</div>
|
|
|
|
<button class="primary" on:click={() => selectStart()}>
|
|
<Tr t={Translations.t.input_helpers.distance.setFirst} />
|
|
</button>
|