vendredi 19 février 2021

angular google map radius search and bound search

I am working on a google map search box. Currently, the search box on organization search is both an address-based search via Google, or a text-based search of our organization database, depending on whether the entered data is a proper address or not. Is there any way that I can separate this into two search boxes with one based on the radius search and the other based on the bound search?

Here is the code that I have(with only one search box):

<div class="map-container">
<div class="sidebar">
    <div class="contents sidebar__contents" id="map-search">
        <div class="sidebar__inputs">
            <input type="text" class="form-control inputs__searchbar" (keydown.enter)="$event.preventDefault()" [value]="searchString ? searchString : ''" [placeholder]="placeholder" #search>
import { Component, Input, Output, OnInit, ViewChild, ElementRef, NgZone } from '@angular/core';
import { MapsAPILoader} from '@agm/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { Organization} from '../organizations/organization';
import { OrganizationService} from '../../services/organization/organization.service';
import constants from '../app.constants';
// import { getResourceByOrganizationId } from '../../../server/api/resource/resource.controller';

// declare var google: any;

@Component({
    selector: 'map-search',
    template: require('./map-search.html'),
    styles: [require('./map-search.scss')],
})

export class MapSearchComponent implements OnInit {
    @ViewChild('search', { static: false })
    public searchElementRef: ElementRef;

    lat: number;
    lng: number;
    zoom: number;

    bounds: google.maps.LatLngBounds;
    center: google.maps.LatLngLiteral;

    searchBarBounds: google.maps.LatLngBounds;

    searchString: string;

    place: google.maps.places.PlaceResult;
    isAddress: boolean;

    queryUrl;
    mapQuery;

    public noResultsFound: boolean; //TODO: implement html to display when there are no results returned by server
    public isCurrentlySearching: boolean; //will allow us to display a loading image when searching

    allOrganizations: Organization[] = [];
    allMarkers: Marker[] = [];

    filterForm: FormGroup;
    populationServedOptions: string[];
    organizationFocusOptions: string[];
    organizationRoleOptions: string[];

    filters: {populationServed: string, organizationFocus: string, organizationRole: string};

    @Input() inputPopulationServed: string;
    //populationServed: string;

    @Input() inputOrganizationFocus: string;
    //organizationFocus: string;

    @Input() inputOrganizationRole: string;
    //organizationRole: string;

    public filterItems;
    public filterItemsSet;
    public filterCategories;

    queryFilters: Filter[];
    activeFilters: Filter[];
    isFiltered: boolean;

    allFilters: Filter[] = [];

    updateResults: boolean;

    map: google.maps.Map;
    placemarkLayer: google.maps.KmlLayer;
    coloradoBounds: google.maps.LatLngBounds;

    limit: number; //the number of results per page
    offset: number; //offset of results ignored to show the current page requested
    numTotalResults: number; //the actual number of results retrieved by search
    lastOffset: number;
    currentPage: number;
    lastPage: number;

    static baseValues = {
        lat: 39.113014, lng: -105.358887, zoom: 8.0, searchBarBounds: {
            east: -104.75481205709076,
            north: 39.81839092319901,
            south: 39.65998965810583,
            west: -105.22568994290924
        }
    };
    static parameters = [MapsAPILoader, NgZone, OrganizationService, Router, ActivatedRoute, FormBuilder];

    constructor(
        public mapsAPILoader: MapsAPILoader,
        private ngZone: NgZone,
        private organizationService: OrganizationService,
        private router: Router,
        private route: ActivatedRoute,
        private formBuilder: FormBuilder) {}


