Привязка перетаскиваемой точки к линии набора векторных листов в Mapbox GL JS с помощью turf.js

Я пытаюсь привязать перетаскиваемую точку к набору векторных элементов мозаики, состоящему из линий, но я не уверен, возможно ли это с использованием набора векторных элементов Mapbox.

По сути, это эквивалент этого примера точечной привязки, в котором используется turf.js https://jsfiddle.net/andi_lo/nmc4kprn/5/, который описан в следующем сообщении о переполнении стека: Значки Mapbox / маркеры BearingSnap or Snap to Position

Я изменил базовый пример перетаскиваемой точки Mapbox, чтобы запросить визуализированные функции, содержащиеся в наборе тайлов. Я просто не знаю, как включить в него функции измерения и привязки. В журнале консоли я вижу, что возвращаются координаты объекта, который я пересекаю. Любые идеи?

mapboxgl.accessToken = 'pk.eyJ1Ijoic2luc3ctc2NpIiwiYSI6ImNqajd6MHYyZjEyZzUzcnBlNnM1OHFmdXoifQ.ZBT_-d26dSFur2oWzXAQvA';

var map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/sinsw-sci/cjl1x0v4489j32qp2nd9swywc',
  center: [151.206, -33.865],
  zoom: 17
});


var canvas = map.getCanvasContainer();


var geojson = {
  "type": "FeatureCollection",
  "features": [{
    "type": "Feature",
    "properties": {},
    "geometry": {
      "type": "Point",
      "coordinates": [151.206, -33.865]
    }
  }]
};


function onMove(e) {
  var coords = e.lngLat;

  // Set a UI indicator for dragging.
  canvas.style.cursor = 'grabbing';

  // Update the Point feature in `geojson` coordinates
  // and call setData to the source layer `point` on it.
  geojson.features[0].geometry.coordinates = [coords.lng, coords.lat];
  map.getSource('point').setData(geojson);

  var features = map.queryRenderedFeatures(e.point, {
    layers: ['snapTo']
  });

  // console.log(features);

  // Change point and cursor style as a UI indicator
  // and set a flag to enable other mouse events.
  if (features.length) {
    console.log(features);
    canvas.style.cursor = 'move';
    isCursorOverPoint = true;
    map.dragPan.disable();
  } else {
    map.setPaintProperty('point', 'circle-color', '#3887be');
    canvas.style.cursor = '';
    isCursorOverPoint = false;
    map.dragPan.enable();
  }


}

function onUp(e) {
  var coords = e.lngLat;
  canvas.style.cursor = '';

  // Unbind mouse/touch events
  map.off('mousemove', onMove);
  map.off('touchmove', onMove);
}

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

  // Add a single point to the map
  map.addSource('point', {
    "type": "geojson",
    "data": geojson
  });

  map.addLayer({
    "id": "point",
    "type": "circle",
    "source": "point",
    "paint": {
      "circle-radius": 10,
      "circle-color": "#3887be"
    }
  });


  map.addSource('snap', {
    type: 'vector',
    url: 'mapbox://mapbox.mapbox-streets-v7'
  });



  map.addLayer({
    id: 'snapTo',
    type: 'line',
    source: 'snap',
    'source-layer': 'road',
    'paint': {
      "line-color": "#2AAAFF",
      "line-opacity": 0.5,
      'line-width': 1
    }
  });








  // When the cursor enters a feature in the point layer, prepare for dragging.
  map.on('mouseenter', 'point', function() {
    map.setPaintProperty('point', 'circle-color', '#3bb2d0');
    canvas.style.cursor = 'move';
  });

  map.on('mouseleave', 'point', function() {
    map.setPaintProperty('point', 'circle-color', '#3887be');
    canvas.style.cursor = '';
  });

  map.on('mousedown', 'point', function(e) {
    // Prevent the default map drag behavior.
    e.preventDefault();

    canvas.style.cursor = 'grab';

    map.on('mousemove', onMove);
    map.once('mouseup', onUp);
  });

  map.on('touchstart', 'point', function(e) {
    if (e.points.length !== 1) return;

    // Prevent the default map drag behavior.
    e.preventDefault();

    map.on('touchmove', onMove);
    map.once('touchend', onUp);
  });
});
<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8' />
  <title>Snap point to vector tileset</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.48.0/mapbox-gl.js'></script>
  <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.48.0/mapbox-gl.css' rel='stylesheet' />
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    
    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }
  </style>
</head>

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

</html>


person Mkov    schedule 20.08.2018    source источник


Ответы (1)


Мне это кажется возможным.

Вам нужно будет сделать два основных изменения из этого примера Point.

Во-первых, используйте queryRenderedFeatures(), чтобы получить все исходные векторные объекты, которые являются кандидатами для привязки. Вероятно, вы захотите обвести ограничивающую рамку вокруг текущего местоположения мыши, чтобы ограничить дальность поиска кандидатов. Вы также захотите передать фильтр для правильного слоя и, вероятно, ограничить его до ["==", "$type", "LineString"]

Во-вторых, перебирая каждый возвращаемый линейный объект, используйте nearestPointOnLine() Турфа, чтобы вычислить расстояние до каждой линии и найти фактическую ближайшую точку на этой линии. Что-то вроде:

var nearestPoint;
turf.featureEach(snapTo, (feature) => {
    var point = turf.nearestPointOnLine(feature, turf.point([coords.lng, coords.lat]));
    // if the distance of the dragging point is under a certain threshold
    if (!nearestPoint || point.properties.dist < nearestPoint.properties.dist) {
      nearestPoint = point;
    }
  });

if (nearestPoint) {
      // do whatever you do, now that you have the closest point
}
person Steve Bennett    schedule 20.08.2018