3
votes

I am trying to add lines between already loaded points and right clicked marker points. I have referred the Mapbox examples and have come till this stage. I am getting only one line, the first time I perform the operation. I want lines for each of the operations. The sequence of operations are as follows:

  1. Left click on a loaded point(point loaded from geojson)
  2. Right click anywhere on map. This should create a marker at the right clicked point and join it with the previously left clciked point.

I would appreciate some help. This is my first post in SO. Please pardon any mistakes from my end. Thank you in advance.

mapboxgl.accessToken = 'pk.eyJ1Ijoic3ViaGFtYmFuc3BocyIsImEiOiJjajc4czNxazEyaWE5MnFwaWllNzdwdDdkIn0.6AZVCVM-wGgh5cykoII9kA';
var map = new mapboxgl.Map({
  container: 'map', // container id
  style: 'mapbox://styles/mapbox/streets-v9',
  center: [-80.486052, 37.830348], // starting position
  zoom: 5 // starting zoom
});


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

  map.addSource("earthquakes", {
    type: "geojson",

    data: "https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"
  });

  map.addLayer({
    id: "markers",
    type: "circle",
    source: "earthquakes",
    paint: {
      "circle-color": "#11b4da",
      "circle-radius": 4,
      "circle-stroke-width": 1,
      "circle-stroke-color": "#fff"
    }
  });
});

map.on('mouseenter', 'markers', () => {
  map.getCanvas().style.cursor = 'pointer'
});

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

let ground
let obs
map.on('contextmenu', (f) => {
  ground = [f.lngLat.lng, f.lngLat.lat]
  var geojson = {
    "type": "FeatureCollection",
    "features": [{
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": f.lngLat
      }
    }]
  };
  // add markers to map
  geojson.features.forEach(function(marker) {
    // create a DOM element for the marker
    var el = document.createElement('div');
    el.className = 'marker';
    el.addEventListener('click', function() {
      window.alert(f.lngLat);
    })
    new mapboxgl.Marker(el)
      .setLngLat(marker.geometry.coordinates)
      .addTo(map);

    map.addLayer({
      "id": "route",
      "type": "line",
      "source": {
        "type": "geojson",
        "data": {
          "type": "FeatureCollection",
          "features": [{
            "type": "Feature",
            "geometry": {
              "type": "LineString",
              "coordinates": [
                ground, obs
              ]
            }
          }, ]
        }
      },
      "layout": {
        "line-join": "round",
        "line-cap": "round"
      },
      "paint": {
        "line-color": "#888",
        "line-width": 3,
        "line-dasharray": [0.1, 1.8]
      }

    });

  });

})


map.on('click', 'markers', (e) => {
  obs = [e.lngLat.lng, e.lngLat.lat]
});
body {
  margin: 0;
  padding: 0;
}

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

.marker {
  display: block;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  background-color: rgba(5, 4, 244, 0.82);
  height: 10px;
  width: 10px
}
<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8' />
  <title></title>
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
  <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.40.1/mapbox-gl.js'></script>
  <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.40.1/mapbox-gl.css' rel='stylesheet' />

</head>

<body>

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

</body>

</html>
1
P.S: The Browser Console gives the following:Error: There is already a source with this ID - Subham Banerjee

1 Answers

2
votes

Instead of recreating a new layer & a source every time the user adds a marker, you should create the line layer and its source once and then just update the underlying data:

mapboxgl.accessToken = 'pk.eyJ1Ijoic3ViaGFtYmFuc3BocyIsImEiOiJjajc4czNxazEyaWE5MnFwaWllNzdwdDdkIn0.6AZVCVM-wGgh5cykoII9kA';
var map = new mapboxgl.Map({
  container: 'map', // container id
  style: 'mapbox://styles/mapbox/streets-v9',
  center: [-80.486052, 37.830348], // starting position
  zoom: 5 // starting zoom
});


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

  map.addSource("earthquakes", {
    type: "geojson",
    data: "https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"
  });

  map.addLayer({
    id: "markers",
    type: "circle",
    source: "earthquakes",
    paint: {
      "circle-color": "#11b4da",
      "circle-radius": 4,
      "circle-stroke-width": 1,
      "circle-stroke-color": "#fff"
    }
  });
  
  map.addSource('line-source', {
    type: 'geojson',
    data: {
      type: 'FeatureCollection',
      features: []
    }
  });
  map.addLayer({
    type: 'line',
    source: 'line-source',
    id: 'line-layer'
  });
});

map.on('mouseenter', 'markers', () => {
  map.getCanvas().style.cursor = 'pointer'
});

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

let ground;
let obs;

map.on('contextmenu', (f) => {
  ground = [f.lngLat.lng, f.lngLat.lat];
  
  map.getSource('line-source').setData({
    type: 'FeatureCollection',
    features: [{
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: [ground, obs]
      }
    }]
  })
});


map.on('click', 'markers', (e) => {
  obs = [e.lngLat.lng, e.lngLat.lat];
});
body {
  margin: 0;
  padding: 0;
}

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

.marker {
  display: block;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  background-color: rgba(5, 4, 244, 0.82);
  height: 10px;
  width: 10px
}
<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8' />
  <title></title>
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
  <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.40.1/mapbox-gl.js'></script>
  <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.40.1/mapbox-gl.css' rel='stylesheet' />

</head>

<body>

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

</body>

</html>

I simplified your snippet, but you should get the gist of it.