mapcomplete/UI/BigComponents/NewPointLocationInput.svelte

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

109 lines
4 KiB
Svelte
Raw Normal View History

<script lang="ts">
2023-05-18 23:44:15 +02:00
import type {SpecialVisualizationState} from "../SpecialVisualization";
import LocationInput from "../InputElement/Helpers/LocationInput.svelte";
import {UIEventSource} from "../../Logic/UIEventSource";
import {Tiles} from "../../Models/TileRange";
import {Map as MlMap} from "maplibre-gl";
import {BBox} from "../../Logic/BBox";
import type {MapProperties} from "../../Models/MapProperties";
import ShowDataLayer from "../Map/ShowDataLayer";
import type {FeatureSource, FeatureSourceForLayer} from "../../Logic/FeatureSource/FeatureSource";
import SnappingFeatureSource from "../../Logic/FeatureSource/Sources/SnappingFeatureSource";
import FeatureSourceMerger from "../../Logic/FeatureSource/Sources/FeatureSourceMerger";
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
import {Utils} from "../../Utils";
2023-05-18 23:44:15 +02:00
/**
* An advanced location input, which has support to:
* - Show more layers
* - Snap to layers
*
2023-05-30 02:52:22 +02:00
* This one is mostly used to insert new points, including when importing
2023-05-18 23:44:15 +02:00
*/
export let state: SpecialVisualizationState;
/**
* The start coordinate
*/
2023-05-30 02:52:22 +02:00
export let coordinate: { lon: number, lat: number };
2023-05-18 23:44:15 +02:00
export let snapToLayers: string[] | undefined;
export let targetLayer: LayerConfig;
export let maxSnapDistance: number = undefined;
2023-05-18 23:44:15 +02:00
export let snappedTo: UIEventSource<string | undefined>;
2023-05-19 01:37:31 +02:00
2023-05-18 23:44:15 +02:00
export let value: UIEventSource<{ lon: number, lat: number }>;
if (value.data === undefined) {
value.setData(coordinate);
}
2023-05-18 23:44:15 +02:00
let preciseLocation: UIEventSource<{ lon: number, lat: number }> = new UIEventSource<{
lon: number;
lat: number
2023-05-19 01:37:31 +02:00
}>(undefined);
2023-05-18 23:44:15 +02:00
const xyz = Tiles.embedded_tile(coordinate.lat, coordinate.lon, 16);
const map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined);
let initialMapProperties: Partial<MapProperties> = {
zoom: new UIEventSource<number>(19),
maxbounds: new UIEventSource(undefined),
/*If no snapping needed: the value is simply the map location;
* If snapping is needed: the value will be set later on by the snapping feature source
* */
location: snapToLayers?.length > 0 ? new UIEventSource<{ lon: number; lat: number }>(coordinate) : value,
bounds: new UIEventSource<BBox>(undefined),
allowMoving: new UIEventSource<boolean>(true),
allowZooming: new UIEventSource<boolean>(true),
2023-05-19 01:37:31 +02:00
minzoom: new UIEventSource<number>(18),
rasterLayer: UIEventSource.feedFrom(state.mapProperties.rasterLayer)
2023-05-18 23:44:15 +02:00
};
2023-05-19 01:37:31 +02:00
const featuresForLayer = state.perLayer.get(targetLayer.id)
if(featuresForLayer){
new ShowDataLayer(map, {
layer: targetLayer,
features: featuresForLayer
})
}
2023-05-18 23:44:15 +02:00
if (snapToLayers?.length > 0) {
2023-05-18 23:44:15 +02:00
const snapSources: FeatureSource[] = [];
for (const layerId of (snapToLayers ?? [])) {
const layer: FeatureSourceForLayer = state.perLayer.get(layerId);
snapSources.push(layer);
if (layer.features === undefined) {
continue;
}
new ShowDataLayer(map, {
layer: layer.layer.layerDef,
zoomToFeatures: false,
features: layer
});
}
const snappedLocation = new SnappingFeatureSource(
new FeatureSourceMerger(...Utils.NoNull(snapSources)),
// We snap to the (constantly updating) map location
initialMapProperties.location,
{
maxDistance: maxSnapDistance ?? 15,
allowUnsnapped: true,
snappedTo,
snapLocation: value
}
);
2023-05-18 23:44:15 +02:00
new ShowDataLayer(map, {
layer: targetLayer,
features: snappedLocation
});
}
</script>
2023-05-18 23:44:15 +02:00
<LocationInput {map} mapProperties={initialMapProperties}
2023-05-30 02:52:22 +02:00
value={preciseLocation} initialCoordinate={coordinate} maxDistanceInMeters=50 />