使 Leaflet 中的折线对齐道路

7
我正在从数据库加载标记,然后在标记之间绘制折线。我使用折线来计算总距离,而不是必须计算从标记A到标记B再到标记C等的距离。
然而,如果两个标记位于弯曲的道路附近,折线只会将它们连接起来,而不是沿着道路绘制它们,因此我的距离不准确。
我知道Google Maps API可以做到这一点,但使用限制不适合我,这就是为什么我决定使用leaflet的原因。
我的标记之间并不相隔太远,因为我的GPS设备每10秒发送一次位置信息。
我找到了leaflet-routing-machine插件,想知道是否可以使用它来使我的折线贴合道路?
以下是我如何向地图添加标记:
function getlocationsfromdb(){
      group.clearLayers();
      latlngArray.length=0;
      var deviceid = $("#selectid").val();

        $.ajax({
            type: "POST",
            url: "functionhandlers/getlocations.php",
            data: {deviceid:deviceid,start:start,end:end},
            dataType: 'json',
            cache: false,
        })
        .success(function(response) {   
            $('input').removeClass('error').next('.errormessage').html('');
            if(!response.errors && response.result) {

                $.each(response.result, function( index, value) {
                    var latlng = L.latLng(value[7], value[8]);
                    var marker = L.circleMarker(latlng,{radius:2}).addTo(group);    
                    latlngArray.push(latlng);   

               });
                  var polyline = L.polyline(latlngArray, {color: '#605ca8'}).addTo(group);  
                  map.fitBounds(group.getBounds());
                  var distancetravelled=polyline.measuredDistance();
                  $("#distancetravelled").html(distancetravelled);


            } else {
                $.each(response.errors, function( index, value) {
                    // add error classes
                    $('input[name*='+index+']').addClass('error').after('<div class="errormessage">'+value+'</div>')
                });
            }
        }); 
}

请问有人可以指导我吗?

2个回答

7

使用leaflet-routing-machine可以轻松实现此操作。您只需在初始化路由控件时将waypoints设置为latlngArray即可:

var control = L.Routing.control({
  waypoints: latlngArray,
  show: false,
  waypointMode: 'snap',
  createMarker: function() {}
}).addTo(map);

在这里,show: false 防止控件在地图上显示,而空的 createMarker 函数则覆盖了路由机器创建的默认标记,什么也不做(尽管当我们删除控件时标记会被移除,但这可以防止它们在找到路线时在屏幕上闪烁)。
您可以通过监听 routeselected 事件来提取路由机器结果的所有顶点,该事件将返回一个包含路线方向和几何信息的 IRoute 对象。将 .route.coordinates 放入新的 L.polyline 对象中将保留路线,因此我们只需摆脱路由控件即可:
control.on('routeselected', function(e) {
  L.polyline(e.route.coordinates).addTo(group);
  map.removeControl(control);
});

将上述代码块放在您的.success回调函数中,并在填充latlngArray之后,应该能够给您想要的路线。这里是一个示例展示:http://fiddle.jshell.net/nathansnider/ygktexbj/ 此外,如果您没有为路由控件设置其他内容并且希望完全隐藏它(当计算路线时可能仍会出现一个小白色控件框),您可以在CSS中简单地将其隐藏:
.leaflet-routing-container {
  display:none;
}

2
我意识到这个解决方案有点绕,因为它创建了一个控件,然后一半的代码只是防止该控件显示在地图上。虽然我怀疑有一种方法可以在不创建控件的情况下完成此操作,可能直接使用L.Routing.osrm,但我无法从文档中弄清楚。 - nathansnider
太棒了!感谢你花时间向我详细解释,Nathan,非常感激! :) - user5563910
7
小提琴已经坏了 :( - DARKGuy

1
我知道这个解决方案有点绕,因为它创建了一个控件,然后一半的代码都是防止该控件显示在地图上。
实际上,你不必将其添加到地图中。此外,你可以直接攻击内部路由器的route函数。
var routingControl = L.Routing.control({
  waypointMode: 'snap'
});

那么

routingControl._router.route(latLngCoordinates, function(err, waypoints) {
  var a = waypoints;
});

请注意,这是原始的复制/粘贴: - 路点适合内部格式(检查它) - latLngCoordinates必须采用{lat:,lng:}格式 - 它可能需要进行一些清理,因为生成的url封装了一些非常长的“hints”数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接