Search code examples
mapboxmapbox-glturfjs

How can I display distance markings on a line (Mapbox-gl)?


I want to display kilometers markings along a route drawn with addlayer: line. With @turf/along, I can calculate the coordinates for the distance markings, but what would be a good way of displaying them on the map? Non-turf related methods are also welcome.

I want to display the coordinates either on the route line itself, or below the line between a certain meter span, like per 100m.


Solution

  • For my purposes, I wanted to display a distance label along the route line for each full kilometer (that's why routeDistance is floored).

    //distanceLabel object
    var distanceLabels = {
      "type": "FeatureCollection",
      "features": []
    }
    
    //added it as a map source
    map.addSource('distanceLabels', {
      "type": "geojson",
      "data": distanceLabels
    })
    
    //added distancLabels as a map layer
    map.addLayer({
      "id": "distanceLabels",
      "type": "symbol",
      "source": "distanceLabels",
      "paint": {
        'text-color': '#000000'
      },
      "layout": {
        'symbol-placement': 'point',
        'text-font': ['Open Sans Regular','Arial Unicode MS Regular'],
        'text-field': '{distance}\n{unit}',
        'text-anchor': 'center',
        'text-justify': 'center',
        'text-size': 13,
        'icon-allow-overlap': true,
        'icon-ignore-placement': true
      }
    })
    
    
    //render labels function
     renderDistanceMarkers() {
      var unit = this.isMetric == true ? 'kilometers' : 'miles'
      var unitShort = this.isMetric == true ? 'km' : 'mi'
    
      //calculate line distance to determine the placement of the labels
      var routeDistance = turf.length(route.features[0], {units: unit})
    
      //rounding down kilometers (11.76km -> 11km)
      routeDistance = Math.floor(routeDistance)
      var points = []
    
      //only draw labels if route is longer than 1km
      if(routeDistance !== 0) {
        // Draw an arc between the `origin` & `destination` of the two points
    
        for (var i = 0; i < routeDistance + 1; i++) {
          var segment = turf.along(route.features[0], i, {units: unit})
    
          if(i !== 0) { //Skip the initial point (start coordinate)
              points.push({
                  "type": "Feature",
                  "properties": {'unit': unitShort},
                  "geometry": {
                      "type": "Point",
                      "coordinates": segment.geometry.coordinates
                  }
              })
          }
    
        }
    
        distanceLabels.features = points
    
        //update distances for the label texts
        for(var i = 0; i < points.length; i++) {
          distanceLabels.features[i].properties.distance = i + 1 //First one would be 0
        }
    
        //render now labels
        map.getSource('distanceLabels').setData(distanceLabels)
    
      }
    },