0

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!

xj-nny
  • 17
  • 4

1 Answers1

0

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.

Constantin Groß
  • 10,719
  • 4
  • 24
  • 50
  • hey @Connum, thank you so much for your help! I'm afraid I may not have explained myself correctly in my original post - I wasn't looking to get the written directions, but the blue polyline directions between the user and the clicked marker – xj-nny Feb 08 '17 at 11:30
  • Alright... So, I still haven't been able to find out why the route is not being displayed by default, although it works in this example: http://jsfiddle.net/user2314737/u9no8te4/ and I just can't spot any difference. I have however been able to display the route based on a suggestion from this question: http://stackoverflow.com/questions/16180104/get-a-polyline-from-google-maps-directions-v3 see https://jsfiddle.net/786zeqc7/9/ (you might have to click "Run" again, there seems to bee an issue with the map in the jsfiddle environment) – Constantin Groß Feb 08 '17 at 12:21