5
votes

I have an app with multiple markers, for displaying a travel. Each marker is a step, and I want to create a route between each marker with it following marker (following step).

For that, right now I have this code :

$(document).ready(function() {
  var map;
  var directions;

  // token access for MAPBOX GL
  mapboxgl.accessToken = 'pk.eyJ1IjoiYW50b3RvIiwiYSI6ImNpdm15YmNwNTAwMDUyb3FwbzlzeWluZHcifQ.r44fcNU5pnX3-mYYM495Fw';

  // generate map
  var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v10',
    center: [-96, 37.8],
    zoom: 5
  });

  // center map on selected marker
  map.on('click', 'markers', function (e) {
    map.flyTo({center: e.features[0].geometry.coordinates});
  });

  // change mouse action on enter / leave in marker
  map.on('mouseenter', 'markers', function () {
    map.getCanvas().style.cursor = 'pointer';
  });

  map.on('mouseleave', 'markers', function () {
    map.getCanvas().style.cursor = '';
  });

  $.ajax({
    dataType: 'json',
    url: grabTravelData(),
    success: function(data) {
        geojson = data;
        map.addSource("markers", {
            "type": "geojson",
            "data": {
                "type": "FeatureCollection",
                "features": data
            }
        });
        map.addLayer({
            "id": "markers",
            "type": "circle",
            "source": "markers",
            "paint": {
                "circle-radius": 7,
                "circle-color": "#ff7e5f"
            },
        });
        // center map on markers
        var bounds = new mapboxgl.LngLatBounds();
        data.forEach(function(feature) {
            bounds.extend(feature.geometry.coordinates);
        });
        map.fitBounds(bounds);

        for(var i = 0; i < data.length; i++) {
            var last = data.length - 1
            var from = data[i];
            var to = data[i + 1];
            if(i != last) {
                apiCall(from.geometry.coordinates[0], from.geometry.coordinates[1], to.geometry.coordinates[0], to.geometry.coordinates[1], mapboxgl.accessToken, i);
            } else {
                apiCall(from.geometry.coordinates[0], from.geometry.coordinates[1], from.geometry.coordinates[0], from.geometry.coordinates[1], mapboxgl.accessToken, i);
            }
        }
    }, error: function(data) {
        console.log(data + ' error');
    }
});

function apiCall(from_one, from_two, to_one, to_two, token, number) {
  $.get("https://api.mapbox.com/directions/v5/mapbox/driving/" + from_one + "," + from_two + ";" + to_one + "," + to_two + "?access_token=" + token, function(data) {
    var naming = "route-" + number;
    map.on('load', function () {
        map.addSource(naming, {
            "type": "geojson",
            "data": {
                "type": "Feature",
                "properties": {},
                "geometry": {
                    "type": "LineString",
                    "coordinates": data.routes[0].geometry
                }
            }
        });

        map.addLayer({
            "id": naming,
            "type": "line",
            "source": naming,
            "layout": {
                "line-join": "round",
                "line-cap": "round"
            },
            "paint": {
                "line-color": "#ff7e5f",
                "line-width": 8
            }
        });
    });
  }
}

But the routes doesn't appear on the map, and I read on the API Documentation this line : // This API is not available through the JavaScript SDK

So maybe I can't call the API. With this code I have a good result:

with this url : https://api.mapbox.com/directions/v5/mapbox/driving/18.0944238,42.65066059999999;15.981919,45.8150108?access_token=

And the result is a json with geometry... so a good result as it's write in the documentation.

Maybe someone know how should I display routes on the map ? And if I can't with the API call, how should I modify my code to use the Directions Plugin ?

1

1 Answers

6
votes

Your problem is that the directions API is returning by default geometries encoded in polylines, which are not geojson features.

To get around that, you can specify the &geometries=geojson query parameter to your url, and it will return you the data in the correct format you can display easily.

Also one thing, it seems better to me to do your ajax after the map has finished loaded.

// This is the token from their docs, don't be evil
mapboxgl.accessToken = 'pk.eyJ1IjoiYXBlcmN1IiwiYSI6ImNpZ3M0ZDZ2OTAwNzl2bmt1M2I0dW1keTIifQ.I5BD9uEHdm_91TiyBEk7Pw'

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v9',
  center: [18.0944238, 42.65066059999999],
  zoom: 9,
})

map.on('load', () => {

  $.get(`https://api.mapbox.com/directions/v5/mapbox/driving/18.0944238,42.65066059999999;15.981919,45.8150108?access_token=${mapboxgl.accessToken}&geometries=geojson`, data => {
  
    map.addLayer({
      id: 'route',
      type: 'line',
      source: {
        type: 'geojson',
        data: {
          type: 'Feature',
          properties: {},
          geometry: data.routes[0].geometry,
        },
      },
      layout: {
        'line-join': 'round',
        'line-cap': 'round',
      },
      paint: {
        'line-color': '#ff7e5f',
        'line-width': 8,
      },
    })
  
  })

})
html, body, #map {
  height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.js"></script>
<link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.37.0/mapbox-gl.css" rel="stylesheet"/>

<body>
  <div id='map'></div>
</body>