简体   繁体   English

使用turf.js将可拖动点捕捉到Mapbox GL JS中的矢量图块设置线

[英]Snapping a draggable point to a vector tile set line in Mapbox GL JS using turf.js

I'm trying to snap a draggable point to a vector tileset that consists of lines, but I'm not sure if it's possible using a Mapbox vector tileset. 我正在尝试将可拖动点捕捉到由线条组成的矢量tileset,但是我不确定是否可以使用Mapbox矢量tileset。

It's essentially the equivalent of this point snapping example that uses turf.js https://jsfiddle.net/andi_lo/nmc4kprn/5/ which is outlined in the following stack overflow post: Mapbox Icons/Markers "BearingSnap" or Snap to Position 从本质上讲,这与使用turf.js https://jsfiddle.net/andi_lo/nmc4kprn/5/的点捕捉示例等效,该示例在以下堆栈溢出文章中概述: Mapbox图标/标记“ BearingSnap”或“捕捉到位置”

I've amended a basic Mapbox draggable point example to query the rendered features contained in the tileset. 我修改了一个基本的Mapbox可拖动点示例,以查询tileset中包含的渲染特征。 I'm just not sure how to incorporate the measuring and snapping functionality into it. 我只是不确定如何将测量和捕捉功能整合到其中。 I can see in the console log that the coordinates for the feature that I intersect are returned. 我可以在控制台日志中看到返回了我相交的要素的坐标。 Any ideas? 有任何想法吗?

 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> 

It seems possible to me. 在我看来,这是可能的。

You'll need to make two major changes from that Point example. 您需要从该Point示例进行两个主要更改。

First, use queryRenderedFeatures() to fetch all the source vector features that are candidates for snapping to. 首先,使用queryRenderedFeatures()提取所有可捕捉到的源向量特征。 You will probably want to pass a bounding box around the current mouse location, to limit how far you look for candidates. 您可能需要在当前鼠标位置周围传递一个边界框,以限制寻找候选对象的距离。 You will also want to pass a filter for the right layer, and probably limit it to ["==", "$type", "LineString"] 您还将需要为正确的图层传递过滤器,并可能将其限制为["==", "$type", "LineString"]

Second, while iterating over every returned line feature, use Turf's nearestPointOnLine() to both calculate the distance to each line, and find the actual nearest point on that line. 其次,在迭代每个返回的线要素时,使用Turf的最近点nearestPointOnLine()来计算到每条线的距离,并找到该线上的实际最近点。 Something like: 就像是:

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM