forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			108 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
<script lang="ts">
 | 
						|
    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";
 | 
						|
 | 
						|
    /**
 | 
						|
     * An advanced location input, which has support to:
 | 
						|
     * - Show more layers
 | 
						|
     * - Snap to layers
 | 
						|
     *
 | 
						|
     * This one is mostly used to insert new points, including when importing
 | 
						|
     */
 | 
						|
    export let state: SpecialVisualizationState;
 | 
						|
    /**
 | 
						|
     * The start coordinate
 | 
						|
     */
 | 
						|
    export let  coordinate: { lon: number, lat: number };
 | 
						|
    export let snapToLayers: string[] | undefined;
 | 
						|
    export let targetLayer: LayerConfig;
 | 
						|
    export let maxSnapDistance: number = undefined;
 | 
						|
 | 
						|
    export let snappedTo: UIEventSource<string | undefined>;
 | 
						|
    
 | 
						|
    export let value: UIEventSource<{ lon: number, lat: number }>;
 | 
						|
    if (value.data === undefined) {
 | 
						|
        value.setData(coordinate);
 | 
						|
    }
 | 
						|
 | 
						|
    let preciseLocation: UIEventSource<{ lon: number, lat: number }> = new UIEventSource<{
 | 
						|
        lon: number;
 | 
						|
        lat: number
 | 
						|
    }>(undefined);
 | 
						|
    
 | 
						|
    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),
 | 
						|
        minzoom: new UIEventSource<number>(18),
 | 
						|
        rasterLayer: UIEventSource.feedFrom(state.mapProperties.rasterLayer)
 | 
						|
    };
 | 
						|
  
 | 
						|
    
 | 
						|
    const featuresForLayer = state.perLayer.get(targetLayer.id)
 | 
						|
    if(featuresForLayer){
 | 
						|
        new ShowDataLayer(map, {
 | 
						|
            layer: targetLayer,
 | 
						|
            features: featuresForLayer
 | 
						|
        })
 | 
						|
    }
 | 
						|
    
 | 
						|
 | 
						|
    if (snapToLayers?.length > 0) {
 | 
						|
 | 
						|
        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
 | 
						|
            }
 | 
						|
        );
 | 
						|
 | 
						|
        new ShowDataLayer(map, {
 | 
						|
            layer: targetLayer,
 | 
						|
            features: snappedLocation
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
</script>
 | 
						|
 | 
						|
 | 
						|
<LocationInput {map} mapProperties={initialMapProperties}
 | 
						|
               value={preciseLocation} initialCoordinate={coordinate} maxDistanceInMeters=50 />
 |