В моем приложении Angular у меня есть карта, построенная из OpenstreetMap с использованием Leaflet и Photon API для поиска города через форму автозаполнения. Сама форма работает очень хорошо, но теперь она имеет только функцию компонента автозаполнения, который показывает только список мест ... теперь я бы реализовал функцию поиска, запускаемую нажатием простой кнопки, которая дает мне маркер на карта выбранного места в форме автозаполнения. Как мне этого добиться?
Это действительные коды моей карты и компонента автозаполнения.
Компонент автозаполнения
import { MatOptionSelectionChange } from '@angular/material';
import { Subject, Subscription } from 'rxjs';
import { FormControl } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import {GeoJSON} from 'geojson';
@Component({
selector: 'app-city-autocomplete',
templateUrl: './city-autocomplete.component.html',
styleUrls: ['./city-autocomplete.component.css']
})
export class CityAutocompleteComponent implements OnDestroy {
@Output()
locationChange: EventEmitter<PlaceSuggestion> = new EventEmitter<PlaceSuggestion>();
searchOptions: Subject<PlaceSuggestion[]> = new Subject<PlaceSuggestion[]>();
inputFieldFormControl: FormControl = new FormControl();
private valueChangesSub: Subscription;
private choosenOption: PlaceSuggestion;
private userInputTimeout: number;
private requestSub: Subscription;
constructor(private http: HttpClient) {
this.valueChangesSub = this.inputFieldFormControl.valueChanges.subscribe((value) => {
if (this.userInputTimeout) {
window.clearTimeout(this.userInputTimeout);
}
if (this.choosenOption && this.choosenOption.shortAddress === value) {
this.searchOptions.next(null);
return;
}
if (!value || value.length < 3) {
// do not need suggestions until for less than 3 letters
this.searchOptions.next(null);
return;
}
this.userInputTimeout = window.setTimeout(() => {
this.generateSuggestions(value);
}, 300);
});
}
ngOnDestroy() {
this.valueChangesSub.unsubscribe();
}
private generateSuggestions(text: string) {
const url = `https://photon.komoot.de/api/?q=${text}`;
if (this.requestSub) {
this.requestSub.unsubscribe();
}
this.requestSub = this.http.get(url).subscribe((data: GeoJSON.FeatureCollection) => {
const placeSuggestions = data.features.map(feature => {
const properties: GeocodingFeatureProperties = (feature.properties as GeocodingFeatureProperties);
return {
shortAddress: this.generateShortAddress(properties),
fullAddress: this.generateFullAddress(properties),
data: properties
}
});
this.searchOptions.next(placeSuggestions.length ? placeSuggestions : null);
}, err => {
console.log(err);
});
}
private generateShortAddress(properties: GeocodingFeatureProperties): string {
let shortAddress = properties.name;
if (!shortAddress && properties.street && properties.housenumber) {
// name is not set for buildings
shortAddress = `${properties.street} ${properties.housenumber}`;
}
shortAddress += (properties.postcode && properties.city) ? `, ${properties.postcode}-${properties.city}`: '';
shortAddress += (!properties.postcode && properties.city && properties.city !== properties.name) ? `, ${properties.city}`: '';
shortAddress += (properties.country && properties.country !== properties.name) ? `, ${properties.country}` : '';
return shortAddress;
}
private generateFullAddress(properties: GeocodingFeatureProperties): string {
let fullAddress = properties.name;
fullAddress += properties.street ? `, ${properties.street}` : '';
fullAddress += properties.housenumber ? ` ${properties.housenumber}` : '';
fullAddress += (properties.postcode && properties.city) ? `, ${properties.postcode}-${properties.city}`: '';
fullAddress += (!properties.postcode && properties.city && properties.city !== properties.name) ? `, ${properties.city}`: '';
fullAddress += properties.state ? `, ${properties.state}`: '';
fullAddress += (properties.country && properties.country !== properties.name) ? `, ${properties.country}` : '';
return fullAddress;
}
public optionSelectionChange(option: PlaceSuggestion, event: MatOptionSelectionChange) {
if (event.isUserInput) {
this.choosenOption = option;
this.locationChange.emit(option);
}
}
}
export interface PlaceSuggestion {
shortAddress: string;
fullAddress: string;
data: GeocodingFeatureProperties;
}
interface GeocodingFeatureProperties {
name: string;
country: string;
state: string;
postcode: string;
city: string;
street: string;
housenumber: string;
}
Компонент карты
declare let L;
@Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.css']
})
export class MapComponent implements OnInit {
constructor() { }
ngOnInit() {
const map = L.map('map', {maxBounds: L.latLngBounds(L.latLng(84.812743, -178.188299), L.latLng(-77.143306, 178.662991))})
.setView([40.852341, 14.270479], 2);
map.locate({setView: true, watch: false})
.on('locationfound', function(e) {
const circleMarker = L.circleMarker([e.latitude, e.longitude], {color: 'white', weight: 4, fillColor: 'dodgerblue', fillOpacity: 10})
.bindPopup('I\'m here');
map.addLayer(circleMarker);
// map.flyTo([e.latitude, e.longitude], 16);
})
L.tileLayer('https://api.maptiler.com/maps/basic/{z}/{x}/{y}.png?key=cQXN0JPT3JRIVWE8Ae8U', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
minZoom: 2,
maxZoom: 16
}).addTo(map);
}
}