Извлечение координат с использованием Leaflet и Photon - PullRequest
0 голосов
/ 05 февраля 2020

В моем приложении 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);

  }

}
...