简体   繁体   中英

JS - Google Maps API - Directions on Marker Click

I've been working on the Google Maps API to create a website that geolocates users and shows them where the nearby open/closed cafes are.

I am currently trying to integrate functionality that gives the user directions from their current geolocation to the cafe when a marker is clicked but I am having trouble getting this to work and wondering if anyone could offer any pointers on how to achieve this

var service, map, pos, infoWindow, google, directionsService, directionsDisplay;


/* create google map & add styling */
function initMap() {

    clicked = null;

    directionsService = new google.maps.DirectionsService;
    directionsDisplay = new google.maps.DirectionsRenderer({
        suppressMarkers: true,
        suppressBicyclingLayer: true
    });
    directionsDisplay.setMap(map);

    var styledMapType = new google.maps.StyledMapType([{"featureType": "all", "elementType": "geometry.fill", "stylers": [{"weight": "2.00"}]}, {"featureType": "all", "elementType": "geometry.stroke", "stylers": [{"color": "#9c9c9c"}]}, {"featureType": "all", "elementType": "labels.text", "stylers": [{"visibility": "on"}]}, {"featureType": "administrative.locality", "elementType": "labels.text.fill", "stylers": [{"color": "#ac8d93"}]}, {"featureType": "landscape", "elementType": "all", "stylers": [{"color": "#f2f2f2"}]}, {"featureType": "landscape", "elementType": "geometry.fill", "stylers": [{"color": "#ffffff"}]}, {"featureType": "landscape.man_made", "elementType": "geometry.fill", "stylers": [{"color": "#ffffff"}]}, {"featureType": "poi", "elementType": "all", "stylers": [{"visibility": "off"}]}, {"featureType": "road", "elementType": "all", "stylers": [{"saturation": -100}, {"lightness": 45}]}, {"featureType": "road", "elementType": "geometry.fill", "stylers": [{"color": "#eeeeee"}]}, {"featureType": "road", "elementType": "labels.text.fill", "stylers": [{"color": "#7b7b7b"}]}, {"featureType": "road", "elementType": "labels.text.stroke", "stylers": [{"color": "#ffffff"}]}, {"featureType": "road.highway", "elementType": "all", "stylers": [{"visibility": "simplified"}]}, {"featureType": "road.arterial", "elementType": "labels.icon", "stylers": [{"visibility": "off"}]}, {"featureType": "transit", "elementType": "all", "stylers": [{"visibility": "off"}]}, {"featureType": "water", "elementType": "all", "stylers": [{"color": "#46bcec"}, {"visibility": "on"}]}, {"featureType": "water", "elementType": "geometry.fill", "stylers": [{"color": "#c8d7d4"}]}, {"featureType": "water", "elementType": "labels.text.fill", "stylers": [{"color": "#070707"}]}, {"featureType": "water", "elementType": "labels.text.stroke", "stylers": [{"color": "#ffffff"}]}],
            {name: 'Styled Map'});
    var chch = {lat: -43.530, lng: 172.646};
    map = new google.maps.Map(document.getElementById('map'), {
        center: chch,
        zoom: 13,
        mapTypeControlOptions: {
            mapTypeIds: ['roadmap', 'satellite', 'hybrid', 'terrain',
                'styled_map']
        }
    });
    map.mapTypes.set('styled_map', styledMapType);
    map.setMapTypeId('styled_map');



    infoWindow = new google.maps.InfoWindow({map: map});

    service = new google.maps.places.PlacesService(map);
    service.nearbySearch({
        location: chch,
        openNow: true && false,
        radius: 5000,
        type: ['cafe']
    }, function (results, status) {
        if (status === google.maps.places.PlacesServiceStatus.OK) {
            for (var i = 0; i < results.length; i++) {
                createMarker(results[i]);
            }
        }
    });

    geolocate();
    initAutocomplete();

}


function createMarker(place) {
    var marker = new google.maps.Marker({
        map: map,
        icon: 'img/greenmarker.svg',
        position: place.geometry.location
    });
    var request = {
        reference: place.reference
    };

    service.getDetails(request, function (place, status) {
        var open = "";

        if (!place.hasOwnProperty('opening_hours')) {
            open += "No open times provided";
            marker.setIcon('img/greymarker.svg');
        } else if (place.opening_hours.open_now === true) {
            open += "We are Open";
        } else {
            open += "We are Closed";
            marker.setIcon('img/redmarker.svg');
        }
        ;


        if (status === google.maps.places.PlacesServiceStatus.OK) {
            var contentStr = '<h5>' + place.name + '</h5><p>' + place.formatted_address;
            if (!!place)
                contentStr += '<br>' + open;

            if (!!place.formatted_phone_number)
                contentStr += '<br>' + place.formatted_phone_number;
            if (!!place.website)
                contentStr += '<br><a target="_blank" href="' + place.website + '">' + place.website + '</a></p>';
        } else {
            var contentStr = "<h5>No Result, status=" + status + "</h5>";
        }
        setupInfowindow(marker, infoWindow, contentStr);

    });

    function setupInfowindow(marker, infoWindow, contentStr) {
        marker.addListener('click', function () {
            infoWindow.setContent(contentStr);
            infoWindow.open(map, this);
        });
    }

    google.maps.event.addListener(marker, 'click', function () {
        clicked = marker.getPosition();
        calculateAndDisplayRoute(directionsService, directionsDisplay, pos, clicked);
        console.log(clicked);

//        clicked = {
//            lat: this.position.lat(),
//            lng: this.position.lng()
//        };
    });
}


function geolocate() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {

            pos = {
                lat: position.coords.latitude,
                lng: position.coords.longitude
            };
            new google.maps.Marker({
                map: map,
                icon: 'img/cross.svg',
                position: pos
            });

            infoWindow.setPosition(pos);
            infoWindow.setContent('Location found.');

            map.setCenter(pos);
            map.setZoom(14);
        }, function () {
            handleLocationError(true, infoWindow, map.getCenter());
        });
    } else {
        // Browser doesn't support Geolocation
        handleLocationError(false, infoWindow, map.getCenter());
    }
}



function initAutocomplete() {

    // Create the search box and link it to the UI element.
    var input = document.getElementById('pac-input');
    var searchBox = new google.maps.places.SearchBox(input);
    //map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);

    // Bias the SearchBox results towards current map's viewport.
    map.addListener('bounds_changed', function () {
        searchBox.setBounds(map.getBounds());
    });

    var markers = [];
    // Listen for the event fired when the user selects a prediction and retrieve
    // more details for that place.
    searchBox.addListener('places_changed', function () {
        var places = searchBox.getPlaces();

        if (places.length === 0) {
            return;
        }

        // Clear out the old markers.
        markers.forEach(function (marker) {
            marker.setMap(null);
        });
        markers = [];

        // For each place, get the icon, name and location.
        var bounds = new google.maps.LatLngBounds();
        places.forEach(function (place) {
            if (!place.geometry) {
                console.log("Returned place contains no geometry");
                return;
            }

            var searched = {
                lat: place.geometry.location.lat(),
                lng: place.geometry.location.lng()
            };

            infoWindow.setPosition(searched);
            infoWindow.setContent('Location found.');
            map.setCenter(searched);
            map.setZoom(14);

            // Create a marker for each place.
            markers.push(new google.maps.Marker({
                map: map,
                icon: 'img/cross.svg',
                title: place.name,
                position: place.geometry.location
            }));


            if (place.geometry.viewport) {
                // Only geocodes have viewport.
                bounds.union(place.geometry.viewport);
            } else {
                bounds.extend(place.geometry.location);
            }
        });
    });
}


function calculateAndDisplayRoute(directionsService, directionsDisplay, pos, clicked) {
    directionsService.route({
        origin: pos,
        destination: clicked,
        travelMode: 'BICYCLING'
    }, function (response, status) {
        if (status === 'OK') {
            directionsDisplay.setDirections(response);
        } else {
            window.alert('Directions request failed due to ' + status);
        }
    });
}



//if browser doesn't have geolocation then search box shows
function handleLocationError() {
    $(".input__wrapper").show();
}

here's a link that shows where i'm currently at with this - (for the purposes of this example i've edited the geolocation functionality so that it redirects to the city where the cafes are being gathered from)

any help with this would be greatly appreciated!

Two things prevented the code you provided from working:

  1. you changed the geolocation finding to a static location in the var chch , so the var pos was never set
  2. You naver attached the directionsDisplay to any panel. I added

     <div id="directionsPanel"></div> 

    to the Markup and

     directionsDisplay.setPanel(document.getElementById("directionsPanel")); 

    after the .setMap() call

and it turns out, apart from that, your code was already right, the result was just not being displayed anywhere: https://jsfiddle.net/786zeqc7/4/ (You have to scroll the output window using the scrollbar, as the map covers the whole frame, to see the directions below the map container after clicking on a marker) see this updated fiddle with a pretty amateurish column layout for preview purposes: https://jsfiddle.net/786zeqc7/5/

some more suggestions going beyond the question:

  1. You should check for status === google.maps.DirectionsStatus.OK instead for the string 'OK' - it's very unlikely, but when the API should change the value of that constant, it would break your code.

  2. there are some more JavaScript errors thrown in the console that you should look into and fix

  3. Use protocoll-less urls for the marker images to make them work in an https environment as well

  4. You have the var pos in global scope as well as an argument of the function calculateAndDisplayRoute() - that confused me and it probably wil lconfuse you too, when you look at this code again in a couple of months or years.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM