forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			100 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
	
		
			3.6 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
 | |
|    */
 | |
|   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 }>(coordinate);
 | |
|   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)
 | |
|   };
 | |
| 
 | |
|   initialMapProperties.bounds.addCallbackAndRunD((bounds: BBox) => {
 | |
|     const max = bounds.pad(3).squarify();
 | |
|     initialMapProperties.maxbounds.setData(max);
 | |
|     return true; // unregister
 | |
|   });
 | |
| 
 | |
|   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>
 | |
| 
 | |
| <div class="w-full h-64">
 | |
|   <LocationInput {map} mapProperties={initialMapProperties}
 | |
|                  value={preciseLocation}></LocationInput>
 | |
| </div>
 |