Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

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



              
            
!

CSS

              
                
    body {
      margin: 0;
      padding: 0;
    }

    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
 
              
            
!

JS

              
                
    mapboxgl.accessToken = '<YOUR_ACCESS_TOKEN>';
    var map = new mapboxgl.Map({
      container: 'map',
      style: 'mapbox://styles/mapbox/light-v10',
      center: [8.677067,50.108],
      zoom: 12
    });

    // multimodal routing
    var coordinates_array_charging_around_origin;
    var coordinates_array_charging_around_destination;
    var mapClickCount = 0;
    var origin_selected;
    var destination_selected;

 
      //Create geoJSON object for displaying RouteLine on Map
    var geojson_walking_1 = {
      'type': 'Feature',
      'properties': {},
      'geometry': {
        'type': 'LineString',
        'coordinates': [
        
        ]
      }
    }

    var geojson_cycling_1 = {
      'type': 'Feature',
      'properties': {},
      'geometry': {
        'type': 'LineString',
        'coordinates': [
        
        ]
      }
    }

    var geojson_walking_2 = {
      'type': 'Feature',
      'properties': {},
      'geometry': {
        'type': 'LineString',
        'coordinates': [
        
        ]
      }
    }

    //create empty geoJSON that will be appended with data from tilequery requests around waypoints of route
    var source_data = { 
        "type" : "FeatureCollection",
        "features": []
    }

    map.on('load', function() {

      var marker = new mapboxgl.Marker({'color': '#008000'})
      map.addSource('tilequery_origin', {
        type: "geojson",
        data: {
          "type": "FeatureCollection",
          "features": []
        }
      });

      map.addLayer({
        id: "tilequery-points-origin",
        type: "circle",
        source: "tilequery_origin",
        paint: {
          "circle-stroke-color": "blue",
          "circle-stroke-width": {
            stops: [
              [0, 0.1],
              [18, 3]
            ],
            base: 5
          },
          "circle-radius": {
            stops: [
              [12, 5],
              [22, 180]
            ],
            base: 5
          },
          "circle-color": "blue"
        }
      });

      map.addSource('tilequery_destination', {
        type: "geojson",
        data: {
          "type": "FeatureCollection",
          "features": []
        }
      });

      map.addLayer({
        id: "tilequery-points-destination",
        type: "circle",
        source: "tilequery_destination",
        paint: {
          "circle-stroke-color": "red",
          "circle-stroke-width": {
            stops: [
              [0, 0.1],
              [18, 3]
            ],
            base: 5
          },
          "circle-radius": {
            stops: [
              [12, 5],
              [22, 180]
            ],
            base: 5
          },
          "circle-color": "red"
        }
      });

      var popup = new mapboxgl.Popup;

      map.on('mouseenter', 'tilequery-points', function(e) {
        map.getCanvas().style.cursor = 'pointer';

        var title = '<h3>' + e.features[0].properties.STORE_NAME + '</h3>';
        var storeType = '<h4>' + e.features[0].properties.STORE_TYPE + '</h4>';
        var storeAddress = '<p>' + e.features[0].properties.ADDRESS_LINE1 + '</p>';
        var obj = JSON.parse(e.features[0].properties.tilequery);
        var distance = '<p>' + (obj.distance / 1000).toFixed(2) + ' km from route' + '</p>';

        var lon = e.features[0].properties.longitude;
        var lat = e.features[0].properties.latitude;
        var coordinates = new mapboxgl.LngLat(lon, lat);
        var content = title + storeType + storeAddress + distance;

        popup.setLngLat(coordinates)
          .setHTML(content)
          .addTo(map);
      })

      map.on('mouseleave', 'tilequery-points', function() {
        map.getCanvas().style.cursor = '';
        popup.remove();
      });

      // select start and destination location from map
      
      map.on('click', (e) => {
        if(mapClickCount == 0){  // initial click --> get origin
          origin_selected = e.lngLat;
          mapClickCount++;

          const marker_orig = new mapboxgl.Marker({
            color: "#54E1E5",
            draggable: false
            }).setLngLat(e.lngLat)
            .addTo(map);

        }else{
          if(mapClickCount == 1){ // get destination
            destination_selected = e.lngLat;
            // init getting multi modal route
            getParkingFromTilequery(origin_selected, destination_selected);
            mapClickCount++;

            const marker_destination = new mapboxgl.Marker({
              color: "#E5D654",
              draggable: false
              }).setLngLat(e.lngLat)
              .addTo(map);

          }
        }
        console.log(`A click event has occurred at ${e.lngLat}`);
      });

    })

    function concatGeoJSON(g1, g2){
        return { 
            "type" : "FeatureCollection",
            "features": g1.features.concat(g2.features)
        }
    }

    function directionsRequest(url, step){
      var request = new XMLHttpRequest();
      var iterator = 0;


      var geojson_1 = {
        'type': 'Feature',
        'properties': {},
        'geometry': {
          'type': 'LineString',
          'coordinates': [
          
          ]
        }
      }
      
      // make a GET request to parse the GeoJSON at the url
      request.open('GET', url, true);
      request.onload = function() {
        if (this.status >= 200 && this.status < 400) {
          // retrieve the JSON from the response
          var json = JSON.parse(this.response);

          for (var i2 = 0; i2 < json.routes[0].geometry.coordinates.length; i2++){
            var coordinates_1 = json.routes[0].geometry.coordinates[i2]; 
            geojson_1.geometry.coordinates.push(coordinates_1); 
          }

          if(step == 0){
            geojson_walking_1 = geojson_1;
            try {
              map.getSource('route_0').setData(geojson_walking_1); //populate the route source
            } catch (error) {
              //Add directions route on map
              map.addSource('route_0', {
                'type': 'geojson',
                'data': geojson_walking_1
              });

              map.addLayer({
                'id': 'route_0',
                'type': 'line',
                'source': 'route_0',
                'layout': {
                  'line-join': 'round',
                  'line-cap': 'round'
                },
                'paint': {
                  'line-color': '#8F3A84',
                  'line-width': 8
                }
              });
              
            }
          }
          if(step == 1){
            geojson_cycling_1 = geojson_1;
            try {
              map.getSource('route_1').setData(geojson_cycling_1); //populate the route source
            } catch (error) {
              //Add directions route on map
              map.addSource('route_1', {
                'type': 'geojson',
                'data': geojson_cycling_1
              });

              map.addLayer({
                'id': 'route_1',
                'type': 'line',
                'source': 'route_1',
                'layout': {
                  'line-join': 'round',
                  'line-cap': 'round'
                },
                'paint': {
                  'line-color': '#3A8F47',
                  'line-width': 10
                }
              });
              
            }
          }
          if(step == 2){
            geojson_walking_2 = geojson_1;
            try {
              map.getSource('route_2').setData(geojson_walking_2); //populate the route source
            } catch (error) {
              //Add directions route on map
              map.addSource('route_2', {
                'type': 'geojson',
                'data': geojson_walking_2
              });

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

          
        };
      }
			request.send();
    }
  
    function getParkingFromTilequery(origin_selected, destination_selected){
      // get charging stations around origin and destination
      tilequery_get_charging_stations(origin_selected, destination_selected, 0); 
    }

    function createMatrixRequests(origin_selected, destination_selected){
      //get 3 cost matrices: origin -> parking, parking -> parking, parking -> destination
      // first cost matrix: origin -> parkings

      var matrix_request_url_1 = "https://api.mapbox.com/directions-matrix/v1/mapbox/walking/" + origin_selected.lng + ',' + origin_selected.lat + ';';
      var limit_parking_1 = 5;
      if(coordinates_array_charging_around_origin.features.length < 5){ // cap number of parking to 5
        limit_parking_1 = coordinates_array_charging_around_origin.features.length;
      }

      for (var i = 0; i < limit_parking_1; i++){
        matrix_request_url_1 = matrix_request_url_1 + coordinates_array_charging_around_origin.features[i].geometry.coordinates[0] + ",";
        matrix_request_url_1 = matrix_request_url_1 + coordinates_array_charging_around_origin.features[i].geometry.coordinates[1] + ";";
      }
      matrix_request_url_1 = matrix_request_url_1.slice(0, -1); // remove the comma
      matrix_request_url_1 = matrix_request_url_1 + "?sources=0&destinations=all&access_token=<YOUR_ACCESS_TOKEN>";
      
      // second cost matrix: parkings -> parkings_2

      var matrix_request_url_2 = "https://api.mapbox.com/directions-matrix/v1/mapbox/cycling/" ;
      var limit_parking_2 = 5;
      if(coordinates_array_charging_around_destination.features.length < 5){ // cap number of parking to 5
        limit_parking_2 = coordinates_array_charging_around_destination.features.length;
      }

      var sourcesString = "?sources=";
      for (var i = 0; i < limit_parking_1; i++){
        matrix_request_url_2 = matrix_request_url_2 + coordinates_array_charging_around_origin.features[i].geometry.coordinates[0] + ",";
        matrix_request_url_2 = matrix_request_url_2 + coordinates_array_charging_around_origin.features[i].geometry.coordinates[1] + ";";
        sourcesString += i + ";";

      }
      sourcesString = sourcesString.slice(0, -1);

      var destinationsString = "&destinations=";
      for (var i2 = 0; i2 < limit_parking_2; i2++){
        
        matrix_request_url_2 = matrix_request_url_2 + coordinates_array_charging_around_destination.features[i2].geometry.coordinates[0] + ",";
        matrix_request_url_2 = matrix_request_url_2 + coordinates_array_charging_around_destination.features[i2].geometry.coordinates[1] + ";";
        destinationsString += (i + i2) +  ";";
      }
      destinationsString = destinationsString.slice(0, -1); // remove the comma
      matrix_request_url_2 = matrix_request_url_2.slice(0, -1); // remove the comma
      matrix_request_url_2 = matrix_request_url_2 + sourcesString + destinationsString;
      matrix_request_url_2 = matrix_request_url_2 + "&access_token=<YOUR_ACCESS_TOKEN>";

      // third cost matrix: parkings_2 -> destination

      var matrix_request_url_3 = "https://api.mapbox.com/directions-matrix/v1/mapbox/walking/" + destination_selected.lng + ',' + destination_selected.lat + ';';
      

      for (var i = 0; i < limit_parking_2; i++){
        matrix_request_url_3 = matrix_request_url_3 + coordinates_array_charging_around_destination.features[i].geometry.coordinates[0] + ",";
        matrix_request_url_3 = matrix_request_url_3 + coordinates_array_charging_around_destination.features[i].geometry.coordinates[1] + ";";
      }
      matrix_request_url_3 = matrix_request_url_3.slice(0, -1); // remove the comma
      matrix_request_url_3 = matrix_request_url_3 + "?sources=all&destinations=0&access_token=<YOUR_ACCESS_TOKEN>";
      
      // send requests
      matrixRequest(matrix_request_url_1, matrix_request_url_2, matrix_request_url_3, 0);
    }

    var matrixArray = [];

    function matrixRequest(matrixUrl1, matrixUrl2, matrixUrl3, step){
      var request = new XMLHttpRequest();
      
      var matrixURL = "";

      if(step == 0){
        matrixURL = matrixUrl1;
      }
      if(step == 1){
        matrixURL = matrixUrl2;
      }
      if(step == 2){
        matrixURL = matrixUrl3;
      }

      
      // make a GET request to parse the GeoJSON at the url
      request.open('GET', matrixURL, true);
      request.onload = function() {
			if (this.status >= 200 && this.status < 400) {
				// retrieve the JSON from the response
				var json = JSON.parse(this.response);

        matrixArray.push(json);

        if(step < 2){
          step++;
          matrixRequest(matrixUrl1, matrixUrl2, matrixUrl3, step);
        }else{
          //continue
          parseMatrices_computeOptimalEdges();

        }
					
			}
			};
			request.send();
    }

    var tilequery_executed = false;

    function tilequery_get_charging_stations(origin_selected, destination_selected, step){
      
          if(step == 0){
            coordinates = origin_selected;
          }else{
            coordinates = destination_selected;
          }

          var tileset = '<YOUR_TILESET>'; // your tileset holding parking location data
          var radius = 30000; //30km distance from route
          var limit = 3;
          var query = 'https://api.mapbox.com/v4/' + tileset + '/tilequery/' + coordinates.lng + ',' + coordinates.lat + '.json?radius=' + radius + '&limit= ' + limit + ' &access_token=' + mapboxgl.accessToken;

          $.ajax({
          method: 'GET',
          url: query,
          }).done(function(data) {
              if(step == 0){
                step++;
                map.getSource('tilequery_origin').setData(data);
                coordinates_array_charging_around_origin = data;
                tilequery_get_charging_stations(origin_selected, destination_selected, step);
              }
              if(step == 1){
                map.getSource('tilequery_destination').setData(data);
                coordinates_array_charging_around_destination = data;
                // create Matrix requests
                if(tilequery_executed == false){
                  createMatrixRequests(origin_selected, destination_selected);
                }
                
                tilequery_executed = true;
                
              }  
          })
    }

    function parseMatrices_computeOptimalEdges(){
      // given the 3 cost matrices in matrixArray, compute all permutations and find cheapest path
      const matrix1 = matrixArray[0];

      var lowestCost = 9999999;  // start with a high value
      var lowestCostSeries = "";  // 0,1 --> means in first node on level 1 and second node on level 2

      for(var i = 1; i < matrixArray[0].durations[0].length; i++){  // do not iterate over distance to origin (0) --> i=1
        var cost = 0;
        var currentSeries = "";
        

        for(var i2 = 0; i2 < matrixArray[1].durations.length; i2++){  // iterate over array of lists (2d-matrix)
          for(var i3 = 0; i3 < matrixArray[1].durations[i2].length; i3++){ // iterate over list (connections from one node)
            if(matrixArray[1].durations[i2][i3] != 0){ // do not take self connections into account

              // iterate over third matrix
              for(var i4 = 1; i4 < matrixArray[2].durations.length; i4++){
                if(matrixArray[2].durations[i4][0] != 0){// do not take self connections into account
                  cost = matrixArray[0].durations[0][i] + matrixArray[1].durations[i2][i3] + matrixArray[2].durations[i4][0];
                  currentSeries = i + "," + i2 + "," + i3 + "," + i4;
                  if(cost < lowestCost){
                    lowestCost = cost;
                    lowestCostSeries = currentSeries;
                  }

                } 
              }
            }
          }
        }
      }

      var lowestCost_ = lowestCost;
        var nodesArray = lowestCostSeries.split(","); 
        const first_parking_geometry = coordinates_array_charging_around_origin.features[nodesArray[1]].geometry;
        const second_parking_geometry = coordinates_array_charging_around_destination.features[nodesArray[3] - 1].geometry;
        // nodesArray[1] = index of first parking
        // nodesArray[3] - 1 = index of second parking (index 0 is destination)

        // create 3 directions API requests to return route geometry, then draw route
        
        var url1 = 'https://api.mapbox.com/directions/v5/mapbox/walking/' + origin_selected.lng + ',' + origin_selected.lat + ";";
        url1 += first_parking_geometry.coordinates[0] + "," + first_parking_geometry.coordinates[1];
        url1 += '?geometries=geojson&access_token=<YOUR_ACCESS_TOKEN>';
        directionsRequest(url1, 0);

        var url2 = 'https://api.mapbox.com/directions/v5/mapbox/walking/' + first_parking_geometry.coordinates[0] + ',' + first_parking_geometry.coordinates[1] + ";";
        url2 += second_parking_geometry.coordinates[0] + "," + second_parking_geometry.coordinates[1];
        url2 += '?geometries=geojson&access_token=<YOUR_ACCESS_TOKEN>';
        directionsRequest(url2, 1);

        var url3 = 'https://api.mapbox.com/directions/v5/mapbox/walking/' + second_parking_geometry.coordinates[0] + ',' + second_parking_geometry.coordinates[1] + ";";
        url3 += destination_selected.lng + "," + destination_selected.lat;
        url3 += '?geometries=geojson&access_token=<YOUR_ACCESS_TOKEN>';
        directionsRequest(url3, 2);

    }



              
            
!
999px

Console