    public ngOnInit() {
        this.lat = MapSearchComponent.baseValues.lat;
        this.lng = MapSearchComponent.baseValues.lng;
        this.center = { lat: this.lat, lng: this.lng };
        this.zoom = MapSearchComponent.baseValues.zoom;
        // this.initMap();
        this.numTotalResults = 0; //actual number of results returned by search

        this.limit = 20; //number of organizations displayed per page
        this.offset = 0; //number of results before current list of organizations
        this.lastOffset = 0; //last number offset able to be sent to server for a search. Must be a multiple of the limit and less than numTotalResults.

        this.currentPage = 1; //current page number
        this.lastPage = 1; //last page number able to be viewed

        this.populationServedOptions = constants.populationServedOptions;
        this.organizationFocusOptions = constants.organizationFocusOptions;
        this.organizationRoleOptions = constants.organizationRoleOptions;

        this.filterForm = this.formBuilder.group({
            selectedPopulationServed: this.populationServedOptions[0],
            selectedOrganizationFocus: this.organizationFocusOptions[0],
            selectedOrganizationRole: this.organizationRoleOptions[0]
        });
        this.filters = {populationServed: '', organizationFocus: '', organizationRole: ''};

        this.updateResults = false;
        this.isAddress = false;

        this.placemarkLayer = null;

        if(this.route) {
            //first get the url/path to determine whether we need to perform simple or advanced search
            this.route.url.subscribe(url => {
                if(url.length > 1) {
                    this.queryUrl = url[1].path;
                }
                if(this.queryUrl === 'search') {
                    this.route.queryParams
                        .subscribe(params => {
                            this.mapQuery = JSON.parse(params.filter);
                            if (this.mapQuery) {
                                this.filters = {...this.mapQuery.filters};
                                this.bounds = {...this.mapQuery.bounds};
                                this.center = {...this.mapQuery.center};
                                this.zoom = this.mapQuery.zoom;
                                this.lat = this.mapQuery.center.lat;
                                this.lng = this.mapQuery.center.lng;
                                this.searchString = this.mapQuery.searchString;
                                this.isAddress = this.mapQuery.isAddress;
                                this.limit = this.mapQuery.limit;
                                this.offset = this.mapQuery.offset;
                            }
                        }
                     );     
                }
            });
        } else { }

        if(this.mapQuery) {
            this.isCurrentlySearching = true;
            //We then call the method from our OrganizationService that subsequently sends a request to the Organizations API
            this.organizationService.searchForOrganizationByLongLat(this.mapQuery).subscribe(
                (toReturn: {}) => { //numTotalResults: number, filters: [], kml: string, results: Organization[]
                    this.allOrganizations = toReturn['results'];
                    this.allMarkers = this.createMarkers(this.allOrganizations);
                    this.noResultsFound = (this.allOrganizations.length === 0); //if no results are found,
                    this.numTotalResults = toReturn['total'];
                    //highest offset index available for last results
                    this.lastOffset = Math.floor(this.numTotalResults / this.limit) * this.limit;
                    //or, total number of pages needed for all results
                    this.lastPage = Math.ceil(this.numTotalResults / this.limit);
                    //finds the current page being viewed based on offset. offset and limit should be multiples
                    this.currentPage = Math.floor(this.offset / this.limit) + 1;
                    this.isCurrentlySearching = false;
                });
        }

        this.mapsAPILoader.load().then(() => {
            let autocomplete = new google.maps.places.Autocomplete(this.searchElementRef.nativeElement);
            autocomplete.setComponentRestrictions({country: 'us'})
            this.coloradoBounds = new google.maps.LatLngBounds(
                new google.maps.LatLng({ lat: 37, lng: -109 }),
                new google.maps.LatLng({ lat: 41, lng: -102 })
            );
            autocomplete.setBounds(this.coloradoBounds);
            autocomplete.addListener('place_changed', () => {
                this.ngZone.run(() => {
                    // get the place result
                    this.place = autocomplete.getPlace();

                    // verify result
                    if (this.place.geometry) {
                        if (!this.coloradoBounds.contains(this.place.geometry.location)) {
                            alert('The search location is outside of the bounds of Colorado.');
                            return;
                        }
                        // set latitude, longitude and zoom
                        this.lat = this.place.geometry.location.lat();
                        this.lng = this.place.geometry.location.lng();
                        this.center = { lat: this.lat, lng: this.lng };
                        this.bounds = this.place.geometry.viewport;

                        if (this.placemarkLayer != null) {
                            this.placemarkLayer.setMap(this.map);
                        }
                    }

                    // search term consisting of the search string and flag if it is a searchable address
                    // tslint:disable-next-line:max-line-length
                    this.searchString = this.place && this.place.formatted_address ? this.place.formatted_address : this.searchElementRef.nativeElement.value;
                    if (this.place.formatted_address) {
                        this.isAddress = true;
                        this.zoom = 12;
                        this.mapSearch();
                    } else {
                        this.isAddress = false;
                        if (this.searchString) {
                            this.verifyAddress();
                        }
                    }
                    // console.log(this.searchString);
                });
            });
        });
    }

    initMap(): void {
        let center = this.center;
        let zooming = this.zoom;
        this.map = new google.maps.Map(document.getElementById('viewDiv') as HTMLElement, {
            center,
            zoom: zooming
        });
    }
    // To re-verify address in case it is typed in correct address format, but is not selected from autocomplete dropdown.
    verifyAddress(): void {
        let map = new google.maps.Map(this.searchElementRef.nativeElement);
        let service = new google.maps.places.PlacesService(map);

        let request = {
            fields: ['name', 'geometry', 'formatted_address'],
            query: this.searchString
        };

        service.findPlaceFromQuery(request, (place, status) => {
            // console.log(status);
            if (status === google.maps.places.PlacesServiceStatus.OK) {
                if (place[0].formatted_address === request.query) {
                    this.isAddress = true;
                    this.zoom = 12;

                    if (place[0].geometry) {
                        if (!this.coloradoBounds.contains(place[0].geometry.location)) {
                            alert('The search location is outside of the bounds of Colorado.');
                            return;
                        }

                        // set latitude, longitude and zoom
                        this.lat = place[0].geometry.location.lat();
                        this.lng = place[0].geometry.location.lng();
                        this.center = { lat: this.lat, lng: this.lng };
                        this.bounds = place[0].geometry.viewport;
                    }
                }
            }
            this.mapSearch();
        });
    }

Right now it looks like this:it can be typed in both address and keywords with autocomplete




Aucun commentaire:

Enregistrer un commentaire